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

[open-formulieren/open-forms#3611] Make time bounds validation inclusive #596

Merged
merged 4 commits into from
Nov 22, 2023
Merged
Show file tree
Hide file tree
Changes from 3 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
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 @@
// 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

Check warning on line 30 in src/formio/validators/MinMaxTimeValidator.js

View check run for this annotation

Codecov / codecov/patch

src/formio/validators/MinMaxTimeValidator.js#L30

Added line #L30 was not covered by tests
errorKeys: ['invalid_time'],
};
}
Expand Down
283 changes: 109 additions & 174 deletions src/jstests/formio/components/time.spec.js
Original file line number Diff line number Diff line change
@@ -1,204 +1,139 @@
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);
});

test('Time component without min/max time validation', done => {
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);
});
};

testValidity(validValues);
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 min time validation', done => {
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 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();
setTimeout(() => {
expect(!!component.error).toBeFalsy();
}, 300);
Viicos marked this conversation as resolved.
Show resolved Hide resolved
}
);

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