src/Wizard.unit.js
/* eslint-disable no-unused-vars */
import Harness from '../test/harness';
import Wizard from './Wizard';
import { Formio } from './Formio';
import assert from 'power-assert';
import _ from 'lodash';
import wizardCond from '../test/forms/wizardConditionalPages';
import wizard from '../test/forms/wizardValidationOnPageChanged';
import wizard1 from '../test/forms/wizardValidationOnNextBtn';
import wizard2 from '../test/forms/wizardWithEditGrid';
import wizard3 from '../test/forms/conditionalWizardPages';
import wizard4 from '../test/forms/wizardWithSimpleConditionalPage';
import wizard5 from '../test/forms/wizardWithCustomConditionalPage';
import wizard6 from '../test/forms/wizardWithFirstConditionalPage';
import wizardWithHighPages from '../test/forms/wizardWithHighPages';
import wizardWithHiddenPanel from '../test/forms/wizardWithHiddenPanel';
import wizardWithAllowPrevious from '../test/forms/wizardWithAllowPrevious';
import wizardWithNestedWizard from '../test/forms/wizardWithNestedWizard';
import formWithSignature from '../test/forms/formWithSignature';
import wizardWithTooltip from '../test/forms/wizardWithTooltip';
import wizardForHtmlModeTest from '../test/forms/wizardForHtmlRenderModeTest';
import wizardTestForm from '../test/forms/wizardTestForm';
import wizardTestFormWithNestedComponents from '../test/forms/wizardTestFormWithNestedComponents';
import formWithNestedWizard from '../test/forms/formWIthNestedWizard';
import wizardWithDataGridAndEditGrid from '../test/forms/wizardWithDataGridAndEditGrid';
import customWizard from '../test/forms/customWizard';
//import wizardChildForm from '../test/forms/wizardChildForm';
//import wizardParentForm from '../test/forms/wizardParentForm';
import wizardWithComponentsWithSameApi from '../test/forms/wizardWithComponentsWithSameApi';
import wizardWithConditionallyVisiblePage from '../test/forms/conditionallyVisiblePage';
import wizardWithPanel from '../test/forms/wizardWithPanel';
import wizardWithWizard from '../test/forms/wizardWithWizard';
import simpleTwoPagesWizard from '../test/forms/simpleTwoPagesWizard';
import wizardWithNestedWizardInEditGrid from '../test/forms/wizardWithNestedWizardInEditGrid';
import wizardNavigateOrSaveOnEnter from '../test/forms/wizardNavigateOrSaveOnEnter';
import wizardWithFieldsValidationChild from '../test/forms/wizardWithFieldsValidationChild';
import wizardWithFieldsValidationParent from '../test/forms/wizardWithFieldsValidationParent';
import nestedConditionalWizard from '../test/forms/nestedConditionalWizard';
import wizardWithPrefixComps from '../test/forms/wizardWithPrefixComps';
import wizardPermission from '../test/forms/wizardPermission';
import formWithFormController from '../test/forms/formWithFormController';
import { fastCloneDeep } from './utils/utils';
global.requestAnimationFrame = (cb) => cb();
global.cancelAnimationFrame = () => {};
// eslint-disable-next-line max-statements
describe('Wizard tests', () => {
it('Should execute form controller', function(done) {
const form = fastCloneDeep(formWithFormController);
form.display = 'wizard';
Formio.createForm(form).then((form) => {
setTimeout(() => {
const textField = form.getComponent('textField');
assert.equal(textField.getValue(), 'Hello World');
assert.equal(textField.disabled, true);
assert.equal(form.components[0].disabled, true);
done();
}, 300);
}).catch((err) => done(err));
});
it('Should check correctly Permissions and disabled sumbit button', (done) => {
const formElement = document.createElement('div');
const wizard = new Wizard(formElement);
wizard.setForm(wizardPermission).then(() => {
wizard.form.disableWizardSubmit = true;
wizard.redraw();
const btn = wizard.element.querySelector('.btn-wizard-nav-submit');
assert.equal(btn.disabled, true);
done();
}).catch(err => done(err));
});
it('Should correctly reset values', function(done) {
const formElement = document.createElement('div');
const wizard = new Wizard(formElement);
wizard.setForm(wizardWithDataGridAndEditGrid).then(() => {
const dataGrid = wizard.getComponent('dataGrid');
const editGrid = wizard.getComponent('editGrid');
const checkComponents = (editGridRowsNumber, dataGridRowsNumber, editGridValue, dataGridValue) => {
assert.equal(editGrid.editRows.length, editGridRowsNumber, `EditGrit should have ${dataGridRowsNumber} rows`);
assert.equal(editGrid.components.length, editGridRowsNumber, `EditGrit should have ${dataGridRowsNumber} components`);
assert.equal(dataGrid.rows.length, dataGridRowsNumber, `DataGrit should have ${dataGridRowsNumber} rows`);
assert.equal(dataGrid.components.length, dataGridRowsNumber, `DataGrit should have ${dataGridRowsNumber} components`);
if (editGridValue) {
assert.deepEqual(editGrid.dataValue, editGridValue, 'Should set correct editGrid value');
}
if (dataGridValue) {
assert.deepEqual(dataGrid.dataValue, dataGridValue, 'Should set correct dataGrid value');
}
};
const event = (name, elem) => {
const event = new Event(name);
elem.dispatchEvent(event);
};
checkComponents(0, 1, [], [{}]);
const submission = {
data: {
dataGrid: [{ number: 1111 }, { number: 2222 }],
editGrid: [{ textField: 'test1' }, { textField: 'test2' }]
}
};
wizard.submission = _.cloneDeep(submission);
setTimeout(() => {
checkComponents(2, 2, submission.data.editGrid,submission.data.dataGrid);
wizard.cancel(true);
setTimeout(() => {
checkComponents(0, 1, [], [{}]);
event('click', editGrid.refs['editgrid-editGrid-addRow'][0]);
setTimeout(() => {
const editGridFirstRowInput = editGrid.element.querySelector('[name="data[editGrid][0][textField]"]');
editGridFirstRowInput.value = 'test row 1';
event('input', editGridFirstRowInput);
event('click', editGrid.refs['editgrid-editGrid-saveRow'][0]);
const dataGridFirstRowInput = dataGrid.element.querySelector('[name="data[dataGrid][0][number]"]');
dataGridFirstRowInput.value = 11;
event('input', dataGridFirstRowInput);
setTimeout(() => {
checkComponents(1, 1, [{ textField:'test row 1' }], [{ number: 11 }]);
event('click', editGrid.refs['editgrid-editGrid-addRow'][0]);
event('click', dataGrid.refs['datagrid-dataGrid-addRow'][0]);
setTimeout(() => {
const editGridFirstRowInput = editGrid.element.querySelector('[name="data[editGrid][1][textField]"]');
editGridFirstRowInput.value = 'test row 2';
event('input', editGridFirstRowInput);
event('click', editGrid.refs['editgrid-editGrid-saveRow'][0]);
const dataGridFirstRowInput = dataGrid.element.querySelector('[name="data[dataGrid][1][number]"]');
dataGridFirstRowInput.value = 22;
event('input', dataGridFirstRowInput);
setTimeout(() => {
const editGridValue = [{ textField:'test row 1' }, { textField:'test row 2' }];
const dataGridValue = [{ number: 11 }, { number: 22 }];
checkComponents(2, 2, editGridValue, dataGridValue);
assert.deepEqual(wizard.submission.data, {
dataGrid: dataGridValue,
editGrid: editGridValue
}, 'Should contain correct submission data');
done();
}, 500);
}, 200);
}, 200);
}, 200);
}, 200);
}, 200);
})
.catch((err) => done(err));
}).timeout(2500);
it('Should render nested wizard, navigate pages and trigger validation', function(done) {
const formElement = document.createElement('div');
const wizard = new Wizard(formElement);
const nestedWizard = _.cloneDeep(wizardTestForm.form);
wizard.setForm(formWithNestedWizard).then(() => {
const nestedFormComp = wizard.getComponent('formNested');
nestedFormComp.loadSubForm = ()=> {
nestedFormComp.formObj = nestedWizard;
nestedFormComp.subFormLoading = false;
return new Promise((resolve) => resolve(nestedWizard));
};
nestedFormComp.createSubForm();
setTimeout(() => {
const clickWizardBtn = (pathPart, clickError) => {
const btn = _.get(wizard.refs, clickError ? pathPart : `${wizard.wizardKey}-${pathPart}`);
const clickEvent = new Event('click');
btn.dispatchEvent(clickEvent);
};
const checkPage = (pageNumber) => {
assert.equal(wizard.page, pageNumber, `Should open wizard page ${pageNumber + 1}`);
};
checkPage(0);
assert.equal(wizard.pages.length, 5, 'Should have 5 pages');
assert.equal(wizard.allPages.length, 5, 'Should have 5 pages');
assert.equal(wizard.refs[`${wizard.wizardKey}-link`].length, 5, 'Should contain refs to breadcrumbs of parent and nested wizard');
clickWizardBtn('next');
setTimeout(() => {
checkPage(1);
assert.equal(wizard.refs[`${wizard.wizardKey}`].querySelectorAll('[ref="component"]').length, 1, 'Should not load nested wizard component of the page of nested form if this page contains other components');
clickWizardBtn('next');
setTimeout(() => {
checkPage(2);
assert.equal(wizard.refs[`${wizard.wizardKey}`].querySelectorAll('[ref="component"]').length, 4, 'Should render nested wizard first page components');
clickWizardBtn('next');
setTimeout(() => {
checkPage(2);
assert.equal(wizard.errors.length, 1, 'Should show validation error for required field');
assert.equal(wizard.refs.errorRef.length, 1, 'Should show alert with error');
clickWizardBtn('previous');
setTimeout(() => {
checkPage(1);
assert.equal(wizard.errors.length, 0, 'Should not have validation errors');
clickWizardBtn('link[4]');
setTimeout(() => {
checkPage(4);
assert.equal(!!wizard.refs[`${wizard.wizardKey}-submit`], true, 'Should have submit btn on the last page');
clickWizardBtn('submit');
setTimeout(() => {
checkPage(4);
assert.equal(wizard.errors.length, 3, 'Should trigger validation errors on submit');
assert.equal(wizard.refs.errorRef.length, 3, 'Should show alert with error on submit');
wizard.getComponent('select').setValue('value1');
setTimeout(() => {
checkPage(4);
assert.equal(wizard.errors.length, 2, 'Should remove validation error if a component is valid');
assert.equal(wizard.refs.errorRef.length, 2, 'Should remove error from alert if component is valid');
done();
}, 500);
}, 500);
}, 200);
}, 200);
}, 200);
}, 200);
}, 200);
}, 200);
})
.catch((err) => done(err));
}).timeout(3000);
it('Should set submission in wizard with nested wizard', function(done) {
const formElement = document.createElement('div');
const wizard = new Wizard(formElement);
const nestedWizard = _.cloneDeep(wizardTestForm.form);
const submission = {
data: {
selectBoxesParent: {
a: true,
b: false,
c: false
},
formNested: {
data: wizardTestForm.submission.data
},
numberParent: 1111
}
};
wizard.setForm(formWithNestedWizard).then(() => {
const nestedFormComp = wizard.getComponent('formNested');
nestedFormComp.loadSubForm = ()=> {
nestedFormComp.formObj = nestedWizard;
nestedFormComp.subFormLoading = false;
return new Promise((resolve) => resolve(nestedWizard));
};
nestedFormComp.createSubForm();
setTimeout(() => {
wizard.submission = _.cloneDeep(submission);
setTimeout(() => {
assert.deepEqual(wizard.data, submission.data, 'Should set wizard submission');
assert.deepEqual(wizard.submission.data, submission.data, 'Should get wizard submission data');
wizard.everyComponent((comp) => {
const expectedValue = _.get(submission.data, comp.path, 'no data');
if (expectedValue !== 'no data') {
assert.deepEqual(comp.getValue(), expectedValue, `Should set value for ${comp.component.type} inside wizard`);
assert.deepEqual(comp.dataValue, expectedValue, `Should set value for ${comp.component.type} inside wizard`);
}
});
done();
}, 300);
}, 300);
})
.catch((err) => done(err));
});
it('Should show conditional page inside nested wizard', function(done) {
const formElement = document.createElement('div');
const wizard = new Wizard(formElement);
const nestedWizard = _.cloneDeep(wizardTestForm.form);
nestedWizard.components[2].conditional = { show: true, when: 'checkbox', eq: 'true' };
wizard.setForm(formWithNestedWizard).then(() => {
const nestedFormComp = wizard.getComponent('formNested');
nestedFormComp.loadSubForm = ()=> {
nestedFormComp.formObj = nestedWizard;
nestedFormComp.subFormLoading = false;
return new Promise((resolve) => resolve(nestedWizard));
};
nestedFormComp.createSubForm();
setTimeout(() => {
const checkPage = (pageNumber) => {
assert.equal(wizard.page, pageNumber, `Should open wizard page ${pageNumber + 1}`);
};
const clickWizardBtn = (pathPart, clickError) => {
const btn = _.get(wizard.refs, clickError ? pathPart : `${wizard.wizardKey}-${pathPart}`);
const clickEvent = new Event('click');
btn.dispatchEvent(clickEvent);
};
checkPage(0);
assert.equal(wizard.pages.length, 4, 'Should have 4 pages');
assert.equal(wizard.allPages.length, 4, 'Should have 4 pages');
assert.equal(wizard.refs[`${wizard.wizardKey}-link`].length, 4, 'Should contain refs to breadcrumbs of parent and nested wizard');
clickWizardBtn('link[3]');
setTimeout(() => {
checkPage(3);
assert.deepEqual(!!wizard.refs[`${wizard.wizardKey}-submit`], true, 'Should hav submit btn on the last page');
wizard.getComponent('checkbox').setValue(true);
setTimeout(() => {
checkPage(3);
assert.deepEqual(!!wizard.refs[`${wizard.wizardKey}-submit`], true, 'Should have submit btn on the last page');
wizard.getComponent('checkbox').setValue(true);
setTimeout(() => {
checkPage(3);
assert.deepEqual(!!wizard.refs[`${wizard.wizardKey}-submit`], false, 'Should not have submit btn ');
assert.equal(wizard.pages.length, 5, 'Should show conditional page');
assert.equal(wizard.allPages.length, 5, 'Should show conditional page');
assert.equal(wizard.refs[`${wizard.wizardKey}-link`].length, 5, 'Should contain refs to breadcrumbs of visible conditional page');
clickWizardBtn('next');
setTimeout(() => {
checkPage(4);
clickWizardBtn('previous');
setTimeout(() => {
checkPage(3);
wizard.getComponent('checkbox').setValue(false);
setTimeout(() => {
assert.equal(wizard.pages.length, 4, 'Should hide conditional page');
assert.equal(wizard.allPages.length, 4, 'Should hide conditional page');
assert.equal(wizard.refs[`${wizard.wizardKey}-link`].length, 4, 'Should contain refs to breadcrumbs of visible pages');
assert.deepEqual(!!wizard.refs[`${wizard.wizardKey}-submit`], true, 'Should have submit btn on the last page');
done();
}, 500);
}, 300);
}, 300);
}, 500);
}, 300);
}, 300);
}, 300);
})
.catch((err) => done(err));
}).timeout(3000);
it('Should render values in HTML render mode', function(done) {
const formElement = document.createElement('div');
const wizard = new Wizard(formElement, {
readOnly: true,
renderMode: 'html'
});
const form = _.cloneDeep(wizardTestForm.form);
wizard.setForm(form, ).then(() => {
const clickWizardBtn = (pathPart, clickError) => {
const btn = _.get(wizard.refs, clickError ? pathPart : `${wizard.wizardKey}-${pathPart}`);
const clickEvent = new Event('click');
btn.dispatchEvent(clickEvent);
};
const checkPage = (pageNumber) => {
assert.equal(wizard.page, pageNumber, `Should open wizard page ${pageNumber + 1}`);
};
const checkValues = () => {
wizard.allPages[wizard.page].everyComponent((comp) => {
const isParent = !!(comp.component.components || comp.component.rows || comp.component.columns);
if (!isParent) {
const isInEditGrid = comp.parent.component.type === 'editgrid';
const value = isInEditGrid ? comp.parent.refs['editgrid-editGrid-row'][comp.rowIndex].textContent.trim() : comp.element.querySelector("[ref='value']").textContent;
const expectedValue = _.get(wizardTestForm.htmlModeValues, comp.path, 'no data');
assert.equal(value, expectedValue === 'true' ? 'True' : expectedValue, `${comp.component.key}: should render value in html render mode`);
}
});
};
wizard.submission = _.cloneDeep(wizardTestForm.submission);
setTimeout(() => {
checkPage(0);
checkValues();
clickWizardBtn('next');
setTimeout(() => {
checkPage(1);
checkValues();
clickWizardBtn('next');
setTimeout(() => {
checkPage(2);
checkValues();
done();
}, 200);
}, 200);
}, 200);
})
.catch((err) => done(err));
});
it('Should render values for prefix Components', function(done) {
const formElement = document.createElement('div');
const wizard = new Wizard(formElement, {
readOnly: true,
});
const form = _.cloneDeep(wizardWithPrefixComps.form);
wizard.setForm(form).then(() => {
const clickWizardBtn = (pathPart, clickError) => {
const btn = _.get(wizard.refs, clickError ? pathPart : `${wizard.wizardKey}-${pathPart}`);
const clickEvent = new Event('click');
btn.dispatchEvent(clickEvent);
};
const checkPage = (pageNumber) => {
assert.equal(wizard.page, pageNumber, `Should open wizard page ${pageNumber + 1}`);
};
const checkValues = () => {
wizard.refs[`wizard-${wizard.id}`].querySelectorAll('input').forEach((element, i)=> {
switch (i) {
case 0:
assert.equal(element.value, 'prefix', 'Should render value');
break;
case 1:
assert.equal(element.value, `page${wizard.page+1}`, 'Should render value');
break;
case 2:
assert.equal(element.value, 'suffix', 'Should render value');
break;
}
});
};
wizard.submission = _.cloneDeep(wizardWithPrefixComps.submission);
setTimeout(() => {
checkPage(0);
checkValues();
clickWizardBtn('next');
setTimeout(() => {
checkPage(1);
checkValues();
done();
}, 200);
}, 200);
})
.catch((err) => done(err));
});
it('Should redirect to the correct page from the Error list', function(done) {
const formElement = document.createElement('div');
const wizard = new Wizard(formElement, {
renderMode: 'html'
});
wizard.setForm(wizardWithComponentsWithSameApi, ).then(() => {
const clickWizardBtn = (pathPart) => {
const [btnKey] = Object.keys(wizard.refs).filter((key) => key.indexOf(pathPart) !== -1);
const btn = _.get(wizard.refs, btnKey);
const clickEvent = new Event('click');
btn.dispatchEvent(clickEvent);
};
const checkPage = (pageNumber) => {
assert.equal(wizard.page, pageNumber, `Should open wizard page ${pageNumber + 1}`);
};
setTimeout(() => {
checkPage(0);
wizard.setPage(1);
setTimeout(() => {
checkPage(1);
clickWizardBtn('submit');
setTimeout(() => {
assert.equal(wizard.refs.errorRef.length, 1, 'Should have an error');
const clickEvent = new Event('click');
wizard.refs.errorRef[0].dispatchEvent(clickEvent);
setTimeout(() => {
checkPage(0);
done();
}, 200);
}, 200);
}, 300);
}, 200);
})
.catch((err) => done(err));
});
it('Should execute advanced logic for wizard pages', function(done) {
const formElement = document.createElement('div');
const wizard = new Wizard(formElement);
const form = _.cloneDeep(wizardTestForm.form);
_.each(form.components, (comp, index) => {
if (index === 1) {
comp.logic = [
{
name: 'simple logic',
trigger: { type: 'simple', simple: { show: true, when: 'textField', eq: 'tooltip' } },
actions: [
{
name: 'merge schema action',
type: 'mergeComponentSchema',
schemaDefinition: "schema = { tooltip: 'some tooltip'}"
}
]
}
];
}
if (index === 2) {
comp.logic = [
{
name: 'logic test',
trigger: { type: 'simple', simple: { show: true, when: 'checkbox', eq: 'true' } },
actions: [
{
name: 'disabled',
type: 'property',
property: { label: 'Disabled', value: 'disabled', type: 'boolean' },
state: true
}
]
}
];
}
});
wizard.setForm(form).then(() => {
const clickWizardBtn = (pathPart, clickError) => {
const btn = _.get(wizard.refs, clickError ? pathPart : `${wizard.wizardKey}-${pathPart}`);
const clickEvent = new Event('click');
btn.dispatchEvent(clickEvent);
};
const checkPage = (pageNumber) => {
assert.equal(wizard.page, pageNumber, `Should open wizard page ${pageNumber + 1}`);
};
checkPage(0);
wizard.getComponent('textField').setValue('tooltip');
clickWizardBtn('next');
setTimeout(() => {
checkPage(1);
assert.equal(wizard.tooltips.length, 1, 'Should have tooltip after advanced logic execution');
assert.equal(!!wizard.refs[`${wizard.wizardKey}-tooltip`][0], true, 'Should render tooltip icon');
wizard.getComponent('checkbox').setValue(true);
clickWizardBtn('next');
setTimeout(() => {
checkPage(2);
assert.equal(wizard.allPages[wizard.page].disabled, true, 'Should disable page components after advanced logic execution');
done();
}, 200);
}, 200);
})
.catch((err) => done(err));
});
it('Should navigate next page according to advanced next page logic', function(done) {
const formElement = document.createElement('div');
const wizard = new Wizard(formElement);
const form = _.cloneDeep(wizardTestForm.form);
_.each(form.components, (comp, index) => {
if (index === 0) {
comp.nextPage = "next = data.textField === 'page3' ? 'page3' : 'page2'";
}
if (index === 1) {
comp.nextPage = "next = data.container && data.container.select === 'value1' ? 'page1' : 'page3'";
}
});
wizard.setForm(form).then(() => {
const clickWizardBtn = (pathPart, clickError) => {
const btn = _.get(wizard.refs, clickError ? pathPart : `${wizard.wizardKey}-${pathPart}`);
const clickEvent = new Event('click');
btn.dispatchEvent(clickEvent);
};
const checkPage = (pageNumber) => {
assert.equal(wizard.page, pageNumber, `Should open wizard page ${pageNumber + 1}`);
};
checkPage(0);
wizard.getComponent('textField').setValue('page3');
clickWizardBtn('next');
setTimeout(() => {
checkPage(2);
wizard.getComponent('select').setValue('value1');
clickWizardBtn('previous');
setTimeout(() => {
checkPage(1);
wizard.getComponent('checkbox').setValue(true);
clickWizardBtn('next');
setTimeout(() => {
checkPage(0);
done();
}, 200);
}, 200);
}, 200);
})
.catch((err) => done(err));
});
it('Should NOT navigate to next page if it contains invalid nested component', function(done) {
const formElement = document.createElement('div');
const wizard = new Wizard(formElement);
const form = _.cloneDeep(wizardTestFormWithNestedComponents.form);
wizard.setForm(form).then(() => {
const checkPage = (pageNumber) => {
assert.equal(wizard.page, pageNumber, `Should open wizard page ${pageNumber + 1}`);
};
checkPage(0);
wizard.submission = {
data: {
outerContainer: {
firstComponent: 'c',
secondComponent: 'q',
}
}
};
wizard.nextPage();
setTimeout(() => {
const errors = wizard.errors;
checkPage(0);
assert(errors.length > 0, 'Must err before next page');
assert.equal(errors[0].message, 'Required Component is required');
done();
}, 200);
})
.catch((err) => done(err));
});
it('Should not render breadcrumb if it has hidden type', function(done) {
const formElement = document.createElement('div');
const wizard = new Wizard(formElement);
const form = _.cloneDeep(wizardTestForm.form);
_.each(form.components, (comp) => {
comp.breadcrumb = 'none';
});
wizard.setForm(form).then(() => {
const clickWizardBtn = (pathPart, clickError) => {
const btn = _.get(wizard.refs, clickError ? pathPart : `${wizard.wizardKey}-${pathPart}`);
const clickEvent = new Event('click');
btn.dispatchEvent(clickEvent);
};
const checkPage = (pageNumber) => {
assert.equal(wizard.page, pageNumber, `Should open wizard page ${pageNumber + 1}`);
};
const checkBreadcrumb = () => {
assert.equal(_.get(wizard.refs, `${wizard.wizardKey}-link`).length, 0, 'Should not render wizard breadcrumb');
};
checkBreadcrumb();
wizard.setSubmission(_.cloneDeep(wizardTestForm.submission));
setTimeout(() => {
checkPage(0);
checkBreadcrumb();
clickWizardBtn('next');
setTimeout(() => {
checkPage(1);
checkBreadcrumb();
clickWizardBtn('next');
setTimeout(() => {
checkPage(2);
checkBreadcrumb();
done();
}, 100);
}, 100);
}, 100);
})
.catch((err) => done(err));
});
it('Should not navigate between wizard pages on breadcrumb click if breadcrumbClickable is false', function(done) {
const formElement = document.createElement('div');
const wizard = new Wizard(formElement);
const form = _.cloneDeep(wizardTestForm.form);
_.each(form.components, (comp) => {
comp.breadcrumbClickable = false;
});
wizard.setForm(form).then(() => {
const clickWizardBtn = (pathPart, clickError) => {
const btn = _.get(wizard.refs, clickError ? pathPart : `${wizard.wizardKey}-${pathPart}`);
const clickEvent = new Event('click');
btn.dispatchEvent(clickEvent);
};
const checkPage = (pageNumber) => {
assert.equal(wizard.page, pageNumber, `Should open wizard page ${pageNumber + 1}`);
};
checkPage(0);
clickWizardBtn('link[1]');
setTimeout(() => {
checkPage(0);
clickWizardBtn('link[2]');
setTimeout(() => {
checkPage(0);
wizard.setSubmission(_.cloneDeep(wizardTestForm.submission));
setTimeout(() => {
checkPage(0);
clickWizardBtn('next');
setTimeout(() => {
checkPage(1);
clickWizardBtn('link[0]');
setTimeout(() => {
checkPage(1);
done();
}, 100);
}, 100);
}, 100);
}, 100);
}, 100);
})
.catch((err) => done(err));
});
it('Should set/get wizard submission', function(done) {
const formElement = document.createElement('div');
const wizard = new Wizard(formElement);
wizard.setForm(wizardTestForm.form).then(() => {
wizard.submission = _.cloneDeep(wizardTestForm.submission);
setTimeout(() => {
assert.deepEqual(wizard.data, wizardTestForm.submission.data, 'Should set wizard submission');
assert.deepEqual(wizard.submission.data, wizardTestForm.submission.data, 'Should get wizard submission data');
wizard.everyComponent((comp) => {
const expectedValue = _.get(wizardTestForm.submission.data, comp.path, 'no data');
if (expectedValue !== 'no data') {
assert.deepEqual(comp.getValue(), expectedValue, `Should set value for ${comp.component.type} inside wizard`);
assert.deepEqual(comp.dataValue, expectedValue, `Should set value for ${comp.component.type} inside wizard`);
}
});
done();
}, 300);
})
.catch((err) => done(err));
});
it('Should correctly render customized wizard and navigate using custom btns', function(done) {
const formElement = document.createElement('div');
const customizedWizard = new Wizard(formElement);
customizedWizard.setForm(customWizard).then(() => {
customizedWizard.on('goToNextPage', function() {
customizedWizard.nextPage();
});
customizedWizard.on('goToPrevPage', function() {
customizedWizard.prevPage();
});
const checkBtns = (page) => {
assert.equal(customizedWizard.page, page, `Should set page ${page + 1}`);
assert.equal(!!customizedWizard.refs[`${customizedWizard.wizardKey}-next`], false, 'Should not render wizard next btn');
assert.equal(!!customizedWizard.refs[`${customizedWizard.wizardKey}-cancel`], false, 'Should not render wizard cancel btn');
assert.equal(!!customizedWizard.refs[`${customizedWizard.wizardKey}-previous`], false, 'Should not render wizard previous btn');
};
const navigatePage = (btnKey) => {
const customBtn = customizedWizard.components[customizedWizard.page].getComponent(btnKey).refs.button;
const clickEvent = new Event('click');
customBtn.dispatchEvent(clickEvent);
};
checkBtns(0);
navigatePage('nextPage');
setTimeout(() => {
checkBtns(1);
navigatePage('nextPage1');
setTimeout(() => {
checkBtns(2);
navigatePage('prevPage1');
setTimeout(() => {
checkBtns(1);
navigatePage('prevPage');
setTimeout(() => {
checkBtns(0);
customizedWizard.destroy();
done();
}, 200);
}, 200);
}, 200);
}, 200);
})
.catch((err) => done(err));
});
it('Should not create a new submission on submission of edited draft submission', function(done) {
const formElement = document.createElement('div');
const customizedWizard = new Wizard(formElement);
const expectedValues = {
'1': {
method: 'post',
urlEnd: 'submission',
state: 'draft',
data: {
textArea1: '',
textField: 'test'
},
id: undefined
},
'2': {
method: 'put',
urlEnd: 'someId',
state: 'draft',
data: {
number: 111111,
textArea1: 'test1',
textField: 'test1'
},
id: 'someId'
},
'3': {
method: 'put',
urlEnd: 'someId',
state: 'draft',
data: {
number: 22222,
textArea1: 'test',
textField: 'test1'
},
id: 'someId'
},
'4': {
method: 'put',
urlEnd: 'someId',
state: 'draft',
data: {
number: 22222,
textArea1: 'test1',
textField: 'test1'
},
id: 'someId'
},
'5': {
method: 'put',
urlEnd: 'someId',
state: 'submitted',
data: {
number: 22222,
textArea1: 'test1',
textField: 'test1'
},
id: 'someId'
}
};
customizedWizard.setForm(customWizard).then(() => {
const formio = new Formio('http://test.localhost/draftwizardpages', {});
let number = 1;
formio.makeRequest = (type, url, method, data) => {
assert.equal(method, expectedValues[number].method, `Should send ${expectedValues[number].method} request`);
assert.equal(data._id, expectedValues[number].id, `Submission data should ${expectedValues[number].id ? '' : 'not'} contain id of editted submission`);
assert.equal(url.endsWith(expectedValues[number].urlEnd), true, `Request url should end with ${expectedValues[number].urlEnd}`);
assert.equal(data.state, expectedValues[number].state, `Should set ${expectedValues[number].state} state for submission`);
_.each(expectedValues[number].data, function(value, key) {
assert.equal(data.data[key], value, `${key} field should contain "${value}" value in submission object`);
});
number = number + 1;
return new Promise(resolve => resolve({
_id: 'someId',
data: {
number: 22222,
textArea1: 'test1',
textField: 'test1'
},
metadata:{},
state: data.state
})
);
};
customizedWizard.formio = formio;
customizedWizard.on('goToNextPage', function() {
customizedWizard.executeSubmit({ state: 'draft' }).then(() => customizedWizard.nextPage());
});
customizedWizard.on('goToPrevPage', function() {
customizedWizard.executeSubmit({ state: 'draft' }).then(() => customizedWizard.prevPage());
});
customizedWizard.on('saveSubmission', function() {
customizedWizard.executeSubmit();
});
const checkPage = (page) => {
assert.equal(customizedWizard.page, page, `Should set page ${page + 1}`);
};
const navigatePage = (btnKey) => {
const customBtn = customizedWizard.components[customizedWizard.page].getComponent(btnKey).refs.button;
const clickEvent = new Event('click');
customBtn.dispatchEvent(clickEvent);
};
const setPageCompValue = (compKey, value) => {
customizedWizard.components[customizedWizard.page].getComponent(compKey).setValue(value);
};
checkPage(0);
setPageCompValue('textField', 'test');
navigatePage('nextPage');
setTimeout(() => {
checkPage(1);
setPageCompValue('number', 111111);
navigatePage('nextPage1');
setTimeout(() => {
checkPage(2);
setPageCompValue('textArea1', 'test');
navigatePage('prevPage1');
setTimeout(() => {
checkPage(1);
navigatePage('nextPage1');
setTimeout(() => {
checkPage(2);
navigatePage('save');
setTimeout(() => {
customizedWizard.destroy();
done();
}, 200);
}, 200);
}, 200);
}, 200);
}, 200);
})
.catch((err) => done(err));
});
it('Should show validation alert and components` errors and navigate pages after clicking alert error', function(done) {
const formElement = document.createElement('div');
const wizard = new Wizard(formElement);
wizard.setForm(wizardTestForm.form).then(() => {
const clickWizardBtn = (pathPart, clickError) => {
const btn = _.get(wizard.refs, clickError ? pathPart : `${wizard.wizardKey}-${pathPart}`);
const clickEvent = new Event('click');
btn.dispatchEvent(clickEvent);
};
const checkPage = (pageNumber) => {
assert.equal(wizard.page, pageNumber, `Should open wizard page ${pageNumber + 1}`);
};
const checkInvalidComp = (compKey, highLight) => {
const comp = wizard.getComponent(compKey);
assert.deepEqual(!!comp.error, true, `${compKey}: should have error`);
assert.deepEqual(comp.error.message, `${comp.component.label} is required`, `${compKey}: should have correct required validation message`);
assert.deepEqual(comp.pristine, false, `${compKey}: should set pristine to false`);
assert.deepEqual(comp.element.classList.contains(`${highLight ? 'formio-error-wrapper' : 'has-error'}`), true, `${compKey}: should set error class`);
assert.deepEqual(comp.refs.messageContainer.querySelector('.error').textContent.trim(), `${comp.component.label} is required`, `${compKey}: should display error message`);
};
checkPage(0);
clickWizardBtn('link[2]');
setTimeout(() => {
checkPage(2);
assert.equal(wizard.errors.length, 0, 'Should not have validation errors');
clickWizardBtn('submit');
setTimeout(() => {
assert.equal(wizard.errors.length, 3, 'Should have validation errors');
assert.equal(wizard.refs.errorRef.length, wizard.errors.length, 'Should show alert with validation errors');
assert.equal(!!wizard.element.querySelector('.alert-danger'), true, 'Should have alert with validation errors');
checkInvalidComp('select', true);
clickWizardBtn('errorRef[0]', true);
setTimeout(() => {
checkPage(0);
assert.equal(wizard.errors.length, 1, 'Should have page validation error');
assert.equal(wizard.refs.errorRef.length, 3, 'Should keep alert with validation errors');
checkInvalidComp('textField');
clickWizardBtn('errorRef[1]', true);
setTimeout(() => {
checkPage(1);
assert.equal(wizard.errors.length, 1, 'Should have page validation error');
assert.equal(wizard.refs.errorRef.length, 3, 'Should keep alert with validation errors');
checkInvalidComp('checkbox');
wizard.getComponent('checkbox').setValue(true);
setTimeout(() => {
checkPage(1);
assert.equal(wizard.errors.length, 0, 'Should not have page validation error');
assert.equal(wizard.refs.errorRef.length, 2, 'Should keep alert with validation errors');
clickWizardBtn('errorRef[1]', true);
setTimeout(() => {
checkPage(2);
assert.equal(wizard.errors.length, 2, 'Should have wizard validation errors');
assert.equal(wizard.refs.errorRef.length, 2, 'Should keep alert with validation errors');
wizard.getComponent('select').setValue('value1');
setTimeout(() => {
assert.equal(wizard.errors.length, 1, 'Should have wizard validation error');
assert.equal(wizard.refs.errorRef.length, 1, 'Should keep alert with validation errors');
clickWizardBtn('errorRef[0]', true);
setTimeout(() => {
checkPage(0);
assert.equal(wizard.errors.length, 1, 'Should have page validation error');
assert.equal(wizard.refs.errorRef.length, 1, 'Should keep alert with validation errors');
wizard.getComponent('textField').setValue('valid');
setTimeout(() => {
assert.equal(wizard.errors.length, 0, 'Should not have page validation error');
assert.equal(!!wizard.element.querySelector('.alert-danger'), false, 'Should not have alert with validation errors');
clickWizardBtn('link[2]');
setTimeout(() => {
clickWizardBtn('submit');
setTimeout(() => {
assert.equal(wizard.submission.state, 'submitted', 'Should submit the form');
done();
}, 300);
}, 300);
}, 300);
}, 300);
}, 300);
}, 300);
}, 300);
}, 100);
}, 100);
}, 100);
}, 100);
})
.catch((err) => done(err));
}).timeout(3500);
it('Should navigate wizard pages using navigation buttons and breadcrumbs', function(done) {
const formElement = document.createElement('div');
const wizard = new Wizard(formElement);
wizard.setForm(wizardTestForm.form).then(() => {
const clickNavigationBtn = (pathPart) => {
const btn = _.get(wizard.refs, `${wizard.wizardKey}-${pathPart}`);
const clickEvent = new Event('click');
btn.dispatchEvent(clickEvent);
};
const checkPage = (pageNumber) => {
assert.equal(wizard.page, pageNumber, `Should open wizard page ${pageNumber + 1}`);
};
checkPage(0);
clickNavigationBtn('next');
setTimeout(() => {
checkPage(0);
assert.equal(wizard.errors.length, 1, 'Should have validation error');
assert.equal(wizard.refs.errorRef.length, wizard.errors.length, 'Should show alert with validation error');
wizard.getComponent('textField').setValue('valid');
clickNavigationBtn('next');
setTimeout(() => {
checkPage(1);
clickNavigationBtn('next');
setTimeout(() => {
checkPage(1);
assert.equal(wizard.errors.length, 1, 'Should have validation error');
assert.equal(wizard.refs.errorRef.length, wizard.errors.length, 'Should show alert with validation error');
clickNavigationBtn('previous');
setTimeout(() => {
checkPage(0);
assert.equal(wizard.errors.length, 0, 'Should not have validation error');
assert.equal(!!wizard.refs.errorRef, false, 'Should not have alert with validation error');
clickNavigationBtn('next');
setTimeout(() => {
checkPage(1);
assert.equal(wizard.errors.length, 1, 'Should have validation error');
wizard.getComponent('checkbox').setValue(true);
clickNavigationBtn('next');
setTimeout(() => {
checkPage(2);
assert.equal(wizard.errors.length, 0, 'Should not have validation error');
clickNavigationBtn('link[0]');
setTimeout(() => {
checkPage(0);
assert.equal(wizard.errors.length, 0, 'Should not have validation error');
clickNavigationBtn('link[2]');
setTimeout(() => {
checkPage(2);
done();
}, 50);
}, 50);
}, 50);
}, 50);
}, 50);
}, 50);
}, 50);
}, 50);
})
.catch((err) => done(err));
});
it('Should correctly set values in HTML render mode', function(done) {
const formElement = document.createElement('div');
const formHTMLMode = new Wizard(formElement, {
readOnly: true,
renderMode: 'html'
});
formHTMLMode.setForm(wizardForHtmlModeTest.form).then(() => {
formHTMLMode.setSubmission(wizardForHtmlModeTest.submission);
setTimeout(() => {
const numberValue = formHTMLMode.element.querySelector('[ref="value"]').textContent;
assert.equal(+numberValue, wizardForHtmlModeTest.submission.data.number);
const nextPageBtn = formHTMLMode.refs[`${formHTMLMode.wizardKey}-next`];
const clickEvent = new Event('click');
nextPageBtn.dispatchEvent(clickEvent);
setTimeout(() => {
const textValue = formHTMLMode.element.querySelector('[ref="value"]').textContent;
assert.equal(textValue, wizardForHtmlModeTest.submission.data.textField);
done();
}, 250);
}, 200);
})
.catch((err) => done(err));
});
it('Should show tooltip for wizard pages', function(done) {
const formElement = document.createElement('div');
const wizardWithPageTooltip = new Wizard(formElement);
wizardWithPageTooltip.setForm(wizardWithTooltip).then(() => {
const clickEvent = new Event('click');
assert.equal(wizardWithPageTooltip.tooltips.length, 1);
const pageTooltipIcon = wizardWithPageTooltip.refs[`${wizardWithPageTooltip.wizardKey}-tooltip`][0];
assert.equal(!!pageTooltipIcon, true);
pageTooltipIcon.dispatchEvent(clickEvent);
setTimeout(() => {
const tooltipText = wizardWithPageTooltip.element.querySelector('.tippy-content').textContent;
assert.equal(tooltipText, wizardWithPageTooltip.currentPanel.tooltip);
done();
}, 300);
})
.catch((err) => done(err));
});
it('Should not clear wizard data when navigating between wizard pages with hidden panel', function(done) {
const formElement = document.createElement('div');
const formWithHiddenPage = new Wizard(formElement);
formWithHiddenPage.setForm(wizardWithHiddenPanel).then(() => {
const clickEvent = new Event('click');
const inputEvent = new Event('input');
assert.equal(formWithHiddenPage.pages.length, 2);
const page1Field = formWithHiddenPage.element.querySelector('[name="data[number]"]');
page1Field.value = '555';
page1Field.dispatchEvent(inputEvent);
setTimeout(() => {
assert.equal(formWithHiddenPage.element.querySelector('[name="data[number]"]').value, 555);
const nextPageBtn = formWithHiddenPage.refs[`${formWithHiddenPage.wizardKey}-next`];
nextPageBtn.dispatchEvent(clickEvent);
setTimeout(() => {
assert.equal(formWithHiddenPage.page, 1);
const prevPageBtn = formWithHiddenPage.refs[`${formWithHiddenPage.wizardKey}-previous`];
prevPageBtn.dispatchEvent(clickEvent);
setTimeout(() => {
assert.equal(formWithHiddenPage.page, 0);
assert.equal(formWithHiddenPage.element.querySelector('[name="data[number]"]').value, 555);
done();
}, 250);
}, 200);
}, 100);
})
.catch((err) => done(err));
});
it('Should show signature submission in HTML render mode', function(done) {
const formElement = document.createElement('div');
const formWithSignatureHTMLMode = new Wizard(formElement, {
readOnly: true,
renderMode: 'html'
});
formWithSignatureHTMLMode.setForm(formWithSignature.form).then(() => {
formWithSignatureHTMLMode.setSubmission(formWithSignature.submission);
setTimeout(() => {
const signatureImage = formWithSignatureHTMLMode.element.querySelector('[ref="signatureImage"]');
assert.equal(signatureImage.src === formWithSignature.submission.data.signature, true);
done();
}, 200);
})
.catch((err) => done(err));
});
it('Should display conditional page after setting submission', function(done) {
const formElement = document.createElement('div');
const wizardWithSimpleConditionalPage = new Wizard(formElement);
wizardWithSimpleConditionalPage.setForm(wizard4).then(() => {
setTimeout(() => {
assert.equal(wizardWithSimpleConditionalPage.pages.length, 1);
assert.equal(wizardWithSimpleConditionalPage.components.length, 1);
const submissionData = { checkbox: true, number: 555 };
wizardWithSimpleConditionalPage.setSubmission({ data:submissionData });
setTimeout(() => {
assert.equal(wizardWithSimpleConditionalPage.pages.length, 2);
assert.equal(wizardWithSimpleConditionalPage.components.length, 2);
assert.deepEqual(wizardWithSimpleConditionalPage.data, submissionData);
done();
}, 500);
}, 200);
})
.catch((err) => done(err));
});
it('Should display submission data on page with custom conditional logic in readOnly', function(done) {
const formElement = document.createElement('div');
const wizardWithCustomConditionalPage = new Wizard(formElement);
wizardWithCustomConditionalPage.setForm(wizard5).then(() => {
setTimeout(() => {
wizardWithCustomConditionalPage.disabled = true;
if (wizardWithCustomConditionalPage.options) {
wizardWithCustomConditionalPage.options.readOnly = true;
}
else {
wizardWithCustomConditionalPage.options = { readOnly: true };
}
setTimeout(() => {
assert.equal(wizardWithCustomConditionalPage.pages.length, 1);
assert.equal(wizardWithCustomConditionalPage.components.length, 1);
const submissionData = { checkbox: true, number: 555 };
wizardWithCustomConditionalPage.setSubmission({ data:submissionData });
setTimeout(() => {
assert.equal(wizardWithCustomConditionalPage.pages.length, 2);
assert.equal(wizardWithCustomConditionalPage.components.length, 2);
assert.deepEqual(wizardWithCustomConditionalPage.data, submissionData);
const clickEvent = new Event('click');
const secondPageBtn = wizardWithCustomConditionalPage.refs[`${wizardWithCustomConditionalPage.wizardKey}-link`][1];
secondPageBtn.dispatchEvent(clickEvent);
setTimeout(() => {
assert.equal(wizardWithCustomConditionalPage.page, 1);
const numberComponent = wizardWithCustomConditionalPage.element.querySelector('[name="data[number]"]');
assert.equal(numberComponent.value, 555);
done();
}, 400);
}, 300);
}, 200);
}, 100);
})
.catch((err) => done(err));
});
it('Should show conditional wizard page', function(done) {
const formElement = document.createElement('div');
const wizardWithConditionalPage = new Wizard(formElement);
wizardWithConditionalPage.setForm(wizard3).then(() => {
setTimeout(() => {
assert.equal(wizardWithConditionalPage.pages.length, 1);
assert.equal(wizardWithConditionalPage.components.length, 1);
const inputEvent = new Event('input');
const numberComponent = wizardWithConditionalPage.element.querySelector('[name="data[number]"]');
numberComponent.value = 5;
numberComponent.dispatchEvent(inputEvent);
setTimeout(() => {
assert.equal(wizardWithConditionalPage.pages.length, 2);
assert.equal(wizardWithConditionalPage.components.length, 2);
done();
}, 300);
}, 200);
})
.catch((err) => done(err));
});
it('Should show first conditional wizard page', function(done) {
const formElement = document.createElement('div');
const wizard = new Wizard(formElement);
wizard.setForm(wizard6).then(() => {
assert.equal(wizard.pages.length, 1);
assert.equal(wizard.components.length, 1);
assert.equal(wizard.page, 0);
assert.equal(wizard.refs[`wizard-${wizard.id}-previous`], null);
assert.equal(
wizard.refs[
`wizard-${wizard.id}-link`
][0].parentElement.classList.contains('active'),
true
);
wizard.setValue({
data: { b: 'true' },
});
setTimeout(() => {
assert.equal(wizard.pages.length, 2);
assert.equal(wizard.components.length, 2);
assert.equal(wizard.page, 1);
assert.notEqual(wizard.refs[`wizard-${wizard.id}-previous`], null);
assert.equal(
wizard.refs[
`wizard-${wizard.id}-link`
][1].parentElement.classList.contains('active'),
true
);
done();
}, 300);
})
.catch((err) => done(err));
});
it('Should display editGrid submission data in readOnly mode', (done) => {
const formElement = document.createElement('div');
const wizardForm = new Wizard(formElement, { readOnly: true });
wizardForm.setForm(wizard2).then(() => {
wizardForm.setValue({ data: { editGrid: [{ textField: '111' }], number: 222 } });
setTimeout(() => {
assert.equal(wizardForm.element.querySelector('[name="data[number]"]').value, '222');
Harness.clickElement(wizardForm, wizardForm.refs[`${wizardForm.wizardKey}-link`][1]);
setTimeout(() => {
assert.equal(wizardForm.page, 1);
const ditGridRowValue = wizardForm.element.querySelector('[ref = "editgrid-editGrid-row"]').querySelector('.col-sm-2').textContent.trim();
assert.equal(ditGridRowValue, '111');
done();
}, 300);
}, 100);
})
.catch((err) => done(err));
});
let wizardForm = null;
it('Should set components errors if they are after page was changed with navigation', (done) => {
const formElement = document.createElement('div');
wizardForm = new Wizard(formElement);
wizardForm.setForm(wizard).then(() => {
Harness.testErrors(wizardForm, {
data: {
a: '1',
c: '',
textField: ''
}
},
[{
component: 'a',
message: 'a must have at least 4 characters.'
}], done);
Harness.clickElement(wizardForm, wizardForm.refs[`${wizardForm.wizardKey}-link`][2]);
assert.equal(wizardForm.page, 2);
setTimeout(() => {
Harness.clickElement(wizardForm, wizardForm.refs[`${wizardForm.wizardKey}-link`][0]);
assert.equal(wizardForm.page, 0);
setTimeout(() => {
const aInput = wizardForm.currentPage.getComponent('a');
assert.equal(aInput.errors.length, 1);
assert.equal(aInput.errors[0].message, 'a must have at least 4 characters.');
done();
}, 100);
}, 100);
})
.catch((err) => done(err));
});
it('Should leave errors for invalid fields after validation on next button and entering valid data in one of the fields', function(done) {
const formElement = document.createElement('div');
wizardForm = new Wizard(formElement);
wizardForm.setForm(wizard1).then(() => {
Harness.clickElement(wizardForm, wizardForm.refs[`${wizardForm.wizardKey}-next`]);
setTimeout(() => {
assert.equal(wizardForm.errors.length, 2);
const inputEvent = new Event('input', { bubbles: true, cancelable: true });
const inputA = formElement.querySelector('input[name="data[a]"]');
for (let i = 0; i < 5; i++) {
inputA.value += i;
inputA.dispatchEvent(inputEvent);
}
setTimeout(() => {
assert.equal(wizardForm.errors.length, 1);
done();
}, 250);
}, 250);
})
.catch((err) => done(err));
});
it('Should not set components errors if in readOnly mode', (done) => {
const formElement = document.createElement('div');
wizardForm = new Wizard(formElement, { readOnly: true });
wizardForm.setForm(wizard).then(() => {
Harness.testSubmission(wizardForm, {
data: {
a: '1',
textField: 'aaa',
c: '0'
}
});
Harness.clickElement(wizardForm, wizardForm.refs[`${wizardForm.wizardKey}-link`][2]);
assert.equal(wizardForm.page, 2);
Harness.clickElement(wizardForm, wizardForm.refs[`${wizardForm.wizardKey}-link`][0]);
assert.equal(wizardForm.page, 0);
const aInput = wizardForm.currentPage.getComponent('a');
assert.equal(aInput.errors.length, 0);
done();
});
});
it('Should keep values during validation that are conditionally visible', async() => {
const submission = {
data: {
a: true,
b: 'b',
c: 'c'
}
};
const form = await Formio.createForm(wizardCond, {});
form.validator.config = {
db: {},
token: '',
form: wizardCond,
submission: submission
};
// Set the submission data
form.data = submission.data;
assert.deepEqual(form.data, submission.data, 'Should set data properly');
// Perform calculations and conditions.
form.calculateValue();
form.checkConditions();
assert(form.components[2], 'Should contain the 3rd page');
assert.equal(form.components[2].visible, true, 'Should be visible');
const textField = form.components[2].components[0];
assert.equal(textField.visible, true, 'Inner components of the 3rd page should be visible');
assert.equal(textField.parentVisible, true, 'parentVisible of the 3rd page\'s child components should be equal to true');
// Reset the data
form.data = {};
form.setValue(submission, {
sanitize: true
});
// Check the validity of the form.
const valid = await form.checkAsyncValidity(null, true);
assert(valid, 'Should be valid');
assert.equal(form.data.c, 'c', 'Should keep the value of a conditionally visible page.');
});
it('If allowPrevious is given, the breadcrumb bar should be clickable for visited tabs.', (done) => {
const formElement = document.createElement('div');
wizardForm = new Wizard(formElement, { allowPrevious: true });
wizardForm.setForm(wizardWithAllowPrevious)
.then(() => {
Harness.clickElement(wizardForm, wizardForm.refs[`${wizardForm.wizardKey}-link`][1]);
setTimeout(() => {
assert.equal(wizardForm.page, 0, 'Should be disabled for unvisited tabs.');
Harness.clickElement(wizardForm, wizardForm.refs[`${wizardForm.wizardKey}-next`]);
setTimeout(() => {
assert.equal(wizardForm.enabledIndex, 1, 'Should be clickable for visited tabs.');
done();
}, 100);
}, 100);
})
.catch(done);
});
it('Should scroll to the top of the page when the page is changed', (done) => {
const formElement = document.createElement('div');
wizardForm = new Wizard(formElement);
wizardForm.setForm(wizardWithHighPages)
.then(() => {
wizardForm.scrollIntoView(wizardForm.refs[`${wizardForm.wizardKey}-next`]);
wizardForm.setPage(1);
setTimeout(() => {
assert.equal(wizardForm.refs[wizardForm.wizardKey].scrollTop, 0, 'The top edge of the page should be aligned to the top edge of the window');
done();
}, 350);
})
.catch(done);
});
it('Should show the actual page after re-rendering due to nested wizards.', (done) => {
const formElement = document.createElement('div');
wizardForm = new Wizard(formElement);
wizardForm.setForm(wizardWithNestedWizard)
.then(() => {
assert.equal(wizardForm.element.querySelector('.wizard-page'), wizardForm.allPages[0].components[0].element.parentNode);
done();
})
.catch(done);
});
// BUG - uncomment once fixed (ticket FIO-6043)
// it('Should render all pages as a part of wizard pagination', (done) => {
// const formElement = document.createElement('div');
// const wizard = new Wizard(formElement);
// const childForm = _.cloneDeep(wizardChildForm);
// const clickEvent = new Event('click');
// wizard.setForm(wizardParentForm).then(() => {
// assert.equal(wizard.components.length, 2);
// assert.equal(wizard.allPages.length, 2);
// assert.equal(wizard.allPages[1].component.title, 'Page 3');
// const radioComp = wizard.getComponent('radio1');
// radioComp.setValue('yes');
// wizard.render();
// setTimeout(() => {
// const nestedFormComp = wizard.getComponent('formNested');
// nestedFormComp.loadSubForm = () => {
// nestedFormComp.formObj = childForm;
// nestedFormComp.subFormLoading = false;
// return new Promise((resolve) => resolve(childForm));
// };
// nestedFormComp.createSubForm();
// setTimeout(() => {
// assert.equal(wizard.components.length, 3);
// assert.equal(wizard.allPages.length, 4);
// assert.equal(wizard.allPages[1].component.title, 'Child Page 1');
// const checboxComp = wizard.getComponent('checkbox');
// checboxComp.setValue(true);
// wizard.render();
// setTimeout(() => {
// assert.equal(wizard.components.length, 3);
// assert.equal(wizard.allPages.length, 5);
// assert.equal(wizard.allPages[1].component.title, 'Page 2');
// assert.equal(wizard.element.querySelector('input[name="data[textFieldNearForm]"]'), null);
// const nextPageBtn = wizard.refs[`${wizard.wizardKey}-next`];
// nextPageBtn.dispatchEvent(clickEvent);
// setTimeout(() => {
// assert.equal(wizard.component.title, 'Page 2');
// assert.ok(wizard.element.querySelector('input[name="data[textFieldNearForm]"]'));
// done();
// }, 200);
// }, 200);
// }, 200);
// }, 200);
// }).catch(done);
// });
describe('Conditional pages', () => {
it('Should remove page from header when it is hidden', (done) => {
const formElement = document.createElement('div');
const form = new Wizard(formElement);
form.setForm(wizardWithConditionallyVisiblePage)
.then(() => {
const textField = form.getComponent(['textField']);
Harness.dispatchEvent(
'input',
textField.element,
'[name="data[textField]"]',
(input) => input.value = 'hide',
);
assert.equal(form.refs[`wizard-${form.id}-link`].length, 3, 'Should show all the pages in header');
setTimeout(() => {
assert.equal(textField.dataValue, 'hide', 'Should set value');
const page2 = form.getComponent(['page2']);
assert.equal(page2.visible, false, 'Should be hidden by logic');
assert.equal(form.refs[`wizard-${form.id}-link`].length, 2, 'Should remove invisible pages from header');
done();
}, 300);
})
.catch(done);
});
it('', (done) => {
const formElement = document.createElement('div');
Formio.createForm(formElement, nestedConditionalWizard).then((form) => {
const nestedFormRadio = form.getComponent(['nestedForm']);
nestedFormRadio.setValue('yes');
setTimeout(() => {
const secondQuestionToOpenNestedFormRadio = form.getComponent(['secondQuestionToOpenNestedForm']);
assert(secondQuestionToOpenNestedFormRadio.visible, 'Should become visible');
secondQuestionToOpenNestedFormRadio.setValue('openChildForm');
setTimeout(() => {
const nestedForm = form.getComponent(['form']);
assert(nestedForm.visible, 'Should become visible');
nestedForm.subForm.components.forEach((comp) => {
assert.equal(comp.root, nestedForm.subForm, 'The root of the nested components should be set to the' +
' Wizard itself');
});
const nestedRadio1 = nestedForm.subForm.getComponent(['radio1']);
nestedRadio1.setValue('unhidePage3');
setTimeout(() => {
const pages = form.element.querySelectorAll('.formio-form nav .pagination .page-item');
assert.equal(pages.length, 3, 'Should show the hidden initially page');
secondQuestionToOpenNestedFormRadio.setValue(2);
setTimeout(() => {
assert(!nestedForm.visible, 'Should become hidden');
secondQuestionToOpenNestedFormRadio.setValue('openChildForm');
setTimeout(() => {
assert(nestedForm.visible, 'Should become visible again');
secondQuestionToOpenNestedFormRadio.setValue('openChildForm');
nestedForm.subForm.components.forEach((comp) => {
assert.equal(comp.root, nestedForm.subForm, 'The root of the nested components should be set to the' +
' Wizard itself');
});
const nestedRadio1 = nestedForm.subForm.getComponent(['radio1']);
nestedRadio1.setValue('unhidePage3');
setTimeout(() => {
const pages = form.element.querySelectorAll('.formio-form nav .pagination .page-item');
assert.equal(pages.length, 3, 'Should show the hidden initially page');
done();
});
}, 400);
}, 500);
}, 400);
}, 500);
}, 400);
}).catch(done);
});
});
it('Should have proper values for localRoot', (done) => {
const formElement = document.createElement('div');
const wizard = new Wizard(formElement);
const form = _.cloneDeep(wizardWithPanel);
const nestedMiddleForm = _.cloneDeep(wizardWithWizard);
const childForm = _.cloneDeep(simpleTwoPagesWizard);
wizard.setForm(form).then(() => {
const nestedMiddleFormComp = wizard.getComponent('middleForm');
nestedMiddleFormComp.loadSubForm = () => {
nestedMiddleFormComp.formObj = nestedMiddleForm;
nestedMiddleFormComp.subFormLoading = false;
return new Promise((resolve) => resolve(nestedMiddleForm));
};
nestedMiddleFormComp.createSubForm();
setTimeout(() => {
const middleWizard = nestedMiddleFormComp.subForm;
const nestedChildFormComp = middleWizard.getComponent('childForm');
nestedChildFormComp.loadSubForm = () => {
nestedChildFormComp.formObj = childForm;
nestedChildFormComp.subFormLoading = false;
return new Promise((resolve) => resolve(childForm));
};
nestedChildFormComp.createSubForm();
setTimeout(() => {
const childWizard = nestedChildFormComp.subForm;
assert.equal(wizard.id, wizard.root.id);
assert.equal(wizard.id, wizard.localRoot.id);
assert.equal(wizard.root.id, wizard.localRoot.id);
assert.notEqual(middleWizard.id, middleWizard.root.id);
assert.equal(middleWizard.id, middleWizard.localRoot.id);
assert.notEqual(middleWizard.root.id, middleWizard.localRoot.id);
assert.notEqual(childWizard.id, childWizard.root.id);
assert.notEqual(childWizard.id, childWizard.localRoot.id);
assert.equal(childWizard.root.id, childWizard.localRoot.id);
done();
}, 200);
}, 200);
});
});
it('Should keep wizard pages separate from edit grid inner wizard pages', (done) => {
const formElement = document.createElement('div');
const wizard = new Wizard(formElement);
const form = _.cloneDeep(wizardWithNestedWizardInEditGrid);
const childForm = _.cloneDeep(simpleTwoPagesWizard);
wizard.setForm(form).then(() => {
assert.equal(wizard.components.length, 1);
assert.equal(wizard.allPages.length, 1);
const editGrid = wizard.getComponent('editGrid');
editGrid.addRow();
setTimeout(() => {
const nestedFormComp = wizard.getComponent('formNested');
nestedFormComp.loadSubForm = () => {
nestedFormComp.formObj = childForm;
nestedFormComp.subFormLoading = false;
return new Promise((resolve) => resolve(childForm));
};
nestedFormComp.createSubForm();
setTimeout(() => {
assert.equal(nestedFormComp.subForm.components.length, 2);
assert.equal(nestedFormComp.subForm.allPages.length, 2);
assert.equal(wizard.components.length, 1);
assert.equal(wizard.allPages.length, 1);
done();
}, 200);
}, 200);
});
});
it('Should navigate wizard pages and submit form using \'Save on Enter\' option', function(done) {
const formElement = document.createElement('div');
const wizard = new Wizard(formElement);
wizard.setForm(wizardNavigateOrSaveOnEnter.form).then(() => {
const pressEnter = () => {
const event = new KeyboardEvent('keyup', {
bubbles : true,
cancelable : true,
key : 'Enter',
keyCode : 13
});
document.dispatchEvent(event);
};
const checkPage = (pageNumber) => {
assert.equal(wizard.page, pageNumber, `Should open wizard page ${pageNumber + 1}`);
};
checkPage(0);
pressEnter();
setTimeout(() => {
checkPage(1);
pressEnter();
setTimeout(() => {
checkPage(2);
pressEnter();
setTimeout(() => {
assert.equal(wizard.submission.state, 'submitted', 'Should submit the form');
done();
}, 50);
}, 50);
}, 50);
})
.catch((err) => done(err));
});
it('Should proper validate nested wizard fields', (done) => {
const formElement = document.createElement('div');
const wizard = new Wizard(formElement);
const childForm = _.cloneDeep(wizardWithFieldsValidationChild);
const parentForm = _.cloneDeep(wizardWithFieldsValidationParent);
const clickEvent = new Event('click');
wizard.setForm(parentForm).then(() => {
const nestedFormComp = wizard.getComponent('formNested');
nestedFormComp.loadSubForm = () => {
nestedFormComp.formObj = childForm;
nestedFormComp.subFormLoading = false;
return new Promise((resolve) => resolve(childForm));
};
nestedFormComp.createSubForm();
setTimeout(() => {
const textField = wizard.getComponent('textField');
const testValidation = wizard.getComponent('testValidation');
textField.setValue('one');
testValidation.setValue('two');
wizard.render();
const checkPage = (pageNumber) => {
assert.equal(wizard.page, pageNumber);
};
const nextPageBtn = wizard.refs[`${wizard.wizardKey}-next`];
setTimeout(() => {
nextPageBtn.dispatchEvent(clickEvent);
setTimeout(() => {
checkPage(0);
assert.equal(wizard.errors.length, 1);
assert.equal(wizard.refs.errorRef.length, wizard.errors.length);
testValidation.setValue('one');
nextPageBtn.dispatchEvent(clickEvent);
setTimeout(() => {
checkPage(1);
assert.equal(wizard.errors.length, 0);
done();
}, 200);
}, 200);
}, 200);
}, 200);
});
});
});