Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Fix typings of toThrowWithMessage, support unconstructable errors #475

Merged
merged 4 commits into from Jul 18, 2022
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Jump to
Jump to file
Failed to load files.
Diff view
Diff view
14 changes: 12 additions & 2 deletions src/matchers/toThrowWithMessage.js
Expand Up @@ -85,9 +85,19 @@ export function toThrowWithMessage(callbackOrPromiseReturn, type, message) {
}

const pass = predicate(error, type, message);
const messageStr = message.toString();
let expectedError;
try {
expectedError = new type(messageStr);
} catch (err) {
const name = type.name;
expectedError = new Error();
expectedError.name = name;
expectedError.message = messageStr;
}
if (pass) {
return { pass: true, message: passMessage(utils, error, new type(message)) };
return { pass: true, message: passMessage(utils, error, expectedError) };
}

return { pass: false, message: failMessage(utils, error, new type(message)) };
return { pass: false, message: failMessage(utils, error, expectedError) };
}
40 changes: 40 additions & 0 deletions test/matchers/__snapshots__/toThrowWithMessage.test.js.snap
Expand Up @@ -56,6 +56,26 @@ Thrown:
"
`;

exports[`.toThrowWithMessage Async passes with an unconstructable error given a regex message 1`] = `
"<dim>expect(</intensity><red>function</color><dim>).not.toThrowWithMessage(</intensity><green>type</color><dim>, </intensity><green>message</color><dim>)</intensity>

Expected not to throw:
<green>[UnconstructableError: /42/]</color>
Thrown:
<red>[UnconstructableError: 42]</color>
"
`;

exports[`.toThrowWithMessage Async passes with an unconstructable error given a string message 1`] = `
"<dim>expect(</intensity><red>function</color><dim>).not.toThrowWithMessage(</intensity><green>type</color><dim>, </intensity><green>message</color><dim>)</intensity>

Expected not to throw:
<green>[UnconstructableError: 42]</color>
Thrown:
<red>[UnconstructableError: 42]</color>
"
`;

exports[`.toThrowWithMessage fails when a callback function is not a function 1`] = `
"<dim>expect(</intensity><red>function</color><dim>).toThrowWithMessage(</intensity><green>type</color><dim>, </intensity><green>message</color><dim>)</intensity>

Expand Down Expand Up @@ -142,3 +162,23 @@ Thrown:
<red>[TypeError: Expected message]</color>
"
`;

exports[`.toThrowWithMessage passes with an unconstructable error given a regex message 1`] = `
"<dim>expect(</intensity><red>function</color><dim>).not.toThrowWithMessage(</intensity><green>type</color><dim>, </intensity><green>message</color><dim>)</intensity>

Expected not to throw:
<green>[UnconstructableError: /42/]</color>
Thrown:
<red>[UnconstructableError: 42]</color>
"
`;

exports[`.toThrowWithMessage passes with an unconstructable error given a string message 1`] = `
"<dim>expect(</intensity><red>function</color><dim>).not.toThrowWithMessage(</intensity><green>type</color><dim>, </intensity><green>message</color><dim>)</intensity>

Expected not to throw:
<green>[UnconstructableError: 42]</color>
Thrown:
<red>[UnconstructableError: 42]</color>
"
`;
68 changes: 68 additions & 0 deletions test/matchers/toThrowWithMessage.test.js
Expand Up @@ -4,6 +4,16 @@ const { toThrowWithMessage } = matcher;

expect.extend(matcher);

class UnconstructableError extends Error {
constructor(message) {
if (typeof message !== 'number') {
throw new TypeError('Expected number arg');
}
super(message.toString());
this.name = 'UnconstructableError';
}
}

describe('.toThrowWithMessage', () => {
test('fails when callback function is not provided', () => {
const { pass, message } = toThrowWithMessage.call({
Expand Down Expand Up @@ -137,6 +147,34 @@ describe('.toThrowWithMessage', () => {
expect(message()).toMatchSnapshot();
});

test('passes with an unconstructable error given a string message', () => {
const callback = () => {
throw new UnconstructableError(42);
};
const { pass, message } = toThrowWithMessage.call(
{ utils: { matcherHint: matcherHint, printExpected: printExpected, printReceived: printReceived } },
callback,
UnconstructableError,
'42',
);
expect(pass).toBe(true);
expect(message()).toMatchSnapshot();
});

test('passes with an unconstructable error given a regex message', () => {
const callback = () => {
throw new UnconstructableError(42);
};
const { pass, message } = toThrowWithMessage.call(
{ utils: { matcherHint: matcherHint, printExpected: printExpected, printReceived: printReceived } },
callback,
UnconstructableError,
/42/,
);
expect(pass).toBe(true);
expect(message()).toMatchSnapshot();
});

test('passes when given an Error with a string error message: end to end', () => {
expect(() => {
throw new TypeError('Expected message');
Expand Down Expand Up @@ -254,6 +292,36 @@ describe('.toThrowWithMessage', () => {
expect(message()).toMatchSnapshot();
});

test('passes with an unconstructable error given a string message', () => {
const rejectValue = new UnconstructableError(42);
const { pass, message } = toThrowWithMessage.call(
{
utils: { matcherHint: matcherHint, printExpected: printExpected, printReceived: printReceived },
promise: 'rejects',
},
rejectValue,
UnconstructableError,
'42',
);
expect(pass).toBe(true);
expect(message()).toMatchSnapshot();
});

test('passes with an unconstructable error given a regex message', () => {
const rejectValue = new UnconstructableError(42);
const { pass, message } = toThrowWithMessage.call(
{
utils: { matcherHint: matcherHint, printExpected: printExpected, printReceived: printReceived },
promise: 'rejects',
},
rejectValue,
UnconstructableError,
/42/,
);
expect(pass).toBe(true);
expect(message()).toMatchSnapshot();
});

test('passes on rejects with rejected promise when given an Error with a string error message: end to end', async () => {
await expect(Promise.reject(new SyntaxError('Expected message'))).rejects.toThrowWithMessage(
SyntaxError,
Expand Down
8 changes: 7 additions & 1 deletion types/index.d.ts
Expand Up @@ -387,7 +387,13 @@ declare namespace jest {
* @param {Function} type
* @param {String | RegExp} message
*/
toThrowWithMessage(type: (...args: unknown[]) => unknown, message: string | RegExp): R;
toThrowWithMessage(
type:
| (new (...args: any[]) => { message: string })
| (abstract new (...args: any[]) => { message: string })
| ((...args: any[]) => { message: string }),
message: string | RegExp,
): R;

/**
* Use `.toBeEmptyObject` when checking if a value is an empty `Object`.
Expand Down