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

feat: add support for Enekto draw widget in forms #8904

Merged
merged 15 commits into from
Jun 14, 2024
Merged
Show file tree
Hide file tree
Changes from 11 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
3 changes: 3 additions & 0 deletions .sonarcloud.properties
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,9 @@ sonar.python.version=3
sonar.issue.ignore.allfile=r1
# Do not analyze since it is copied from https://github.com/enketo/enketo-transformer
sonar.issue.ignore.allfile.r1.fileRegexp=**/openrosa2html5form.xsl
# Do not analyze since it is copied from https://github.com/enketo/enketo
sonar.issue.ignore.allfile.r2.fileRegexp=**/draw.scss
sonar.issue.ignore.allfile.r3.fileRegexp=**/draw.js

sonar.issue.ignore.block=e1
sonar.issue.ignore.block.e1.beginBlockRegexp=NOSONAR_BEGIN
Expand Down
3 changes: 3 additions & 0 deletions api/resources/translations/messages-en.properties
Original file line number Diff line number Diff line change
Expand Up @@ -638,6 +638,9 @@ email.invalid = Invalid email address.
empty = It looks like you sent an empty message, please try to resend. If you continue to have this problem please contact your supervisor.
enketo.constraint.invalid = Value not allowed
enketo.constraint.required = This field is required
enketo.drawwidget.signature = signature
enketo.drawwidget.drawing = drawing
enketo.drawwidget.annotation = annotation
jkuester marked this conversation as resolved.
Show resolved Hide resolved
enketo.error.max_attachment_size = The uploaded files exceed the total size limit. Please upload smaller files.
enketo.form.required = required
enketo.filepicker.file = file
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -27,7 +27,9 @@ describe('Submit Photo Upload form', () => {
it('submit and edit (no changes)', async () => {
const reportId = await reportsPage.getCurrentReportId();
const initialReport = await utils.getDoc(reportId);
expect(Object.keys(initialReport._attachments)).to.deep.equal(['user-file/photo-upload/my_photo']);
const attachmentNames = Object.keys(initialReport._attachments);
expect(attachmentNames).to.have.lengthOf(1);
expect(attachmentNames[0]).to.match(/^user-file-photo-for-upload-form-\d\d?_\d\d?_\d\d?\.png$/);

await reportsPage.openReport(reportId);
await reportsPage.editReport();
Expand All @@ -44,7 +46,9 @@ describe('Submit Photo Upload form', () => {
it('submit and edit (with changes)', async () => {
const reportId = await reportsPage.getCurrentReportId();
const initialReport = await utils.getDoc(reportId);
expect(Object.keys(initialReport._attachments)).to.deep.equal(['user-file/photo-upload/my_photo']);
const attachmentNames = Object.keys(initialReport._attachments);
expect(attachmentNames).to.have.lengthOf(1);
expect(attachmentNames[0]).to.match(/^user-file-photo-for-upload-form-\d\d?_\d\d?_\d\d?\.png$/);

await reportsPage.openReport(reportId);
await reportsPage.editReport();
Expand Down
33 changes: 33 additions & 0 deletions tests/integration/cht-form/default/draw-widget.wdio-spec.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,33 @@
const mockConfig = require('../mock-config');
const commonEnketoPage = require('@page-objects/default/enketo/common-enketo.wdio.page');
const path = require('path');

describe('cht-form web component - Draw Widget', () => {
it('supports attaching drawn images to report', async () => {
await mockConfig.loadForm('default', 'test', 'draw-widget');

await commonEnketoPage.drawShapeOnCanvas('Draw widget');
await commonEnketoPage.drawShapeOnCanvas('Signature widget');
const filePath = path.join(__dirname, '/../../../e2e/default/enketo/images/photo-for-upload-form.png');
await commonEnketoPage.addFileInputValue('Annotate image widget', filePath);
await commonEnketoPage.drawShapeOnCanvas('Annotate image widget');

const [doc] = await mockConfig.submitForm();

const drawName = doc.fields.media_widgets.draw;
expect(drawName).to.match(/^drawing-\d\d?_\d\d?_\d\d?\.png$/);
const drawAttachmentName = `user-file-${drawName}`;
const signatureName = doc.fields.media_widgets.signature;
expect(signatureName).to.match(/^signature-\d\d?_\d\d?_\d\d?\.png$/);
const signatureAttachmentName = `user-file-${signatureName}`;
const annotateName = doc.fields.media_widgets.annotate;
expect(annotateName).to.match(/^annotation-\d\d?_\d\d?_\d\d?\.png$/);
const annotateAttachmentName = `user-file-${annotateName}`;
expect(doc._attachments).to.have.all.keys(drawAttachmentName, signatureAttachmentName, annotateAttachmentName);
const contentTypes = Object.values(doc._attachments).map(({ content_type }) => content_type);
expect(contentTypes).to.deep.equal(['image/png', 'image/png', 'image/png']);
expect(doc._attachments[drawAttachmentName].data.size).to.be.closeTo(19600, 2000);
expect(doc._attachments[signatureAttachmentName].data.size).to.be.closeTo(12800, 2000);
expect(doc._attachments[annotateAttachmentName].data.size).to.be.closeTo(29000, 2000);
});
});
29 changes: 29 additions & 0 deletions tests/integration/cht-form/default/file-upload.wdio-spec.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,29 @@
const mockConfig = require('../mock-config');
const commonEnketoPage = require('@page-objects/default/enketo/common-enketo.wdio.page');
const path = require('path');

describe('cht-form web component - File upload', () => {
const imagePath0 = path.join(__dirname, '../../../e2e/default/enketo/images/photo-for-upload-form.png');
const imagePath1 = path.join(__dirname, '../../../../webapp/src/img/layers.png');

it('attaches multiple images selected in a repeat', async () => {
await mockConfig.loadForm('default', 'test', 'file-upload');

await commonEnketoPage.addRepeatSection();
await commonEnketoPage.addFileInputValue('Upload image', imagePath0, { repeatIndex: 0 });
await commonEnketoPage.addRepeatSection();
await commonEnketoPage.addFileInputValue('Upload image', imagePath1, { repeatIndex: 1 });

const [doc] = await mockConfig.submitForm();

const attachmentNames = Object.keys(doc._attachments);
expect(attachmentNames).to.have.lengthOf(2);
expect(attachmentNames[1]).to.match(/^user-file-photo-for-upload-form-\d\d?_\d\d?_\d\d?\.png$/);
expect(attachmentNames[0]).to.match(/^user-file-layers-\d\d?_\d\d?_\d\d?\.png$/);

expect(doc.fields.files.images).to.have.lengthOf(2);
const [{ image: image0 }, { image: image1 }] = doc.fields.files.images;
expect(image0).to.equal(attachmentNames[1].substring(10));
expect(image1).to.equal(attachmentNames[0].substring(10));
});
});
Binary file not shown.
55 changes: 55 additions & 0 deletions tests/integration/cht-form/default/forms/draw-widget.xml
Original file line number Diff line number Diff line change
@@ -0,0 +1,55 @@
<?xml version="1.0"?>
<h:html xmlns="http://www.w3.org/2002/xforms" 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>Draw Widget</h:title>
<model>
<itext>
<translation lang="en">
<text id="/draw-widget/media_widgets/annotate:label">
<value>Annotate image widget</value>
</text>
<text id="/draw-widget/media_widgets/draw:label">
<value>Draw widget</value>
</text>
<text id="/draw-widget/media_widgets/signature:label">
<value>Signature widget</value>
</text>
<text id="/draw-widget/media_widgets:label">
<value>Media input widgets</value>
</text>
</translation>
</itext>
<instance>
<draw-widget delimiter="#" id="draw-widget" prefix="J1!draw-widget!" version="2024-06-07 00:00:00">
<media_widgets>
<draw/>
<signature/>
<annotate/>
</media_widgets>
<meta tag="hidden">
<instanceID/>
</meta>
</draw-widget>
</instance>
<instance id="contact-summary"/>
<bind nodeset="/draw-widget/media_widgets/draw" type="binary"/>
<bind nodeset="/draw-widget/media_widgets/signature" type="binary"/>
<bind nodeset="/draw-widget/media_widgets/annotate" type="binary"/>
<bind calculate="concat('uuid:', uuid())" nodeset="/draw-widget/meta/instanceID" readonly="true()" type="string"/>
</model>
</h:head>
<h:body class="pages">
<group appearance="field-list" ref="/draw-widget/media_widgets">
<label ref="jr:itext('/draw-widget/media_widgets:label')"/>
<upload appearance="draw" mediatype="image/*" ref="/draw-widget/media_widgets/draw">
<label ref="jr:itext('/draw-widget/media_widgets/draw:label')"/>
</upload>
<upload appearance="signature" mediatype="image/*" ref="/draw-widget/media_widgets/signature">
<label ref="jr:itext('/draw-widget/media_widgets/signature:label')"/>
</upload>
<upload appearance="annotate" mediatype="image/*" ref="/draw-widget/media_widgets/annotate">
<label ref="jr:itext('/draw-widget/media_widgets/annotate:label')"/>
</upload>
</group>
</h:body>
</h:html>
Binary file not shown.
46 changes: 46 additions & 0 deletions tests/integration/cht-form/default/forms/file-upload.xml
Original file line number Diff line number Diff line change
@@ -0,0 +1,46 @@
<?xml version="1.0"?>
<h:html xmlns="http://www.w3.org/2002/xforms" 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>File Upload</h:title>
<model>
<itext>
<translation lang="en">
<text id="/file-upload/files/images/image:label">
<value>Upload image</value>
</text>
<text id="/file-upload/files:label">
<value>Files</value>
</text>
</translation>
</itext>
<instance>
<file-upload delimiter="#" id="file-upload" prefix="J1!file-upload!" version="2024-06-07 00:00:00">
<files>
<images jr:template="">
<image/>
</images>
</files>
<meta tag="hidden">
<instanceID/>
</meta>
</file-upload>
</instance>
<instance id="contact-summary"/>
<bind nodeset="/file-upload/files/images/image" type="binary"/>
<bind calculate="concat('uuid:', uuid())" nodeset="/file-upload/meta/instanceID" readonly="true()" type="string"/>
</model>
</h:head>
<h:body class="pages">
<group appearance="field-list" ref="/file-upload/files">
<label ref="jr:itext('/file-upload/files:label')"/>
<group ref="/file-upload/files/images">
<label ref="jr:itext('/file-upload/files/images:label')"/>
<repeat nodeset="/file-upload/files/images">
<upload mediatype="image/*" ref="/file-upload/files/images/image">
<label ref="jr:itext('/file-upload/files/images/image:label')"/>
</upload>
</repeat>
</group>
</group>
</h:body>
</h:html>
34 changes: 34 additions & 0 deletions tests/page-objects/default/enketo/common-enketo.wdio.page.js
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,8 @@ const getCurrentPageSection = async () => await currentSection().isExisting() ?

const enabledFieldset = (section) => section.$$('fieldset.or-branch:not(.disabled)');

const addRepeatSectionButton = () => $(`button.add-repeat-btn`);

const getCorrectFieldsetSection = async (section) => {
const countFieldset = await enabledFieldset(section).length;
if (countFieldset){
Expand Down Expand Up @@ -60,6 +62,13 @@ const setTextareaValue = async (question, value) => {
await setValue('textarea', question, value);
};

const addFileInputValue = async (question, value, { repeatIndex = 0 } = {}) => {
const element = await (await getCurrentPageSection())
.$$(`label*=${question}`)[repeatIndex]
.$('input[type=file]');
await element.addValue(value);
};

const validateSummaryReport = async (textArray) => {
const element = await getCurrentPageSection();
for (const text of textArray) {
Expand Down Expand Up @@ -94,14 +103,39 @@ const getInputValue = async (question) => {
.getValue();
};

const addRepeatSection = async () => {
const repeatButton = await addRepeatSectionButton();
await repeatButton.click();
};

const drawShapeOnCanvas = async (question) => {
const canvas = await (await getCurrentPageSection())
.$(`label*=${question}`)
.$('canvas');
await canvas.waitForDisplayed();
await browser.action('pointer')
jkuester marked this conversation as resolved.
Show resolved Hide resolved
.move({ origin: canvas })
.down()
.move({ origin: canvas, x: 50, y: 0 })
.move({ origin: canvas, x: 50, y: 50 })
.move({ origin: canvas, x: 0, y: 50 })
.move({ origin: canvas, x: 0, y: 0 })
.move({ origin: canvas, x: 50, y: 0 })
.up()
.perform();
};

module.exports = {
isElementDisplayed,
selectRadioButton,
selectCheckBox,
setInputValue,
setDateValue,
setTextareaValue,
addFileInputValue,
validateSummaryReport,
uploadForm,
getInputValue,
addRepeatSection,
drawShapeOnCanvas,
};
23 changes: 17 additions & 6 deletions webapp/package-lock.json

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

1 change: 1 addition & 0 deletions webapp/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -68,6 +68,7 @@
"pouchdb-generate-replication-id": "^7.3.1",
"rxjs": "^7.8.1",
"select2": "4.0.3",
"signature_pad": "2.3.x",
"simple-password-tester": "^1.0.0",
"tslib": "^2.5.3",
"uuid": "^9.0.1",
Expand Down
1 change: 1 addition & 0 deletions webapp/src/css/enketo/_widgets.scss
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@
@import "../../../node_modules/enketo-core/src/widget/table/tablewidget.scss";
@import "../../../node_modules/enketo-core/src/widget/radio/radiopicker.scss";
@import "../../../node_modules/enketo-core/src/widget/date/datepicker-extended.scss";
@import "./draw.scss";
@import "../../../node_modules/enketo-core/src/widget/time/timepicker-extended.scss";
@import "../../../node_modules/enketo-core/src/widget/datetime/datetimepicker-extended.scss";
@import "../../../node_modules/enketo-core/src/widget/file/filepicker.scss";
Expand Down
Loading