如何在 Jest 中正确模拟 Audio API?

How do I mock Audio API in Jest properly?

我正在编写一个测试,需要模拟并提供访问工具来验证我的音频实现是否正确。我成功地实现了我的设置方法:

import "regenerator-runtime/runtime";
import { AudioState } from '../src';

export class MockAudio extends Audio {
  src: string;
  state: AudioState;
  duration: number;
  playing: boolean;
  constructor() {
    super();
    this.playing = false;
    this.duration = NaN;
    this.state = AudioState.STOPPED;
    this.src = '';
  }
  fastSeek = (time: number): Promise<void> => {
    this.currentTime = time;
    return Promise.resolve();
  }
  play = (): Promise<void> => {
    this.playing = true;
    this.state = AudioState.PLAYING;
    return super.play();
  }
  pause = (): void => {
    this.playing = false;
    this.state = AudioState.PAUSED;
    return super.pause();
  }
}

HTMLMediaElement.prototype.pause = () => Promise.resolve();
HTMLMediaElement.prototype.play = () => Promise.resolve();

window.Audio = MockAudio;

Object.defineProperty(window, 'MediaSource', {
  writable: true,
  value: jest.fn().mockImplementation((params) => ({
    // MediaSource implementation goes here
    addEventListener: jest.fn(),
  })),
});

如您所见,我正在设置方法,以便它们能够以模拟音频的方式影响对象属性 API。我想知道如何使用 mockImplementation 和 defineProperty 正确地做到这一点?

您可以使用此处描述的方法解决此问题(或模拟任何其他内置 API classes):https://jestjs.io/docs/es6-class-mocks#manual-mock

我喜欢做的是首先定义我的模拟,以便以后在 test-utils.js 中使用,如下所示:

export const mocks = {
  Audio: {
    pause: jest.fn(),
    play: jest.fn(),
  },
}

现在我在我的 jest.setup.js 中模拟实际的 class(在 jest 配置中定义):

import { mocks } from "./test-utils"

// Audio mock
global.Audio = jest.fn().mockImplementation(() => ({
  pause: mocks.Audio.pause,
  play: mocks.Audio.play,
}))

最后我可以期待在我的测试中对抗模拟:

import { mocks } from "./test-utils"

describe("Something", () => {
  it("should work", () => {
    // run your test here
    expect(mocks.Audio.pause).toHaveBeenCalled()
  })
})

当然记得根据需要清理模拟。

以及我 package.json 中 jest 配置的相关部分以触发设置文件:

  "jest": {
    ...,
    "setupFilesAfterEnv": [
      "<rootDir>/jest.setup.js"
    ],
    ...
  },