typescript - Mocking puppeteer for testing
Jeg har jobbet med puppeteer-kode for å ta skjermbilder av et nettsted, og skriver enhetstestkode med jest. Koden min er noe sånt som dette: index.ts
import puppeteer from "puppeteer";
export async function takeScreenshot() {
const browser = await puppeteer.launch({ headless: true });
try {
const page = await browser.newPage();
const url = "https://someurl.com/somepage";
await page.goto(url);
await page.waitForSelector("test");
const buffer = page.screenshot();
return buffer;
} catch (e) {
throw e;
} finally {
await browser.close();
}
}
Det ser ut til å være noen måter å teste Puppeteer-kode på, men jeg foretrekker at testkoden min er uavhengig av nettleseren, så jeg bestemte meg for å mocke Puppeteer slik denne artikkelen foreslår: https://cobaltintelligence.com/blog/jordan-mocks-puppeteer-with-jest/
Imidlertid fungerer ikke mocken som beskrevet. Faktisk fungerer ikke koden som er beskrevet i artikkelen i mitt miljø (node v18.13.0, jest v25.3.0). Etter flere timer med å finjustere mocken min, kom jeg endelig fram til testkoden som fungerer fint:
index.test.ts
import { takeScreenshot } from "../src/index";
import { stubPage } from "./mockPuppeteer";
import { Browser } from "puppeteer";
jest.mock("puppeteer", () => {
return {
__esModule: true,
default: {
launch: jest.fn().mockImplementation(() => {
return {
newPage() {
return Promise.resolve(stubPage);
},
close() {
return Promise.resolve();
},
} as unknown as Browser;
}),
},
};
});
jest.setTimeout(0);
beforeEach(() => {
jest.restoreAllMocks();
});
describe("action()", () => {
test.only("it exports pdf", async () => {
const screenshotSpy = jest.spyOn(stubPage, 'screenshot')
await takeScreenshot();
expect(screenshotSpy).toHaveBeenCalled();
});
});
mockPuppeteer.ts
import { Browser, Page } from "puppeteer";
export const stubPage = {
goto(url: string) {
return Promise.resolve();
},
screenshot() {
return Promise.resolve();
},
waitForSelector(selector: string) {
return Promise.resolve();
},
} as unknown as Page;
export const stubBrowser = {
newPage() {
return Promise.resolve(stubPage);
},
close() {
return Promise.resolve();
},
} as unknown as Browser;
Nå har jeg en fungerende kode, men delen for å mocke puppeteer er litt lang, og ikke gjenbrukbar for andre tester. Jeg har prøvd andre metoder som å lage en manuell mock i __mocks__-mappen, og bruke spyOn. Men den første kan ikke spionere på metoden, noe som kan begrense hva jeg kan observere, og den andre krever oppsett for hver metode som brukes i hovedkoden. Spørsmålet mitt er om det finnes andre løsninger slik at mock-delen kan være gjenbrukbar i prosjektet, eller en bedre måte å implementere dette på?
Bedre måte å gjøre narr av en node-modul som puppeteer