Skip to content

Commit a71cb81

Browse files
authored
Normalize speech snapshot matcher signatures (#16)
1 parent 741dd42 commit a71cb81

File tree

5 files changed

+75
-32
lines changed

5 files changed

+75
-32
lines changed

.changeset/small-starfishes-yell.md

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,6 @@
1+
---
2+
"example-jest": patch
3+
"screen-reader-testing-library": patch
4+
---
5+
6+
Implement same signature as `toMatchSpeechSnapshot` in `toMatchSpeechInlineSnapshot`

examples/jest/index.test.ts

Lines changed: 10 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -43,26 +43,20 @@ describe("chromium", () => {
4343
await page.bringToFront();
4444
await awaitNvdaRecording();
4545

46-
await expect(
47-
speechRecorder.record(async () => {
48-
await page.keyboard.press("s");
49-
})
50-
).resolves.toMatchSpeechInlineSnapshot(`
46+
await expect(async () => {
47+
await page.keyboard.press("s");
48+
}).toMatchSpeechInlineSnapshot(`
5149
"banner landmark"
5250
"Search, combo box, expanded, has auto complete, editable, Search…, blank"
5351
`);
5452

55-
await expect(
56-
speechRecorder.record(async () => {
57-
await page.keyboard.type("Rating");
58-
})
59-
).resolves.toMatchSpeechInlineSnapshot(``);
60-
61-
await expect(
62-
speechRecorder.record(async () => {
63-
await page.keyboard.press("ArrowDown");
64-
})
65-
).resolves.toMatchSpeechInlineSnapshot(`
53+
await expect(async () => {
54+
await page.keyboard.type("Rating");
55+
}).toMatchSpeechInlineSnapshot(``);
56+
57+
await expect(async () => {
58+
await page.keyboard.press("ArrowDown");
59+
}).toMatchSpeechInlineSnapshot(`
6660
"list"
6761
"Link to the result, 1 of 5"
6862
`);

src/__tests__/extendExpect.js

Lines changed: 50 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -1,19 +1,62 @@
1+
const { promises: fs } = require("fs");
2+
const os = require("os");
3+
const path = require("path");
14
const { extendExpect } = require("../index");
25

3-
extendExpect(expect, "unused");
6+
/**
7+
* @type {string}
8+
*/
9+
let logFilePath;
10+
/**
11+
* @param {string[][]} speech
12+
*/
13+
function speakMock(speech) {
14+
// Check existing fixtures for how to mock speech output.
15+
const mockedSpeach = speech
16+
.map((line) => {
17+
return `Speaking [${line
18+
.map((group) => {
19+
return `'${group}'`;
20+
})
21+
.join(", ")}]\n`;
22+
})
23+
.join("");
24+
return fs.writeFile(logFilePath, mockedSpeach, { flag: "a" });
25+
}
426

5-
test("custom inline snapshot with no lines", () => {
6-
expect([]).toMatchSpeechInlineSnapshot(``);
27+
beforeAll(async () => {
28+
logFilePath = path.join(
29+
os.tmpdir(),
30+
"srtl-testing",
31+
`extendExpect-${new Date().valueOf()}.log`
32+
);
33+
await fs.mkdir(path.dirname(logFilePath), { recursive: true });
34+
await fs.writeFile(logFilePath, "", { flag: "w" });
35+
extendExpect(expect, logFilePath);
736
});
837

9-
test("custom inline snapshot with one line", () => {
38+
afterAll(async () => {
39+
await fs.unlink(logFilePath);
40+
});
41+
42+
test("custom inline snapshot with no lines", async () => {
43+
await expect(async () => {
44+
await speakMock([]);
45+
}).toMatchSpeechInlineSnapshot(``);
46+
});
47+
48+
test("custom inline snapshot with one line", async () => {
1049
const actualSpeech = [["banner landmark"]];
11-
expect(actualSpeech).toMatchSpeechInlineSnapshot(`"banner landmark"`);
50+
await expect(async () => {
51+
await speakMock(actualSpeech);
52+
}).toMatchSpeechInlineSnapshot(`"banner landmark"`);
1253
});
1354

14-
test("custom inline snapshot with two lines", () => {
55+
test("custom inline snapshot with two lines", async () => {
1556
const actualSpeech = [["banner landmark"], ["Search", "combobox"]];
16-
expect(actualSpeech).toMatchSpeechInlineSnapshot(`
57+
await expect(async () => {
58+
await speakMock(actualSpeech);
59+
}).toMatchSpeechInlineSnapshot(`
1760
"banner landmark"
1861
"Search, combobox"
1962
`);

src/index.js

Lines changed: 6 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -102,21 +102,19 @@ function createMatchers(logFilePath) {
102102
const speechRecorder = createSpeechRecorder(logFilePath);
103103

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

117+
const recordedSpeech = await speechRecorder.record(fn);
120118
const actualSpeechSnapshot = {
121119
[speechSnapshotBrand]: true,
122120
speech: recordedSpeech,

src/matcherTypes.d.ts

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -7,7 +7,9 @@ declare global {
77
interface Matchers<R> {
88
toAnnounceNVDA(expectedLines: Speech): Promise<void>;
99
toMatchSpeechSnapshot(snapshotName?: string): Promise<void>;
10-
toMatchSpeechInlineSnapshot(expectedLinesSnapshot?: string): void;
10+
toMatchSpeechInlineSnapshot(
11+
expectedLinesSnapshot?: string
12+
): Promise<void>;
1113
}
1214
}
1315
}

0 commit comments

Comments
 (0)