Commits (14)
# html-validate changelog
## [5.3.0](https://gitlab.com/html-validate/html-validate/compare/v5.2.1...v5.3.0) (2021-08-23)
### Features
- jest matchers support async results ([ef7331f](https://gitlab.com/html-validate/html-validate/commit/ef7331f28c90fc7623b1124ed60e02e6c6018e28))
### Bug Fixes
- **jest:** handle when `jest-diff` default import is object ([7413db9](https://gitlab.com/html-validate/html-validate/commit/7413db9d2b02dde00ba1b32fb58ec6e47e7cc951))
### [5.2.1](https://gitlab.com/html-validate/html-validate/compare/v5.2.0...v5.2.1) (2021-08-09)
### Bug Fixes
......
This source diff could not be displayed because it is too large. You can view the blob instead.
{
"name": "html-validate",
"version": "5.2.1",
"version": "5.3.0",
"description": "Offline html5 validator",
"keywords": [
"html",
......@@ -151,7 +151,7 @@
"@babel/preset-env": "7.15.0",
"@commitlint/cli": "13.1.0",
"@html-validate/commitlint-config": "2.0.0",
"@html-validate/eslint-config": "4.4.4",
"@html-validate/eslint-config": "4.4.5",
"@html-validate/eslint-config-jest": "4.4.2",
"@html-validate/eslint-config-typescript": "4.4.0",
"@html-validate/jest-config": "2.2.0",
......@@ -167,18 +167,18 @@
"@types/estree": "0.0.47",
"@types/glob": "7.1.4",
"@types/inquirer": "7.3.3",
"@types/jest": "26.0.24",
"@types/jest": "27.0.1",
"@types/json-merge-patch": "0.0.5",
"@types/minimist": "1.2.2",
"@types/node": "11.15.54",
"@types/prompts": "2.0.14",
"@types/semver": "7.3.8",
"autoprefixer": "10.3.1",
"autoprefixer": "10.3.2",
"babar": "0.2.0",
"babelify": "10.0.0",
"bootstrap-sass": "3.4.1",
"canonical-path": "1.0.0",
"cssnano": "5.0.7",
"cssnano": "5.0.8",
"dgeni": "0.4.14",
"dgeni-front-matter": "3.0.0",
"dgeni-packages": "0.29.1",
......@@ -203,14 +203,14 @@
"npm-pkg-lint": "1.4.0",
"postcss": "8.3.6",
"prettier": "2.3.2",
"rollup": "2.56.0",
"rollup": "2.56.2",
"rollup-plugin-copy": "3.4.0",
"rollup-plugin-dts": "3.0.2",
"sass": "1.37.5",
"semantic-release": "17.4.4",
"sass": "1.38.0",
"semantic-release": "17.4.5",
"serve-static": "1.14.1",
"stringmap": "0.2.2",
"ts-jest": "27.0.4",
"ts-jest": "27.0.5",
"typescript": "4.3.5"
},
"peerDependencies": {
......
// 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([
......
......@@ -13,9 +13,23 @@ interface TokenMatcher {
data?: any;
}
/* ignore typing for compatibility so it will seem "impossible" but different version will yield different source */
const diffCandidates: Array<typeof jestDiff.diff> = [
// @ts-ignore
jestDiffDefault?.diff,
// @ts-ignore
jestDiffDefault,
// @ts-ignore
jestDiff?.diff,
// @ts-ignore
jestDiff,
];
const isFunction = (fn: unknown): boolean => typeof fn === "function";
/* istanbul ignore next: covered by compatibility tests but not a single pass */
/* @ts-ignore typing for compatibility so it will seem "impossible" but different version will yield different source */
const diff: typeof jestDiff.diff = jestDiffDefault ?? jestDiff?.diff ?? jestDiff;
/* @ts-ignore assume one of the candidate matches, there will be a reasonable error later on if not */
const diff: typeof jestDiff.diff = diffCandidates.find(isFunction);
declare global {
namespace jest {
......@@ -57,7 +71,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 +85,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 +108,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 +152,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 };
......