Skip to content

Commit

Permalink
Normalize speech snapshot matcher signatures (#16)
Browse files Browse the repository at this point in the history
  • Loading branch information
eps1lon committed Dec 6, 2020
1 parent 741dd42 commit a71cb81
Show file tree
Hide file tree
Showing 5 changed files with 75 additions and 32 deletions.
6 changes: 6 additions & 0 deletions .changeset/small-starfishes-yell.md
@@ -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
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
@@ -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
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
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>;
}
}
}

0 comments on commit a71cb81

Please sign in to comment.