You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

Jest测试超时求助:Spotify SDK初始化测试超5000ms

解决Jest测试Spotify SDK初始化超时问题

执行Jest测试时遇到超时错误,报错信息为thrown: Exceeded timeout of 5000 ms for a test,以下是问题代码、测试代码、错误信息及解决方案:

问题代码

export const initializeSpotifySDK = async (token: string, trackId: string, contextUri: string, playbackStateChangeHandler: (state) => void, errorHandler: (message: string) => void): Promise<SpotifyPlayer> => {
  embedSpotifyScript();

  return new Promise(resolve => {
    window.onSpotifyWebPlaybackSDKReady = () => {
      try {
        // @ts-ignore
        const player = new Spotify.Player({
          name: 'Mira',
          getOAuthToken: callback => { callback(token); }
        });

        // Error handling - pass an error handler!!!
        player.addListener('initialization_error', ({ message }) => {
          errorHandler(message);
        });
        player.addListener('authentication_error', ({ message }) => {
          errorHandler(message);
        });
        player.addListener('account_error', ({ message }) => {
          errorHandler(message);
        });
        player.addListener('playback_error', ({ message }) => {
          errorHandler(message);
        });

        // Playback state handler - pass a handler as well!!!
        player.addListener('player_state_changed', state => { playbackStateChangeHandler(state); });

        player.addListener('ready', ({ device_id }) => {
          const spotifyPlayer = new SpotifyPlayer(player, device_id, trackId, contextUri, token, true);
          resolve(spotifyPlayer);
        });

        player.addListener('not_ready', ({ device_id }) => {
          const spotifyPlayer = new SpotifyPlayer(player, device_id, trackId, contextUri, token, false);
          resolve(spotifyPlayer);
        });

        player.connect();
      } catch (err) {
        logError(err);
        resolve(new SpotifyPlayer(null, '', '', token, '', false));
      }
    };
  });
};

测试代码

it('should initialize the Spotify SDK and return a SpotifyPlayer object', async () => {
  const token = 'abc123';
  const trackId = '123';
  const contextUri = 'spotify:album:456';
  const playbackStateChangeHandler = jest.fn();
  const errorHandler = jest.fn();

  const spotifyPlayer = await initializeSpotifySDK(
    token,
    trackId,
    contextUri,
    playbackStateChangeHandler,
    errorHandler
  );

  console.log({ spotifyPlayer });

  expect(spotifyPlayer).toBeInstanceOf(SpotifyPlayer);
  expect(spotifyPlayer.deviceId).toBeDefined();
  expect(spotifyPlayer.trackId).toEqual(trackId);
  expect(spotifyPlayer.contextUri).toEqual(contextUri);
  expect(spotifyPlayer.token).toEqual(token);
});

完整错误信息

✕ should initialize the Spotify SDK and return a SpotifyPlayer object (5003 ms)

● spotifySdkService › should initialize the Spotify SDK and return a SpotifyPlayer object

  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."

    108 |   });
    109 |
> 110 |   it('should initialize the Spotify SDK and return a SpotifyPlayer object', async () => {
      |   ^
    111 |     const token = 'abc123';
    112 |     const trackId = '123';
    113 |     const contextUri = 'spotify:album:456';

    at services/spotifySdkService.spec.ts:110:3
    at Object.<anonymous> (services/spotifySdkService.spec.ts:17:1)
    at TestScheduler.scheduleTests (../node_modules/@jest/core/build/TestScheduler.js:333:13)
    at runJest (../node_modules/@jest/core/build/runJest.js:404:19)
    at _run10000 (../node_modules/@jest/core/build/cli/index.js:320:7)
    at runCLI (../node_modules/@jest/core/build/cli/index.js:173:3)

问题原因及解决方法

核心原因

测试超时的根本原因是:测试环境中未实际加载Spotify Web Playback SDK脚本,window.onSpotifyWebPlaybackSDKReady回调永远不会触发,导致Promise一直处于pending状态,直到Jest触发超时。

解决步骤

  • 模拟Spotify SDK的加载与回调
    在测试前手动触发SDK就绪回调,并mock Spotify Player类,避免依赖真实SDK:
beforeEach(() => {
  // 模拟Spotify Player类
  window.Spotify = {
    Player: jest.fn().mockImplementation(() => ({
      addListener: jest.fn(),
      connect: jest.fn(() => Promise.resolve(true))
    }))
  };
  // 手动触发SDK就绪回调
  window.onSpotifyWebPlaybackSDKReady?.();
});
  • Mock embedSpotifyScript函数
    避免测试中尝试加载真实脚本,直接mock该函数:
import { embedSpotifyScript } from './your-file-path';

jest.mock('./your-file-path', () => ({
  ...jest.requireActual('./your-file-path'),
  embedSpotifyScript: jest.fn()
}));
  • 手动触发Player事件,让Promise resolve
    通过mock的addListener获取事件回调,手动调用触发ready或not_ready事件:
it('should initialize the Spotify SDK and return a SpotifyPlayer object', async () => {
  const token = 'abc123';
  const trackId = '123';
  const contextUri = 'spotify:album:456';
  const playbackStateChangeHandler = jest.fn();
  const errorHandler = jest.fn();

  // 先启动初始化Promise
  const spotifyPlayerPromise = initializeSpotifySDK(
    token,
    trackId,
    contextUri,
    playbackStateChangeHandler,
    errorHandler
  );

  // 获取mock的Player实例,触发ready事件
  const mockPlayer = window.Spotify.Player.mock.instances[0];
  const readyCallback = mockPlayer.addListener.mock.calls.find(call => call[0] === 'ready')[1];
  readyCallback({ device_id: 'mock-device-id' });

  // 等待Promise完成
  const spotifyPlayer = await spotifyPlayerPromise;

  expect(spotifyPlayer).toBeInstanceOf(SpotifyPlayer);
  expect(spotifyPlayer.deviceId).toBe('mock-device-id');
  expect(spotifyPlayer.trackId).toEqual(trackId);
  expect(spotifyPlayer.contextUri).toEqual(contextUri);
  expect(spotifyPlayer.token).toEqual(token);
});
  • 可选:临时增加超时时间(不推荐)
    若仅临时验证,可在测试中增加超时时间,但这无法解决根本问题:
it('should initialize the Spotify SDK and return a SpotifyPlayer object', async () => {
  jest.setTimeout(10000); // 延长至10秒
  // ... 测试代码
});

内容的提问来源于stack exchange,提问作者Reacting

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.08.06 18:55:28