使用ts-jest与testing-library/react测试localStorage调用失败问题
解决ts-jest测试localStorage.setItem未被调用的问题
以下是针对性的测试代码调整方案,覆盖常见的问题场景:
1. 显式模拟并监听localStorage方法
Jest的jsdom环境虽自带localStorage,但测试前显式重置、监听方法能避免测试间污染,确保mock准确:
import { render, screen, fireEvent } from '@testing-library/react'; import { AuthProvider, useAuth } from './AuthProvider'; // 每个测试前重置localStorage的mock beforeEach(() => { jest.spyOn(Storage.prototype, 'setItem').mockImplementation(() => {}); jest.spyOn(Storage.prototype, 'getItem').mockImplementation(() => null); }); // 测试后清除mock afterEach(() => { jest.clearAllMocks(); });
2. 确保正确触发onLoginAction
需确认测试组件正确挂载在AuthProvider下,且按钮点击确实调用了context中的onLoginAction:
// 封装测试组件,直接绑定登录动作 const TestLoginComponent = () => { const { onLoginAction } = useAuth(); const testUser = { id: 1, username: 'test_user' }; return <button onClick={() => onLoginAction(testUser)}>Trigger Login</button>; }; test('localStorage.setItem is called on login', () => { render( <AuthProvider> <TestLoginComponent /> </AuthProvider> ); // 触发登录按钮点击 fireEvent.click(screen.getByText('Trigger Login')); // 验证localStorage.setItem被调用,参数匹配预期 expect(Storage.prototype.setItem).toHaveBeenCalledWith( 'user', JSON.stringify({ id: 1, username: 'test_user' }) ); });
3. 处理异步场景的登录逻辑
如果onLoginAction包含异步操作(如API请求、异步dispatch),必须用async/await配合waitFor等待异步完成:
test('localStorage.setItem is called after async login', async () => { render( <AuthProvider> <TestLoginComponent /> </AuthProvider> ); fireEvent.click(screen.getByText('Trigger Login')); // 等待异步操作完成后验证mock await waitFor(() => { expect(Storage.prototype.setItem).toHaveBeenCalled(); }); });
4. 适配自定义Storage封装
若AuthProvider未直接使用window.localStorage,而是封装了自定义Storage工具,需针对性mock该工具:
// 假设自定义Storage工具路径为./utils/storage jest.mock('./utils/storage', () => ({ setItem: jest.fn(), getItem: jest.fn() })); import { setItem } from './utils/storage'; test('custom storage setItem is called on login', () => { render( <AuthProvider> <TestLoginComponent /> </AuthProvider> ); fireEvent.click(screen.getByText('Trigger Login')); expect(setItem).toHaveBeenCalledWith('user', expect.any(String)); });
内容的提问来源于stack exchange,提问作者Jesús V.
相关产品推荐
相关产品推荐

