diff --git a/packages/jest-structure/.eslintrc.js b/packages/jest-structure/.eslintrc.js new file mode 100644 index 0000000..b7b711a --- /dev/null +++ b/packages/jest-structure/.eslintrc.js @@ -0,0 +1,3 @@ +module.exports = { + extends: [require.resolve('../../.eslintrc')], +}; diff --git a/packages/jest-structure/.gitignore b/packages/jest-structure/.gitignore new file mode 100644 index 0000000..6bd5bd7 --- /dev/null +++ b/packages/jest-structure/.gitignore @@ -0,0 +1 @@ +distTest/ diff --git a/packages/jest-structure/.prettierignore b/packages/jest-structure/.prettierignore new file mode 100644 index 0000000..b43bf86 --- /dev/null +++ b/packages/jest-structure/.prettierignore @@ -0,0 +1 @@ +README.md diff --git a/packages/jest-structure/.prettierrc.js b/packages/jest-structure/.prettierrc.js new file mode 100644 index 0000000..f004026 --- /dev/null +++ b/packages/jest-structure/.prettierrc.js @@ -0,0 +1 @@ +module.exports = require('../../.prettierrc.json'); diff --git a/packages/jest-structure/README.md b/packages/jest-structure/README.md new file mode 100644 index 0000000..f595601 --- /dev/null +++ b/packages/jest-structure/README.md @@ -0,0 +1,178 @@ +# jest-structure + +Custom [Jest](https://www.npmjs.com/package/jest) matchers to test [Structure](https://www.npmjs.com/package/structure) instances. + +## Example usage + +```js +expect(user).toBeValidStructure() + +expect(user).toBeInvalidStructure() + +expect(user).toHaveInvalidAttribute(['name']) + +expect(user).toHaveInvalidAttribute(['name'], ['"name" is required']) + +expect(user).toHaveInvalidAttribute(['name'], expect.arrayContaining(['"name" is required'])) + +expect(user).toHaveInvalidAttributes([ + { path: ['name'], messages: expect.arrayContaining(['"name" is required']) }, + { + path: ['age'], + messages: [ + '"age" must be larger than or equal to 2', + '"age" must be a positive number' + ] + } +]) +``` + + +## Installation + +jest-structure is available in npm, so you can install it with npm or yarn as a development dependency: + +```sh +npm install --save-dev jest-structure + +# or + +yarn --dev add jest-structure +``` + + +## Setup + +After installing, you need to tell Jest to use jest-structure, this can be done in two ways: + +1. By importing and manually adding it to Jest (in a setup file or directly in the top of your test file): + +```js +import jestStructure from 'jest-structure' + +expect.extend(jestStructure); +``` + +2. By allowing jest-structure to add itself to Jest matchers: + +```js +import 'jest-structure/extend-expect' +``` + +## Matchers + +### `toBeValidStructure()` + +This matcher passes if the structure is _valid_: + +```js +const User = attributes({ + name: { type: String, required: true } +})(class User {}) + +const validUser = new User({ name: 'Me' }) + +expect(validUser).toBeValidStructure() // passes + +const invalidUser = new User() + +expect(invalidUser).toBeValidStructure() // fails +``` + +### `toBeInvalidStructure()` + +This matcher passes if the structure is _invalid_: + +```js +const User = attributes({ + name: { type: String, required: true } +})(class User {}) + +const invalidUser = new User() + +expect(invalidUser).toBeInvalidStructure() // passes + +const validUser = new User({ name: 'Me' }) + +expect(validUser).toBeInvalidStructure() // fails +``` + +## `toHaveInvalidAttribute(path, messages)` + +This matcher allows you to assert that a _single attribute_ of the structure is invalid, optionally passing the array of error messages for that attribute: + +```js +const User = attributes({ + name: { type: String, required: true }, + age: { type: Number, required: true } +})(class User {}) + +const user = new User({ age: 42 }) + +// passes, because name is invalid +expect(user).toHaveInvalidAttribute(['name']) + +// fails, because age is valid +expect(user).toHaveInvalidAttribute(['age']) + +// passes, because name is invalid with this message +expect(user).toHaveInvalidAttribute(['name'], ['"name" is required']) + +// fails, because name is invalid but not with this message +expect(user).toHaveInvalidAttribute(['name'], ['"name" is not cool']) + +// passes. Notice that you can even use arrayContaining to check for a subset of the errros +expect(user).toHaveInvalidAttribute(['name'], expect.arrayContaining(['"name" is required'])) + +// passes. And stringContaining can be used as well +expect(user).toHaveInvalidAttribute(['name'], [expect.stringContaining('required')]) +``` + +## `toHaveInvalidAttributes([ { path, messages } ])` + +This matcher allows you to assert that _multiple attributes_ of the structure are invalid, optionally passing the array of error messages for each attribute: + +```js +const User = attributes({ + name: { type: String, required: true }, + age: { type: Number, required: true } +})(class User {}) + +const user = new User({ age: 42 }) + +// passes, because name is invalid +expect(user).toHaveInvalidAttributes([ + { path: ['name'] } +]) + +// fails, because age is valid +expect(user).toHaveInvalidAttributes([ + { path: ['age'] } +]) + +// fails, because name is invalid but age is valid +expect(user).toHaveInvalidAttributes([ + { path: ['name'] }, + { path: ['age'] } +]) + +// passes, because name is invalid with this message +expect(user).toHaveInvalidAttributes([ + { path: ['name'], messages: ['"name" is required'] } +]) + +// fails, because name is invalid but not with this message +expect(user).toHaveInvalidAttributes([ + { path: ['name'], messages: ['"name" is not cool'] } +]) + +// passes. Notice that you can even use arrayContaining to check for a subset of the errros +expect(user).toHaveInvalidAttributes([ + { path: ['name'], messages: expect.arrayContaining(['"name" is required']) } +]) + +// passes. And stringContaining can be used as well +expect(user).toHaveInvalidAttributes([ + { path: ['name'], messages: [expect.stringContaining('required')] } +]) +``` diff --git a/packages/jest-structure/extend-expect.js b/packages/jest-structure/extend-expect.js new file mode 100644 index 0000000..3bd76a6 --- /dev/null +++ b/packages/jest-structure/extend-expect.js @@ -0,0 +1 @@ +expect.extend(require('./')); diff --git a/packages/jest-structure/index.js b/packages/jest-structure/index.js new file mode 100644 index 0000000..6583013 --- /dev/null +++ b/packages/jest-structure/index.js @@ -0,0 +1,6 @@ +module.exports = { + toBeValidStructure: require('./src/assertions/toBeValidStructure'), + toBeInvalidStructure: require('./src/assertions/toBeInvalidStructure'), + toHaveInvalidAttribute: require('./src/assertions/toHaveInvalidAttribute'), + toHaveInvalidAttributes: require('./src/assertions/toHaveInvalidAttributes'), +}; diff --git a/packages/jest-structure/package.json b/packages/jest-structure/package.json new file mode 100644 index 0000000..3002f26 --- /dev/null +++ b/packages/jest-structure/package.json @@ -0,0 +1,18 @@ +{ + "name": "jest-structure", + "version": "2.0.0-alpha", + "description": "Jest assertions to use with Structure", + "main": "index.js", + "author": "Talysson ", + "license": "MIT", + "scripts": { + "test": "jest" + }, + "devDependencies": { + "structure": "2.0.0-alpha" + }, + "peerDependencies": { + "jest": "^24.0.0" + }, + "dependencies": {} +} diff --git a/packages/jest-structure/src/assertions/toBeInvalidStructure.js b/packages/jest-structure/src/assertions/toBeInvalidStructure.js new file mode 100644 index 0000000..824bbbf --- /dev/null +++ b/packages/jest-structure/src/assertions/toBeInvalidStructure.js @@ -0,0 +1,7 @@ +const createValidityAssertion = require('../lib/validityAssertion'); + +module.exports = createValidityAssertion({ + pass: (valid) => !valid, + passName: 'invalid', + failName: 'valid', +}); diff --git a/packages/jest-structure/src/assertions/toBeValidStructure.js b/packages/jest-structure/src/assertions/toBeValidStructure.js new file mode 100644 index 0000000..be2db4b --- /dev/null +++ b/packages/jest-structure/src/assertions/toBeValidStructure.js @@ -0,0 +1,7 @@ +const createValidityAssertion = require('../lib/validityAssertion'); + +module.exports = createValidityAssertion({ + pass: (valid) => valid, + passName: 'valid', + failName: 'invalid', +}); diff --git a/packages/jest-structure/src/assertions/toHaveInvalidAttribute.js b/packages/jest-structure/src/assertions/toHaveInvalidAttribute.js new file mode 100644 index 0000000..ae24438 --- /dev/null +++ b/packages/jest-structure/src/assertions/toHaveInvalidAttribute.js @@ -0,0 +1,68 @@ +const { sortMessagesByExpected } = require('../lib/sorting'); +const { isValidPath } = require('../lib/attributePath'); +const { failInvalidUsage, failNoNegative, failWrongValidity } = require('../lib/errors'); +const matcherName = 'toHaveInvalidAttribute'; +const exampleName = 'structure'; +const attributePathHint = 'attributePath'; +const errorMessagesHint = '[errorMessages]'; + +module.exports = function toHaveInvalidAttribute(structure, attributePath, expectedErrorMessages) { + if (this.isNot) { + return failNoNegative(matcherName); + } + + if (!isValidPath(attributePath)) { + return failInvalidUsage( + matcherName, + usageHint(this), + 'must not be called without the attribute path' + ); + } + + const { valid, errors } = structure.validate(); + + if (valid) { + return failWrongValidity({ + pass: false, + passName: 'invalid', + failName: 'valid', + context: this, + }); + } + + const attributeErrors = errors.filter((error) => this.equals(error.path, attributePath)); + + const joinedAttributeName = attributePath.join('.'); + + if (isExpectedAttributeValid(expectedErrorMessages, attributeErrors)) { + return { + pass: Boolean(attributeErrors.length), + message: () => + `Expected: ${joinedAttributeName} to be ${this.utils.EXPECTED_COLOR('invalid')}\n` + + `Received: ${joinedAttributeName} is ${this.utils.RECEIVED_COLOR('valid')}`, + }; + } + + const validationErrorMessages = attributeErrors.map((error) => error.message); + const errorMessages = sortMessagesByExpected(validationErrorMessages, expectedErrorMessages); + + return { + pass: this.equals(errorMessages, expectedErrorMessages), + message: () => + this.utils.printDiffOrStringify( + expectedErrorMessages, + errorMessages, + `Expected ${joinedAttributeName} error messages`, + `Received ${joinedAttributeName} error messages`, + this.expand + ), + }; +}; + +const usageHint = (context) => + context.utils.matcherHint(matcherName, exampleName, attributePathHint, { + secondArgument: errorMessagesHint, + }); + +const isExpectedAttributeValid = (expectedErrorMessages, attributeErrors) => + !(expectedErrorMessages && attributeErrors.length); diff --git a/packages/jest-structure/src/assertions/toHaveInvalidAttributes.js b/packages/jest-structure/src/assertions/toHaveInvalidAttributes.js new file mode 100644 index 0000000..d1fe45c --- /dev/null +++ b/packages/jest-structure/src/assertions/toHaveInvalidAttributes.js @@ -0,0 +1,61 @@ +const { sortErrorsByExpected } = require('../lib/sorting'); +const { areExpectedErrorsPathsValid } = require('../lib/attributePath'); +const { failInvalidUsage, failNoNegative, failWrongValidity } = require('../lib/errors'); +const matcherName = 'toHaveInvalidAttributes'; +const exampleName = 'structure'; +const expectedErrorsHint = '[{ path (required), messages (optional) }]'; + +module.exports = function toHaveInvalidAttributes(structure, expectedErrors) { + if (this.isNot) { + return failNoNegative(matcherName); + } + + if (!areExpectedErrorsPresent(expectedErrors)) { + return failInvalidUsage( + matcherName, + usageHint(this), + 'must not be called without the expected errros' + ); + } + + const { valid, errors } = structure.validate(); + + if (valid) { + return failWrongValidity({ + pass: false, + passName: 'invalid', + failName: 'valid', + context: this, + }); + } + + if (!areExpectedErrorsPathsValid(expectedErrors)) { + return failNoPath(this); + } + + const errorsForComparison = sortErrorsByExpected(errors, expectedErrors, this); + + return { + pass: this.equals(errorsForComparison, expectedErrors), + message: () => + this.utils.printDiffOrStringify( + expectedErrors, + errorsForComparison, + `Expected errors`, + `Received errors`, + this.expand + ), + }; +}; + +const areExpectedErrorsPresent = (expectedErrors) => expectedErrors && expectedErrors.length; + +const usageHint = (context) => + context.utils.matcherHint(matcherName, exampleName, expectedErrorsHint); + +const failNoPath = (context) => ({ + pass: false, + message: () => + `${matcherName} must not be called without the attribute paths\n` + + `Example: ${usageHint(context)}`, +}); diff --git a/packages/jest-structure/src/lib/attributePath.js b/packages/jest-structure/src/lib/attributePath.js new file mode 100644 index 0000000..7836b6b --- /dev/null +++ b/packages/jest-structure/src/lib/attributePath.js @@ -0,0 +1,20 @@ +const isValidPath = (path) => Boolean(path && path.length); + +const areExpectedErrorsPathsValid = (expectedErrors) => expectedErrors.every(errorHasPath); +const errorHasPath = (error) => isValidPath(error.path); + +const groupByPath = (errors, context) => + errors.reduce((grouped, error) => { + const group = grouped.find((group) => context.equals(group.path, error.path)); + + if (group) { + group.messages.push(error.message); + return grouped; + } + + const newGroup = { path: error.path, messages: [error.message] }; + + return [...grouped, newGroup]; + }, []); + +module.exports = { isValidPath, areExpectedErrorsPathsValid, groupByPath }; diff --git a/packages/jest-structure/src/lib/errors.js b/packages/jest-structure/src/lib/errors.js new file mode 100644 index 0000000..6f069b2 --- /dev/null +++ b/packages/jest-structure/src/lib/errors.js @@ -0,0 +1,16 @@ +module.exports = { + failNoNegative: (matcherName) => ({ + pass: true, // it has to be true because it's using .not + message: () => `${matcherName} must not be used with .not`, + }), + failWrongValidity: ({ pass, passName, failName, context }) => ({ + pass, + message: () => + `Expected: to be ${context.utils.EXPECTED_COLOR(context.isNot ? failName : passName)}\n` + + `Received: is ${context.utils.RECEIVED_COLOR(context.isNot ? passName : failName)}`, + }), + failInvalidUsage: (matcherName, usageHint, message) => ({ + pass: false, + message: () => `${matcherName} ${message}\n` + `Example: ${usageHint}`, + }), +}; diff --git a/packages/jest-structure/src/lib/sorting.js b/packages/jest-structure/src/lib/sorting.js new file mode 100644 index 0000000..dc861dc --- /dev/null +++ b/packages/jest-structure/src/lib/sorting.js @@ -0,0 +1,41 @@ +const { groupByPath } = require('./attributePath'); + +function sortMessagesByExpected(errorMessages, expectedErrorMessages) { + expectedErrorMessages = expectedErrorMessages.sample || expectedErrorMessages; + + const equalMessages = expectedErrorMessages.filter((message) => errorMessages.includes(message)); + const differentMessages = errorMessages.filter( + (message) => !expectedErrorMessages.includes(message) + ); + + return [...equalMessages, ...differentMessages]; +} + +function sortErrorsByExpected(errors, expectedErrors, context) { + const groupedErrors = groupByPath(errors, context); + + const equalErrors = expectedErrors + .filter((error) => + groupedErrors.find((groupedError) => context.equals(groupedError.path, error.path)) + ) + .map((expectedError) => { + const error = groupedErrors.find((error) => context.equals(expectedError.path, error.path)); + + if (expectedError.messages) { + return { + ...error, + messages: sortMessagesByExpected(error.messages, expectedError.messages), + }; + } + + return { path: error.path }; + }); + + const differentErrors = groupedErrors.filter( + (groupedError) => !expectedErrors.find((error) => context.equals(groupedError.path, error.path)) + ); + + return [...equalErrors, ...differentErrors]; +} + +module.exports = { sortErrorsByExpected, sortMessagesByExpected }; diff --git a/packages/jest-structure/src/lib/validityAssertion.js b/packages/jest-structure/src/lib/validityAssertion.js new file mode 100644 index 0000000..c4fe034 --- /dev/null +++ b/packages/jest-structure/src/lib/validityAssertion.js @@ -0,0 +1,16 @@ +const { failWrongValidity } = require('../lib/errors'); + +module.exports = function createValidityAssertion({ pass, passName, failName }) { + return function(structure, expected) { + this.utils.ensureNoExpected(expected); + + const { valid } = structure.validate(); + + return failWrongValidity({ + pass: pass(valid), + passName, + failName, + context: this, + }); + }; +}; diff --git a/packages/jest-structure/test/__snapshots__/jest-structure.test.js.snap b/packages/jest-structure/test/__snapshots__/jest-structure.test.js.snap new file mode 100644 index 0000000..913cd76 --- /dev/null +++ b/packages/jest-structure/test/__snapshots__/jest-structure.test.js.snap @@ -0,0 +1,358 @@ +// Jest Snapshot v1, https://goo.gl/fbAQLP + +exports[`jest-structure toBeInvalid .not fails for invalid structures 1`] = ` +"Expected: to be valid +Received: is invalid" +`; + +exports[`jest-structure toBeInvalid fails for valid structures 1`] = ` +"Expected: to be invalid +Received: is valid" +`; + +exports[`jest-structure toBeValid .not fails for valid structures 1`] = ` +"Expected: to be invalid +Received: is valid" +`; + +exports[`jest-structure toBeValid fails for invalid structures 1`] = ` +"Expected: to be valid +Received: is invalid" +`; + +exports[`jest-structure toHaveInvalidAttribute can not be called with empty attribute path 1`] = ` +"toHaveInvalidAttribute must not be called without the attribute path +Example: expect(structure).toHaveInvalidAttribute(attributePath, [errorMessages])" +`; + +exports[`jest-structure toHaveInvalidAttribute can not be called without attribute path 1`] = ` +"toHaveInvalidAttribute must not be called without the attribute path +Example: expect(structure).toHaveInvalidAttribute(attributePath, [errorMessages])" +`; + +exports[`jest-structure toHaveInvalidAttribute can not be used with .not 1`] = `"toHaveInvalidAttribute must not be used with .not"`; + +exports[`jest-structure toHaveInvalidAttribute when attribute path and error messages are passed fails for valid structures 1`] = ` +"Expected: to be invalid +Received: is valid" +`; + +exports[`jest-structure toHaveInvalidAttribute when attribute path and error messages are passed when the attribute is not the invalid one fails 1`] = ` +"Expected: age to be invalid +Received: age is valid" +`; + +exports[`jest-structure toHaveInvalidAttribute when attribute path and error messages are passed when the attribute is the only one invalid when the expected errors are a subset of the actual errors fails 1`] = ` +"- Expected name error messages ++ Received name error messages + + Array [ + \\"\\\\\\"name\\\\\\" length must be at least 2 characters long\\", ++ \\"\\\\\\"name\\\\\\" must only contain alpha-numeric characters\\", + ]" +`; + +exports[`jest-structure toHaveInvalidAttribute when attribute path and error messages are passed when the attribute is the only one invalid when the expected errors are a superset of the actual errors fails 1`] = ` +"- Expected name error messages ++ Received name error messages + + Array [ + \\"\\\\\\"name\\\\\\" must only contain alpha-numeric characters\\", +- \\"\\\\\\"name\\\\\\" is not from this planet\\", + \\"\\\\\\"name\\\\\\" length must be at least 2 characters long\\", + ]" +`; + +exports[`jest-structure toHaveInvalidAttribute when attribute path and error messages are passed when the attribute is the only one invalid when using arrayContaining when arrayContaining has an intersection with the errors + other different errors fails 1`] = ` +"Expected name error messages: ArrayContaining [\\"\\\\\\"name\\\\\\" is not from this planet\\", \\"\\\\\\"name\\\\\\" length must be at least 2 characters long\\"] +Received name error messages: [\\"\\\\\\"name\\\\\\" length must be at least 2 characters long\\", \\"\\\\\\"name\\\\\\" must only contain alpha-numeric characters\\"]" +`; + +exports[`jest-structure toHaveInvalidAttribute when attribute path and error messages are passed when the attribute is the only one invalid when using arrayContaining when arrayContaining is a superset of the errors fails 1`] = ` +"Expected name error messages: ArrayContaining [\\"\\\\\\"name\\\\\\" must only contain alpha-numeric characters\\", \\"\\\\\\"name\\\\\\" is not from this planet\\", \\"\\\\\\"name\\\\\\" length must be at least 2 characters long\\"] +Received name error messages: [\\"\\\\\\"name\\\\\\" must only contain alpha-numeric characters\\", \\"\\\\\\"name\\\\\\" length must be at least 2 characters long\\"]" +`; + +exports[`jest-structure toHaveInvalidAttribute when only attribute path is passed fails for valid structures 1`] = ` +"Expected: to be invalid +Received: is valid" +`; + +exports[`jest-structure toHaveInvalidAttribute when only attribute path is passed when the attribute is not the invalid one fails 1`] = ` +"Expected: name to be invalid +Received: name is valid" +`; + +exports[`jest-structure toHaveInvalidAttributes can not be called with empty array of expected errors 1`] = ` +"toHaveInvalidAttributes must not be called without the expected errros +Example: expect(structure).toHaveInvalidAttributes([{ path (required), messages (optional) }])" +`; + +exports[`jest-structure toHaveInvalidAttributes can not be called with no path 1`] = ` +"toHaveInvalidAttributes must not be called without the attribute paths +Example: expect(structure).toHaveInvalidAttributes([{ path (required), messages (optional) }])" +`; + +exports[`jest-structure toHaveInvalidAttributes can not be called without the array of expected errors 1`] = ` +"toHaveInvalidAttributes must not be called without the expected errros +Example: expect(structure).toHaveInvalidAttributes([{ path (required), messages (optional) }])" +`; + +exports[`jest-structure toHaveInvalidAttributes can not be used with .not 1`] = `"toHaveInvalidAttributes must not be used with .not"`; + +exports[`jest-structure toHaveInvalidAttributes when messages are passed only for some fails for valid structures 1`] = ` +"Expected: to be invalid +Received: is valid" +`; + +exports[`jest-structure toHaveInvalidAttributes when messages are passed only for some when attribute is invalid but messages array is empty fails 1`] = ` +"- Expected errors ++ Received errors + +@@ -1,8 +1,11 @@ + Array [ + Object { +- \\"messages\\": Array [], ++ \\"messages\\": Array [ ++ \\"\\\\\\"name\\\\\\" length must be at least 2 characters long\\", ++ \\"\\\\\\"name\\\\\\" must only contain alpha-numeric characters\\", ++ ], + \\"path\\": Array [ + \\"name\\", + ], + }, + Object {" +`; + +exports[`jest-structure toHaveInvalidAttributes when messages are passed only for some when there are missing attributes and messages fails 1`] = ` +"- Expected errors ++ Received errors + + Array [ + Object { + \\"messages\\": Array [ + \\"\\\\\\"name\\\\\\" length must be at least 2 characters long\\", ++ \\"\\\\\\"name\\\\\\" must only contain alpha-numeric characters\\", + ], + \\"path\\": Array [ + \\"name\\", + ], + }, + Object { + \\"path\\": Array [ + \\"age\\", ++ ], ++ }, ++ Object { ++ \\"messages\\": Array [ ++ \\"\\\\\\"favoriteBook.name\\\\\\" is required\\", ++ ], ++ \\"path\\": Array [ ++ \\"favoriteBook\\", ++ \\"name\\", + ], + }, + ]" +`; + +exports[`jest-structure toHaveInvalidAttributes when messages are passed only for some when there are missing attributes fails 1`] = ` +"- Expected errors ++ Received errors + +@@ -2,6 +2,14 @@ + Object { + \\"path\\": Array [ + \\"name\\", + ], + }, ++ Object { ++ \\"messages\\": Array [ ++ \\"\\\\\\"age\\\\\\" must be a positive number\\", ++ ], ++ \\"path\\": Array [ ++ \\"age\\", ++ ], ++ }, + ]" +`; + +exports[`jest-structure toHaveInvalidAttributes when messages are passed only for some when there are missing messages fails 1`] = ` +"- Expected errors ++ Received errors + +@@ -1,9 +1,10 @@ + Array [ + Object { + \\"messages\\": Array [ + \\"\\\\\\"name\\\\\\" length must be at least 2 characters long\\", ++ \\"\\\\\\"name\\\\\\" must only contain alpha-numeric characters\\", + ], + \\"path\\": Array [ + \\"name\\", + ], + }," +`; + +exports[`jest-structure toHaveInvalidAttributes when only paths are passed fails for valid structures 1`] = ` +"Expected: to be invalid +Received: is valid" +`; + +exports[`jest-structure toHaveInvalidAttributes when only paths are passed when none of the passed attributes are invalid fails 1`] = ` +"- Expected errors ++ Received errors + + Array [ + Object { ++ \\"messages\\": Array [ ++ \\"\\\\\\"name\\\\\\" length must be at least 2 characters long\\", ++ \\"\\\\\\"name\\\\\\" must only contain alpha-numeric characters\\", ++ ], + \\"path\\": Array [ +- \\"age\\", ++ \\"name\\", + ], + }, + ]" +`; + +exports[`jest-structure toHaveInvalidAttributes when only paths are passed when only some of the passed attributes are invalid fails 1`] = ` +"- Expected errors ++ Received errors + + Array [ + Object { + \\"path\\": Array [ +- \\"age\\", +- ], +- }, +- Object { +- \\"path\\": Array [ + \\"name\\", + ], + }, + ]" +`; + +exports[`jest-structure toHaveInvalidAttributes when paths and messages are passed fails for valid structures 1`] = ` +"Expected: to be invalid +Received: is valid" +`; + +exports[`jest-structure toHaveInvalidAttributes when paths and messages are passed when attribute is invalid but messages array is empty fails 1`] = ` +"- Expected errors ++ Received errors + + Array [ + Object { +- \\"messages\\": Array [], ++ \\"messages\\": Array [ ++ \\"\\\\\\"name\\\\\\" length must be at least 2 characters long\\", ++ \\"\\\\\\"name\\\\\\" must only contain alpha-numeric characters\\", ++ ], + \\"path\\": Array [ + \\"name\\", + ], + }, + ]" +`; + +exports[`jest-structure toHaveInvalidAttributes when paths and messages are passed when there are missing attributes and messages fails 1`] = ` +"- Expected errors ++ Received errors + + Array [ + Object { + \\"messages\\": Array [ + \\"\\\\\\"name\\\\\\" length must be at least 2 characters long\\", ++ \\"\\\\\\"name\\\\\\" must only contain alpha-numeric characters\\", + ], + \\"path\\": Array [ + \\"name\\", ++ ], ++ }, ++ Object { ++ \\"messages\\": Array [ ++ \\"\\\\\\"age\\\\\\" must be a positive number\\", ++ ], ++ \\"path\\": Array [ ++ \\"age\\", + ], + }, + ]" +`; + +exports[`jest-structure toHaveInvalidAttributes when paths and messages are passed when there are missing attributes fails 1`] = ` +"- Expected errors ++ Received errors + +@@ -5,6 +5,14 @@ + ], + \\"path\\": Array [ + \\"name\\", + ], + }, ++ Object { ++ \\"messages\\": Array [ ++ \\"\\\\\\"age\\\\\\" must be a positive number\\", ++ ], ++ \\"path\\": Array [ ++ \\"age\\", ++ ], ++ }, + ]" +`; + +exports[`jest-structure toHaveInvalidAttributes when paths and messages are passed when there are missing messages fails 1`] = ` +"- Expected errors ++ Received errors + +@@ -1,9 +1,10 @@ + Array [ + Object { + \\"messages\\": Array [ + \\"\\\\\\"name\\\\\\" length must be at least 2 characters long\\", ++ \\"\\\\\\"name\\\\\\" must only contain alpha-numeric characters\\", + ], + \\"path\\": Array [ + \\"name\\", + ], + }," +`; + +exports[`jest-structure toHaveInvalidAttributes when using arrayContaining when arrayContaining has an intersection with the errors + other different errors fails 1`] = ` +"- Expected errors ++ Received errors + +@@ -1,10 +1,10 @@ + Array [ + Object { +- \\"messages\\": ArrayContaining [ +- \\"\\\\\\"name\\\\\\" is not from this planet\\", ++ \\"messages\\": Array [ + \\"\\\\\\"name\\\\\\" length must be at least 2 characters long\\", ++ \\"\\\\\\"name\\\\\\" must only contain alpha-numeric characters\\", + ], + \\"path\\": Array [ + \\"name\\", + ], + }," +`; + +exports[`jest-structure toHaveInvalidAttributes when using arrayContaining when arrayContaining is a superset of the errors fails 1`] = ` +"- Expected errors ++ Received errors + +@@ -1,10 +1,9 @@ + Array [ + Object { +- \\"messages\\": ArrayContaining [ ++ \\"messages\\": Array [ + \\"\\\\\\"name\\\\\\" must only contain alpha-numeric characters\\", +- \\"\\\\\\"name\\\\\\" is not from this planet\\", + \\"\\\\\\"name\\\\\\" length must be at least 2 characters long\\", + ], + \\"path\\": Array [ + \\"name\\", + ]," +`; diff --git a/packages/jest-structure/test/jest-structure.test.js b/packages/jest-structure/test/jest-structure.test.js new file mode 100644 index 0000000..4ca3aa2 --- /dev/null +++ b/packages/jest-structure/test/jest-structure.test.js @@ -0,0 +1,616 @@ +const { attributes } = require('structure'); +require('../extend-expect'); + +describe('jest-structure', () => { + let User; + + beforeEach(() => { + const Book = attributes({ + name: { + type: String, + required: true, + }, + })(class Book {}); + + User = attributes({ + name: { + type: String, + required: true, + minLength: 2, + alphanumeric: true, + }, + age: { + type: Number, + required: true, + positive: true, + }, + favoriteBook: Book, + })(class User {}); + }); + + describe('toBeValid', () => { + it('suceeds for valid structures', () => { + const user = new User({ name: 'abc', age: 42 }); + + expect(user).toBeValidStructure(); + }); + + it('fails for invalid structures', () => { + const user = new User(); + + expect(() => { + expect(user).toBeValidStructure(); + }).toThrowErrorMatchingSnapshot(); + }); + + describe('.not', () => { + it('succeeds for invalid structures', () => { + const user = new User(); + + expect(user).not.toBeValidStructure(); + }); + + it('fails for valid structures', () => { + const user = new User({ name: 'abc', age: 42 }); + + expect(() => { + expect(user).not.toBeValidStructure(); + }).toThrowErrorMatchingSnapshot(); + }); + }); + }); + + describe('toBeInvalid', () => { + it('suceeds for invalid structures', () => { + const user = new User(); + + expect(user).toBeInvalidStructure(); + }); + + it('fails for valid structures', () => { + const user = new User({ name: 'abc', age: 42 }); + + expect(() => { + expect(user).toBeInvalidStructure(); + }).toThrowErrorMatchingSnapshot(); + }); + + describe('.not', () => { + it('succeeds for valid structures', () => { + const user = new User({ name: 'abc', age: 42 }); + + expect(user).not.toBeInvalidStructure(); + }); + + it('fails for invalid structures', () => { + const user = new User(); + + expect(() => { + expect(user).not.toBeInvalidStructure(); + }).toThrowErrorMatchingSnapshot(); + }); + }); + }); + + describe('toHaveInvalidAttribute', () => { + it('can not be used with .not', () => { + const user = new User(); + + expect(() => { + expect(user).not.toHaveInvalidAttribute(['name']); + }).toThrowErrorMatchingSnapshot(); + }); + + it('can not be called without attribute path', () => { + const user = new User(); + + expect(() => { + expect(user).toHaveInvalidAttribute(); + }).toThrowErrorMatchingSnapshot(); + }); + + it('can not be called with empty attribute path', () => { + const user = new User(); + + expect(() => { + expect(user).toHaveInvalidAttribute([]); + }).toThrowErrorMatchingSnapshot(); + }); + + describe('when only attribute path is passed', () => { + it('fails for valid structures', () => { + const user = new User({ name: 'abc', age: 42 }); + + expect(() => { + expect(user).toHaveInvalidAttribute(['name']); + }).toThrowErrorMatchingSnapshot(); + }); + + describe('when the attribute is the only one invalid', () => { + it('succeeds ', () => { + const user = new User({ age: 42 }); + + expect(user).toHaveInvalidAttribute(['name']); + }); + }); + + describe('when the attribute is not the only one invalid', () => { + it('succeeds ', () => { + const user = new User({}); + + expect(user).toHaveInvalidAttribute(['name']); + }); + }); + + describe('when the attribute is not the invalid one', () => { + it('fails ', () => { + const user = new User({ name: 'abc' }); + + expect(() => { + expect(user).toHaveInvalidAttribute(['name']); + }).toThrowErrorMatchingSnapshot(); + }); + }); + }); + + describe('when attribute path and error messages are passed', () => { + it('fails for valid structures', () => { + const user = new User({ name: 'abc', age: 42 }); + + expect(() => { + expect(user).toHaveInvalidAttribute(['name'], ['nope']); + }).toThrowErrorMatchingSnapshot(); + }); + + describe('when the attribute is the only one invalid', () => { + describe('when the errors are passed the same order returned by validate()', () => { + it('succeeds', () => { + const user = new User({ name: '$', age: 42 }); + + expect(user).toHaveInvalidAttribute( + ['name'], + [ + '"name" length must be at least 2 characters long', + '"name" must only contain alpha-numeric characters', + ] + ); + }); + }); + + describe('when the errors are passed in an order different from the returned by validate()', () => { + it('succeeds', () => { + const user = new User({ name: '$', age: 42 }); + + expect(user).toHaveInvalidAttribute( + ['name'], + [ + '"name" must only contain alpha-numeric characters', + '"name" length must be at least 2 characters long', + ] + ); + }); + }); + + describe('when the expected errors are a subset of the actual errors', () => { + it('fails', () => { + const user = new User({ name: '$', age: 42 }); + + expect(() => { + expect(user).toHaveInvalidAttribute( + ['name'], + ['"name" length must be at least 2 characters long'] + ); + }).toThrowErrorMatchingSnapshot(); + }); + }); + + describe('when the expected errors are a superset of the actual errors', () => { + it('fails', () => { + const user = new User({ name: '$', age: 42 }); + + expect(() => { + expect(user).toHaveInvalidAttribute( + ['name'], + [ + '"name" must only contain alpha-numeric characters', + '"name" is not from this planet', + '"name" length must be at least 2 characters long', + ] + ); + }).toThrowErrorMatchingSnapshot(); + }); + }); + + describe('when using arrayContaining', () => { + describe('when arrayContaining is a subset of the errors', () => { + it('succeeds', () => { + const user = new User({ name: '$', age: 42 }); + + expect(user).toHaveInvalidAttribute( + ['name'], + expect.arrayContaining(['"name" length must be at least 2 characters long']) + ); + }); + }); + + describe('when arrayContaining is a superset of the errors', () => { + it('fails', () => { + const user = new User({ name: '$', age: 42 }); + + expect(() => { + expect(user).toHaveInvalidAttribute( + ['name'], + expect.arrayContaining([ + '"name" must only contain alpha-numeric characters', + '"name" is not from this planet', + '"name" length must be at least 2 characters long', + ]) + ); + }).toThrowErrorMatchingSnapshot(); + }); + }); + + describe('when arrayContaining has an intersection with the errors + other different errors', () => { + it('fails', () => { + const user = new User({ name: '$', age: 42 }); + + expect(() => { + expect(user).toHaveInvalidAttribute( + ['name'], + expect.arrayContaining([ + '"name" is not from this planet', + '"name" length must be at least 2 characters long', + ]) + ); + }).toThrowErrorMatchingSnapshot(); + }); + }); + }); + }); + + describe('when the attribute is not the only one invalid', () => { + it('succeeds ', () => { + const user = new User({}); + + expect(user).toHaveInvalidAttribute(['name'], ['"name" is required']); + }); + }); + + describe('when the attribute is not the invalid one', () => { + it('fails ', () => { + const user = new User({ age: 42 }); + + expect(() => { + expect(user).toHaveInvalidAttribute(['age'], ['"age" is wrong']); + }).toThrowErrorMatchingSnapshot(); + }); + }); + }); + }); + + describe('toHaveInvalidAttributes', () => { + it('can not be used with .not', () => { + const user = new User(); + + expect(() => { + expect(user).not.toHaveInvalidAttributes([]); + }).toThrowErrorMatchingSnapshot(); + }); + + it('can not be called without the array of expected errors', () => { + const user = new User(); + + expect(() => { + expect(user).toHaveInvalidAttributes(); + }).toThrowErrorMatchingSnapshot(); + }); + + it('can not be called with empty array of expected errors', () => { + const user = new User(); + + expect(() => { + expect(user).toHaveInvalidAttributes([]); + }).toThrowErrorMatchingSnapshot(); + }); + + it('can not be called with no path', () => { + const user = new User({ name: '$', age: -42 }); + + expect(() => { + expect(user).toHaveInvalidAttributes([{ path: [] }, { path: ['age'] }]); + }).toThrowErrorMatchingSnapshot(); + }); + + describe('when only paths are passed', () => { + it('fails for valid structures', () => { + const user = new User({ name: 'abc', age: 42 }); + + expect(() => { + expect(user).toHaveInvalidAttributes([{ path: ['name'] }]); + }).toThrowErrorMatchingSnapshot(); + }); + + describe('when all the passed attributes are invalid', () => { + describe('when attributes are passed in the same order returned by validate', () => { + it('succeeds', () => { + const user = new User({ name: '$', age: -42 }); + + expect(user).toHaveInvalidAttributes([{ path: ['name'] }, { path: ['age'] }]); + }); + }); + + describe('when attributes are passed in an order different from the returned by validate', () => { + it('succeeds', () => { + const user = new User({ name: '$', age: -42 }); + + expect(user).toHaveInvalidAttributes([{ path: ['age'] }, { path: ['name'] }]); + }); + }); + }); + + describe('when only some of the passed attributes are invalid', () => { + it('fails', () => { + const user = new User({ name: '$', age: 42 }); + + expect(() => { + expect(user).toHaveInvalidAttributes([{ path: ['age'] }, { path: ['name'] }]); + }).toThrowErrorMatchingSnapshot(); + }); + }); + + describe('when none of the passed attributes are invalid', () => { + it('fails', () => { + const user = new User({ name: '$', age: 42 }); + + expect(() => { + expect(user).toHaveInvalidAttributes([{ path: ['age'] }]); + }).toThrowErrorMatchingSnapshot(); + }); + }); + }); + + describe('when paths and messages are passed', () => { + it('fails for valid structures', () => { + const user = new User({ name: 'abc', age: 42 }); + + expect(() => { + expect(user).toHaveInvalidAttributes([ + { path: ['name'], messages: ['something wrong is not right'] }, + ]); + }).toThrowErrorMatchingSnapshot(); + }); + + describe('when attribute is invalid and messages are right', () => { + describe('when messages are passed in the same order returned by validate', () => { + it('succeeds', () => { + const user = new User({ name: '$', age: 42 }); + + expect(user).toHaveInvalidAttributes([ + { + path: ['name'], + messages: [ + '"name" length must be at least 2 characters long', + '"name" must only contain alpha-numeric characters', + ], + }, + ]); + }); + }); + + describe('when messages are passed in a order different from the returned by validate', () => { + it('succeeds', () => { + const user = new User({ name: '$', age: 42 }); + + expect(user).toHaveInvalidAttributes([ + { + path: ['name'], + messages: [ + '"name" must only contain alpha-numeric characters', + '"name" length must be at least 2 characters long', + ], + }, + ]); + }); + }); + }); + + describe('when attribute is invalid but messages array is empty', () => { + it('fails', () => { + const user = new User({ name: '$', age: 42 }); + + expect(() => { + expect(user).toHaveInvalidAttributes([{ path: ['name'], messages: [] }]); + }).toThrowErrorMatchingSnapshot(); + }); + }); + + describe('when there are missing attributes', () => { + it('fails', () => { + const user = new User({ name: 'A', age: -42 }); + + expect(() => { + expect(user).toHaveInvalidAttributes([ + { path: ['name'], messages: ['"name" length must be at least 2 characters long'] }, + ]); + }).toThrowErrorMatchingSnapshot(); + }); + }); + + describe('when there are missing messages', () => { + it('fails', () => { + const user = new User({ name: '$', age: 42 }); + + expect(() => { + expect(user).toHaveInvalidAttributes([ + { path: ['name'], messages: ['"name" length must be at least 2 characters long'] }, + ]); + }).toThrowErrorMatchingSnapshot(); + }); + }); + + describe('when there are missing attributes and messages', () => { + it('fails', () => { + const user = new User({ name: '$', age: -42 }); + + expect(() => { + expect(user).toHaveInvalidAttributes([ + { path: ['name'], messages: ['"name" length must be at least 2 characters long'] }, + ]); + }).toThrowErrorMatchingSnapshot(); + }); + }); + }); + + describe('when messages are passed only for some', () => { + it('fails for valid structures', () => { + const user = new User({ name: 'abc', age: 42 }); + + expect(() => { + expect(user).toHaveInvalidAttributes([ + { path: ['name'], messages: ['something wrong is not right'] }, + { path: ['age'] }, + ]); + }).toThrowErrorMatchingSnapshot(); + }); + + describe('when attribute is invalid and messages are right', () => { + describe('when messages are passed in the same order returned by validate', () => { + it('succeeds', () => { + const user = new User({ name: '$', age: -42 }); + + expect(user).toHaveInvalidAttributes([ + { + path: ['name'], + messages: [ + '"name" length must be at least 2 characters long', + '"name" must only contain alpha-numeric characters', + ], + }, + { path: ['age'] }, + ]); + }); + }); + + describe('when messages are passed in a order different from the returned by validate', () => { + it('succeeds', () => { + const user = new User({ name: '$', age: -42 }); + + expect(user).toHaveInvalidAttributes([ + { + path: ['name'], + messages: [ + '"name" must only contain alpha-numeric characters', + '"name" length must be at least 2 characters long', + ], + }, + { path: ['age'] }, + ]); + }); + }); + }); + + describe('when attribute is invalid but messages array is empty', () => { + it('fails', () => { + const user = new User({ name: '$', age: -42 }); + + expect(() => { + expect(user).toHaveInvalidAttributes([ + { path: ['name'], messages: [] }, + { path: ['age'] }, + ]); + }).toThrowErrorMatchingSnapshot(); + }); + }); + + describe('when there are missing attributes', () => { + it('fails', () => { + const user = new User({ name: 'A', age: -42 }); + + expect(() => { + expect(user).toHaveInvalidAttributes([{ path: ['name'] }]); + }).toThrowErrorMatchingSnapshot(); + }); + }); + + describe('when there are missing messages', () => { + it('fails', () => { + const user = new User({ name: '$', age: -42 }); + + expect(() => { + expect(user).toHaveInvalidAttributes([ + { path: ['name'], messages: ['"name" length must be at least 2 characters long'] }, + { path: ['age'] }, + ]); + }).toThrowErrorMatchingSnapshot(); + }); + }); + + describe('when there are missing attributes and messages', () => { + it('fails', () => { + const user = new User({ name: '$', age: -42, favoriteBook: {} }); + + expect(() => { + expect(user).toHaveInvalidAttributes([ + { path: ['name'], messages: ['"name" length must be at least 2 characters long'] }, + { path: ['age'] }, + ]); + }).toThrowErrorMatchingSnapshot(); + }); + }); + }); + + describe('when using arrayContaining', () => { + describe('when arrayContaining is a subset of the errors', () => { + it('succeeds', () => { + const user = new User({ name: '$', age: 42 }); + + expect(user).toHaveInvalidAttributes([ + { + path: ['name'], + messages: expect.arrayContaining([ + '"name" length must be at least 2 characters long', + ]), + }, + ]); + }); + }); + + describe('when arrayContaining is a superset of the errors', () => { + it('fails', () => { + const user = new User({ name: '$', age: 42 }); + + expect(() => { + expect(user).toHaveInvalidAttributes([ + { + path: ['name'], + messages: expect.arrayContaining([ + '"name" must only contain alpha-numeric characters', + '"name" is not from this planet', + '"name" length must be at least 2 characters long', + ]), + }, + ]); + }).toThrowErrorMatchingSnapshot(); + }); + }); + + describe('when arrayContaining has an intersection with the errors + other different errors', () => { + it('fails', () => { + const user = new User({ name: '$', age: 42 }); + + expect(() => { + expect(user).toHaveInvalidAttributes([ + { + path: ['name'], + messages: expect.arrayContaining([ + '"name" is not from this planet', + '"name" length must be at least 2 characters long', + ]), + }, + ]); + }).toThrowErrorMatchingSnapshot(); + }); + }); + }); + }); +}); diff --git a/packages/structure/package.json b/packages/structure/package.json index 1f98c8f..b83d298 100644 --- a/packages/structure/package.json +++ b/packages/structure/package.json @@ -29,14 +29,14 @@ "domain" ], "scripts": { - "test": "jest", + "test": "jest --config=test/jest.node.js", "test:browser:build": "webpack --config test/webpack.pretest.js", "test:browser:run": "jest --config=test/jest.browser.js", "test:browser": "yarn run test:browser:build && yarn run test:browser:run", - "coverage": "jest --coverage", + "coverage": "yarn test --coverage", "build": "webpack", "prepublish": "yarn run build", - "coveralls": "jest --coverage --coverageReporters=text-lcov | coveralls", + "coveralls": "yarn run coverage --coverageReporters=text-lcov | coveralls", "lint": "eslint {src,test,benchmark}/**/*.js", "format": "prettier --write {src,test}/**/*.js" }, @@ -52,6 +52,7 @@ "babel-loader": "^8.0.6", "coveralls": "^3.0.7", "electron": "^6.0.12", + "jest-structure": "2.0.0-alpha", "webpack": "^4.41.2", "webpack-cli": "^3.3.9" } diff --git a/packages/structure/test/jest.browser.js b/packages/structure/test/jest.browser.js index 2f3c1c9..195d2d9 100644 --- a/packages/structure/test/jest.browser.js +++ b/packages/structure/test/jest.browser.js @@ -1,6 +1,7 @@ module.exports = { runner: '@jest-runner/electron', testEnvironment: '@jest-runner/electron/environment', + setupFilesAfterEnv: ['/support/setup.js'], moduleNameMapper: { src$: '/../distTest/structure.js', }, diff --git a/packages/structure/test/jest.node.js b/packages/structure/test/jest.node.js new file mode 100644 index 0000000..886ca5c --- /dev/null +++ b/packages/structure/test/jest.node.js @@ -0,0 +1,3 @@ +module.exports = { + setupFilesAfterEnv: ['/support/setup.js'], +}; diff --git a/packages/structure/test/support/setup.js b/packages/structure/test/support/setup.js new file mode 100644 index 0000000..3d8fddb --- /dev/null +++ b/packages/structure/test/support/setup.js @@ -0,0 +1,3 @@ +const jestStructure = require('jest-structure'); + +expect.extend(jestStructure); diff --git a/packages/structure/test/support/validationMatchers.js b/packages/structure/test/support/validationMatchers.js deleted file mode 100644 index c95ce0b..0000000 --- a/packages/structure/test/support/validationMatchers.js +++ /dev/null @@ -1,15 +0,0 @@ -exports.assertValid = function assertValid(structure) { - const { valid, errors } = structure.validate(); - - expect(valid).toBe(true); - expect(errors).toBeUndefined(); -}; - -exports.assertInvalid = function assertInvalid(structure, path) { - const { valid, errors } = structure.validate(); - - expect(valid).toBe(false); - expect(errors).toBeInstanceOf(Array); - expect(errors).toHaveLength(1); - expect(errors[0].path).toEqual(path); -}; diff --git a/packages/structure/test/unit/validation/array.spec.js b/packages/structure/test/unit/validation/array.spec.js index 1a7fe1f..21338f1 100644 --- a/packages/structure/test/unit/validation/array.spec.js +++ b/packages/structure/test/unit/validation/array.spec.js @@ -1,5 +1,4 @@ const { attributes } = require('../../../src'); -const { assertValid, assertInvalid } = require('../../support/validationMatchers'); describe('validation', () => { describe('Array', () => { @@ -21,7 +20,7 @@ describe('validation', () => { books: [], }); - assertValid(user); + expect(user).toBeValidStructure(); }); }); @@ -31,7 +30,7 @@ describe('validation', () => { books: undefined, }); - assertValid(user); + expect(user).toBeValidStructure(); }); }); }); @@ -55,7 +54,7 @@ describe('validation', () => { books: [], }); - assertValid(user); + expect(user).toBeValidStructure(); }); }); @@ -65,7 +64,7 @@ describe('validation', () => { books: undefined, }); - assertInvalid(user, ['books']); + expect(user).toHaveInvalidAttribute(['books'], ['"books" is required']); }); }); }); @@ -87,7 +86,7 @@ describe('validation', () => { it('is valid', () => { const user = new User(); - assertValid(user); + expect(user).toBeValidStructure(); }); }); @@ -97,7 +96,7 @@ describe('validation', () => { books: undefined, }); - assertValid(user, 'books'); + expect(user).toBeValidStructure(); }); }); }); @@ -122,7 +121,7 @@ describe('validation', () => { books: ['Poetic Edda', 'Prose Edda'], }); - assertValid(user); + expect(user).toBeValidStructure(); }); }); @@ -132,7 +131,10 @@ describe('validation', () => { books: ['The Lusiads', undefined], }); - assertInvalid(user, ['books', 1]); + expect(user).toHaveInvalidAttribute( + ['books', 1], + ['"books[1]" must not be a sparse array item'] + ); }); }); }); @@ -156,7 +158,7 @@ describe('validation', () => { books: ['Poetic Edda', 'Prose Edda'], }); - assertValid(user); + expect(user).toBeValidStructure(); }); }); @@ -166,7 +168,7 @@ describe('validation', () => { books: ['The Lusiads', undefined], }); - assertValid(user); + expect(user).toBeValidStructure(); }); }); }); @@ -202,7 +204,7 @@ describe('validation', () => { ], }); - assertValid(user); + expect(user).toBeValidStructure(); }); }); @@ -212,7 +214,10 @@ describe('validation', () => { books: [new Book({ name: 'The Hobbit' }), new Book({ name: undefined })], }); - assertInvalid(user, ['books', 1, 'name']); + expect(user).toHaveInvalidAttribute( + ['books', 1, 'name'], + ['"books[1].name" is required'] + ); }); }); }); @@ -235,7 +240,7 @@ describe('validation', () => { favoriteBook: {}, }); - assertValid(user); + expect(user).toBeValidStructure(); }); }); @@ -251,7 +256,10 @@ describe('validation', () => { favoriteBook: {}, }); - assertInvalid(user, ['friends', 1, 'favoriteBook']); + expect(user).toHaveInvalidAttribute( + ['friends', 1, 'favoriteBook'], + ['"friends[1].favoriteBook" is required'] + ); }); }); }); @@ -275,7 +283,7 @@ describe('validation', () => { books: ['The Name of the Wind', "The Wise Man's Fear"], }); - assertValid(user); + expect(user).toBeValidStructure(); }); }); @@ -285,7 +293,7 @@ describe('validation', () => { books: ['1984'], }); - assertInvalid(user, ['books']); + expect(user).toHaveInvalidAttribute(['books'], ['"books" must contain at least 2 items']); }); }); }); @@ -309,7 +317,7 @@ describe('validation', () => { books: ['The Name of the Wind'], }); - assertValid(user); + expect(user).toBeValidStructure(); }); }); @@ -319,7 +327,10 @@ describe('validation', () => { books: ['1984', 'The Game of Thrones', 'Dragons of Ether'], }); - assertInvalid(user, ['books']); + expect(user).toHaveInvalidAttribute( + ['books'], + ['"books" must contain less than or equal to 2 items'] + ); }); }); }); @@ -343,7 +354,7 @@ describe('validation', () => { books: ['The Gunslinger', 'The Drawing of the Three'], }); - assertValid(user); + expect(user).toBeValidStructure(); }); }); @@ -353,7 +364,7 @@ describe('validation', () => { books: ['The Wastelands'], }); - assertInvalid(user, ['books']); + expect(user).toHaveInvalidAttribute(['books'], ['"books" must contain 2 items']); }); }); @@ -363,7 +374,7 @@ describe('validation', () => { books: ['Wizard and Glass', 'The Wind Through the Keyhole', 'Wolves of the Calla'], }); - assertInvalid(user, ['books']); + expect(user).toHaveInvalidAttribute(['books'], ['"books" must contain 2 items']); }); }); }); @@ -385,7 +396,7 @@ describe('validation', () => { books: ['The Gunslinger', 'The Drawing of the Three'], }); - assertValid(user); + expect(user).toBeValidStructure(); }); }); describe('when array is not unique', () => { @@ -394,7 +405,10 @@ describe('validation', () => { books: ['The Wastelands', 'The Wastelands'], }); - assertInvalid(user, ['books', 1]); + expect(user).toHaveInvalidAttribute( + ['books', 1], + ['"books[1]" contains a duplicate value'] + ); }); }); }); diff --git a/packages/structure/test/unit/validation/boolean.spec.js b/packages/structure/test/unit/validation/boolean.spec.js index ef79c1b..e0652ab 100644 --- a/packages/structure/test/unit/validation/boolean.spec.js +++ b/packages/structure/test/unit/validation/boolean.spec.js @@ -1,5 +1,4 @@ const { attributes } = require('../../../src'); -const { assertValid, assertInvalid } = require('../../support/validationMatchers'); describe('validation', () => { describe('Boolean', () => { @@ -24,7 +23,7 @@ describe('validation', () => { isAdmin: true, }); - assertValid(user); + expect(user).toBeValidStructure(); }); }); @@ -34,7 +33,7 @@ describe('validation', () => { isAdmin: undefined, }); - assertValid(user); + expect(user).toBeValidStructure(); }); it('is valid with null when nullable', () => { @@ -42,7 +41,7 @@ describe('validation', () => { hasAccepted: null, }); - assertValid(user); + expect(user).toBeValidStructure(); }); }); }); @@ -65,7 +64,7 @@ describe('validation', () => { isAdmin: true, }); - assertValid(user); + expect(user).toBeValidStructure(); }); }); @@ -84,7 +83,7 @@ describe('validation', () => { isAdmin: undefined, }); - assertInvalid(user, ['isAdmin']); + expect(user).toHaveInvalidAttribute(['isAdmin'], ['"isAdmin" is required']); }); }); @@ -103,7 +102,7 @@ describe('validation', () => { it('is valid', () => { const user = new User({ isAdmin: null }); - assertValid(user); + expect(user).toBeValidStructure(); }); }); @@ -121,7 +120,7 @@ describe('validation', () => { it('is not valid and has errors set', () => { const user = new User({ isAdmin: null }); - assertInvalid(user, ['isAdmin']); + expect(user).toHaveInvalidAttribute(['isAdmin'], ['"isAdmin" is required']); }); }); }); @@ -143,7 +142,7 @@ describe('validation', () => { it('is valid', () => { const user = new User(); - assertValid(user); + expect(user).toBeValidStructure(); }); }); }); @@ -166,7 +165,7 @@ describe('validation', () => { isAdmin: true, }); - assertValid(user); + expect(user).toBeValidStructure(); }); }); @@ -176,7 +175,7 @@ describe('validation', () => { isAdmin: false, }); - assertInvalid(user, ['isAdmin']); + expect(user).toHaveInvalidAttribute(['isAdmin'], ['"isAdmin" must be [true]']); }); }); }); diff --git a/packages/structure/test/unit/validation/date.spec.js b/packages/structure/test/unit/validation/date.spec.js index 86f64cd..998c044 100644 --- a/packages/structure/test/unit/validation/date.spec.js +++ b/packages/structure/test/unit/validation/date.spec.js @@ -1,5 +1,4 @@ const { attributes } = require('../../../src'); -const { assertValid, assertInvalid } = require('../../support/validationMatchers'); describe('validation', () => { describe('Date', () => { @@ -24,7 +23,7 @@ describe('validation', () => { birth: new Date(), }); - assertValid(user); + expect(user).toBeValidStructure(); }); }); @@ -34,7 +33,7 @@ describe('validation', () => { birth: undefined, }); - assertValid(user); + expect(user).toBeValidStructure(); }); it('is valid with null when nullable', () => { @@ -42,7 +41,7 @@ describe('validation', () => { death: null, }); - assertValid(user); + expect(user).toBeValidStructure(); }); }); }); @@ -65,7 +64,7 @@ describe('validation', () => { birth: new Date(), }); - assertValid(user); + expect(user).toBeValidStructure(); }); }); @@ -84,7 +83,7 @@ describe('validation', () => { birth: undefined, }); - assertInvalid(user, ['birth']); + expect(user).toHaveInvalidAttribute(['birth'], ['"birth" is required']); }); }); @@ -103,7 +102,7 @@ describe('validation', () => { it('is valid', () => { const user = new User({ birth: null }); - assertValid(user); + expect(user).toBeValidStructure(); }); }); @@ -121,7 +120,7 @@ describe('validation', () => { it('is not valid and has errors set', () => { const user = new User({ birth: null }); - assertInvalid(user, ['birth']); + expect(user).toHaveInvalidAttribute(['birth'], ['"birth" is required']); }); }); }); @@ -143,7 +142,7 @@ describe('validation', () => { it('is valid', () => { const user = new User(); - assertValid(user); + expect(user).toBeValidStructure(); }); }); }); @@ -171,7 +170,7 @@ describe('validation', () => { birth: nowCopy, }); - assertValid(user); + expect(user).toBeValidStructure(); }); }); @@ -183,7 +182,10 @@ describe('validation', () => { birth: otherTime, }); - assertInvalid(user, ['birth']); + expect(user).toHaveInvalidAttribute( + ['birth'], + [expect.stringContaining('"birth" must be')] + ); }); }); }); @@ -214,7 +216,7 @@ describe('validation', () => { birth: before, }); - assertValid(user); + expect(user).toBeValidStructure(); }); }); @@ -226,7 +228,10 @@ describe('validation', () => { birth: after, }); - assertInvalid(user, ['birth']); + expect(user).toHaveInvalidAttribute( + ['birth'], + [expect.stringContaining('"birth" must be less than or equal to')] + ); }); }); }); @@ -260,7 +265,7 @@ describe('validation', () => { updatedAt: now, }); - assertValid(user); + expect(user).toBeValidStructure(); }); }); @@ -273,7 +278,10 @@ describe('validation', () => { updatedAt: now, }); - assertInvalid(user, ['createdAt']); + expect(user).toHaveInvalidAttribute( + ['createdAt'], + ['"createdAt" must be less than or equal to "ref:updatedAt"'] + ); }); }); }); @@ -301,7 +309,7 @@ describe('validation', () => { birth: after, }); - assertValid(user); + expect(user).toBeValidStructure(); }); }); @@ -313,7 +321,10 @@ describe('validation', () => { birth: before, }); - assertInvalid(user, ['birth']); + expect(user).toHaveInvalidAttribute( + ['birth'], + [expect.stringContaining('"birth" must be larger than or equal to')] + ); }); }); }); diff --git a/packages/structure/test/unit/validation/nestedPojo.spec.js b/packages/structure/test/unit/validation/nestedPojo.spec.js index 946f999..af00759 100644 --- a/packages/structure/test/unit/validation/nestedPojo.spec.js +++ b/packages/structure/test/unit/validation/nestedPojo.spec.js @@ -1,5 +1,4 @@ const { attributes } = require('../../../src'); -const { assertValid, assertInvalid } = require('../../support/validationMatchers'); describe('validation', () => { describe('Nested with POJO class', () => { @@ -27,7 +26,7 @@ describe('validation', () => { lastLocation: new Location(), }); - assertValid(user); + expect(user).toBeValidStructure(); }); }); @@ -37,7 +36,7 @@ describe('validation', () => { lastLocation: undefined, }); - assertValid(user); + expect(user).toBeValidStructure(); }); it('is valid with null when nullable', () => { @@ -45,7 +44,7 @@ describe('validation', () => { nextLocation: null, }); - assertValid(user); + expect(user).toBeValidStructure(); }); }); }); @@ -71,7 +70,7 @@ describe('validation', () => { lastLocation: new Location(), }); - assertValid(user); + expect(user).toBeValidStructure(); }); }); @@ -90,7 +89,7 @@ describe('validation', () => { lastLocation: undefined, }); - assertInvalid(user, ['lastLocation']); + expect(user).toHaveInvalidAttribute(['lastLocation'], ['"lastLocation" is required']); }); }); @@ -109,7 +108,7 @@ describe('validation', () => { it('is valid', () => { const user = new User({ lastLocation: null }); - assertValid(user); + expect(user).toBeValidStructure(); }); }); @@ -127,7 +126,7 @@ describe('validation', () => { it('is not valid and has errors set', () => { const user = new User({ lastLocation: null }); - assertInvalid(user, ['lastLocation']); + expect(user).toHaveInvalidAttribute(['lastLocation'], ['"lastLocation" is required']); }); }); }); @@ -152,7 +151,7 @@ describe('validation', () => { it('is valid', () => { const user = new User(); - assertValid(user); + expect(user).toBeValidStructure(); }); }); }); diff --git a/packages/structure/test/unit/validation/nestedStructure.spec.js b/packages/structure/test/unit/validation/nestedStructure.spec.js index 0da0d52..7741f2b 100644 --- a/packages/structure/test/unit/validation/nestedStructure.spec.js +++ b/packages/structure/test/unit/validation/nestedStructure.spec.js @@ -1,5 +1,4 @@ const { attributes } = require('../../../src'); -const { assertValid, assertInvalid } = require('../../support/validationMatchers'); describe('validation', () => { describe('Nested with structure class', () => { @@ -30,7 +29,7 @@ describe('validation', () => { lastLocation: new Location(), }); - assertValid(user); + expect(user).toBeValidStructure(); }); }); @@ -40,7 +39,7 @@ describe('validation', () => { lastLocation: undefined, }); - assertValid(user); + expect(user).toBeValidStructure(); }); }); }); @@ -71,7 +70,7 @@ describe('validation', () => { lastLocation: new Location(), }); - assertValid(user); + expect(user).toBeValidStructure(); }); }); @@ -90,7 +89,7 @@ describe('validation', () => { lastLocation: undefined, }); - assertInvalid(user, ['lastLocation']); + expect(user).toHaveInvalidAttribute(['lastLocation'], ['"lastLocation" is required']); }); }); @@ -109,7 +108,7 @@ describe('validation', () => { it('is valid', () => { const user = new User({ lastLocation: null }); - assertValid(user); + expect(user).toBeValidStructure(); }); }); @@ -127,7 +126,7 @@ describe('validation', () => { it('is not valid and has errors set', () => { const user = new User({ lastLocation: null }); - assertInvalid(user, ['lastLocation']); + expect(user).toHaveInvalidAttribute(['lastLocation'], ['"lastLocation" is required']); }); }); }); @@ -159,7 +158,7 @@ describe('validation', () => { it('is valid', () => { const user = new User(); - assertValid(user); + expect(user).toBeValidStructure(); }); }); }); @@ -185,7 +184,7 @@ describe('validation', () => { lastLocation: new Location({ x: 1, y: 2 }), }); - assertValid(user); + expect(user).toBeValidStructure(); }); }); @@ -206,7 +205,10 @@ describe('validation', () => { lastLocation: new Location({ x: 1, y: undefined }), }); - assertInvalid(user, ['lastLocation', 'y']); + expect(user).toHaveInvalidAttribute( + ['lastLocation', 'y'], + ['"lastLocation.y" is required'] + ); }); }); @@ -228,7 +230,7 @@ describe('validation', () => { lastLocation: new Location({ x: 1, y: null }), }); - assertValid(user); + expect(user).toBeValidStructure(); }); }); @@ -249,7 +251,10 @@ describe('validation', () => { lastLocation: new Location({ x: 1, y: null }), }); - assertInvalid(user, ['lastLocation', 'y']); + expect(user).toHaveInvalidAttribute( + ['lastLocation', 'y'], + ['"lastLocation.y" is required'] + ); }); }); }); @@ -273,7 +278,7 @@ describe('validation', () => { favoriteBook: {}, }); - assertValid(user); + expect(user).toBeValidStructure(); }); }); @@ -283,7 +288,7 @@ describe('validation', () => { favoriteBook: {}, }); - assertValid(user); + expect(user).toBeValidStructure(); }); }); }); @@ -295,7 +300,7 @@ describe('validation', () => { favoriteBook: {}, }); - assertValid(user); + expect(user).toBeValidStructure(); }); }); @@ -303,7 +308,7 @@ describe('validation', () => { it('is invalid', () => { const user = new CircularUser(); - assertInvalid(user, ['favoriteBook']); + expect(user).toHaveInvalidAttribute(['favoriteBook'], ['"favoriteBook" is required']); }); }); }); @@ -317,7 +322,7 @@ describe('validation', () => { }, }); - assertValid(book); + expect(book).toBeValidStructure(); }); }); @@ -327,7 +332,10 @@ describe('validation', () => { owner: new CircularUser(), }); - assertInvalid(book, ['owner', 'favoriteBook']); + expect(book).toHaveInvalidAttribute( + ['owner', 'favoriteBook'], + ['"owner.favoriteBook" is required'] + ); }); }); }); diff --git a/packages/structure/test/unit/validation/number.spec.js b/packages/structure/test/unit/validation/number.spec.js index 7a866af..5adba0e 100644 --- a/packages/structure/test/unit/validation/number.spec.js +++ b/packages/structure/test/unit/validation/number.spec.js @@ -1,5 +1,4 @@ const { attributes } = require('../../../src'); -const { assertValid, assertInvalid } = require('../../support/validationMatchers'); describe('validation', () => { describe('Number', () => { @@ -24,7 +23,7 @@ describe('validation', () => { age: 42, }); - assertValid(user); + expect(user).toBeValidStructure(); }); }); @@ -34,7 +33,7 @@ describe('validation', () => { age: undefined, }); - assertValid(user); + expect(user).toBeValidStructure(); }); it('is valid with null when nullable', () => { @@ -42,7 +41,7 @@ describe('validation', () => { earnings: null, }); - assertValid(user); + expect(user).toBeValidStructure(); }); }); }); @@ -65,7 +64,7 @@ describe('validation', () => { age: 42, }); - assertValid(user); + expect(user).toBeValidStructure(); }); }); @@ -84,7 +83,7 @@ describe('validation', () => { age: undefined, }); - assertInvalid(user, ['age']); + expect(user).toHaveInvalidAttribute(['age'], ['"age" is required']); }); }); @@ -103,7 +102,7 @@ describe('validation', () => { it('is valid', () => { const user = new User({ age: null }); - assertValid(user); + expect(user).toBeValidStructure(); }); }); @@ -121,7 +120,7 @@ describe('validation', () => { it('is not valid and has errors set', () => { const user = new User({ age: null }); - assertInvalid(user, ['age']); + expect(user).toHaveInvalidAttribute(['age'], ['"age" is required']); }); }); }); @@ -143,7 +142,7 @@ describe('validation', () => { it('is valid', () => { const user = new User(); - assertValid(user); + expect(user).toBeValidStructure(); }); }); }); @@ -167,7 +166,7 @@ describe('validation', () => { age: 2, }); - assertValid(user); + expect(user).toBeValidStructure(); }); }); @@ -177,7 +176,7 @@ describe('validation', () => { age: 1, }); - assertInvalid(user, ['age']); + expect(user).toHaveInvalidAttribute(['age'], ['"age" must be [2]']); }); }); }); @@ -204,7 +203,7 @@ describe('validation', () => { currentAge: 2, }); - assertValid(user); + expect(user).toBeValidStructure(); }); }); @@ -215,7 +214,7 @@ describe('validation', () => { currentAge: 3, }); - assertValid(user); + expect(user).toBeValidStructure(); }); }); @@ -226,7 +225,10 @@ describe('validation', () => { currentAge: 2, }); - assertInvalid(user, ['currentAge']); + expect(user).toHaveInvalidAttribute( + ['currentAge'], + ['"currentAge" must be one of [3, ref:startAge]'] + ); }); }); }); @@ -253,7 +255,7 @@ describe('validation', () => { currentAge: 2, }); - assertValid(user); + expect(user).toBeValidStructure(); }); }); @@ -264,7 +266,10 @@ describe('validation', () => { currentAge: 2, }); - assertInvalid(user, ['currentAge']); + expect(user).toHaveInvalidAttribute( + ['currentAge'], + ['"currentAge" must be [ref:startAge]'] + ); }); }); }); @@ -289,7 +294,7 @@ describe('validation', () => { age: 2, }); - assertValid(user); + expect(user).toBeValidStructure(); }); }); @@ -299,7 +304,7 @@ describe('validation', () => { age: 3, }); - assertValid(user); + expect(user).toBeValidStructure(); }); }); @@ -309,7 +314,10 @@ describe('validation', () => { age: 1, }); - assertInvalid(user, ['age']); + expect(user).toHaveInvalidAttribute( + ['age'], + ['"age" must be larger than or equal to 2'] + ); }); }); }); @@ -336,7 +344,7 @@ describe('validation', () => { currentAge: 2, }); - assertValid(user); + expect(user).toBeValidStructure(); }); }); @@ -347,7 +355,7 @@ describe('validation', () => { currentAge: 3, }); - assertValid(user); + expect(user).toBeValidStructure(); }); }); @@ -358,7 +366,10 @@ describe('validation', () => { currentAge: 2, }); - assertInvalid(user, ['currentAge']); + expect(user).toHaveInvalidAttribute( + ['currentAge'], + ['"currentAge" must be larger than or equal to ref:startAge'] + ); }); }); }); @@ -382,7 +393,7 @@ describe('validation', () => { age: 2, }); - assertInvalid(user, ['age']); + expect(user).toHaveInvalidAttribute(['age'], ['"age" must be greater than 2']); }); }); @@ -392,7 +403,7 @@ describe('validation', () => { age: 3, }); - assertValid(user); + expect(user).toBeValidStructure(); }); }); @@ -402,7 +413,7 @@ describe('validation', () => { age: 1, }); - assertInvalid(user, ['age']); + expect(user).toHaveInvalidAttribute(['age'], ['"age" must be greater than 2']); }); }); }); @@ -425,7 +436,7 @@ describe('validation', () => { age: 2, }); - assertValid(user); + expect(user).toBeValidStructure(); }); }); @@ -435,7 +446,7 @@ describe('validation', () => { age: 1, }); - assertValid(user); + expect(user).toBeValidStructure(); }); }); @@ -445,7 +456,7 @@ describe('validation', () => { age: 3, }); - assertInvalid(user, ['age']); + expect(user).toHaveInvalidAttribute(['age'], ['"age" must be less than or equal to 2']); }); }); }); @@ -468,7 +479,7 @@ describe('validation', () => { age: 2, }); - assertInvalid(user, ['age']); + expect(user).toHaveInvalidAttribute(['age'], ['"age" must be less than 2']); }); }); @@ -478,7 +489,7 @@ describe('validation', () => { age: 1, }); - assertValid(user); + expect(user).toBeValidStructure(); }); }); @@ -488,7 +499,7 @@ describe('validation', () => { age: 3, }); - assertInvalid(user, ['age']); + expect(user).toHaveInvalidAttribute(['age'], ['"age" must be less than 2']); }); }); }); @@ -511,7 +522,7 @@ describe('validation', () => { age: 42, }); - assertValid(user); + expect(user).toBeValidStructure(); }); }); @@ -521,7 +532,7 @@ describe('validation', () => { age: 4.2, }); - assertInvalid(user, ['age']); + expect(user).toHaveInvalidAttribute(['age'], ['"age" must be an integer']); }); }); }); @@ -544,7 +555,7 @@ describe('validation', () => { age: 4.2, }); - assertValid(user); + expect(user).toBeValidStructure(); }); }); @@ -554,7 +565,10 @@ describe('validation', () => { age: 0.042, }); - assertInvalid(user, ['age']); + expect(user).toHaveInvalidAttribute( + ['age'], + ['"age" must have no more than 2 decimal places'] + ); }); }); }); @@ -577,7 +591,7 @@ describe('validation', () => { age: 6, }); - assertValid(user); + expect(user).toBeValidStructure(); }); }); @@ -587,7 +601,7 @@ describe('validation', () => { age: 7, }); - assertInvalid(user, ['age']); + expect(user).toHaveInvalidAttribute(['age'], ['"age" must be a multiple of 3']); }); }); }); @@ -610,7 +624,7 @@ describe('validation', () => { age: 1, }); - assertValid(user); + expect(user).toBeValidStructure(); }); }); @@ -620,7 +634,7 @@ describe('validation', () => { age: 0, }); - assertInvalid(user, ['age']); + expect(user).toHaveInvalidAttribute(['age'], ['"age" must be a positive number']); }); }); @@ -630,7 +644,7 @@ describe('validation', () => { age: -1, }); - assertInvalid(user, ['age']); + expect(user).toHaveInvalidAttribute(['age'], ['"age" must be a positive number']); }); }); }); @@ -653,7 +667,7 @@ describe('validation', () => { age: -1, }); - assertValid(user); + expect(user).toBeValidStructure(); }); }); @@ -663,7 +677,7 @@ describe('validation', () => { age: 0, }); - assertInvalid(user, ['age']); + expect(user).toHaveInvalidAttribute(['age'], ['"age" must be a negative number']); }); }); @@ -673,7 +687,7 @@ describe('validation', () => { age: 1, }); - assertInvalid(user, ['age']); + expect(user).toHaveInvalidAttribute(['age'], ['"age" must be a negative number']); }); }); }); diff --git a/packages/structure/test/unit/validation/string.spec.js b/packages/structure/test/unit/validation/string.spec.js index 93e7554..ce6b5fc 100644 --- a/packages/structure/test/unit/validation/string.spec.js +++ b/packages/structure/test/unit/validation/string.spec.js @@ -1,5 +1,4 @@ const { attributes } = require('../../../src'); -const { assertValid, assertInvalid } = require('../../support/validationMatchers'); describe('validation', () => { describe('String', () => { @@ -24,7 +23,7 @@ describe('validation', () => { name: 'Some name', }); - assertValid(user); + expect(user).toBeValidStructure(); }); }); @@ -34,7 +33,7 @@ describe('validation', () => { name: undefined, }); - assertValid(user); + expect(user).toBeValidStructure(); }); it('is valid with null when nullable', () => { @@ -42,7 +41,7 @@ describe('validation', () => { fatherName: null, }); - assertValid(user); + expect(user).toBeValidStructure(); }); }); }); @@ -65,7 +64,7 @@ describe('validation', () => { name: 'Some name', }); - assertValid(user); + expect(user).toBeValidStructure(); }); }); @@ -84,7 +83,7 @@ describe('validation', () => { name: undefined, }); - assertInvalid(user, ['name']); + expect(user).toHaveInvalidAttribute(['name'], ['"name" is required']); }); }); @@ -103,7 +102,7 @@ describe('validation', () => { it('is valid', () => { const user = new User({ name: null }); - assertValid(user); + expect(user).toBeValidStructure(); }); }); @@ -121,7 +120,7 @@ describe('validation', () => { it('is not valid and has errors set', () => { const user = new User({ name: null }); - assertInvalid(user, ['name']); + expect(user).toHaveInvalidAttribute(['name'], ['"name" is required']); }); }); }); @@ -145,7 +144,7 @@ describe('validation', () => { name: undefined, }); - assertValid(user); + expect(user).toBeValidStructure(); }); }); }); @@ -168,7 +167,7 @@ describe('validation', () => { name: 'Something', }); - assertValid(user); + expect(user).toBeValidStructure(); }); }); @@ -178,7 +177,7 @@ describe('validation', () => { name: 'Another thing', }); - assertInvalid(user, ['name']); + expect(user).toHaveInvalidAttribute(['name'], ['"name" must be [Something]']); }); }); }); @@ -202,7 +201,7 @@ describe('validation', () => { name: 'Some name', }); - assertValid(user); + expect(user).toBeValidStructure(); }); }); @@ -212,7 +211,7 @@ describe('validation', () => { name: '', }); - assertValid(user); + expect(user).toBeValidStructure(); }); }); }); @@ -235,7 +234,7 @@ describe('validation', () => { name: 'Some name', }); - assertValid(user); + expect(user).toBeValidStructure(); }); }); @@ -245,7 +244,7 @@ describe('validation', () => { name: '', }); - assertInvalid(user, ['name']); + expect(user).toHaveInvalidAttribute(['name'], ['"name" is not allowed to be empty']); }); }); }); @@ -269,7 +268,7 @@ describe('validation', () => { name: 'Some name', }); - assertValid(user); + expect(user).toBeValidStructure(); }); }); @@ -279,7 +278,10 @@ describe('validation', () => { name: 'Hi', }); - assertInvalid(user, ['name']); + expect(user).toHaveInvalidAttribute( + ['name'], + ['"name" length must be at least 3 characters long'] + ); }); }); }); @@ -302,7 +304,7 @@ describe('validation', () => { name: 'Some', }); - assertValid(user); + expect(user).toBeValidStructure(); }); }); @@ -312,7 +314,10 @@ describe('validation', () => { name: 'Some name', }); - assertInvalid(user, ['name']); + expect(user).toHaveInvalidAttribute( + ['name'], + ['"name" length must be less than or equal to 4 characters long'] + ); }); }); }); @@ -335,7 +340,7 @@ describe('validation', () => { name: 'Some', }); - assertValid(user); + expect(user).toBeValidStructure(); }); }); @@ -345,7 +350,10 @@ describe('validation', () => { name: 'Some name', }); - assertInvalid(user, ['name']); + expect(user).toHaveInvalidAttribute( + ['name'], + ['"name" length must be 4 characters long'] + ); }); }); @@ -355,7 +363,10 @@ describe('validation', () => { name: 'Hi', }); - assertInvalid(user, ['name']); + expect(user).toHaveInvalidAttribute( + ['name'], + ['"name" length must be 4 characters long'] + ); }); }); }); @@ -378,7 +389,7 @@ describe('validation', () => { name: 'A1', }); - assertValid(user); + expect(user).toBeValidStructure(); }); }); @@ -388,7 +399,10 @@ describe('validation', () => { name: 'Something', }); - assertInvalid(user, ['name']); + expect(user).toHaveInvalidAttribute( + ['name'], + ['"name" with value "Something" fails to match the required pattern: /\\w\\d/'] + ); }); }); }); @@ -411,7 +425,7 @@ describe('validation', () => { name: 'A1B2', }); - assertValid(user); + expect(user).toBeValidStructure(); }); }); @@ -421,7 +435,10 @@ describe('validation', () => { name: 'No alphanumeric $ string', }); - assertInvalid(user, ['name']); + expect(user).toHaveInvalidAttribute( + ['name'], + ['"name" must only contain alpha-numeric characters'] + ); }); }); }); @@ -444,7 +461,7 @@ describe('validation', () => { name: 'abc', }); - assertValid(user); + expect(user).toBeValidStructure(); }); }); @@ -454,7 +471,10 @@ describe('validation', () => { name: 'Abc', }); - assertInvalid(user, ['name']); + expect(user).toHaveInvalidAttribute( + ['name'], + ['"name" must only contain lowercase characters'] + ); }); }); }); @@ -477,7 +497,7 @@ describe('validation', () => { name: 'ABC', }); - assertValid(user); + expect(user).toBeValidStructure(); }); }); @@ -487,7 +507,10 @@ describe('validation', () => { name: 'Abc', }); - assertInvalid(user, ['name']); + expect(user).toHaveInvalidAttribute( + ['name'], + ['"name" must only contain uppercase characters'] + ); }); }); }); @@ -510,7 +533,7 @@ describe('validation', () => { name: 'name@host.com', }); - assertValid(user); + expect(user).toBeValidStructure(); }); }); @@ -520,7 +543,7 @@ describe('validation', () => { name: 'Not a valid email', }); - assertInvalid(user, ['name']); + expect(user).toHaveInvalidAttribute(['name'], ['"name" must be a valid email']); }); }); }); @@ -544,7 +567,7 @@ describe('validation', () => { id: '759535af-3314-4ace-81b9-a519c29d0e17', }); - assertValid(user); + expect(user).toBeValidStructure(); }); }); @@ -554,7 +577,7 @@ describe('validation', () => { id: 'Not a valid guid', }); - assertInvalid(user, ['id']); + expect(user).toHaveInvalidAttribute(['id'], ['"id" must be a valid GUID']); }); }); }); @@ -581,7 +604,7 @@ describe('validation', () => { id: uuidv4, }); - assertValid(user); + expect(user).toBeValidStructure(); }); }); @@ -593,7 +616,7 @@ describe('validation', () => { id: uuidv1, }); - assertInvalid(user, ['id']); + expect(user).toHaveInvalidAttribute(['id'], ['"id" must be a valid GUID']); }); }); }); diff --git a/packages/structure/test/unit/validation/structureSubclass.spec.js b/packages/structure/test/unit/validation/structureSubclass.spec.js index d7a9f13..6fd02ea 100644 --- a/packages/structure/test/unit/validation/structureSubclass.spec.js +++ b/packages/structure/test/unit/validation/structureSubclass.spec.js @@ -1,5 +1,4 @@ const { attributes } = require('../../../src'); -const { assertValid, assertInvalid } = require('../../support/validationMatchers'); describe('validation', () => { describe('structure subclass', () => { @@ -28,7 +27,7 @@ describe('validation', () => { level: 3, }); - assertInvalid(admin, ['name']); + expect(admin).toHaveInvalidAttribute(['name'], ['"name" is required']); }); }); @@ -38,7 +37,7 @@ describe('validation', () => { name: 'The admin', }); - assertInvalid(admin, ['level']); + expect(admin).toHaveInvalidAttribute(['level'], ['"level" is required']); }); }); @@ -49,7 +48,7 @@ describe('validation', () => { level: 3, }); - assertValid(admin); + expect(admin).toBeValidStructure(); }); }); @@ -75,7 +74,7 @@ describe('validation', () => { it('is valid', () => { const car = new Car({ name: null }); - assertValid(car); + expect(car).toBeValidStructure(); }); }); @@ -97,7 +96,7 @@ describe('validation', () => { it('is not valid and has errors set', () => { const car = new Car({ name: null }); - assertInvalid(car, ['name']); + expect(car).toHaveInvalidAttribute(['name'], ['"name" is required']); }); }); });