@qavajs/validation
Version:
Lib that transform plain english definition to validation functions
144 lines • 6.49 kB
JavaScript
;
Object.defineProperty(exports, "__esModule", { value: true });
exports.expect = exports.validationRegexp = exports.validationExtractRegexp = exports.validations = void 0;
exports.verify = verify;
exports.getValidation = getValidation;
exports.getPollValidation = getPollValidation;
exports.poll = poll;
const matchers_1 = require("./matchers");
Object.defineProperty(exports, "expect", { enumerable: true, get: function () { return matchers_1.expect; } });
exports.validations = {
EQUAL: 'equal',
DEEPLY_EQUAL: 'deeply equal',
STRICTLY_EQUAL: 'strictly equal',
HAVE_MEMBERS: 'have member',
MATCH: 'match',
CONTAIN: 'contain',
ABOVE: 'above',
BELOW: 'below',
GREATER: 'greater than',
LESS: 'less than',
HAVE_TYPE: 'have type',
INCLUDE_MEMBERS: 'include member',
HAVE_PROPERTY: 'have property',
MATCH_SCHEMA: 'match schema',
CASE_INSENSITIVE_EQUAL: 'case insensitive equal',
SATISFY: 'satisfy'
};
const isClause = '(?:is |do |does |to )?';
const notClause = '(?<reverse>not |to not )?';
const toBeClause = '(?:to )?(?:be )?';
const softlyClause = '(?<soft>softly )?';
const validationClause = `(?:(?<validation>${Object.values(exports.validations).join('|')})(?:s|es| to)?)`;
exports.validationExtractRegexp = new RegExp(`^${isClause}${notClause}${toBeClause}${softlyClause}${validationClause}$`);
exports.validationRegexp = new RegExp(`(${isClause}${notClause}${toBeClause}${softlyClause}${validationClause})`);
const aboveFn = (expectClause, expected) => expectClause.toBeGreaterThan(toNumber(expected));
const belowFn = (expectClause, expected) => expectClause.toBeLessThan(toNumber(expected));
const validationFns = {
[exports.validations.EQUAL]: (expectClause, expected) => expectClause.toSimpleEqual(expected),
[exports.validations.STRICTLY_EQUAL]: (expectClause, expected) => expectClause.toEqual(expected),
[exports.validations.DEEPLY_EQUAL]: (expectClause, expected) => expectClause.toDeepEqual(expected),
[exports.validations.HAVE_MEMBERS]: (expectClause, expected) => expectClause.toHaveMembers(expected),
[exports.validations.MATCH]: (expectClause, expected) => expectClause.toMatch(toRegexp(expected)),
[exports.validations.CONTAIN]: (expectClause, expected) => expectClause.toContain(expected),
[exports.validations.ABOVE]: aboveFn,
[exports.validations.BELOW]: belowFn,
[exports.validations.GREATER]: aboveFn,
[exports.validations.LESS]: belowFn,
[exports.validations.HAVE_TYPE]: (expectClause, expected) => expectClause.toHaveType(expected),
[exports.validations.INCLUDE_MEMBERS]: (expectClause, expected) => expectClause.toIncludeMembers(expected),
[exports.validations.HAVE_PROPERTY]: (expectClause, expected) => expectClause.toHaveProperty(expected),
[exports.validations.MATCH_SCHEMA]: (expectClause, expected) => expectClause.toMatchSchema(expected),
[exports.validations.CASE_INSENSITIVE_EQUAL]: (expectClause, expected) => expectClause.toCaseInsensitiveEqual(expected),
[exports.validations.SATISFY]: (expectClause, expected) => expectClause.toSatisfy(expected),
};
/**
* Basic verification function
* @param {VerifyInput} object with all needed data for validation
*/
function verify({ received, expected, validation, reverse, soft }) {
const expectClause = (0, matchers_1.expect)(received).configure({ not: reverse, soft });
const validate = validationFns[validation];
validate(expectClause, expected);
}
function getValidation(validationType, options) {
const match = exports.validationExtractRegexp.exec(validationType);
if (!match)
throw new Error(`Validation '${validationType}' is not supported`);
const { reverse, validation, soft } = match.groups;
const softProp = options?.soft || !!soft;
return function (received, expected) {
verify({ received, expected, validation, reverse: Boolean(reverse), soft: softProp });
};
}
function getPollValidation(validationType, options) {
const match = exports.validationExtractRegexp.exec(validationType);
if (!match)
throw new Error(`Poll validation '${validationType}' is not supported`);
const { reverse, validation, soft } = match.groups;
const softProp = options?.soft || !!soft;
return async function (received, expected, options) {
const timeout = options?.timeout ?? 5000;
const interval = options?.interval ?? 500;
let lastError = new Error(`Promise was not settled before timeout`);
let intervalId;
const evaluatePromise = new Promise(resolve => {
intervalId = setInterval(async () => {
try {
const actualValue = await received();
verify({
received: actualValue,
expected,
validation,
reverse: Boolean(reverse),
soft: softProp
});
clearInterval(intervalId);
resolve();
}
catch (err) {
lastError = err;
}
}, interval);
});
const timeoutPromise = new Promise((_, reject) => setTimeout(() => {
clearInterval(intervalId);
reject(lastError);
}, timeout));
return Promise.race([evaluatePromise, timeoutPromise]);
};
}
async function poll(fn, options) {
const timeout = options?.timeout ?? 5000;
const interval = options?.interval ?? 500;
let lastError = new Error('Unexpected error');
let intervalId;
const evaluatePromise = new Promise(resolve => {
intervalId = setInterval(async () => {
try {
await fn();
clearInterval(intervalId);
resolve();
}
catch (err) {
lastError = err;
}
}, interval);
});
const timeoutPromise = new Promise((_, reject) => setTimeout(() => {
clearInterval(intervalId);
reject(lastError);
}, timeout));
return Promise.race([evaluatePromise, timeoutPromise]);
}
function toNumber(n) {
const parsedNumber = Number.parseFloat(n);
if (Number.isNaN(parsedNumber)) {
throw new TypeError(`${n} is not a number`);
}
return parsedNumber;
}
function toRegexp(r) {
return r instanceof RegExp ? r : new RegExp(r);
}
//# sourceMappingURL=verify.js.map