Skip to content

Commit

Permalink
Refactor usage error and remove hint for non-usage-related errors
Browse files Browse the repository at this point in the history
  • Loading branch information
talyssonoc committed Oct 29, 2019
1 parent 88ede3b commit 7cf2dc1
Show file tree
Hide file tree
Showing 6 changed files with 93 additions and 111 deletions.
13 changes: 6 additions & 7 deletions packages/jest-structure/src/assertions/toHaveInvalidAttribute.js
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
const { sortMessagesByExpected } = require('../lib/sorting');
const { isValidPath } = require('../lib/attributePath');
const { failNoNegative, failWrongValidity } = require('../lib/errors');
const { failInvalidUsage, failNoNegative, failWrongValidity } = require('../lib/errors');
const matcherName = 'toHaveInvalidAttribute';
const exampleName = 'structure';
const attributePathHint = 'attributePath';
Expand All @@ -12,7 +12,11 @@ module.exports = function toHaveInvalidAttribute(structure, attributePath, expec
}

if (!isValidPath(attributePath)) {
return failInvalidUsage(this, 'must not be called without the attribute path');
return failInvalidUsage(
matcherName,
usageHint(this),
'must not be called without the attribute path'
);
}

const { valid, errors } = structure.validate();
Expand Down Expand Up @@ -55,11 +59,6 @@ module.exports = function toHaveInvalidAttribute(structure, attributePath, expec
};
};

const failInvalidUsage = (context, message) => ({
pass: false,
message: () => `${matcherName} ${message}\n` + `Example: ${usageHint(context)}`,
});

const usageHint = (context) =>
context.utils.matcherHint(matcherName, exampleName, attributePathHint, {
secondArgument: errorMessagesHint,
Expand Down
88 changes: 20 additions & 68 deletions packages/jest-structure/src/assertions/toHaveInvalidAttributes.js
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
const { sortMessagesByExpected } = require('../lib/sorting');
const { isValidPath } = require('../lib/attributePath');
const { failNoNegative, failWrongValidity } = require('../lib/errors');
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) }]';
Expand All @@ -10,13 +10,12 @@ module.exports = function toHaveInvalidAttributes(structure, expectedErrors) {
return failNoNegative(matcherName);
}

if (!expectedErrors || !expectedErrors.length) {
return {
pass: false,
message: () =>
`${matcherName} must not be called without the expected errros\n` +
`Example: ${usageHint(this)}`,
};
if (!areExpectedErrorsPresent(expectedErrors)) {
return failInvalidUsage(
matcherName,
usageHint(this),
'must not be called without the expected errros'
);
}

const { valid, errors } = structure.validate();
Expand All @@ -30,77 +29,30 @@ module.exports = function toHaveInvalidAttributes(structure, expectedErrors) {
});
}

if (!expectedErrors.every(errorHasPath)) {
if (!areExpectedErrorsPathsValid(expectedErrors)) {
return failNoPath(this);
}

const errorsForComparison = sortByExpected(errors, expectedErrors, this);
const errorsForComparison = sortErrorsByExpected(errors, expectedErrors, this);

return {
pass: this.equals(errorsForComparison, expectedErrors),
message: () => {
const hint = this.utils.matcherHint(matcherName, exampleName, expectedErrorsHint);

return (
`${hint}\n\n` +
this.utils.printDiffOrStringify(
expectedErrors,
errorsForComparison,
`Expected errors`,
`Received errors`,
this.expand
)
);
},
message: () =>
this.utils.printDiffOrStringify(
expectedErrors,
errorsForComparison,
`Expected errors`,
`Received errors`,
this.expand
),
};
};

const sortByExpected = (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];
};

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];
}, []);
const areExpectedErrorsPresent = (expectedErrors) => expectedErrors && expectedErrors.length;

const usageHint = (context) =>
context.utils.matcherHint(matcherName, exampleName, expectedErrorsHint);

const errorHasPath = (error) => isValidPath(error.path);

const failNoPath = (context) => ({
pass: false,
message: () =>
Expand Down
21 changes: 20 additions & 1 deletion packages/jest-structure/src/lib/attributePath.js
Original file line number Diff line number Diff line change
@@ -1 +1,20 @@
exports.isValidPath = (path) => Boolean(path && path.length);
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 };
4 changes: 4 additions & 0 deletions packages/jest-structure/src/lib/errors.js
Original file line number Diff line number Diff line change
Expand Up @@ -9,4 +9,8 @@ module.exports = {
`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}`,
}),
};
38 changes: 33 additions & 5 deletions packages/jest-structure/src/lib/sorting.js
Original file line number Diff line number Diff line change
@@ -1,7 +1,6 @@
exports.sortMessagesByExpected = function sortMessagesByExpected(
errorMessages,
expectedErrorMessages
) {
const { groupByPath } = require('./attributePath');

function sortMessagesByExpected(errorMessages, expectedErrorMessages) {
expectedErrorMessages = expectedErrorMessages.sample || expectedErrorMessages;

const equalMessages = expectedErrorMessages.filter((message) => errorMessages.includes(message));
Expand All @@ -10,4 +9,33 @@ exports.sortMessagesByExpected = function sortMessagesByExpected(
);

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 };
Original file line number Diff line number Diff line change
Expand Up @@ -106,9 +106,7 @@ 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`] = `
"expect(structure).toHaveInvalidAttributes([{ path (required), messages (optional) }])

- Expected errors
"- Expected errors
+ Received errors
@@ -1,8 +1,11 @@
Expand All @@ -127,9 +125,7 @@ exports[`jest-structure toHaveInvalidAttributes when messages are passed only fo
`;
exports[`jest-structure toHaveInvalidAttributes when messages are passed only for some when there are missing attributes and messages fails 1`] = `
"expect(structure).toHaveInvalidAttributes([{ path (required), messages (optional) }])

- Expected errors
"- Expected errors
+ Received errors
 Array [
Expand Down Expand Up @@ -160,9 +156,7 @@ exports[`jest-structure toHaveInvalidAttributes when messages are passed only fo
`;
exports[`jest-structure toHaveInvalidAttributes when messages are passed only for some when there are missing attributes fails 1`] = `
"expect(structure).toHaveInvalidAttributes([{ path (required), messages (optional) }])

- Expected errors
"- Expected errors
+ Received errors
@@ -2,6 +2,14 @@
Expand All @@ -183,9 +177,7 @@ exports[`jest-structure toHaveInvalidAttributes when messages are passed only fo
`;
exports[`jest-structure toHaveInvalidAttributes when messages are passed only for some when there are missing messages fails 1`] = `
"expect(structure).toHaveInvalidAttributes([{ path (required), messages (optional) }])

- Expected errors
"- Expected errors
+ Received errors
@@ -1,9 +1,10 @@
Expand All @@ -207,9 +199,7 @@ Received: is valid"
`;
exports[`jest-structure toHaveInvalidAttributes when only paths are passed when none of the passed attributes are invalid fails 1`] = `
"expect(structure).toHaveInvalidAttributes([{ path (required), messages (optional) }])

- Expected errors
"- Expected errors
+ Received errors
 Array [
Expand All @@ -227,9 +217,7 @@ exports[`jest-structure toHaveInvalidAttributes when only paths are passed when
`;
exports[`jest-structure toHaveInvalidAttributes when only paths are passed when only some of the passed attributes are invalid fails 1`] = `
"expect(structure).toHaveInvalidAttributes([{ path (required), messages (optional) }])

- Expected errors
"- Expected errors
+ Received errors
 Array [
Expand All @@ -252,9 +240,7 @@ Received: is valid"
`;
exports[`jest-structure toHaveInvalidAttributes when paths and messages are passed when attribute is invalid but messages array is empty fails 1`] = `
"expect(structure).toHaveInvalidAttributes([{ path (required), messages (optional) }])

- Expected errors
"- Expected errors
+ Received errors
 Array [
Expand All @@ -272,9 +258,7 @@ exports[`jest-structure toHaveInvalidAttributes when paths and messages are pass
`;
exports[`jest-structure toHaveInvalidAttributes when paths and messages are passed when there are missing attributes and messages fails 1`] = `
"expect(structure).toHaveInvalidAttributes([{ path (required), messages (optional) }])

- Expected errors
"- Expected errors
+ Received errors
 Array [
Expand All @@ -299,9 +283,7 @@ exports[`jest-structure toHaveInvalidAttributes when paths and messages are pass
`;
exports[`jest-structure toHaveInvalidAttributes when paths and messages are passed when there are missing attributes fails 1`] = `
"expect(structure).toHaveInvalidAttributes([{ path (required), messages (optional) }])

- Expected errors
"- Expected errors
+ Received errors
@@ -5,6 +5,14 @@
Expand All @@ -322,9 +304,7 @@ exports[`jest-structure toHaveInvalidAttributes when paths and messages are pass
`;
exports[`jest-structure toHaveInvalidAttributes when paths and messages are passed when there are missing messages fails 1`] = `
"expect(structure).toHaveInvalidAttributes([{ path (required), messages (optional) }])

- Expected errors
"- Expected errors
+ Received errors
@@ -1,9 +1,10 @@
Expand Down

0 comments on commit 7cf2dc1

Please sign in to comment.