src/components/datagrid/DataGrid.unit.js
import _ from 'lodash';
import assert from 'power-assert';
import { expect } from 'chai';
import sinon from 'sinon';
import Harness from '../../../test/harness';
import DataGridComponent from './DataGrid';
import Formio from '../../Formio';
import {
comp1,
comp2,
comp3,
comp4,
comp5,
withDefValue,
withRowGroupsAndDefValue,
modalWithRequiredFields,
withConditionalFieldsAndValidations,
withLogic
} from './fixtures';
describe('DataGrid Component', () => {
it('Test modal edit confirmation dialog', (done) => {
Harness.testCreate(DataGridComponent, comp5).then((component) => {
component.componentModal.openModal();
const fakeEvent = {
preventDefault: () => {}
};
component.componentModal.showDialogListener(fakeEvent);
assert.equal(component.componentModal.isOpened, false, 'Should be closed without confirmation dialog since value was not changed');
setTimeout(() => {
component.componentModal.openModal();
Harness.setInputValue(component, 'data[dataGrid][0][textField]', 'My Text');
setTimeout(() => {
component.componentModal.showDialogListener(fakeEvent);
assert.equal(component.componentModal.isValueChanged(), true, 'Should return true since value was modified');
assert.equal(component.componentModal.isOpened, true, 'Should stay opened and wait until user confirm closing without changes saving');
assert(component.componentModal.dialog, 'Should open confirmation dialog');
component.componentModal.closeDialog(fakeEvent);
component.destroy();
done();
}, 100);
}, 100);
}).catch(done);
});
it(`Should show alert message in modal edit, when clicking on modal overlay and value was changed,
and clear values when pushing 'yes, delete it' in alert container`, (done) => {
Harness.testCreate(DataGridComponent, comp4).then((component) => {
const hiddenModalWindow = component.element.querySelector('.component-rendering-hidden');
assert.equal(!!hiddenModalWindow, true);
const clickEvent = new Event('click');
const openModalElement = component.refs.openModal;
//open modal edit window
openModalElement.dispatchEvent(clickEvent);
setTimeout(() => {
assert.equal(!!component.element.querySelector('.component-rendering-hidden'), false);
const inputEvent = new Event('input');
const dataGridInputField = component.element.querySelector('[name="data[dataGrid][0][number]"]');
dataGridInputField.value = 55555;
//input value in dataGrid field inside modal edit window
dataGridInputField.dispatchEvent(inputEvent);
setTimeout(() => {
assert.equal(component.element.querySelector('[name="data[dataGrid][0][number]"]').value, '55555');
const clickEvent = new Event('click');
const modalOverlay = component.refs.modalOverlay;
//click outside modal edit window
modalOverlay.dispatchEvent(clickEvent);
setTimeout(() => {
assert.equal(!!component.componentModal.dialog, true);
const clickEvent = new Event('click');
const btnForCleaningValues = document.querySelector('[ref="dialogYesButton"]');
//click on 'yes, delete it' button inside alert window
btnForCleaningValues.dispatchEvent(clickEvent);
setTimeout(() => {
const clickEvent = new Event('click');
const openModalElement = component.refs.openModal;
//open edit modal window again
openModalElement.dispatchEvent(clickEvent);
setTimeout(() => {
assert.equal( component.element.querySelector('[name="data[dataGrid][0][number]"]').value, '');
done();
}, 350);
}, 300);
}, 250);
}, 200);
}, 150);
});
});
it('Should build a data grid component', () => {
return Harness.testCreate(DataGridComponent, comp1).then((component) => {
Harness.testElements(component, 'input[type="text"]', 3);
});
});
it('Should not skip validation on input nested components', done => {
Harness.testCreate(DataGridComponent, comp1)
.then(cmp => {
expect(cmp.shouldSkipValidation()).to.be.false;
done();
}, done)
.catch(done);
});
it('Should get and set values within the grid.', () => {
return Harness.testCreate(DataGridComponent, comp1).then((component) => {
Harness.testSetGet(component, [
{
make: 'Jeep',
model: 'Wrangler',
year: 1997
},
{
make: 'Chevy',
model: 'Tahoe',
year: 2014
}
]);
});
});
it('Should be able to add another row.', () => {
return Harness.testCreate(DataGridComponent, comp1).then((component) => {
Harness.testSetGet(component, [
{
make: 'Jeep',
model: 'Wrangler',
year: 1997
}
]);
component.addRow();
assert.deepEqual(component.getValue(), [
{
make: 'Jeep',
model: 'Wrangler',
year: 1997
},
{
make: '',
model: '',
year: ''
}
]);
});
});
it('Should allow provide default value', function(done) {
try {
Harness.testCreate(DataGridComponent, withDefValue)
.then((datagrid) => {
expect(datagrid.getValue()).to.deep.equal([
{ name: 'Alex', age: 1 },
{ name: 'Bob', age: 2 },
{ name: 'Conny', age: 3 }
]);
done();
}, done)
.catch(done);
}
catch (err) {
done(err);
}
});
it('Should allow provide default value in row-groups model', function(done) {
try {
Harness.testCreate(DataGridComponent, withRowGroupsAndDefValue)
.then((datagrid) => {
expect(datagrid.getValue()).to.deep.equal([
{ name: 'Alex', age: 1 },
{ name: 'Bob', age: 2 },
{ name: 'Conny', age: 3 },
{ name: '', age: '' },
{ name: '', age: '' }
]);
done();
}, done)
.catch(done);
}
catch (err) {
done(err);
}
});
it('Should not cause setValue loops when logic within hidden component is set', function(done) {
Formio.createForm(document.createElement('div'), withLogic)
.then((form) => {
const datagrid = form.getComponent('dataGrid');
const spyFunc = sinon.spy(datagrid, 'checkComponentConditions');
const textField = form.getComponent('escalationId');
const select = form.getComponent('teamName');
textField.component.hidden = true;
select.setValue('preRiskAnalysis', { modified: true });
setTimeout(() => {
expect(spyFunc.callCount).to.be.lessThan(4);
done();
}, 1500);
});
});
describe('get minLength', () => {
it('should return minimal number of required rows', () => {
const EIDV = 'Invalid default value';
const EDFC = 'Differ from configured value';
const EDFG = 'Differ from number of rows in groups';
const base = { type: 'datagrid', key: 'testkey' };
let schema = _.cloneDeep(base);
let datagrid = new DataGridComponent(schema, {});
expect(datagrid.minLength, EIDV).to.equal(0);
schema = Object.assign(_.cloneDeep(base), { validate: { minLength: 5 } });
datagrid = new DataGridComponent(schema, {});
expect(datagrid.minLength, EDFC).to.equal(5);
schema = Object.assign(_.cloneDeep(base), {
enableRowGroups: true,
rowGroups: [
{ label: 'H1', numberOfRows: 1 },
{ label: 'B2', numberOfRows: 3 },
{ label: 'C3', numberOfRows: 3 },
{ label: 'M4', numberOfRows: 2 }
]
});
datagrid = new DataGridComponent(schema, {});
expect(datagrid.minLength, EDFG).to.equal(9);
schema = Object.assign(_.cloneDeep(base), {
validate: { minLength: 5 },
enableRowGroups: true,
rowGroups: [
{ label: 'H1', numberOfRows: 1 },
{ label: 'B2', numberOfRows: 3 },
{ label: 'C3', numberOfRows: 3 },
{ label: 'M4', numberOfRows: 2 }
]
});
datagrid = new DataGridComponent(schema, {});
if (datagrid.minLength === 5) {
expect.fail('Number of row should take precedence over config');
}
else {
expect(datagrid.minLength, EDFG).to.equal(9);
}
});
});
describe('getGroupSizes', () => {
it('should return array of numbers representing group sizes', () => {
const { getGroupSizes } = DataGridComponent.prototype;
let self = { component: {} };
expect(getGroupSizes.call(self)).to.deep.equal([]);
self = { component: {
rowGroups: [{ numberOfRows: 1 }]
} };
expect(getGroupSizes.call(self)).to.deep.equal([1]);
self = { component: {
rowGroups: [{ numberOfRows: 1 }, { numberOfRows: 2 }]
} };
expect(getGroupSizes.call(self)).to.deep.equal([1, 2]);
self = { component: {
rowGroups: [{ numberOfRows: 1 }, { numberOfRows: 3 }, { numberOfRows: 10 }]
} };
expect(getGroupSizes.call(self)).to.deep.equal([1, 3, 10]);
});
});
it('Test "components" property and their context', (done) => {
const testComponentsData = (components, expectedData) => {
components.forEach((comp) => assert.deepEqual(
comp.data,
expectedData,
'Data of components inside DataGrid should be equal to row\'s data'
));
};
Formio.createForm(document.createElement('div'), withConditionalFieldsAndValidations)
.then((form) => {
const rootText = form.getComponent(['text']);
rootText.setValue('Match', { modified: true });
setTimeout(() => {
const emptyRowData = {
rootTest: '',
rowTest: ''
};
const dataGrid = form.getComponent(['dataGrid']);
assert.equal(dataGrid.components.length, 6, 'DataGrid.components should contain 6 components');
testComponentsData(dataGrid.components, emptyRowData);
const showTextFieldInsideDataGridRadio = form.getComponent(['radio']);
showTextFieldInsideDataGridRadio.setValue('show', { modified: true });
setTimeout(() => {
const rowData1 = { ...emptyRowData, radio1: '' };
const dataGridRowRadio = form.getComponent(['dataGrid', 0, 'radio1']);
assert.equal(dataGrid.components.length, 6, 'DataGrid.components should contain 6 components');
testComponentsData(dataGrid.components, rowData1);
assert.equal(dataGridRowRadio.visible, true, 'Radio inside DataGrid should become visible');
dataGridRowRadio.setValue('dgShow', { modified: true });
setTimeout(() => {
const rowData2 = {
...emptyRowData,
radio1: 'dgShow',
rowShowShowTextfieldWhenDataGridRadioHasShowValue: ''
};
const dataGridRowConditionalField = form.getComponent(['dataGrid', 0, 'rowShowShowTextfieldWhenDataGridRadioHasShowValue']);
assert.equal(dataGrid.components.length, 6, 'DataGrid.components should contain 6 components');
testComponentsData(dataGrid.components, rowData2);
assert.equal(dataGridRowConditionalField.visible, true, 'Conditional field inside DataGrid should become visible');
const rootTest = form.getComponent(['dataGrid', 0, 'rootTest']);
const rowTest = form.getComponent(['dataGrid', 0, 'rowTest']);
rootTest.setValue('Match', { modified: true });
rowTest.setValue('Match', { modified: true });
setTimeout(() => {
const rowData3 = {
...rowData2,
rowTest: 'Match',
rootTest: 'Match'
};
assert.equal(dataGrid.components.length, 6, 'DataGrid.components should contain 6 components');
testComponentsData(dataGrid.components, rowData3);
form.checkAsyncValidity(null, true).then((valid) => {
assert(valid, 'Form should be valid');
done();
}).catch(done);
}, 300);
}, 300);
}, 300);
}, 300);
})
.catch(done);
});
});
describe('DataGrid Panels', () => {
it('Should build a data grid component', () => {
return Harness.testCreate(DataGridComponent, comp2);
});
it('Should be able to set the values of one panel in the DataGrid.', () => {
return Harness.testCreate(DataGridComponent, comp2).then((component) => {
Harness.testSetGet(component, [
{
firstName: 'Joe',
lastName: 'Smith'
}
]);
// Now add a new row.
component.addRow();
assert.deepEqual(component.getValue(), [
{
firstName: 'Joe',
lastName: 'Smith'
},
{
firstName: '',
lastName: ''
}
]);
});
});
});
describe('DataGrid disabling', () => {
it('Child components should be disabled', () => {
return Harness.testCreate(DataGridComponent, comp3).then((component) => {
assert.equal(component.components.reduce((acc, child) => acc && child.parentDisabled, true), true);
});
});
});
describe('DataGrid modal', () => {
it('Should be highlighted in red when invalid', (done) => {
const formElement = document.createElement('div');
Formio.createForm(formElement, {
display: 'form',
components: [modalWithRequiredFields]
})
.then((form) => {
const data = {
dataGrid: [
{
textField: '',
textArea: ''
}
]
};
form.checkValidity(data, true, data);
setTimeout(() => {
Harness.testModalWrapperErrorClasses(form);
const validData = {
dataGrid: [
{
textField: 'Some text',
textArea: 'Mre text'
}
]
};
form.setSubmission({ data: validData });
setTimeout(() => {
Harness.testModalWrapperErrorClasses(form, false);
done();
}, 200);
}, 200);
})
.catch(done);
});
});