Closed
Description
🚀 Feature Proposal
Nest jest asymmetric matchers / use multiple of them at same point.
Preserve all error messages in each of nested matcher to quickly resolve errors.
Something like this?
expect.extend({
all<T>(received: T, fn: (received: T) => void) {
try {
fn(received);
} catch (e) {
process.nextTick(() => {
throw e;
});
const res = (e as any).matcherResult;
return res || { pass: false, message: e.message };
}
return { pass: true, message: "" };
},
});
it("pieces to compose", async () => {
expect([1, { a: 1 }]).toMatchObject([1, expect.objectContaining({ a: 1 })]);
expect([1, 2]).toEqual(expect.arrayContaining([1, expect.anything()]));
expect({ a: 1, b: 2 }).toMatchObject({
a: 1,
b: expect.any(Number),
});
});
/*
## Motivation
Please outline the motivation for the proposal.
*/
it("jest all asymmetric matcher", async () => {
expect(1).toEqual(
expect.all(v => {
expect(v).toBe(1);
expect(v + 1).toBe(2);
})
);
});
it("FAIL expect", async () => {
expect(1).toEqual(
expect.all(v => {
expect(v).toBe(2);
expect(v + 1).toBe(2);
})
);
});
it("FAIL error", async () => {
expect(1).toEqual(
expect.all(v => {
throw new Error("foo!");
expect(v).toBe(2);
expect(v + 1).toBe(2);
})
);
});
/*
## Example
Please provide an example for how this feature would be used.
*/
describe("complex example", () => {
it("use like this", async () => {
const res = {
users: [
{
id: "user1",
posts: [{ id: "post1" }, { id: "post2" }],
},
{
id: "user2",
posts: [{ id: "post3" }],
},
],
};
expect(res).toMatchObject({
// users: expect.arrayContaining([
users: expect.objectContaining([
expect.objectContaining({
id: "user1",
posts: expect.all(v => {
expect(v).toHaveLength(2);
expect(v).toMatchObject([
expect.objectContaining({ id: "post1" }),
expect.objectContaining({ id: expect.anything() }),
]);
}),
}),
expect.objectContaining({
id: "user2",
posts: expect.all(v => {
expect(v).toHaveLength(1);
}),
}),
]),
});
});
it("FAIL shows point where failed", async () => {
const res = {
users: [
{
id: "user1",
posts: [{ id: "post1" }, { id: "post2" }],
},
{
id: "user2",
posts: [{ id: "post3" }],
},
],
};
expect(res).toMatchObject({
// users: expect.arrayContaining([
users: expect.objectContaining([
expect.objectContaining({
id: "user1",
posts: expect.all(v => {
expect(v).toHaveLength(2);
expect(v).toMatchObject([
expect.objectContaining({ id: "post1" }),
expect.objectContaining({ id: expect.anything() }),
]);
}),
}),
expect.objectContaining({
id: "user2",
posts: expect.all(v => {
expect(v).toHaveLength(2); // THIS WAS CHANGED
}),
}),
]),
});
});
});
Pitch
Why does this feature belong in the Jest core platform?
- Good way to test data that is commonly returned from apis / orms / queries
- It is not only a matcher, but a new way to use all matchers
- This pattern can be extended to all asymmetric matchers towards solving Do not highlight passing asymmetric matchers in diffs #6184 Correct highlighting for asymmetric matchers #7893
- We can use all matchers everywhere, consistent experience for matcher behaviour
- It needs a better implementation that takes care of jest internals
todo / to test
- use with resolve rejects
- pass async functions
- nested expectation failures / thrown errors: should not print the test name again (but it should still print both error messages)
- typescript types
references #5788