Skip to content
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.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
6 changes: 6 additions & 0 deletions .changeset/small-starfishes-yell.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
---
"example-jest": patch
"screen-reader-testing-library": patch
---

Implement same signature as `toMatchSpeechSnapshot` in `toMatchSpeechInlineSnapshot`
26 changes: 10 additions & 16 deletions examples/jest/index.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -43,26 +43,20 @@ describe("chromium", () => {
await page.bringToFront();
await awaitNvdaRecording();

await expect(
speechRecorder.record(async () => {
await page.keyboard.press("s");
})
).resolves.toMatchSpeechInlineSnapshot(`
await expect(async () => {
await page.keyboard.press("s");
}).toMatchSpeechInlineSnapshot(`
"banner landmark"
"Search, combo box, expanded, has auto complete, editable, Search…, blank"
`);

await expect(
speechRecorder.record(async () => {
await page.keyboard.type("Rating");
})
).resolves.toMatchSpeechInlineSnapshot(``);

await expect(
speechRecorder.record(async () => {
await page.keyboard.press("ArrowDown");
})
).resolves.toMatchSpeechInlineSnapshot(`
await expect(async () => {
await page.keyboard.type("Rating");
}).toMatchSpeechInlineSnapshot(``);

await expect(async () => {
await page.keyboard.press("ArrowDown");
}).toMatchSpeechInlineSnapshot(`
"list"
"Link to the result, 1 of 5"
`);
Expand Down
57 changes: 50 additions & 7 deletions src/__tests__/extendExpect.js
Original file line number Diff line number Diff line change
@@ -1,19 +1,62 @@
const { promises: fs } = require("fs");
const os = require("os");
const path = require("path");
const { extendExpect } = require("../index");

extendExpect(expect, "unused");
/**
* @type {string}
*/
let logFilePath;
/**
* @param {string[][]} speech
*/
function speakMock(speech) {
// Check existing fixtures for how to mock speech output.
const mockedSpeach = speech
.map((line) => {
return `Speaking [${line
.map((group) => {
return `'${group}'`;
})
.join(", ")}]\n`;
})
.join("");
return fs.writeFile(logFilePath, mockedSpeach, { flag: "a" });
}

test("custom inline snapshot with no lines", () => {
expect([]).toMatchSpeechInlineSnapshot(``);
beforeAll(async () => {
logFilePath = path.join(
os.tmpdir(),
"srtl-testing",
`extendExpect-${new Date().valueOf()}.log`
);
await fs.mkdir(path.dirname(logFilePath), { recursive: true });
await fs.writeFile(logFilePath, "", { flag: "w" });
extendExpect(expect, logFilePath);
});

test("custom inline snapshot with one line", () => {
afterAll(async () => {
await fs.unlink(logFilePath);
});

test("custom inline snapshot with no lines", async () => {
await expect(async () => {
await speakMock([]);
}).toMatchSpeechInlineSnapshot(``);
});

test("custom inline snapshot with one line", async () => {
const actualSpeech = [["banner landmark"]];
expect(actualSpeech).toMatchSpeechInlineSnapshot(`"banner landmark"`);
await expect(async () => {
await speakMock(actualSpeech);
}).toMatchSpeechInlineSnapshot(`"banner landmark"`);
});

test("custom inline snapshot with two lines", () => {
test("custom inline snapshot with two lines", async () => {
const actualSpeech = [["banner landmark"], ["Search", "combobox"]];
expect(actualSpeech).toMatchSpeechInlineSnapshot(`
await expect(async () => {
await speakMock(actualSpeech);
}).toMatchSpeechInlineSnapshot(`
"banner landmark"
"Search, combobox"
`);
Expand Down
14 changes: 6 additions & 8 deletions src/index.js
Original file line number Diff line number Diff line change
Expand Up @@ -102,21 +102,19 @@ function createMatchers(logFilePath) {
const speechRecorder = createSpeechRecorder(logFilePath);

/**
* @param {Speech} recordedSpeech
* @param {() => Promise<void>} fn
* @param {string} [expectedSpeechSnapshot]
* @returns {ReturnType<typeof toMatchInlineSnapshot>}
* @returns {Promise<ReturnType<typeof toMatchInlineSnapshot>>}
* @this {import('jest-snapshot/build/types').Context}
*/
function toMatchSpeechInlineSnapshot(recordedSpeech, expectedSpeechSnapshot) {
async function toMatchSpeechInlineSnapshot(fn, expectedSpeechSnapshot) {
// Otherwise jest uses the async stack trace which makes it impossible to know the actual callsite of `toMatchSpeechInlineSnapshot`.
this.error = new Error();
// Abort test on first mismatch.
// Subsequent actions will be based on an incorrect state otherwise and almost always fail as well.
this.dontThrow = () => {};
if (typeof recordedSpeech === "function") {
throw new Error(
"Recording lines is not implemented by the matcher. Use `expect(recordLines(async () => {})).resolves.toMatchInlineSnapshot()` instead"
);
}

const recordedSpeech = await speechRecorder.record(fn);
const actualSpeechSnapshot = {
[speechSnapshotBrand]: true,
speech: recordedSpeech,
Expand Down
4 changes: 3 additions & 1 deletion src/matcherTypes.d.ts
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,9 @@ declare global {
interface Matchers<R> {
toAnnounceNVDA(expectedLines: Speech): Promise<void>;
toMatchSpeechSnapshot(snapshotName?: string): Promise<void>;
toMatchSpeechInlineSnapshot(expectedLinesSnapshot?: string): void;
toMatchSpeechInlineSnapshot(
expectedLinesSnapshot?: string
): Promise<void>;
}
}
}