Skip to content

Commit

Permalink
Removes need for report xml attachments (#7596)
Browse files Browse the repository at this point in the history
Instead of relying on xml attachments, uses report fields to populate form model on report edits.

Some changes have been required:
(1) db-doc fields will be saved in the main report fields. To maintain old report content display, these fields will become "hidden".
(2) Because of (1), it's not safe to default to using fields when editing a report that has a content attachment, so if the content attachment exists, it will be used to populate the form, but it will be deleted upon saving.
(3) bindJsonToXml is refactored so it treats arrays (repeats) correctly.

Limitations:
- Editing a report that created extra docs duplicates all extra docs #7594 - this behavior existed before
- Reports created as extra docs in forms are not editable #7605 - the additional context part
- Reports created as extra docs might not always be faithful to the model of the form itself.

Migrates a bunch of e2e tests from protractor to wdio.

#5549
  • Loading branch information
dianabarsan committed Sep 7, 2022
1 parent 922abab commit 58ea748
Show file tree
Hide file tree
Showing 30 changed files with 1,723 additions and 656 deletions.
2 changes: 1 addition & 1 deletion config/default/forms/contact/clinic-create.xml
Expand Up @@ -1023,7 +1023,7 @@ DOB ISO: <output value=" /data/contact/ephemeral_dob/dob_iso "/></value></text>
<bind nodeset="/data/contact/ephemeral_dob/age_months" type="int" relevant="selected(../dob_method,'approx')" jr:constraintMsg="Months must between 0 and 11" constraint=". &gt;= 0 and . &lt;= 11"/>
<bind nodeset="/data/contact/ephemeral_dob/dob_method" type="select"/>
<bind nodeset="/data/contact/ephemeral_dob/dob_approx" type="string" calculate="add-date(today(), 0- /data/contact/ephemeral_dob/age_years , 0- /data/contact/ephemeral_dob/age_months )"/>
<bind nodeset="/data/contact/ephemeral_dob/dob_raw" type="string" calculate="if(not(selected( ../dob_method,'approx')),
<bind nodeset="/data/contact/ephemeral_dob/dob_raw" type="string" calculate="if(not(selected( ../dob_method,'approx')),
../dob_calendar,
../dob_approx)"/>
<bind nodeset="/data/contact/ephemeral_dob/dob_iso" type="string" calculate="format-date-time(../dob_raw,&quot;%Y-%m-%d&quot;)"/>
Expand Down
110 changes: 110 additions & 0 deletions tests/e2e/default/enketo/edit-report-with-attachment.wdio-spec.js
@@ -0,0 +1,110 @@
const genericForm = require('../../../page-objects/forms/generic-form.wdio.page');
const reportsPage = require('../../../page-objects/reports/reports.wdio.page');
const uuid = require('uuid').v4;
const common = require('../../../page-objects/common/common.wdio.page');
const loginPage = require('../../../page-objects/login/login.wdio.page');
const utils = require('../../../utils');
const userData = require('../../../page-objects/forms/data/user.po.data');
const fs = require('fs');
const commonElements = require('../../../page-objects/common/common.wdio.page');
const oneTextForm = fs.readFileSync(`${__dirname}/forms/one-text-form.xml`, 'utf8');

const instanceID = uuid();
const reportModelXml = `
<one_text_form xmlns:jr="http://openrosa.org/javarosa" id="required_note">
<intro>initial text</intro>
<meta>
<instanceID>uuid:${instanceID}</instanceID>
<deprecatedID/>
</meta>
</one_text_form>`;

const { userContactDoc, docs } = userData;
const formDoc = {
_id: 'form:one_text_form',
internalId: 'one_text_form',
title: 'One text form',
type: 'form',
_attachments: {
xml: {
content_type: 'application/octet-stream',
data: Buffer.from(oneTextForm).toString('base64'),
}
}
};
const reportDoc ={
_id: uuid(),
form: formDoc.internalId,
type: 'data_record',
reported_date: Date.now(),
content_type: 'xml',
contact: userContactDoc,
hidden_fields: ['meta'],
fields: {
// to prove that when xml attachment exists, it is used to populate edit form instead of fields
intro: 'not same text as in xml attachment',
meta: {
instanceID: `uuid:${instanceID}`,
deprecatedID: ''
}
},
_attachments: {
content: {
content_type: 'application/octet-stream',
data: Buffer.from(reportModelXml).toString('base64'),
}
}
};


describe('Edit report with attachmnet', () => {
before(async () => {
await utils.seedTestData(userContactDoc, [...docs, formDoc]);
await loginPage.cookieLogin();
await common.hideSnackbar();
});

it('should remove attachment when saving', async () => {
reportDoc._id = uuid();
await utils.saveDoc(reportDoc);

await commonElements.goToReports();

await reportsPage.editReport(reportDoc._id);
// await browser.debug();
await reportsPage.submitForm();

const editedReport = await utils.getDoc(reportDoc._id);
expect(editedReport._attachments).to.be.undefined;
expect(editedReport.fields).excludingEvery('meta').to.deep.equal({ intro: 'initial text' });

await reportsPage.editReport(reportDoc._id);
await reportsPage.submitForm();

const twiceEditedReport = await utils.getDoc(reportDoc._id);
expect(editedReport._attachments).to.be.undefined;
expect(twiceEditedReport.fields).excludingEvery('meta').to.deep.equal({ intro: 'initial text' });
});

it('should save edits', async () => {
reportDoc._id = uuid();
await utils.saveDoc(reportDoc);

await commonElements.goToReports();
await reportsPage.editReport(reportDoc._id);
await (await genericForm.fieldByName(formDoc.internalId, 'intro')).setValue('updated text');
await reportsPage.submitForm();

const editedReport = await utils.getDoc(reportDoc._id);
expect(editedReport._attachments).to.be.undefined;
expect(editedReport.fields).excludingEvery('meta').to.deep.equal({ intro: 'updated text' });

await reportsPage.editReport(reportDoc._id);
await (await genericForm.fieldByName(formDoc.internalId, 'intro')).setValue('twice updated text');
await reportsPage.submitForm();

const twiceEditedReport = await utils.getDoc(reportDoc._id);
expect(twiceEditedReport._attachments).to.be.undefined;
expect(twiceEditedReport.fields).excludingEvery('meta').to.deep.equal({ intro: 'twice updated text' });
});
});
23 changes: 23 additions & 0 deletions tests/e2e/default/enketo/forms/one-text-form.xml
@@ -0,0 +1,23 @@
<?xml version="1.0"?>
<h:html xmlns="http://www.w3.org/2002/xforms" xmlns:h="http://www.w3.org/1999/xhtml" xmlns:ev="http://www.w3.org/2001/xml-events" xmlns:xsd="http://www.w3.org/2001/XMLSchema" xmlns:jr="http://openrosa.org/javarosa" xmlns:orx="http://openrosa.org/xforms">
<h:head>
<h:title>One text form</h:title>
<model>
<instance>
<one_text_form id="one_text_form" prefix="J1!one_text_form!" delimiter="#" version="2021-12-01 00:00:00">
<intro/>
<meta tag="hidden">
<instanceID/>
</meta>
</one_text_form>
</instance>
<bind nodeset="/one_text_form/intro" type="string" required="true()"/>
<bind nodeset="/one_text_form/meta/instanceID" type="string" readonly="true()" calculate="concat('uuid:', uuid())"/>
</model>
</h:head>
<h:body class="pages">
<input ref="/one_text_form/intro">
<label>Enter text</label>
</input>
</h:body>
</h:html>
69 changes: 66 additions & 3 deletions tests/e2e/default/enketo/pregnancy-danger-sign.wdio-spec.js
Expand Up @@ -27,15 +27,17 @@ describe('Pregnancy danger sign follow-up form', () => {
await utils.saveDoc(formDocument);
await utils.seedTestData(userData.userContactDoc, userData.docs);
await loginPage.cookieLogin();
await commonPage.goToReports();
await commonPage.hideSnackbar();
});

it('Submit and validate Pregnancy danger sign follow-up form and keeps the report minified', async () => {
await commonPage.goToReports();

await reportsPage.openForm('Pregnancy danger sign follow-up');
await pregnancyDangerSignForm.selectPatient('jack');
await genericForm.nextPage();
await pregnancyDangerSignForm.selectVisitedHealthFacility();
await pregnancyDangerSignForm.selectNoDangerSigns();
await pregnancyDangerSignForm.selectVisitedHealthFacility(true);
await pregnancyDangerSignForm.selectDangerSigns(false);
await reportsPage.submitForm();

const reportId = await reportsPage.getCurrentReportId();
Expand All @@ -54,4 +56,65 @@ describe('Pregnancy danger sign follow-up form', () => {
expect(validatedReport.verified).to.be.true;
expect(validatedReport.patient).to.be.undefined;
});

it('should submit and edit Pregnancy danger sign follow-up form (no changes)', async () => {
await commonPage.goToReports();

await reportsPage.openForm('Pregnancy danger sign follow-up');
await pregnancyDangerSignForm.selectPatient('jill');
await genericForm.nextPage();
await pregnancyDangerSignForm.selectVisitedHealthFacility(true);
await pregnancyDangerSignForm.selectDangerSigns(false);
await reportsPage.submitForm();

const reportId = await reportsPage.getCurrentReportId();
const initialReport = await utils.getDoc(reportId);

expect(initialReport._attachments).to.equal(undefined);

await reportsPage.editReport(reportId);
await genericForm.nextPage();
await reportsPage.submitForm();

const updatedReport = await utils.getDoc(reportId);
expect(updatedReport.fields).excludingEvery('instanceID').to.deep.equal(initialReport.fields);

});

it('should submit and edit Pregnancy danger sign follow-up form with changes', async () => {
await commonPage.goToReports();

await reportsPage.openForm('Pregnancy danger sign follow-up');
await pregnancyDangerSignForm.selectPatient('jill');
await genericForm.nextPage();
await pregnancyDangerSignForm.selectVisitedHealthFacility(true);
await pregnancyDangerSignForm.selectDangerSigns(false);
await reportsPage.submitForm();

const reportId = await reportsPage.getCurrentReportId();
const initialReport = await utils.getDoc(reportId);

expect(initialReport._attachments).to.equal(undefined);

await reportsPage.editReport(reportId);
await pregnancyDangerSignForm.selectPatient('jack');
await genericForm.nextPage();
await pregnancyDangerSignForm.selectVisitedHealthFacility(false);
await pregnancyDangerSignForm.selectDangerSigns(true);
await reportsPage.submitForm();

const updatedReport = await utils.getDoc(reportId);

await reportsPage.openForm('Pregnancy danger sign follow-up');
await pregnancyDangerSignForm.selectPatient('jack');
await genericForm.nextPage();
await pregnancyDangerSignForm.selectVisitedHealthFacility(false);
await pregnancyDangerSignForm.selectDangerSigns(true);
await reportsPage.submitForm();

const compareReportId = await reportsPage.getCurrentReportId();
const compareReport = await utils.getDoc(compareReportId);

expect(updatedReport.fields).excludingEvery('instanceID').to.deep.equal(compareReport.fields);
});
});
4 changes: 2 additions & 2 deletions tests/e2e/default/enketo/pregnancy-visit.wdio-spec.js
Expand Up @@ -33,13 +33,13 @@ describe('Pregnancy Visit', () => {
const firstReport = await reportsPage.getListReportInfo(await reportsPage.firstReport());
expect(firstReport.heading).to.equal(userData.userContactDoc.name);
expect(firstReport.form).to.equal('Pregnancy Visit');
expect(firstReport.lineage).to.equal(userData.userContactDoc.parent.name);
expect(firstReport.lineage).to.equal(userData.docs[0].name);

//report details
expect(await (await reportsPage.submitterName()).getText())
.to.equal(`Submitted by ${userData.userContactDoc.name} `);
expect(await (await reportsPage.submitterPhone()).getText()).to.equal(userData.userContactDoc.phone);
expect(await (await reportsPage.submitterPlace()).getText()).to.equal(userData.userContactDoc.parent.name);
expect(await (await reportsPage.submitterPlace()).getText()).to.equal(userData.docs[0].name);
expect(await (await reportsPage.selectedCaseId()).getText()).to.match(/^\d{5}$/);
});
});
Expand Down

0 comments on commit 58ea748

Please sign in to comment.