Skip to content
Open
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
37 changes: 37 additions & 0 deletions src/lib/validation/form/note-countdown-timer.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,37 @@
const semver = require('semver');
const { getNodes, getBindNodes } = require('../../forms-utils');

const validateNoteCountdownTimer = async ({ xformPath, xmlDoc, apiVersion }) => {
if (!apiVersion) {
return { errors: [], warnings: [] };
}
if (semver.lt(apiVersion, '4.7.0')) {
return { errors: [], warnings: [] };
}

const bindNodes = getBindNodes(xmlDoc);

const warnings = getNodes(xmlDoc, '/h:html/h:body//*[@appearance]')
.filter(node => node.getAttribute('appearance').match(/(?:^|\s)countdown-timer(?:$|\s)/))
.map(node => node.getAttribute('ref'))
.filter(ref => {
const bind = bindNodes.find(b => b.getAttribute('nodeset') === ref);
return bind?.hasAttribute('readonly');
})
.map(ref => ` - ${ref}`);

if (warnings.length) {
warnings.unshift(
`Form at ${xformPath} contains fields with the deprecated countdown-timer note appearance. `
+ 'Please update the following fields to use trigger fields instead:'
);
}

return { errors: [], warnings };
};

module.exports = {
requiresInstance: true,
skipFurtherValidation: false,
execute: validateNoteCountdownTimer
};
5 changes: 5 additions & 0 deletions test/lib/validate-forms.spec.js
Original file line number Diff line number Diff line change
Expand Up @@ -77,6 +77,11 @@ describe('validate-forms', () => {
expect(noRequiredNotes.requiresInstance).to.equal(false);
expect(noRequiredNotes.skipFurtherValidation).to.equal(false);

const noteCountdownTimer = validations.shift();
expect(noteCountdownTimer.name).to.equal('note-countdown-timer.js');
expect(noteCountdownTimer.requiresInstance).to.equal(true);
expect(noteCountdownTimer.skipFurtherValidation).to.equal(false);

expect(validations, 'Update this test if you have added a new form validation.').to.be.empty;
});

Expand Down
106 changes: 106 additions & 0 deletions test/lib/validation/form/note-countdown-timer.spec.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,106 @@
const { expect } = require('chai');
const { DOMParser } = require('@xmldom/xmldom');
const noteCountdownTimer = require('../../../../src/lib/validation/form/note-countdown-timer');

const domParser = new DOMParser();
const xformPath = 'test/form/path.xml';

const getXml = ({ deprecated = false, newStyle = false } = {}) => `
<?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>
<model>
<instance>
<data id="test">
${deprecated ? '<deprecated_timer>15</deprecated_timer>' : ''}
${newStyle ? '<required_timer/>' : ''}
</data>
</instance>
${deprecated ? '<bind nodeset="/data/deprecated_timer" readonly="true()" type="string"/>' : ''}
${newStyle ? '<bind nodeset="/data/required_timer" type="string" required="true()"/>' : ''}
</model>
</h:head>
<h:body>
${deprecated
? '<input ref="/data/deprecated_timer" appearance="countdown-timer"><label>Deprecated Timer</label></input>' : ''}
${newStyle
? '<trigger ref="/data/required_timer" appearance="countdown-timer"><label>Required Timer</label></trigger>' : ''}
</h:body>
</h:html>`;

const getXmlDoc = (opts) => domParser.parseFromString(getXml(opts), 'text/xml');

const LATEST_VERSION = '999.99.99';
const ERROR_HEADER = `Form at ${xformPath} contains fields with the deprecated countdown-timer note appearance. `
+ 'Please update the following fields to use trigger fields instead:';

describe('note-countdown-timer', () => {
it('resolves OK when no countdown-timer fields present', () => {
return noteCountdownTimer
.execute({ xformPath, xmlDoc: getXmlDoc(), apiVersion: LATEST_VERSION })
.then(({ errors, warnings }) => {
expect(errors).is.empty;
expect(warnings).is.empty;
});
});

it('returns warning for deprecated countdown-timer note field', () => {
return noteCountdownTimer
.execute({ xformPath, xmlDoc: getXmlDoc({ deprecated: true }), apiVersion: LATEST_VERSION })
.then(({ errors, warnings }) => {
expect(errors).is.empty;
expect(warnings).to.have.length(2);
expect(warnings[0]).to.equal(ERROR_HEADER);
expect(warnings[1]).to.equal(' - /data/deprecated_timer');
});
});

it('resolves OK for new trigger style countdown-timer', () => {
return noteCountdownTimer
.execute({ xformPath, xmlDoc: getXmlDoc({ newStyle: true }), apiVersion: LATEST_VERSION })
.then(({ errors, warnings }) => {
expect(errors).is.empty;
expect(warnings).is.empty;
});
});

it('returns warning only for deprecated when both deprecated and new style present', () => {
return noteCountdownTimer
.execute({ xformPath, xmlDoc: getXmlDoc({ deprecated: true, newStyle: true }), apiVersion: LATEST_VERSION })
.then(({ errors, warnings }) => {
expect(errors).is.empty;
expect(warnings).to.have.length(2);
expect(warnings[0]).to.equal(ERROR_HEADER);
expect(warnings[1]).to.equal(' - /data/deprecated_timer');
});
});

it('resolves OK when apiVersion is below 4.7.0', () => {
return noteCountdownTimer
.execute({ xformPath, xmlDoc: getXmlDoc({ deprecated: true }), apiVersion: '4.6.0' })
.then(({ errors, warnings }) => {
expect(errors).is.empty;
expect(warnings).is.empty;
});
});

it('resolves OK when no apiVersion provided', () => {
return noteCountdownTimer
.execute({ xformPath, xmlDoc: getXmlDoc({ deprecated: true }) })
.then(({ errors, warnings }) => {
expect(errors).is.empty;
expect(warnings).is.empty;
});
});

it('returns warning when apiVersion is exactly 4.7.0', () => {
return noteCountdownTimer
.execute({ xformPath, xmlDoc: getXmlDoc({ deprecated: true }), apiVersion: '4.7.0' })
.then(({ errors, warnings }) => {
expect(errors).is.empty;
expect(warnings).to.have.length(2);
expect(warnings[0]).to.equal(ERROR_HEADER);
expect(warnings[1]).to.equal(' - /data/deprecated_timer');
});
});
});
Loading