Skip to content

Commit

Permalink
feat(#6390): update phone widget to allow not checking for dupes (#9340)
Browse files Browse the repository at this point in the history
  • Loading branch information
jkuester authored Aug 22, 2024
1 parent 4692ee7 commit 6a3d444
Show file tree
Hide file tree
Showing 16 changed files with 663 additions and 228 deletions.
18 changes: 1 addition & 17 deletions tests/e2e/default/enketo/enketo-widgets.wdio-spec.js
Original file line number Diff line number Diff line change
Expand Up @@ -47,7 +47,7 @@ describe('Enketo Widgets', () => {
);
};

const verifyReport = async (selectMultiple, selectOne, country, city, neighborhood, uuid, id, name, phoneNumber) => {
const verifyReport = async (selectMultiple, selectOne, country, city, neighborhood, uuid, id, name) => {
const firstReport = await reportsPage.firstReport();
const firstReportInfo = await reportsPage.getListReportInfo(firstReport);

Expand All @@ -73,7 +73,6 @@ describe('Enketo Widgets', () => {
expect((await reportsPage.getDetailReportRowContent('patient_uuid')).rowValues[0]).to.equal(uuid);
expect((await reportsPage.getDetailReportRowContent('patient_id')).rowValues[0]).to.equal(id);
expect((await reportsPage.getDetailReportRowContent('patient_name')).rowValues[0]).to.equal(name);
expect((await reportsPage.getDetailReportRowContent('phone')).rowValues[0]).to.equal(phoneNumber);
};

before(async () => {
Expand Down Expand Up @@ -101,20 +100,6 @@ describe('Enketo Widgets', () => {
expect(await enketoWidgetsPage.getDropdownValue(await enketoWidgetsPage.selectOneDropdown()))
.to.equal('option d');

// try to move to next page without filling the mandatory phone number field
await genericForm.nextPage(1, false);
expect(await enketoWidgetsPage.phoneFieldRequiredMessage().getAttribute('data-i18n'))
.to.equal('constraint.required');

// try to move to next page with an invalid phone number
await commonEnketoPage.setInputValue('Phone Number', '+4076');
await genericForm.nextPage(1, false);
expect(await enketoWidgetsPage.phoneFieldConstraintMessage().getAttribute('data-itext-id'))
.to.equal('/enketo_widgets_test/enketo_test_select/phone:jr:constraintMsg');

// finally set a valid phone number and continue
await commonEnketoPage.setInputValue('Phone Number', phoneNumber);

await genericForm.nextPage();
await fillCascadingWidgetsSection('usa', 'nyc', 'bronx', 3, 2);
await genericForm.submitForm();
Expand Down Expand Up @@ -149,7 +134,6 @@ describe('Enketo Widgets', () => {
await enketoWidgetsPage.selectDropdownOptions(await enketoWidgetsPage.selectOneDropdown(), 'radio', 'a');
expect(await enketoWidgetsPage.getDropdownValue(await enketoWidgetsPage.selectOneDropdown()))
.to.equal('option a');
await commonEnketoPage.setInputValue('Phone Number', phoneNumber);

await genericForm.nextPage();
await fillCascadingWidgetsSection('nl', 'dro', 'havendr', 3, 1);
Expand Down
Binary file modified tests/e2e/default/enketo/forms/enketo_widgets_test.xlsx
Binary file not shown.
95 changes: 42 additions & 53 deletions tests/e2e/default/enketo/forms/enketo_widgets_test.xml
Original file line number Diff line number Diff line change
Expand Up @@ -44,12 +44,6 @@
<text id="/enketo_widgets_test/cascading_widgets:label">
<value>Cascading Select widgets</value>
</text>
<text id="/enketo_widgets_test/enketo_test_select/phone:jr:constraintMsg">
<value>Please enter a valid local number, or use the standard international format, which includes a plus sign (+) and country code. For example: +254712345678</value>
</text>
<text id="/enketo_widgets_test/enketo_test_select/phone:label">
<value>Phone Number</value>
</text>
<text id="/enketo_widgets_test/enketo_test_select/select1_spinner/a:label">
<value>option a</value>
</text>
Expand Down Expand Up @@ -173,11 +167,10 @@
</translation>
</itext>
<instance>
<enketo_widgets_test delimiter="#" id="enketo_widgets_test" prefix="J1!enketo_widgets_test!" version="2023-09-11 00:00:00">
<enketo_widgets_test delimiter="#" id="enketo_widgets_test" prefix="J1!enketo_widgets_test!" version="2024-08-16 00:00:00">
<enketo_test_select>
<select_spinner/>
<select1_spinner/>
<phone/>
</enketo_test_select>
<cascading_widgets>
<group1>
Expand Down Expand Up @@ -217,6 +210,38 @@
</enketo_widgets_test>
</instance>
<instance id="contact-summary"/>
<instance id="list">
<root>
<item>
<itextId>static_instance-list-0</itextId>
<name>a</name>
</item>
<item>
<itextId>static_instance-list-1</itextId>
<name>b</name>
</item>
<item>
<itextId>static_instance-list-2</itextId>
<name>c</name>
</item>
<item>
<itextId>static_instance-list-3</itextId>
<name>d</name>
</item>
</root>
</instance>
<instance id="countries">
<root>
<item>
<itextId>static_instance-countries-0</itextId>
<name>nl</name>
</item>
<item>
<itextId>static_instance-countries-1</itextId>
<name>usa</name>
</item>
</root>
</instance>
<instance id="cities">
<root>
<item>
Expand Down Expand Up @@ -251,99 +276,66 @@
</item>
</root>
</instance>
<instance id="list">
<root>
<item>
<itextId>static_instance-list-0</itextId>
<name>a</name>
</item>
<item>
<itextId>static_instance-list-1</itextId>
<name>b</name>
</item>
<item>
<itextId>static_instance-list-2</itextId>
<name>c</name>
</item>
<item>
<itextId>static_instance-list-3</itextId>
<name>d</name>
</item>
</root>
</instance>
<instance id="neighborhoods">
<root>
<item>
<itextId>static_instance-neighborhoods-0</itextId>
<country>usa</country>
<name>bronx</name>
<city>nyc</city>
<name>bronx</name>
</item>
<item>
<itextId>static_instance-neighborhoods-1</itextId>
<country>usa</country>
<name>harlem</name>
<city>nyc</city>
<name>harlem</name>
</item>
<item>
<itextId>static_instance-neighborhoods-2</itextId>
<country>usa</country>
<name>belair</name>
<city>la</city>
<name>belair</name>
</item>
<item>
<itextId>static_instance-neighborhoods-3</itextId>
<country>nl</country>
<name>wes</name>
<city>ams</city>
<name>wes</name>
</item>
<item>
<itextId>static_instance-neighborhoods-4</itextId>
<country>usa</country>
<name>parkhill</name>
<city>den</city>
<name>parkhill</name>
</item>
<item>
<itextId>static_instance-neighborhoods-5</itextId>
<country>nl</country>
<name>haven</name>
<city>rot</city>
<name>haven</name>
</item>
<item>
<itextId>static_instance-neighborhoods-6</itextId>
<country>nl</country>
<name>dam</name>
<city>ams</city>
<name>dam</name>
</item>
<item>
<itextId>static_instance-neighborhoods-7</itextId>
<country>nl</country>
<name>centrum</name>
<city>rot</city>
<name>centrum</name>
</item>
<item>
<itextId>static_instance-neighborhoods-8</itextId>
<country>nl</country>
<name>havendr</name>
<city>dro</city>
</item>
</root>
</instance>
<instance id="countries">
<root>
<item>
<itextId>static_instance-countries-0</itextId>
<name>nl</name>
</item>
<item>
<itextId>static_instance-countries-1</itextId>
<name>usa</name>
<name>havendr</name>
</item>
</root>
</instance>
<bind nodeset="/enketo_widgets_test/enketo_test_select/select_spinner" type="select"/>
<bind nodeset="/enketo_widgets_test/enketo_test_select/select1_spinner" type="select1"/>
<bind constraint="true()" jr:constraintMsg="jr:itext('/enketo_widgets_test/enketo_test_select/phone:jr:constraintMsg')" nodeset="/enketo_widgets_test/enketo_test_select/phone" required="true()" type="tel"/>
<bind nodeset="/enketo_widgets_test/cascading_widgets/group1/country" type="select1"/>
<bind nodeset="/enketo_widgets_test/cascading_widgets/group1/city" type="select1"/>
<bind nodeset="/enketo_widgets_test/cascading_widgets/group1/neighborhood" type="select1"/>
Expand Down Expand Up @@ -405,9 +397,6 @@
<value>d</value>
</item>
</select1>
<input ref="/enketo_widgets_test/enketo_test_select/phone">
<label ref="jr:itext('/enketo_widgets_test/enketo_test_select/phone:label')"/>
</input>
</group>
<group appearance="field-list" ref="/enketo_widgets_test/cascading_widgets">
<label ref="jr:itext('/enketo_widgets_test/cascading_widgets:label')"/>
Expand Down
Binary file added tests/e2e/default/enketo/forms/phone_widget.xlsx
Binary file not shown.
60 changes: 60 additions & 0 deletions tests/e2e/default/enketo/forms/phone_widget.xml
Original file line number Diff line number Diff line change
@@ -0,0 +1,60 @@
<?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>Phone Widget</h:title>
<model>
<itext>
<translation lang="en">
<text id="/phone_widget/phone_widgets/deprecated_phone:jr:constraintMsg">
<value>Please enter a valid local number, or use the standard international format, which includes a plus sign (+) and country code. For example: +254712345678</value>
</text>
<text id="/phone_widget/phone_widgets/deprecated_phone:label">
<value>Deprecated Phone</value>
</text>
<text id="/phone_widget/phone_widgets/phone:jr:constraintMsg">
<value>Please enter a valid local number, or use the standard international format, which includes a plus sign (+) and country code. For example: +254712345678</value>
</text>
<text id="/phone_widget/phone_widgets/phone:label">
<value>Phone – allow duplicates</value>
</text>
<text id="/phone_widget/phone_widgets/phone_unique:jr:constraintMsg">
<value>Please enter a valid local number, or use the standard international format, which includes a plus sign (+) and country code. For example: +254712345678</value>
</text>
<text id="/phone_widget/phone_widgets/phone_unique:label">
<value>Phone – unique</value>
</text>
</translation>
</itext>
<instance>
<phone_widget delimiter="#" id="phone_widget" prefix="J1!phone_widget!" version="2024-08-16 00:00:00">
<phone_widgets>
<deprecated_phone/>
<phone/>
<phone_unique cht:unique_tel="true"/>
</phone_widgets>
<meta tag="hidden">
<instanceID/>
</meta>
</phone_widget>
</instance>
<instance id="contact-summary"/>
<bind constraint="true()" jr:constraintMsg="jr:itext('/phone_widget/phone_widgets/deprecated_phone:jr:constraintMsg')" nodeset="/phone_widget/phone_widgets/deprecated_phone" required="true()" type="tel"/>
<bind constraint="true()" jr:constraintMsg="jr:itext('/phone_widget/phone_widgets/phone:jr:constraintMsg')" nodeset="/phone_widget/phone_widgets/phone" type="string"/>
<bind constraint="true()" jr:constraintMsg="jr:itext('/phone_widget/phone_widgets/phone_unique:jr:constraintMsg')" nodeset="/phone_widget/phone_widgets/phone_unique" required="true()" type="string"/>
<bind calculate="concat('uuid:', uuid())" nodeset="/phone_widget/meta/instanceID" readonly="true()" type="string"/>
</model>
</h:head>
<h:body class="pages">
<group appearance="field-list" ref="/phone_widget/phone_widgets">
<input ref="/phone_widget/phone_widgets/deprecated_phone">
<label ref="jr:itext('/phone_widget/phone_widgets/deprecated_phone:label')"/>
</input>
<input appearance="numbers tel" ref="/phone_widget/phone_widgets/phone">
<label ref="jr:itext('/phone_widget/phone_widgets/phone:label')"/>
</input>
<input appearance="numbers tel" ref="/phone_widget/phone_widgets/phone_unique">
<label ref="jr:itext('/phone_widget/phone_widgets/phone_unique:label')"/>
</input>
</group>
</h:body>
</h:html>
78 changes: 78 additions & 0 deletions tests/e2e/default/enketo/phone-widget.wdio-spec.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,78 @@
const commonPage = require('@page-objects/default/common/common.wdio.page');
const reportsPage = require('@page-objects/default/reports/reports.wdio.page');
const utils = require('@utils');
const loginPage = require('@page-objects/default/login/login.wdio.page');
const genericForm = require('@page-objects/default/enketo/generic-form.wdio.page');
const contactsPage = require('@page-objects/default/contacts/contacts.wdio.page');
const commonEnketoPage = require('@page-objects/default/enketo/common-enketo.wdio.page');
const personFactory = require('@factories/cht/contacts/person');
const { expect } = require('chai');

describe('Phone widget', () => {
const phone = '+254712345678';
const person0 = personFactory.build({ phone });
const person1 = personFactory.build({ phone: '+254712345679' });

before(async () => {
await commonEnketoPage.uploadForm('phone_widget');
await utils.saveDocs([person0, person1]);
await loginPage.cookieLogin();
await commonPage.hideSnackbar();
});

// Only testing the duplicate checking logic here.
// The rest of the phone widget logic is covered by the cht-form integration tests

it('duplicate phone numbers violate constraint when configured in app form', async () => {
await commonPage.goToReports();

await commonPage.openFastActionReport('phone_widget', false);

await commonEnketoPage.setInputValue('Deprecated Phone', phone);
await commonEnketoPage.setInputValue('Phone – allow duplicates', phone);
await commonEnketoPage.setInputValue('Phone – unique', phone);

expect(await commonEnketoPage.isConstraintMessageDisplayed('Deprecated Phone')).to.be.true;
expect(await commonEnketoPage.isConstraintMessageDisplayed('Phone – allow duplicates')).to.be.false;
expect(await commonEnketoPage.isConstraintMessageDisplayed('Phone – unique')).to.be.true;

await commonEnketoPage.setInputValue('Deprecated Phone', '+254712345671');
await commonEnketoPage.setInputValue('Phone – unique', '+254712345674');

expect(await commonEnketoPage.isConstraintMessageDisplayed('Deprecated Phone')).to.be.false;
expect(await commonEnketoPage.isConstraintMessageDisplayed('Phone – unique')).to.be.false;

await genericForm.submitForm();

const reportId = await reportsPage.getCurrentReportId();
const { fields } = await utils.getDoc(reportId);
expect(fields).excluding(['meta']).to.deep.equal({
phone_widgets: {
deprecated_phone: '+254712345671',
phone,
phone_unique: '+254712345674',
}
});
});

it('can use duplicate phone number when editing contact with same number', async () => {
await commonPage.goToPeople(person1._id);
await contactsPage.openEditContactForm();

await (await genericForm.nextPage());
// Try setting phone to number of the other person
await commonEnketoPage.setInputValue('Phone Number', person0.phone);

expect(await commonEnketoPage.isConstraintMessageDisplayed('Phone Number')).to.be.true;

// Reset phone back to original value for this person
await commonEnketoPage.setInputValue('Phone Number', person1.phone);

expect(await commonEnketoPage.isConstraintMessageDisplayed('Phone Number')).to.be.false;

await genericForm.submitForm();

const editedPerson = await utils.getDoc(person1._id);
expect(editedPerson.phone).to.equal(person1.phone);
});
});
16 changes: 0 additions & 16 deletions tests/integration/cht-form/default/enketo-widgets.wdio-spec.js
Original file line number Diff line number Diff line change
Expand Up @@ -22,21 +22,6 @@ describe('cht-form web component - Enketo Widgets', () => {
expect(await enketoWidgetsPage.getDropdownValue(await enketoWidgetsPage.selectOneDropdown()))
.to.equal('option d');

// try to move to next page without filling the mandatory phone number field
await genericForm.nextPage(1, false);
expect(await enketoWidgetsPage.phoneFieldRequiredMessage().getAttribute('data-i18n'))
.to.equal('constraint.required');

// try to move to next page with an invalid phone number
await commonEnketoPage.setInputValue('Phone Number', '+4076');
await genericForm.nextPage(1, false);
expect(await enketoWidgetsPage.phoneFieldConstraintMessage().getAttribute('data-itext-id'))
.to.equal('/enketo_widgets_test/enketo_test_select/phone:jr:constraintMsg');

// finally set a valid phone number and continue
await commonEnketoPage.setInputValue('Phone Number', '+40766565656');

await $('.form-footer').click();
await genericForm.nextPage();

await commonEnketoPage.selectRadioButton('Country', 'United States');
Expand Down Expand Up @@ -76,7 +61,6 @@ describe('cht-form web component - Enketo Widgets', () => {
expect(jsonObj.patient_name).to.equal('Elias');
expect(jsonObj.enketo_test_select.select_spinner).to.equal('a c');
expect(jsonObj.enketo_test_select.select1_spinner).to.equal('d');
expect(jsonObj.enketo_test_select.phone).to.equal('+40766565656');
expect(jsonObj.cascading_widgets.group1.country).to.equal('usa');
expect(jsonObj.cascading_widgets.group1.city).to.equal('nyc');
expect(jsonObj.cascading_widgets.group1.neighborhood).to.equal('bronx');
Expand Down
Loading

0 comments on commit 6a3d444

Please sign in to comment.