تايب سكريبت - محاكاة Puppeteer للاختبار


لقد كنت أعمل على كود Puppeteer لأخذ لقطة شاشة لموقع ويب، وكتابة كود اختبار وحدات باستخدام Jest. الكود الخاص بي يشبه هذا: 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();
  }
}

يبدو أن هناك بعض الطرق لاختبار كود Puppeteer، لكنني أفضل أن يكون كود الاختبار الخاص بي مستقلاً عن المتصفح، لذلك قررت أن أحاكي Puppeteer كما يقترح هذا المقال: https://cobaltintelligence.com/blog/jordan-mocks-puppeteer-with-jest/

ومع ذلك، الاختبار الوهمي لا يعمل كما هو موصوف. في الواقع، الكود نفسه الموصوف في المقال لا يعمل في بيئتي (node v18.13.0، jest v25.3.0). بعد عدة ساعات من تعديل الاختبار الوهمي، توصلت أخيراً إلى كود الاختبار الذي يعمل بشكل جيد:

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;

الآن لدي كود يعمل، لكن الجزء الخاص بمحاكاة Puppeteer طويل قليلاً، وغير قابل لإعادة الاستخدام لاختبارات أخرى. حاولت طرقًا أخرى مثل إنشاء محاكاة يدوية في مجلد __mocks__، واستخدام spyOn. لكن الطريقة الأولى لا يمكنها مراقبة الطريقة مما قد يحدد ما يمكنني ملاحظته، والطريقة الثانية تتطلب إعدادًا لكل طريقة مستخدمة في الكود الرئيسي. سؤالي هو هل هناك حلول أخرى يمكن أن يكون الجزء الخاص بالمحاكاة قابلاً لإعادة الاستخدام في المشروع، أو طريقة أفضل لتنفيذ ذلك؟

طريقة أفضل للسخرية من وحدة نود مثل puppeteer