Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

fix(#8225): fix handling of inputs group with contact selector #9382

Merged
merged 6 commits into from
Sep 10, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
50 changes: 43 additions & 7 deletions tests/e2e/default/enketo/db-object-widget.wdio-spec.js
Original file line number Diff line number Diff line change
Expand Up @@ -20,26 +20,62 @@ describe('DB Object Widget', () => {
});

const offlineUser = userFactory.build({ place: districtHospital._id, roles: [ 'chw' ] });
offlineUser.contact.sex = 'female';
const personArea1 = personFactory.build({ parent: { _id: area1._id, parent: area1.parent } });
const personArea2 = personFactory.build({ name: 'Patricio', parent: { _id: area2._id, parent: area2.parent } });

before(async () => {
await commonEnketoPage.uploadForm('db-object-widget');
await commonEnketoPage.uploadForm('db-object-form');
await utils.saveDocs([ ...places.values(), area2, personArea1, personArea2 ]);
await utils.createUsers([ offlineUser ]);
await loginPage.login(offlineUser);
});

it('should load contacts in non-relevant inputs group and from calculations', async () => {
await commonPage.goToReports();
await commonPage.openFastActionReport('db-object-form', false);

await genericForm.submitForm();

const reportId = await reportsPage.getCurrentReportId();
await commonPage.sync();
const { fields } = await utils.getDoc(reportId);
expect(fields).excluding(['meta']).to.deep.equal({
inputs: {
meta: { location: { lat: '', long: '', error: '', message: '' } },
user: {
contact_id: offlineUser.contact._id,
name: offlineUser.contact.name,
sex: offlineUser.contact.sex
},
user_contact: {
_id: offlineUser.contact._id,
name: offlineUser.contact.name,
sex: offlineUser.contact.sex
},
},
people: {
user_contact: {
_id: offlineUser.contact._id,
name: offlineUser.contact.name,
sex: offlineUser.contact.sex
},
person_test_same_parent: '',
person_test_all: ''
},
});
});

it('should display only the contacts from the parent contact', async () => {
await commonPage.goToPeople(area1._id);
await commonPage.openFastActionReport('db-object-widget');
await commonPage.openFastActionReport('db-object-form');

const sameParent = await genericForm.getDBObjectWidgetValues('/db_object_form/people/person_test_same_parent');
const sameParent = await genericForm.getDBObjectWidgetValues('/db-object-form/people/person_test_same_parent');
await sameParent[0].click();
expect(sameParent.length).to.equal(1);
expect(sameParent[0].name).to.equal(personArea1.name);

const allContacts = await genericForm.getDBObjectWidgetValues('/db_object_form/people/person_test_all');
const allContacts = await genericForm.getDBObjectWidgetValues('/db-object-form/people/person_test_all');
await allContacts[2].click();
expect(allContacts.length).to.equal(3);
expect(allContacts[0].name).to.equal(personArea1.name);
Expand All @@ -51,12 +87,12 @@ describe('DB Object Widget', () => {

const firstReport = await reportsPage.getListReportInfo(await reportsPage.firstReport());
expect(firstReport.heading).to.equal(offlineUser.contact.name);
expect(firstReport.form).to.equal('db-object-widget');
expect(firstReport.form).to.equal('db-object-form');

await reportsPage.openReport(firstReport.dataId);
expect((await reportsPage.getDetailReportRowContent('report.db-object-widget.people.person_test_same_parent'))
expect((await reportsPage.getDetailReportRowContent('report.db-object-form.people.person_test_same_parent'))
.rowValues[0]).to.equal(personArea1._id);
expect((await reportsPage.getDetailReportRowContent('report.db-object-widget.people.person_test_all'))
expect((await reportsPage.getDetailReportRowContent('report.db-object-form.people.person_test_all'))
.rowValues[0]).to.equal(personArea2._id);
});

Expand Down
Binary file not shown.
89 changes: 89 additions & 0 deletions tests/e2e/default/enketo/forms/db-object-form.xml
Original file line number Diff line number Diff line change
@@ -0,0 +1,89 @@
<?xml version="1.0"?>
<h:html xmlns="http://www.w3.org/2002/xforms" xmlns:cht="https://communityhealthtoolkit.org" xmlns:ev="http://www.w3.org/2001/xml-events" xmlns:h="http://www.w3.org/1999/xhtml" xmlns:jr="http://openrosa.org/javarosa" xmlns:orx="http://openrosa.org/xforms" xmlns:xsd="http://www.w3.org/2001/XMLSchema">
<h:head>
<h:title>DB Object Form</h:title>
<model>
<itext>
<translation lang="en">
<text id="/db-object-form/people/person_test_all:label">
<value>Select a person from all</value>
</text>
<text id="/db-object-form/people/person_test_same_parent:label">
<value>Select a person from the same parent</value>
</text>
</translation>
</itext>
<instance>
<db-object-form delimiter="#" id="db-object-form" prefix="J1!db-object-form!" version="2024-09-05 00:00:00">
<inputs>
<meta>
<location>
<lat/>
<long/>
<error/>
<message/>
</location>
</meta>
<user>
<contact_id/>
<name/>
<sex/>
</user>
<user_contact>
<_id/>
<name/>
<sex/>
</user_contact>
</inputs>
<people>
<user_contact>
<_id/>
<name/>
<sex/>
</user_contact>
<person_test_same_parent/>
<person_test_all/>
</people>
<meta tag="hidden">
<instanceID/>
</meta>
</db-object-form>
</instance>
<instance id="contact-summary"/>
<bind nodeset="/db-object-form/inputs" relevant="false()"/>
<bind nodeset="/db-object-form/inputs/user/contact_id" type="string"/>
<bind nodeset="/db-object-form/inputs/user/name" type="string"/>
<bind nodeset="/db-object-form/inputs/user/sex" type="string"/>
<bind calculate="../../user/contact_id" nodeset="/db-object-form/inputs/user_contact/_id" type="string"/>
<bind nodeset="/db-object-form/inputs/user_contact/name" type="string"/>
<bind nodeset="/db-object-form/inputs/user_contact/sex" type="string"/>
<bind calculate="../../../inputs/user/contact_id" nodeset="/db-object-form/people/user_contact/_id" type="string"/>
<bind nodeset="/db-object-form/people/user_contact/name" type="string"/>
<bind nodeset="/db-object-form/people/user_contact/sex" type="string"/>
<bind nodeset="/db-object-form/people/person_test_same_parent" type="string"/>
<bind nodeset="/db-object-form/people/person_test_all" type="string"/>
<bind calculate="concat('uuid:', uuid())" nodeset="/db-object-form/meta/instanceID" readonly="true()" type="string"/>
</model>
</h:head>
<h:body class="pages">
<group ref="/db-object-form/inputs">
<group ref="/db-object-form/inputs/user">
<input appearance="hidden select-contact type-person" ref="/db-object-form/inputs/user/contact_id"/>
</group>
<group ref="/db-object-form/inputs/user_contact">
<input appearance="hidden select-contact type-person" ref="/db-object-form/inputs/user_contact/_id"/>
</group>
</group>
<group appearance="field-list" ref="/db-object-form/people">
<group ref="/db-object-form/people/user_contact">
<input appearance="hidden select-contact type-person" ref="/db-object-form/people/user_contact/_id"/>
</group>
<input appearance="select-contact type-person descendant-of-current-contact" ref="/db-object-form/people/person_test_same_parent">
<label ref="jr:itext('/db-object-form/people/person_test_same_parent:label')"/>
</input>
<input appearance="select-contact type-person" ref="/db-object-form/people/person_test_all">
<label ref="jr:itext('/db-object-form/people/person_test_all:label')"/>
</input>
</group>
</h:body>
</h:html>
32 changes: 0 additions & 32 deletions tests/e2e/default/enketo/forms/db-object-widget.xml

This file was deleted.

Original file line number Diff line number Diff line change
Expand Up @@ -247,7 +247,7 @@ describe('Contact Delivery Form', () => {
source_id: '',
user: {
contact_id: offlineUser.contact._id,
name: offlineUser.username,
name: offlineUser.contact.name,
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This change actually demonstrates this fix in action! The regression scenario from the forum was doing the exact same thing as the delivery form where they are trying to load the user's contact document directly into the inputs/user group. The complication is that the inputs/user group already contains data from the users user-settings doc. So, when you use the contact selector to load the user's contact into the same group, it will override the data that is already there.

In this case, both the user's contact and the user-settings document contain a name field. For the user-settings it is the username. For the contact, it is just the normal contact name value. Because the contact-selector functionality in non-relevant inputs was broken before this PR, the user's contact data was not actually being loaded and so the name was just populated with the username from the user-settings document. Now that this PR has fixed the contact selector functionality, we see inputs/user/name getting overridden with the value from the user's contact (which is the proper behavior that we expect).

phone: offlineUser.contact.phone,
},
contact: {
Expand Down
35 changes: 20 additions & 15 deletions webapp/patches/enketo-core+7.2.5.patch
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@ index 62003af..db02cba 100644
@@ -939,6 +939,10 @@ Form.prototype.getDataStrWithoutIrrelevantNodes = function () {
const path = that.input.getName(node);
let target;

+ // CHT-CORE PATCH
+ // /inputs is ALWAYS relevant #4875
+ if(/\/inputs$/.test(path)) return;
Expand All @@ -14,20 +14,25 @@ index 62003af..db02cba 100644
* Copied from relevant.js:
*
diff --git a/node_modules/enketo-core/src/js/relevant.js b/node_modules/enketo-core/src/js/relevant.js
index 463af2c..f7dbe4d 100644
index 463af2c..d10ec81 100644
--- a/node_modules/enketo-core/src/js/relevant.js
+++ b/node_modules/enketo-core/src/js/relevant.js
@@ -458,7 +458,9 @@ export default {
: currentValue,
});
} else {
- if (isLeafNode && textContent !== '') {
+ // CHT PATCH
+ // /inputs is ALWAYS relevant #4875
+ if (isLeafNode && textContent !== '' && !path.endsWith('/inputs')) {
node.textContent = '';
}

@@ -265,7 +265,14 @@ export default {
alreadyCovered.push(node.getAttribute('name'));
}

- if (
+ // CHT-CORE PATCH
+ // /inputs is ALWAYS relevant #4875
+ if(!result && /^\/[^/]+\/inputs$/.test(path)) {
+ this.enable(branchNode, path, options);
+ branchChange = true;
+ branchNode.classList.add('disabled');
+ }
+ else if (
this.process(branchNode, path, result, forceClearNonRelevant, {
...options,
repeatIndex: ind,
diff --git a/node_modules/enketo-core/src/widget/date/datepicker-extended.js b/node_modules/enketo-core/src/widget/date/datepicker-extended.js
index 6febee3..afbf8df 100644
--- a/node_modules/enketo-core/src/widget/date/datepicker-extended.js
Expand All @@ -42,7 +47,7 @@ index 6febee3..afbf8df 100644
+ $fakeDateI.blur();
});
}

diff --git a/node_modules/enketo-core/src/widget/datetime/datetimepicker-extended.js b/node_modules/enketo-core/src/widget/datetime/datetimepicker-extended.js
index 4a71bfa..7c72f94 100644
--- a/node_modules/enketo-core/src/widget/datetime/datetimepicker-extended.js
Expand All @@ -57,4 +62,4 @@ index 4a71bfa..7c72f94 100644
+ $els.eq(0).blur();
});
}