Skip to content

Commit

Permalink
Add expect with custom message logic
Browse files Browse the repository at this point in the history
  • Loading branch information
mattphillips committed Aug 7, 2018
1 parent 273bdb3 commit 79d8b42
Show file tree
Hide file tree
Showing 7 changed files with 149 additions and 0 deletions.
1 change: 1 addition & 0 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -64,6 +64,7 @@
]
},
"jest": {
"testEnvironment": "node",
"setupTestFrameworkScriptFile": "jest-extended"
}
}
16 changes: 16 additions & 0 deletions src/__snapshots__/index.test.js.snap
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
// Jest Snapshot v1, https://goo.gl/fbAQLP

exports[`jest-expect-message should fail with custom message 1`] = `
"Custom message:
Woah this should be false!
expect(received).toBeTruthy()
Received: false"
`;

exports[`jest-expect-message should fail without custom message 1`] = `
"expect(received).toBeTruthy()
Received: false"
`;
8 changes: 8 additions & 0 deletions src/__snapshots__/withMessage.test.js.snap
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
// Jest Snapshot v1, https://goo.gl/fbAQLP

exports[`withMessage() throws error with custom message when matcher fails 1`] = `
"Custom message:
should fail
expected ACTUAL to be 1"
`;
3 changes: 3 additions & 0 deletions src/index.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
import withMessage from './withMessage';

global.expect = withMessage(global.expect);
11 changes: 11 additions & 0 deletions src/index.test.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
import './';

describe('jest-expect-message', () => {
test('should fail with custom message', () => {
expect(() => expect(false, 'Woah this should be false!').toBeTruthy()).toThrowErrorMatchingSnapshot();
});

test('should fail without custom message', () => {
expect(() => expect(false).toBeTruthy()).toThrowErrorMatchingSnapshot();
});
});
33 changes: 33 additions & 0 deletions src/withMessage.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,33 @@
class JestAssertionError extends Error {
constructor(result, callsite) {
super(result.message());
this.matcherResult = result;

if (Error.captureStackTrace) {
Error.captureStackTrace(this, callsite);
}
}
}

export default expect => (actual, customMessage) => {
const matchers = expect(actual);

return Object.keys(matchers).reduce((acc, key) => {
const matcher = matchers[key];
const newMatcher = (...args) => {
try {
matcher(...args);
} catch (error) {
if (typeof customMessage !== 'string' || customMessage.length < 1 || !error.matcherResult) {
throw error;
}

const { matcherResult } = error;
const message = () => 'Custom message:\n ' + customMessage + '\n\n' + matcherResult.message();

throw new JestAssertionError(Object.assign({}, matcherResult, { message }), newMatcher);
}
};
return Object.assign({}, acc, { [key]: newMatcher });
}, {});
};
77 changes: 77 additions & 0 deletions src/withMessage.test.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,77 @@
import withMessage from './withMessage';

describe('withMessage()', () => {
const ACTUAL = 'ACTUAL';

test('does not throw when matcher passes', () => {
expect.assertions(1);
const toBeMock = jest.fn();
const expectMock = jest.fn(() => ({ toBe: toBeMock }));

withMessage(expectMock)(ACTUAL, 'should fail').toBe(1);
expect(1).toBe(1);
});

test.each([undefined, ''])('throws original error when given message: %s', message => {
expect.assertions(3);
const originalError = new Error('Boo');
const toBeMock = jest.fn(() => {
throw originalError;
});
const expectMock = jest.fn(() => ({ toBe: toBeMock }));

try {
withMessage(expectMock)(ACTUAL, message).toBe(1);
} catch (e) {
expect(e).toBe(originalError);
expect(expectMock).toHaveBeenCalledWith(ACTUAL);
expect(toBeMock).toHaveBeenCalledWith(1);
}
});

test('throws original error when matcher error does not contain matcherResult', () => {
expect.assertions(3);
const originalError = new Error('Boo');
const toBeMock = jest.fn(() => {
throw originalError;
});
const expectMock = jest.fn(() => ({ toBe: toBeMock }));

try {
withMessage(expectMock)(ACTUAL, 'should fail').toBe(1);
} catch (e) {
expect(e).toBe(originalError);
expect(expectMock).toHaveBeenCalledWith(ACTUAL);
expect(toBeMock).toHaveBeenCalledWith(1);
}
});

test('throws error with custom message when matcher fails', () => {
expect.assertions(4);
const originalError = new Error('Boo');
originalError.matcherResult = {
actual: ACTUAL,
expected: 1,
message: () => 'expected ACTUAL to be 1',
pass: false
};

const toBeMock = jest.fn(() => {
throw originalError;
});
const expectMock = jest.fn(() => ({ toBe: toBeMock }));

try {
withMessage(expectMock)(ACTUAL, 'should fail').toBe(1);
} catch (e) {
expect(e.matcherResult).toMatchObject({
actual: ACTUAL,
expected: 1,
pass: false
});
expect(e.message).toMatchSnapshot();
expect(expectMock).toHaveBeenCalledWith(ACTUAL);
expect(toBeMock).toHaveBeenCalledWith(1);
}
});
});

0 comments on commit 79d8b42

Please sign in to comment.