Skip to content

Commit c99d8c8

Browse files
authored
[INT-1] visual-snapshots: add ESM support for Jest (#206)
1 parent 8a67e48 commit c99d8c8

File tree

11 files changed

+102
-67
lines changed

11 files changed

+102
-67
lines changed

Diff for: visual-js/visual-snapshots/jest.config.cjs

+8-7
Original file line numberDiff line numberDiff line change
@@ -1,20 +1,21 @@
11
/** @type {import('ts-jest').JestConfigWithTsJest} */
22
module.exports = {
33
// [...]
4-
preset: 'ts-jest/presets/default-esm', // or other ESM presets
4+
preset: "ts-jest/presets/default-esm", // or other ESM presets
55
moduleNameMapper: {
6-
'^(\\.{1,2}/.*)\\.js$': '$1',
6+
"^(\\.{1,2}/.*)\\.js$": "$1",
77
},
8-
testPathIgnorePatterns: ['/lib/'],
8+
testPathIgnorePatterns: ["/lib/"],
9+
setupFiles: ["./jest.setup.mjs"],
910
transform: {
1011
// '^.+\\.[tj]sx?$' to process js/ts with `ts-jest`
1112
// '^.+\\.m?[tj]sx?$' to process js/ts/mjs/mts with `ts-jest`
12-
'^.+\\.tsx?$': [
13-
'ts-jest',
13+
"^.+\\.tsx?$": [
14+
"ts-jest",
1415
{
1516
useESM: true,
16-
tsconfig: 'tsconfig.test.json'
17+
tsconfig: "tsconfig.test.json",
1718
},
1819
],
1920
},
20-
}
21+
};

Diff for: visual-js/visual-snapshots/jest.setup.mjs

+2
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,2 @@
1+
import { jest } from "@jest/globals";
2+
global.jest = jest;

Diff for: visual-js/visual-snapshots/package.json

+3-3
Original file line numberDiff line numberDiff line change
@@ -24,9 +24,9 @@
2424
"watch": "rimraf *.tsbuildinfo && tsc -b tsconfig.json -w",
2525
"lint": "eslint \"{src,test}/**/*.ts\"",
2626
"lint-fix": "eslint \"{src,test}/**/*.ts\" --fix",
27-
"test": "jest",
28-
"test-update-snapshots": "jest -u",
29-
"test-with-coverage": "jest --collect-coverage"
27+
"test": "cross-env NODE_NO_WARNINGS=1 NODE_OPTIONS=\"$NODE_OPTIONS --experimental-vm-modules\" jest",
28+
"test-update-snapshots": "cross-env NODE_NO_WARNINGS=1 NODE_OPTIONS=\"$NODE_OPTIONS --experimental-vm-modules\" jest -u",
29+
"test-with-coverage": "cross-env NODE_NO_WARNINGS=1 NODE_OPTIONS=\"$NODE_OPTIONS --experimental-vm-modules\" jest --collect-coverage"
3030
},
3131
"dependencies": {
3232
"@saucelabs/visual": "^0.13.0",

Diff for: visual-js/visual-snapshots/src/api/visual-client.ts

+7-7
Original file line numberDiff line numberDiff line change
@@ -1,9 +1,9 @@
11
import { getApi, VisualConfig } from "@saucelabs/visual";
22

3-
export const initializeVisualApi = (
4-
params: VisualConfig,
5-
clientVersion: string
6-
) =>
7-
getApi(params, {
8-
userAgent: `visual-snapshots/${clientVersion}`,
9-
});
3+
export const visualApiInitializer =
4+
(_getApi: typeof getApi) => (params: VisualConfig, clientVersion: string) =>
5+
_getApi(params, {
6+
userAgent: `visual-snapshots/${clientVersion}`,
7+
});
8+
9+
export const initializeVisualApi = visualApiInitializer(getApi);

Diff for: visual-js/visual-snapshots/src/app/pdf-converter.ts

+5-1
Original file line numberDiff line numberDiff line change
@@ -2,10 +2,14 @@ import { pdf } from "pdf-to-img";
22
import { PdfFile } from "./pdf-file.js";
33

44
export class PdfConverter {
5+
constructor(private readonly _pdf: typeof pdf = pdf) {}
6+
57
public async *convertPagesToImages(
68
pdfFilePath: string
79
): AsyncGenerator<Buffer> {
8-
for await (const pdfPageImage of await pdf(pdfFilePath, { scale: 1 })) {
10+
for await (const pdfPageImage of await this._pdf(pdfFilePath, {
11+
scale: 1,
12+
})) {
913
yield pdfPageImage;
1014
}
1115
}

Diff for: visual-js/visual-snapshots/test/api/visual-api.spec.ts

+3-3
Original file line numberDiff line numberDiff line change
@@ -28,14 +28,14 @@ describe("VisualSnapshots", () => {
2828
const createSnapshotMock = jest.fn();
2929
const finishBuildMock = jest.fn();
3030
const buildStatusMock = jest.fn();
31-
const visualApiMock: VisualApi = {
32-
...jest.requireActual<VisualApi>("@saucelabs/visual"),
31+
const visualApiMock = {
3332
createBuild: createBuildMock,
3433
uploadSnapshot: uploadSnapshotMock,
3534
createSnapshot: createSnapshotMock,
3635
finishBuild: finishBuildMock,
3736
buildStatus: buildStatusMock,
38-
};
37+
} as never as VisualApi;
38+
3939
const visualSnapshots = new VisualSnapshotsApi(visualApiMock);
4040
const files = [new TestPdfFile("file1.pdf"), new TestPdfFile("file2.pdf")];
4141

Diff for: visual-js/visual-snapshots/test/api/visual-client.spec.ts

+4-3
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
import { initializeVisualApi } from "../../src/api/visual-client.js";
1+
import { visualApiInitializer } from "../../src/api/visual-client.js";
22
import * as sauceVisual from "@saucelabs/visual";
33

44
jest.mock("@saucelabs/visual", () => {
@@ -8,8 +8,9 @@ jest.mock("@saucelabs/visual", () => {
88
});
99

1010
describe("visual api client", () => {
11-
test("initializeVisualApi", async () => {
12-
const getApiSpy = sauceVisual.getApi;
11+
test("visualApiInitializer", async () => {
12+
const getApiSpy = jest.fn();
13+
const initializeVisualApi = visualApiInitializer(getApiSpy);
1314

1415
const pkgVersion = "0.1.0";
1516
const params = {
+32-25
Original file line numberDiff line numberDiff line change
@@ -1,35 +1,42 @@
1+
import path from "path";
12
import { PdfConverter } from "../../src/app/pdf-converter.js";
3+
import { __dirname } from "../helpers.js";
24

3-
jest.mock("pdf-to-img", () => {
4-
async function* asyncIterable() {
5-
for (let i = 0; i < 2; i++) {
6-
yield `fake-image-buffer-${i}`;
5+
describe("PdfConverter", () => {
6+
test("convertPagesToImages", async () => {
7+
const pdf = jest.fn().mockResolvedValue([]);
8+
9+
const pdfFilePath = "./fake-pdf-file-path.pdf";
10+
const pdfConverter = new PdfConverter(pdf);
11+
for await (const _ of pdfConverter.convertPagesToImages(pdfFilePath)) {
712
}
8-
}
913

10-
return {
11-
pdf: asyncIterable,
12-
};
13-
});
14+
expect(pdf).toHaveBeenCalledWith(pdfFilePath, { scale: 1 });
15+
});
1416

15-
describe("PdfConverter", () => {
1617
test("convertPagesToImages", async () => {
17-
const pdfFilePath = "./fake-pdf-file-path.pdf";
18+
const pdfFilePath = path.join(__dirname(import.meta), "../files/test.pdf");
1819
const pdfConverter = new PdfConverter();
19-
const pdfPageImagesGenerator = await pdfConverter.convertPagesToImages(
20-
pdfFilePath
21-
);
22-
23-
for (let i = 0; i < 2; ++i) {
24-
const pdfPageImage = await pdfPageImagesGenerator.next();
25-
expect(pdfPageImage).toEqual({
26-
done: false,
27-
value: `fake-image-buffer-${i}`,
28-
});
20+
21+
let pages = 0;
22+
for await (const _ of pdfConverter.convertPagesToImages(pdfFilePath)) {
23+
pages++;
2924
}
30-
expect(await pdfPageImagesGenerator.next()).toEqual({
31-
done: true,
32-
value: undefined,
33-
});
25+
26+
expect(pages).toEqual(3);
27+
});
28+
29+
test("createPdfFile", async () => {
30+
const pdf = jest.fn().mockResolvedValue([]);
31+
const pdfConverter = new PdfConverter(pdf);
32+
33+
const pdfFilePath = "./fake-pdf-file-path.pdf";
34+
const pdfFile = pdfConverter.createPdfFile(pdfFilePath);
35+
36+
for await (const _ of pdfFile.convertPagesToImages()) {
37+
}
38+
39+
expect(pdfFile.path).toBe(pdfFilePath);
40+
expect(pdf).toHaveBeenCalledWith(pdfFilePath, { scale: 1 });
3441
});
3542
});

Diff for: visual-js/visual-snapshots/test/files/test.pdf

51.7 KB
Binary file not shown.

Diff for: visual-js/visual-snapshots/test/helpers.ts

+16
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,16 @@
1+
import { dirname } from "node:path";
2+
import { fileURLToPath } from "node:url";
3+
4+
/**
5+
* ESM helper for getting __filename. Pass `import.meta` to this function.
6+
* @param meta `import.meta`
7+
* @returns __filename equivalent
8+
*/
9+
export const __filename = (meta: ImportMeta) => fileURLToPath(meta.url);
10+
11+
/**
12+
* ESM helper for getting __dirname. Pass `import.meta` to this function.
13+
* @param meta `import.meta`
14+
* @returns __dirname equivalent
15+
*/
16+
export const __dirname = (meta: ImportMeta) => dirname(__filename(meta));

Diff for: visual-js/visual-snapshots/test/utils/glob.spec.ts

+22-18
Original file line numberDiff line numberDiff line change
@@ -1,56 +1,60 @@
11
import { getFiles } from "../../src/utils/glob.js";
22
import path from "path";
3+
import { __dirname, __filename } from "../helpers.js";
34

45
describe("getFiles", () => {
5-
function resolvePath(p: string) {
6-
return path.resolve(p);
6+
function normalize(paths: string[]) {
7+
return paths.map((p) => path.resolve(p)).sort((a, b) => a.localeCompare(b));
78
}
89

910
it("should return a file", async () => {
1011
const input = ["./src/index.ts"];
11-
const expected = input.map(resolvePath);
12+
const expected = normalize(input);
1213

1314
const result = await getFiles(input, "*");
14-
expect(result.map(resolvePath)).toEqual(expected);
15+
expect(normalize(result)).toEqual(expected);
1516
});
1617

1718
it("should return multiple files", async () => {
18-
const input = ["./src/index.ts", __filename];
19-
const expected = input.map(resolvePath);
19+
const input = ["./src/index.ts", __filename(import.meta)];
20+
const expected = normalize(input);
2021

2122
const actual = await getFiles(input, "*");
22-
expect(actual.map(resolvePath)).toEqual(expected);
23+
expect(normalize(actual)).toEqual(expected);
2324
});
2425

2526
it("should return files matched by glob", async () => {
26-
const input = [path.join(__dirname, "*.spec.ts")];
27-
const expected = [resolvePath(__filename)];
27+
const input = [path.join(__dirname(import.meta), "*.spec.ts")];
28+
const expected = normalize([__filename(import.meta)]);
2829

2930
const actual = await getFiles(input, "*");
30-
expect(actual.map(resolvePath)).toEqual(expect.arrayContaining(expected));
31+
expect(normalize(actual)).toEqual(expect.arrayContaining(expected));
3132
});
3233

3334
it("should return files in directory matched by dir glob", async () => {
34-
const input = [__dirname];
35-
const expected = [resolvePath(__filename)];
35+
const input = [__dirname(import.meta)];
36+
const expected = normalize([__filename(import.meta)]);
3637

3738
const actual = await getFiles(input, "*.spec.ts");
38-
expect(actual.map(resolvePath)).toEqual(expect.arrayContaining(expected));
39+
expect(normalize(actual)).toEqual(expect.arrayContaining(expected));
3940
});
4041

4142
it("should not return non-existing files", async () => {
42-
const input = [__filename, __filename + ".not-existing"];
43-
const expected = [resolvePath(__filename)];
43+
const input = [
44+
__filename(import.meta),
45+
__filename(import.meta) + ".not-existing",
46+
];
47+
const expected = normalize([__filename(import.meta)]);
4448

4549
const result = await getFiles(input, "*");
46-
expect(result.map(resolvePath)).toEqual(expected);
50+
expect(normalize(result)).toEqual(expected);
4751
});
4852

4953
it("should not return files from not existing dirs", async () => {
50-
const input = [__dirname + ".not-existing"];
54+
const input = [__dirname(import.meta) + ".not-existing"];
5155
const expected: string[] = [];
5256

5357
const result = await getFiles(input, "*");
54-
expect(result.map(resolvePath)).toEqual(expected);
58+
expect(normalize(result)).toEqual(expected);
5559
});
5660
});

0 commit comments

Comments
 (0)