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
相关产品推荐
相关产品推荐

