视频元素的Jest抛出超时错误

00jrzges  于 2024-01-04  发布在  Jest
关注(0)|答案(1)|浏览(180)

我有一个从视频元素中提取像宽度和高度这样的Meta数据的函数,如下所示:

export async function getVideoMetadata(
  videoBlobUrl: string,
  videoElement: HTMLVideoElement,
): Promise<{ width: number; height: number }> {
  // Trigger video load
  return new Promise<{ width: number; height: number }>((resolve, reject) => {
    videoElement.onloadedmetadata = () => {
      videoElement.width = videoElement.videoWidth;
      videoElement.height = videoElement.videoHeight;
      videoElement.currentTime = videoElement.duration * 0.25;
    };

    videoElement.onseeked = () => {
      resolve({ width: videoElement.videoWidth, height: videoElement.videoHeight });
    };

    videoElement.onerror = () => {
      reject(`Error loading video`);
    };
    videoElement.src = videoBlobUrl;
  });
}

字符串
在一个运行的环境中,代码运行完美,并提供了正确的高度和宽度的视频所需的结果。我在另一个函数中使用此函数在画布上绘制视频,以在客户端生成视频的缩略图。
但是,当我试图用jest编写一个测试时,与下面的函数相同:

it('should return video metadata', async () => {
    // Mock the videoBlobUrl
    const videoBlobUrl = 'https://example.com/mock-video-url.mp4';

    // Mock the HTMLVideoElement
    const videoElementMock: HTMLVideoElement = {
      onloadedmetadata: null,
      onseeked: null,
      onerror: null,
      width: 0,
      height: 0,
      videoWidth: 640, // Mock video width
      videoHeight: 480, // Mock video height
      duration: 10, // Mock video duration
      currentTime: 0,
      src: '',
      addEventListener: jest.fn(),
      removeEventListener: jest.fn(),
      dispatchEvent: jest.fn(),
      play: jest.fn(),
      pause: jest.fn(),
      load: jest.fn(),
    };

    // Spy on addEventListener to capture the event handlers
    const addEventListenerSpy = jest.spyOn(videoElementMock, 'addEventListener');

    // Call the function with the mocked data
    const result = await getVideoMetadata(videoBlobUrl, videoElementMock);

    // Assertions
    expect(videoElementMock.src).toBe(videoBlobUrl);
    expect(addEventListenerSpy).toHaveBeenCalledWith('loadedmetadata', expect.any(Function));
    expect(addEventListenerSpy).toHaveBeenCalledWith('seeked', expect.any(Function));

    // Trigger the loadedmetadata event
    const loadedMetadataHandler = (addEventListenerSpy as jest.Mock).mock.calls.find(
      (call) => call[0] === 'loadedmetadata',
    )[1] as EventListener;
    loadedMetadataHandler(new Event('loadedmetadata'));

    // Trigger the seeked event
    const seekedHandler = (addEventListenerSpy as jest.Mock).mock.calls.find(
      (call) => call[0] === 'seeked',
    )[1] as EventListener;
    seekedHandler(new Event('seeked'));

    // Validate the result
    expect(result).toEqual({width:640, height:480});
  });


测试用例总是失败,只要我在测试用例中调用getVideoMetadata函数,就抛出,而不继续下一行。

thrown: "Exceeded timeout of 5000 ms for a test.
    Use jest.setTimeout(newTimeout) to increase the timeout value, if this is a long-running test."


我试过增加测试的超时时间,但没有帮助。一旦测试代码videoElement.src = videoBlobUrl;到达,下一步就会失败,抛出错误。

fsi0uk1n

fsi0uk1n1#

我们通过video元素的属性.onloadedmetadata.onseeked.onerror将事件处理程序附加到video元素上。它们都是匿名函数,而不是jestjsmock函数。因此jest.spyOn(videoElementMock, 'addEventListener')expect(addEventListenerSpy).toHaveBeenCalledWith('loadedmetadata', expect.any(Function))将无法工作。
由于您传递了videoElement to getVideoMetadata函数,因此在事件发生时修改video元素的属性,您可以在测试中获取video元素的属性(事件处理程序)。然后手动触发它们。
例如
getVideoMetadata.test.ts

import { expect, it } from '@jest/globals';
import { getVideoMetadata } from './getVideoMetadata';

it('should return video metadata', async () => {
  const videoBlobUrl = 'https://example.com/mock-video-url.mp4';

  const videoElementMock = {
    width: 0,
    height: 0,
    videoWidth: 640,
    videoHeight: 480,
    duration: 10,
    currentTime: 0,
    src: '',
    onloadedmetadata: () => {},
    onseeked: () => {},
  };

  const promise = getVideoMetadata(videoBlobUrl, videoElementMock as unknown as HTMLVideoElement);

  expect(videoElementMock.src).toBe(videoBlobUrl);

  // Trigger the loadedmetadata event
  videoElementMock.onloadedmetadata();

  // Trigger the seeked event
  videoElementMock.onseeked();

  // Validate the result
  const result = await promise;
  expect(result).toEqual({ width: 640, height: 480 });
  expect(videoElementMock.src).toBe(videoBlobUrl);
});

字符串
测试结果:

PASS  stackoverflow/77550452/getVideoMetadata.test.ts
  ✓ should return video metadata (1 ms)

---------------------|---------|----------|---------|---------|-------------------
File                 | % Stmts | % Branch | % Funcs | % Lines | Uncovered Line #s 
---------------------|---------|----------|---------|---------|-------------------
All files            |      90 |      100 |      80 |      90 |                   
 getVideoMetadata.ts |      90 |      100 |      80 |      90 | 15                
---------------------|---------|----------|---------|---------|-------------------
Test Suites: 1 passed, 1 total
Tests:       1 passed, 1 total
Snapshots:   0 total
Time:        0.553 s

相关问题