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

Relaterte artikler