无法为Jest单元测试模拟“webextension-polyfill”。

4
我正在为Firefox和Chrome编写浏览器扩展。我使用browser.*命令和Mozilla的"webextension-polyfill"模块来在chrome中使浏览器工作。我有一个名为browser.ts的文件,其中包含一行代码: export const browser = require('webextension-polyfill'); 然后在每个文件中像这样使用它: import {browser} from '../path/to/browser.ts'
我想让它可以编写单元测试,但是require('webextension-polyfill')这一行让我头疼,因为任何带有browser的测试都会抛出This script should only be loaded in a browser extension并引用了先前的require语句。
我尝试使用rewireproxyquire和jest mocks来避免在单元测试中调用require语句,但我无法成功覆盖它。我唯一能够避免这个错误的方法是使用try-catch并返回异常时的模拟对象,但那看起来很麻烦和混乱。

如何最好地解决这个问题?我看到像 mockzilla 这样的软件包对于模拟很有帮助,但我认为在我可以首先使用 webextension-polyfill 的要求行之后再使用它们。

1个回答

1
很不幸,你将不得不创建整个模拟类。或者至少创建一个包含你使用的方法的类。我现在将解释一下你可以用jest来解决这个问题的方法。
1. 模拟类
假设你有一个名为browser.ts的文件(你可以使用javascript),它位于__mocks__文件夹中。
import { jest } from "@jest/globals";

const mockBrowser = {
    // Define mock implementations for browser APIs you use
    storage: {
        local: {
            get: jest.fn(),
            set: jest.fn(),
        },
    },
    // Add more mock APIs as needed
};

export default mockBrowser;

2. 更新 jest 配置

在 jest 配置文件 jest.config.js 中,你需要添加 moduleNameWrapper。例如,我有以下配置:

/** @type {import('ts-jest').JestConfigWithTsJest} */

const path = require('path');

module.exports = {
  preset: 'ts-jest',
  testEnvironment: 'node',
  testMatch: ['**/extension/src/**/*.test.ts'],
  "moduleNameMapper": {
    "^webextension-polyfill$": path.join(process.cwd(), "src", "__mocks__", "browser.ts"),
    // Add other mocks if needed
  }
};

3. 测试文件

现在您可以创建一个带有模拟调用的类。在这个例子中,我将直接执行浏览器操作。但这也可以在被测试的函数上调用。

import { describe, expect, test } from "@jest/globals";
import mockBrowser from "../__mocks__/browser";
test("Browser Mock", async () => {
    const getStorage = async (data: null | string | string[] | Record<string, any>): Promise<Record<string, any>> => {
        return { key: data };
    };

    mockBrowser.storage.local.get.mockImplementation(getStorage);

    const testMock = await mockBrowser.storage.local.get("dataX");
    expect(testMock).toEqual({ key: "dataX" });
});

如您所见,我在指定get操作的类型。但是,除非您使用TypeScript,否则这是不必要的。在这个示例中,您还可以看到参数如何用于输出。
希望您会发现这个答案有帮助。

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接