如何为 Jest 模拟导航器 mediaDevices

Kar*_*lor 1 unit-testing navigator reactjs jestjs

我有一个需要使用的测试,navigator.mediaDevices但我无法让任何模拟正常工作。

我正在使用create-react-app.

这是我的测试:

import getConnectedDevices from "./getConnectedDevices";

describe("getConnectedDevices", () => {
  it("Should work", () => {
    console.log(navigator);              // Navigator {}
    console.log(navigator.mediaDevices); // undefined
  });
});
Run Code Online (Sandbox Code Playgroud)

我尝试添加一个模拟,因为它在 jest 文档中说明

import getConnectedDevices from "./getConnectedDevices";

describe("getConnectedDevices", () => {
  it("Should work", () => {
    console.log(navigator);              // Navigator {}
    console.log(navigator.mediaDevices); // undefined
  });
});
Run Code Online (Sandbox Code Playgroud)
import "../../tests/navigator.mock"; // <- Mock added

import getConnectedDevices from "./getConnectedDevices";

describe("getConnectedDevices", () => {
  it("Should work", () => {
    console.log(navigator);              // Navigator {}
    console.log(navigator.mediaDevices); // undefined
  });
});
Run Code Online (Sandbox Code Playgroud)

我也尝试过根据 create-react-app 文档初始化测试环境

// src/setupTests.ts

// jest-dom adds custom jest matchers for asserting on DOM nodes.
// allows you to do things like:
// expect(element).toHaveTextContent(/react/i)
// learn more: https://github.com/testing-library/jest-dom
import "@testing-library/jest-dom";

const navigatorMock = {
  mediaDevices: {
    enumerateDevices: jest.fn(),
  },
};

global.navigator = navigatorMock;
Run Code Online (Sandbox Code Playgroud)

我究竟做错了什么?

小智 5

我在打字稿中做到了:

const mockGetUserMedia = jest.fn(async () => {
    return new Promise<void>(resolve => {
        resolve()
    })
})

Object.defineProperty(global.navigator, 'mediaDevices', {
    value: {
        getUserMedia: mockGetUserMedia,
    },
})
Run Code Online (Sandbox Code Playgroud)

  • 我认为这个答案需要更多澄清信息。与测试相比,它到底在哪里被调用?除了 jest 之外是否还需要任何库?我还尝试实现此代码,但它没有为我将“mediaDevices”添加到导航器属性中。 (2认同)

Kar*_*lor 1

看来因为已经存在一个navigator对象,所以不可能重新分配它。

感谢这个 stackoverflow 答案,您可以模拟 中的对象navigator并将其分配给现有的导航器对象。

// src/setupTests.ts

const mediaDevicesMock = {
  enumerateDevices: jest.fn(),
};

global.navigator.mediaDevices = mediaDevicesMock; // here
Run Code Online (Sandbox Code Playgroud)

注意:这将引发 TSC 错误Cannot assign to 'mediaDevices' because it is a read-only property.ts(2540)。仍在努力弄清楚这一点。

  • 您可以使用“Object.defineProperty()”,并且如果您稍后要在某些测试中覆盖它,请不要忘记添加“{ writable: true }”。 (2认同)