Commit ef7331f2 authored by David Sveningsson's avatar David Sveningsson
Browse files

feat: jest matchers support async results

It is now possible to pass promises to:

* `toBeValid()`
* `toBeInvalid()`
* `toHaveError()`
* `toHaveErrors()`
parent 9a771f29
Pipeline #351602136 passed with stages
in 11 minutes and 21 seconds
// Jest Snapshot v1, https://goo.gl/fbAQLP
exports[`toBeInvalid() should fail if async report is valid 1`] = `"Result should be invalid but had no errors"`;
exports[`toBeInvalid() should fail if report is valid 1`] = `"Result should be invalid but had no errors"`;
exports[`toBeToken() should fail if token doesn't match 1`] = `
......@@ -34,12 +36,14 @@ Difference:
}"
`;
exports[`toBeValid() should fail if report is invalid 1`] = `"Result should be successful but had error \\"mock message\\""`;
exports[`toBeValid() should fail if async report is invalid 1`] = `"Result should be valid but had error \\"mock message\\""`;
exports[`toBeValid() should fail if report is invalid 1`] = `"Result should be valid but had error \\"mock message\\""`;
exports[`toHaveError() should fail if error has mismatched context 1`] = `
"expect(received).toHaveError(expected)
Expected token to equal:
Expected error to equal:
[ObjectContaining {\\"context\\": {\\"foo\\": \\"spam\\"}, \\"message\\": \\"mock message\\", \\"ruleId\\": \\"my-rule\\"}]
Received:
[{\\"column\\": 15, \\"context\\": {\\"foo\\": \\"bar\\"}, \\"line\\": 2, \\"message\\": \\"mock message\\", \\"offset\\": 43, \\"ruleId\\": \\"my-rule\\", \\"selector\\": null, \\"severity\\": 2, \\"size\\": 12}]
......@@ -68,10 +72,43 @@ Difference:
]"
`;
exports[`toHaveError() should fail if error is missing 1`] = `
exports[`toHaveError() should fail if expected async error is missing 1`] = `
"expect(received).toHaveError(expected)
Expected token to equal:
Expected error to equal:
[ObjectContaining {\\"message\\": \\"asdf\\", \\"ruleId\\": \\"asdf\\"}]
Received:
[{\\"column\\": 15, \\"context\\": {\\"foo\\": \\"bar\\"}, \\"line\\": 2, \\"message\\": \\"mock message\\", \\"offset\\": 43, \\"ruleId\\": \\"my-rule\\", \\"selector\\": null, \\"severity\\": 2, \\"size\\": 12}]
Difference:
- Expected
+ Received
Array [
- ObjectContaining {
- \\"message\\": \\"asdf\\",
- \\"ruleId\\": \\"asdf\\",
+ Object {
+ \\"column\\": 15,
+ \\"context\\": Object {
+ \\"foo\\": \\"bar\\",
+ },
+ \\"line\\": 2,
+ \\"message\\": \\"mock message\\",
+ \\"offset\\": 43,
+ \\"ruleId\\": \\"my-rule\\",
+ \\"selector\\": null,
+ \\"severity\\": 2,
+ \\"size\\": 12,
},
]"
`;
exports[`toHaveError() should fail if expected error is missing 1`] = `
"expect(received).toHaveError(expected)
Expected error to equal:
[ObjectContaining {\\"message\\": \\"asdf\\", \\"ruleId\\": \\"asdf\\"}]
Received:
[{\\"column\\": 15, \\"context\\": {\\"foo\\": \\"bar\\"}, \\"line\\": 2, \\"message\\": \\"mock message\\", \\"offset\\": 43, \\"ruleId\\": \\"my-rule\\", \\"selector\\": null, \\"severity\\": 2, \\"size\\": 12}]
......@@ -104,7 +141,7 @@ Difference:
exports[`toHaveErrors() should fail if error any missing 1`] = `
"expect(received).toHaveErrors(expected)
Expected token to equal:
Expected error to equal:
[ObjectContaining {\\"message\\": \\"mock message\\", \\"ruleId\\": \\"my-rule\\"}, ObjectContaining {\\"message\\": \\"spam\\", \\"ruleId\\": \\"spam\\"}]
Received:
[{\\"column\\": 15, \\"context\\": {\\"foo\\": \\"bar\\"}, \\"line\\": 2, \\"message\\": \\"mock message\\", \\"offset\\": 43, \\"ruleId\\": \\"my-rule\\", \\"selector\\": null, \\"severity\\": 2, \\"size\\": 12}, {\\"column\\": 15, \\"line\\": 2, \\"message\\": \\"another message\\", \\"offset\\": 43, \\"ruleId\\": \\"another-rule\\", \\"selector\\": null, \\"severity\\": 2, \\"size\\": 12}]
......
......@@ -62,6 +62,11 @@ describe("toBeValid()", () => {
await expect(reportOk).toBeValid();
});
it("should pass if async report is valid", async () => {
expect.assertions(1);
await expect(Promise.resolve(reportOk)).toBeValid();
});
it("should fail if report is invalid", async () => {
expect.assertions(3);
let error: Error | undefined = undefined;
......@@ -73,6 +78,18 @@ describe("toBeValid()", () => {
expect(error).toBeDefined();
expect(error?.message).toMatchSnapshot();
});
it("should fail if async report is invalid", async () => {
expect.assertions(3);
let error: Error | undefined = undefined;
try {
await expect(Promise.resolve(reportError)).toBeValid();
} catch (e) {
error = e;
}
expect(error).toBeDefined();
expect(error?.message).toMatchSnapshot();
});
});
describe("toBeInvalid()", () => {
......@@ -81,6 +98,11 @@ describe("toBeInvalid()", () => {
await expect(reportError).toBeInvalid();
});
it("should pass if async report is invalid", async () => {
expect.assertions(1);
await expect(Promise.resolve(reportError)).toBeInvalid();
});
it("should fail if report is valid", async () => {
expect.assertions(3);
let error: Error | undefined = undefined;
......@@ -92,6 +114,18 @@ describe("toBeInvalid()", () => {
expect(error).toBeDefined();
expect(error?.message).toMatchSnapshot();
});
it("should fail if async report is valid", async () => {
expect.assertions(3);
let error: Error | undefined = undefined;
try {
await expect(Promise.resolve(reportOk)).toBeInvalid();
} catch (e) {
error = e;
}
expect(error).toBeDefined();
expect(error?.message).toMatchSnapshot();
});
});
describe("toHaveError()", () => {
......@@ -100,6 +134,11 @@ describe("toHaveError()", () => {
await expect(reportError).toHaveError("my-rule", "mock message");
});
it("should pass if async error is preset", async () => {
expect.assertions(1);
await expect(Promise.resolve(reportError)).toHaveError("my-rule", "mock message");
});
it("should pass if error have matching context", async () => {
expect.assertions(1);
await expect(reportError).toHaveError("my-rule", "mock message", {
......@@ -107,7 +146,7 @@ describe("toHaveError()", () => {
});
});
it("should fail if error is missing", async () => {
it("should fail if expected error is missing", async () => {
expect.assertions(3);
let error: Error | undefined = undefined;
try {
......@@ -132,6 +171,18 @@ describe("toHaveError()", () => {
expect(error).toBeDefined();
expect(stripAnsi(error?.message || "")).toMatchSnapshot();
});
it("should fail if expected async error is missing", async () => {
expect.assertions(3);
let error: Error | undefined = undefined;
try {
await expect(Promise.resolve(reportError)).toHaveError("asdf", "asdf");
} catch (e) {
error = e;
}
expect(error).toBeDefined();
expect(stripAnsi(error?.message || "")).toMatchSnapshot();
});
});
describe("toHaveErrors()", () => {
......@@ -140,6 +191,11 @@ describe("toHaveErrors()", () => {
await expect(reportError).toHaveErrors([["my-rule", "mock message"]]);
});
it("should pass if async error is preset", async () => {
expect.assertions(1);
await expect(Promise.resolve(reportError)).toHaveErrors([["my-rule", "mock message"]]);
});
it("should pass if error have matching context", async () => {
expect.assertions(1);
await expect(reportError).toHaveErrors([
......
......@@ -57,7 +57,11 @@ function flattenMessages(report: Report): Message[] {
}, []);
}
function toBeValid(this: jest.MatcherUtils, report: Report): jest.CustomMatcherResult {
async function toBeValid(
this: jest.MatcherUtils,
actual: Report | Promise<Report>
): Promise<jest.CustomMatcherResult> {
const report = await actual;
if (report.valid) {
return {
pass: true,
......@@ -67,12 +71,16 @@ function toBeValid(this: jest.MatcherUtils, report: Report): jest.CustomMatcherR
const firstError = report.results[0].messages[0];
return {
pass: false,
message: () => `Result should be successful but had error "${firstError.message}"`,
message: () => `Result should be valid but had error "${firstError.message}"`,
};
}
}
function toBeInvalid(this: jest.MatcherUtils, report: Report): jest.CustomMatcherResult {
async function toBeInvalid(
this: jest.MatcherUtils,
actual: Report | Promise<Report>
): Promise<jest.CustomMatcherResult> {
const report = await actual;
if (report.valid) {
return {
pass: false,
......@@ -86,40 +94,42 @@ function toBeInvalid(this: jest.MatcherUtils, report: Report): jest.CustomMatche
}
}
function toHaveError(
async function toHaveError(
this: jest.MatcherUtils,
report: Report,
actual: Report | Promise<Report>,
ruleId: any,
message: any,
context?: any
): jest.CustomMatcherResult {
const actual = flattenMessages(report);
): Promise<jest.CustomMatcherResult> {
const report = await actual;
const flattened = flattenMessages(report);
const expected: any = { ruleId, message };
if (context) {
expected.context = context;
}
const matcher = [expect.objectContaining(expected)];
const pass = this.equals(actual, matcher);
const diffString = diff(matcher, actual, { expand: this.expand });
const pass = this.equals(flattened, matcher);
const diffString = diff(matcher, flattened, { expand: this.expand });
const resultMessage = (): string =>
this.utils.matcherHint(".toHaveError") +
"\n\n" +
"Expected token to equal:\n" +
"Expected error to equal:\n" +
` ${this.utils.printExpected(matcher)}\n` +
"Received:\n" +
` ${this.utils.printReceived(actual)}` +
` ${this.utils.printReceived(flattened)}` +
/* istanbul ignore next */ (diffString ? `\n\nDifference:\n\n${diffString}` : "");
return { pass, message: resultMessage };
}
function toHaveErrors(
async function toHaveErrors(
this: jest.MatcherUtils,
report: Report,
actual: Report | Promise<Report>,
errors: Array<[string, string] | Record<string, unknown>>
): jest.CustomMatcherResult {
const actual = flattenMessages(report);
): Promise<jest.CustomMatcherResult> {
const report = await actual;
const flattened = flattenMessages(report);
const matcher = errors.map((entry) => {
if (Array.isArray(entry)) {
const [ruleId, message] = entry;
......@@ -128,15 +138,15 @@ function toHaveErrors(
return expect.objectContaining(entry);
}
});
const pass = this.equals(actual, matcher);
const diffString = diff(matcher, actual, { expand: this.expand });
const pass = this.equals(flattened, matcher);
const diffString = diff(matcher, flattened, { expand: this.expand });
const resultMessage = (): string =>
this.utils.matcherHint(".toHaveErrors") +
"\n\n" +
"Expected token to equal:\n" +
"Expected error to equal:\n" +
` ${this.utils.printExpected(matcher)}\n` +
"Received:\n" +
` ${this.utils.printReceived(actual)}` +
` ${this.utils.printReceived(flattened)}` +
/* istanbul ignore next */ (diffString ? `\n\nDifference:\n\n${diffString}` : "");
return { pass, message: resultMessage };
......
Supports Markdown
0% or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment