Skip to content

Commit

Permalink
🐛 [open-formulieren/open-forms#3611] Make time bounds validation incl…
Browse files Browse the repository at this point in the history
…usive

Backport-of: #596
  • Loading branch information
Viicos authored and sergei-maertens committed Nov 22, 2023
1 parent 6e0436e commit 41138f2
Show file tree
Hide file tree
Showing 2 changed files with 108 additions and 174 deletions.
6 changes: 3 additions & 3 deletions src/formio/validators/MinMaxTimeValidator.js
Original file line number Diff line number Diff line change
Expand Up @@ -14,20 +14,20 @@ const validateTimeBoundaries = (minBoundary, maxBoundary, timeValue) => {
// Case 1: only one boundary is given
if (!minTime || !maxTime) {
if (minTime) return {isValid: parsedValue >= minTime, errorKeys: ['minTime']};
if (maxTime) return {isValid: parsedValue < maxTime, errorKeys: ['maxTime']};
if (maxTime) return {isValid: parsedValue <= maxTime, errorKeys: ['maxTime']};
} else {
// Case 2: min boundary is smaller than max boundary
if (minTime < maxTime) {
const isTooEarly = parsedValue < minTime;
const isTooLate = parsedValue >= maxTime;
const isTooLate = parsedValue > maxTime;
return {
isValid: !isTooEarly && !isTooLate,
errorKeys: [isTooEarly ? 'minTime' : 'maxTime', 'invalid_time'],
};
} else {
// Case 3: min boundary is bigger than max boundary (it's the next day. For example min = 08:00, max = 01:00)
return {
isValid: !(parsedValue >= maxTime && parsedValue < minTime),
isValid: !(parsedValue > maxTime && parsedValue < minTime), // Basically, the opposite of 01:00 < `parsedValue` < 08:00
errorKeys: ['invalid_time'],
};
}
Expand Down
276 changes: 105 additions & 171 deletions src/jstests/formio/components/time.spec.js
Original file line number Diff line number Diff line change
@@ -1,204 +1,138 @@
import _ from 'lodash';
import React from 'react';
import {Formio} from 'react-formio';

import OpenFormsModule from 'formio/module';
import {sleep} from 'utils';

import {timeForm} from './fixtures/time';

// Use our custom components
Formio.use(OpenFormsModule);

describe('Time Component', () => {
test('Time component with min/max time validation', done => {
it.each([
['09:00:00', true],
['10:30:00', true],
['11:11:11', true],
['17:00:00', true],
['17:30:00', false],
['08:30:00', false],
])('Time component with min/max time validation', async (value, valid) => {
let formJSON = _.cloneDeep(timeForm);
formJSON.components[0].validate.minTime = '09:00:00';
formJSON.components[0].validate.maxTime = '17:00:00';

const validValues = ['09:00:00', '10:30:00', '11:11:11'];

const invalidValues = ['17:00:00', '17:30:00', '08:30:00'];

const testValidity = (values, valid) => {
values.forEach(value => {
const element = document.createElement('div');

Formio.createForm(element, formJSON)
.then(form => {
form.setPristine(false);
const component = form.getComponent('time');
const changed = component.setValue(value);
expect(changed).toBeTruthy();

setTimeout(() => {
if (valid) {
expect(!!component.error).toBeFalsy();
} else {
expect(!!component.error).toBeTruthy();
expect(component.error.message).toEqual('invalid_time');
}

if (value === invalidValues[2]) {
done();
}
}, 300);
})
.catch(done);
});
};

testValidity(validValues, true);
testValidity(invalidValues, false);
const element = document.createElement('div');
const form = await Formio.createForm(element, formJSON);
form.setPristine(false);

const component = form.getComponent('time');
const changed = component.setValue(value);
expect(changed).toBeTruthy();
await sleep(300);
if (valid) {
expect(!!component.error).toBeFalsy();
} else {
expect(!!component.error).toBeTruthy();
expect(component.error.message).toEqual('invalid_time');
}
});

test('Time component without min/max time validation', done => {
let formJSON = _.cloneDeep(timeForm);
it.each(['00:00:00', '23:59:59', '11:11:11'])(
'Time component without min/max time validation',
async value => {
let formJSON = _.cloneDeep(timeForm);

const validValues = ['00:00:00', '23:59:59', '11:11:11'];

const testValidity = values => {
values.forEach(value => {
const element = document.createElement('div');

Formio.createForm(element, formJSON)
.then(form => {
form.setPristine(false);
const component = form.getComponent('time');
const changed = component.setValue(value);
expect(changed).toBeTruthy();

setTimeout(() => {
expect(!!component.error).toBeFalsy();

if (value === validValues[2]) {
done();
}
}, 300);
})
.catch(done);
});
};
const element = document.createElement('div');
const form = await Formio.createForm(element, formJSON);
form.setPristine(false);

testValidity(validValues);
});
const component = form.getComponent('time');
const changed = component.setValue(value);
await sleep(300);

expect(changed).toBeTruthy();
expect(!!component.error).toBeFalsy();
}
);

test('Time component with only min time validation', done => {
it.each([
['17:00:00', true],
['08:00:00', false],
])('Time component with only min time validation', async (value, valid) => {
let formJSON = _.cloneDeep(timeForm);
formJSON.components[0].validate.minTime = '09:00:00';

const validValues = ['17:00:00'];

const invalidValues = ['08:00:00'];

const testValidity = (values, valid) => {
values.forEach(value => {
const element = document.createElement('div');

Formio.createForm(element, formJSON)
.then(form => {
form.setPristine(false);
const component = form.getComponent('time');
const changed = component.setValue(value);
expect(changed).toBeTruthy();

setTimeout(() => {
if (valid) {
expect(!!component.error).toBeFalsy();
} else {
expect(!!component.error).toBeTruthy();
}

if (value === invalidValues[0]) {
done();
}
}, 300);
})
.catch(done);
});
};

testValidity(validValues, true);
testValidity(invalidValues, false);
const element = document.createElement('div');
const form = await Formio.createForm(element, formJSON);
form.setPristine(false);

const component = form.getComponent('time');
const changed = component.setValue(value);
expect(changed).toBeTruthy();
await sleep(300);
if (valid) {
expect(!!component.error).toBeFalsy();
} else {
expect(!!component.error).toBeTruthy();
expect(component.error.message).toEqual('invalid_time');
}
});

test('Time component with only max time validation', done => {
it.each([
['08:00:00', true],
['09:00:00', true],
['17:00:00', false],
])('Time component with only max time validation', async (value, valid) => {
let formJSON = _.cloneDeep(timeForm);
formJSON.components[0].validate.maxTime = '09:00:00';

const validValues = ['08:00:00'];

const invalidValues = ['17:00:00'];

const testValidity = (values, valid) => {
values.forEach(value => {
const element = document.createElement('div');

Formio.createForm(element, formJSON)
.then(form => {
form.setPristine(false);
const component = form.getComponent('time');
const changed = component.setValue(value);
expect(changed).toBeTruthy();

setTimeout(() => {
if (valid) {
expect(!!component.error).toBeFalsy();
} else {
expect(!!component.error).toBeTruthy();
}

if (value === invalidValues[0]) {
done();
}
}, 300);
})
.catch(done);
});
};

testValidity(validValues, true);
testValidity(invalidValues, false);
const element = document.createElement('div');
const form = await Formio.createForm(element, formJSON);
form.setPristine(false);

const component = form.getComponent('time');
const changed = component.setValue(value);
expect(changed).toBeTruthy();
await sleep(300);
if (valid) {
expect(!!component.error).toBeFalsy();
} else {
expect(!!component.error).toBeTruthy();
expect(component.error.message).toEqual('invalid_time');
}
});

test('Time component with min time boundary larger than max time boundary', done => {
let formJSON = _.cloneDeep(timeForm);
formJSON.components[0].validate.maxTime = '01:00:00';
formJSON.components[0].validate.minTime = '08:00:00';

const validValues = ['09:00:00', '00:30:00'];

const invalidValues = ['02:00:00'];

const testValidity = (values, valid) => {
values.forEach(value => {
const element = document.createElement('div');

Formio.createForm(element, formJSON)
.then(form => {
form.setPristine(false);
const component = form.getComponent('time');
const changed = component.setValue(value);
expect(changed).toBeTruthy();

setTimeout(() => {
if (valid) {
expect(!!component.error).toBeFalsy();
} else {
expect(!!component.error).toBeTruthy();
}

if (value === invalidValues[0]) {
done();
}
}, 300);
})
.catch(done);
});
};

testValidity(validValues, true);
testValidity(invalidValues, false);
});
it.each([
['09:00:00', true],
['00:30:00', true],
['01:00:00', true],
['08:00:00', true],
['02:00:00', false],
])(
'Time component with min time boundary larger than max time boundary',
async (value, valid) => {
let formJSON = _.cloneDeep(timeForm);
formJSON.components[0].validate.maxTime = '01:00:00';
formJSON.components[0].validate.minTime = '08:00:00';

const element = document.createElement('div');
const form = await Formio.createForm(element, formJSON);
form.setPristine(false);

const component = form.getComponent('time');
const changed = component.setValue(value);
expect(changed).toBeTruthy();

await sleep(300);
if (valid) {
expect(!!component.error).toBeFalsy();
} else {
expect(!!component.error).toBeTruthy();
expect(component.error.message).toEqual('invalid_time');
}
}
);

test('Time component with both min/max and max > min validation and custom error', done => {
let formJSON = _.cloneDeep(timeForm);
Expand Down

0 comments on commit 41138f2

Please sign in to comment.