Skip to content

Commit

Permalink
fix: fix error cause bug
Browse files Browse the repository at this point in the history
  • Loading branch information
BondarenkoAlex committed Oct 8, 2024
1 parent 0a0a9f7 commit b20075a
Show file tree
Hide file tree
Showing 3 changed files with 95 additions and 34 deletions.
1 change: 1 addition & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -49,6 +49,7 @@

### Fixes

- `[expect]` Fix `error causes`
- `[babel-plugin-jest-hoist]` Use `denylist` instead of the deprecated `blacklist` for Babel 8 support ([#14109](https://github.com/jestjs/jest/pull/14109))
- `[expect]` Check error instance type for `toThrow/toThrowError` ([#14576](https://github.com/jestjs/jest/pull/14576))
- `[expect]` Improve diff for failing `expect.objectContaining` ([#15038](https://github.com/jestjs/jest/pull/15038))
Expand Down
46 changes: 46 additions & 0 deletions packages/expect/src/__tests__/toThrowMatchers.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -307,6 +307,38 @@ describe('toThrow', () => {
throw new Error('good', {cause: errorA});
}).not.toThrow(expected);
});

test('isNot false, cause is object', () => {
jestExpect(() => {
throw errorB;
}).toThrow({
message: 'B',
// eslint-disable-next-line sort-keys
cause: {
message: 'A',
},
});
});

test('isNot false, cause is string', () => {
jestExpect(() => {
throw new Error('Message', {cause: 'line 123'});
}).toThrow({
message: 'Message',
// eslint-disable-next-line sort-keys
cause: 'line 123',
});
});

test('isNot false, cause is boolean', () => {
jestExpect(() => {
throw new Error('Message', {cause: true});
}).toThrow({
message: 'Message',
// eslint-disable-next-line sort-keys
cause: true,
});
});
});

describe('fail', () => {
Expand All @@ -329,6 +361,20 @@ describe('toThrow', () => {
/^(?=.*Expected message and cause: ).*Received message and cause: /s,
);
});

test('isNot true, incorrect cause object', () => {
expect(() =>
jestExpect(() => {
throw new Error('Message', {cause: {cause: undefined}});
}).toThrow({
message: 'Message',
// eslint-disable-next-line sort-keys
cause: {cause: null},
}),
).toThrow(
/^(?=.*Expected message and cause: ).*Received message and cause: /s,
);
});
});
});

Expand Down
82 changes: 48 additions & 34 deletions packages/expect/src/toThrowMatchers.ts
Original file line number Diff line number Diff line change
Expand Up @@ -170,9 +170,9 @@ const toThrowExpectedRegExp = (
(thrown === null
? `\n${DID_NOT_THROW}`
: thrown.hasMessage
? formatReceived('Received message: ', thrown, 'message') +
formatStack(thrown)
: formatReceived('Received value: ', thrown, 'value'));
? formatReceived('Received message: ', thrown, 'message') +
formatStack(thrown)
: formatReceived('Received value: ', thrown, 'value'));

return {message, pass};
};
Expand Down Expand Up @@ -210,10 +210,10 @@ const toThrowExpectedAsymmetric = (
(thrown === null
? DID_NOT_THROW
: thrown.hasMessage
? formatReceived('Received name: ', thrown, 'name') +
formatReceived('Received message: ', thrown, 'message') +
formatStack(thrown)
: formatReceived('Thrown value: ', thrown, 'value'));
? formatReceived('Received name: ', thrown, 'name') +
formatReceived('Received message: ', thrown, 'message') +
formatStack(thrown)
: formatReceived('Thrown value: ', thrown, 'value'));

return {message, pass};
};
Expand Down Expand Up @@ -264,20 +264,20 @@ const toThrowExpectedObject = (
'\n' +
DID_NOT_THROW
: thrown.hasMessage
? // eslint-disable-next-line prefer-template
printDiffOrStringify(
expectedMessageAndCause,
thrownMessageAndCause,
`Expected ${messageAndCause(expected)}`,
`Received ${messageAndCause(thrown.value)}`,
true,
) +
'\n' +
formatStack(thrown)
: formatExpected(
`Expected ${messageAndCause(expected)}: `,
expectedMessageAndCause,
) + formatReceived('Received value: ', thrown, 'value'));
? // eslint-disable-next-line prefer-template
printDiffOrStringify(
expectedMessageAndCause,
thrownMessageAndCause,
`Expected ${messageAndCause(expected)}`,
`Received ${messageAndCause(thrown.value)}`,
true,
) +
'\n' +
formatStack(thrown)
: formatExpected(
`Expected ${messageAndCause(expected)}: `,
expectedMessageAndCause,
) + formatReceived('Received value: ', thrown, 'value'));

return {message, pass};
};
Expand Down Expand Up @@ -366,9 +366,9 @@ const toThrowExpectedString = (
(thrown === null
? `\n${DID_NOT_THROW}`
: thrown.hasMessage
? formatReceived('Received message: ', thrown, 'message') +
formatStack(thrown)
: formatReceived('Received value: ', thrown, 'value'));
? formatReceived('Received message: ', thrown, 'message') +
formatStack(thrown)
: formatReceived('Received value: ', thrown, 'value'));

return {message, pass};
};
Expand Down Expand Up @@ -467,22 +467,36 @@ const formatStack = (thrown: Thrown | null) =>
},
);

function createMessageAndCauseMessage(error: Error): string {
if (error.cause instanceof Error) {
return `{ message: ${error.message}, cause: ${createMessageAndCauseMessage(
error.cause,
)}}`;
function createMessageAndCause(error: Error) {
if (error.cause) {
return JSON.stringify(buildSerializeError(error));
}

return `{ message: ${error.message} }`;
return error.message;
}

function createMessageAndCause(error: Error) {
if (error.cause instanceof Error) {
return createMessageAndCauseMessage(error);
function buildSerializeError(error) {
if (!isObject(error)) {
return error;
}

return error.message;
const result = {};
for (const name of Object.getOwnPropertyNames(error)) {
if (['stack', 'fileName', 'lineNumber'].includes(name)) {
continue;
}
if (name === 'cause') {
result[name] = buildSerializeError(error['cause']);
continue;
}
result[name] = error[name];
}

return result;
}

function isObject(obj) {
return !!obj && typeof obj === 'object';
}

function messageAndCause(error: Error) {
Expand Down

0 comments on commit b20075a

Please sign in to comment.