Skip to content

Commit

Permalink
feat: Improve colors in UnexpectedCall error message
Browse files Browse the repository at this point in the history
  • Loading branch information
NiGhTTraX committed Sep 24, 2023
1 parent 7a04a43 commit f326954
Show file tree
Hide file tree
Showing 4 changed files with 31 additions and 22 deletions.
17 changes: 9 additions & 8 deletions src/errors.ts
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
import { EXPECTED_COLOR } from 'jest-matcher-utils';
import { DIM_COLOR, EXPECTED_COLOR, RECEIVED_COLOR } from 'jest-matcher-utils';
import type { Expectation } from './expectation/expectation';
import { getMatcherDiffs } from './expectation/matcher';
import type { CallMap } from './expectation/repository/expectation-repository';
Expand Down Expand Up @@ -58,20 +58,21 @@ export class UnexpectedCall extends Error implements MatcherError {
args: unknown[],
expectations: Expectation[]
) {
const header = `Didn't expect mock${printCall(
property,
args
const header = `Didn't expect mock${RECEIVED_COLOR(
printCall(property, args, true)
)} to be called.`;

const propertyExpectations = expectations.filter(
(e) => e.property === property
);

if (propertyExpectations.length) {
super(`${header}
super(
DIM_COLOR(`${header}
Remaining expectations:
${printDiffForAllExpectations(propertyExpectations, args)}`);
${printDiffForAllExpectations(propertyExpectations, args)}`)
);

// If we have a single expectation we can attach the actual/expected args
// to the error instance, so that an IDE may show its own diff for them.
Expand Down Expand Up @@ -117,8 +118,8 @@ export class UnmetExpectations extends Error {
* into a single call.
*
* @example
* mergeCalls({ foo: [{ arguments: undefined }, { arguments: [1, 2, 3] }] }
* // returns { foo: [{ arguments: [1, 2, 3] } }
* mergeCalls({ getData: [{ arguments: undefined }, { arguments: [1, 2, 3] }] }
* // returns { getData: [{ arguments: [1, 2, 3] } }
*/
const mergeCalls = (callMap: CallMap): CallMap =>
new Map(
Expand Down
3 changes: 1 addition & 2 deletions src/expectation/it.ts
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,6 @@ import {
isUndefined,
omitBy,
} from 'lodash';
import { printArg } from '../print';
import type { Matcher, TypeMatcher } from './matcher';
import { isMatcher, MATCHER_SYMBOL } from './matcher';

Expand Down Expand Up @@ -83,7 +82,7 @@ const deepEquals = <T>(
return isEqual(removeUndefined(actual), removeUndefined(expected));
},
{
toJSON: () => printArg(expected),
toJSON: () => printExpected(expected),
getDiff: (actual) => ({ actual, expected }),
}
);
Expand Down
8 changes: 4 additions & 4 deletions src/print.spec.ts
Original file line number Diff line number Diff line change
Expand Up @@ -162,22 +162,22 @@ describe('print', () => {
getDiff: (actual) => ({ actual, expected: 'foo' }),
});

const expectation = new StrongExpectation(':irrelevant:', [matcher], {
value: ':irrelevant:',
const expectation = new StrongExpectation('prop', [matcher], {
value: 'return',
});

const args = ['bar'];

expectAnsilessEqual(
printDiffForAllExpectations([expectation, expectation], args),
`when(() => mock.:irrelevant:(matches(() => false))).thenReturn(":irrelevant:").between(1, 1)
`when(() => mock.prop(matches(() => false))).thenReturn("return").between(1, 1)
- Expected
+ Received
- "foo",
+ "bar"
when(() => mock.:irrelevant:(matches(() => false))).thenReturn(":irrelevant:").between(1, 1)
when(() => mock.prop(matches(() => false))).thenReturn("return").between(1, 1)
- Expected
+ Received
Expand Down
25 changes: 17 additions & 8 deletions src/print.ts
Original file line number Diff line number Diff line change
Expand Up @@ -23,12 +23,21 @@ export const printProperty = (property: Property) => {
return `.${property}`;
};

export const printArg = (arg: unknown): string =>
// Call toJSON on matchers directly to avoid wrapping them in quotes.
isMatcher(arg) ? arg.toJSON() : printReceived(arg);
const printArg = (arg: unknown, received = false): string => {
// Call toJSON on matchers directly to avoid wrapping strings returned by them in quotes.
if (isMatcher(arg)) {
return arg.toJSON();
}

return received ? printReceived(arg) : printExpected(arg);
};

export const printCall = (property: Property, args: any[]) => {
const prettyArgs = args.map((arg) => printArg(arg)).join(', ');
export const printCall = (
property: Property,
args: any[],
received = false // TODO: fix boolean trap
) => {
const prettyArgs = args.map((arg) => printArg(arg, received)).join(', ');
const prettyProperty = printProperty(property);

return `${prettyProperty}(${prettyArgs})`;
Expand All @@ -53,15 +62,15 @@ export const printReturns = (
thenPrefix += 'thenReturn';
}

return `.${thenPrefix}(${printExpected(value)}).between(${min}, ${max})`;
return `.${thenPrefix}(${printReceived(value)}).between(${min}, ${max})`;
};

export const printWhen = (property: Property, args: any[] | undefined) => {
if (args) {
return `when(() => mock${printCall(property, args)})`;
return `when(() => mock${EXPECTED_COLOR(`${printCall(property, args)}`)})`;
}

return `when(() => mock${printProperty(property)})`;
return `when(() => mock${EXPECTED_COLOR(`${printProperty(property)}`)})`;
};

export const printExpectation = (
Expand Down

0 comments on commit f326954

Please sign in to comment.