React测试Mock localStorage时触发JSON.parse错误该如何解决?
问题分析与解决方案
核心问题
- Key大小写不匹配:组件中读取的是
"lastplayed"(全小写),但测试代码中设置的是"lastPlayed"(驼峰),导致localStorage.getItem("lastplayed")返回undefined而非预期的null。此时逻辑或||的左侧条件不成立,会执行右侧的getTimeDiff(),进而触发JSON.parse(undefined)的语法错误。 - Mock的localStorage行为不符合真实环境:真实浏览器的
localStorage仅支持存储字符串,调用setItem存入null时会自动转为字符串"null",但当前Mock实现直接存储了null值,和真实行为存在差异。
解决方案
1. 统一Key的大小写
将测试代码中的"lastPlayed"改为和组件一致的"lastplayed":
it("Renders game part of the component when lastPlayed is null", () => { localStorage.setItem("lastplayed", null); // 修正为全小写key render(<Game />); // ... 其余断言代码 });
2. 修正Mock的localStorage行为,匹配真实环境
修改setItem和getItem的Mock实现,确保和真实localStorage的行为一致:
beforeAll(() => { global.Storage.prototype.setItem = jest.fn((key, value) => { // 模拟真实localStorage:所有值转为字符串存储 mockStorage[key] = String(value); }); global.Storage.prototype.getItem = jest.fn((key) => { // 若key不存在,返回null而非undefined,匹配真实行为 return mockStorage.hasOwnProperty(key) ? mockStorage[key] : null; }); });
3. 优化组件中的条件判断(可选但推荐)
为避免localStorage.getItem返回undefined的情况(比如key拼写错误),调整条件判断逻辑:
return( <div> { // 先判断值是否为空,再执行getTimeDiff !localStorage.getItem("lastplayed") || getTimeDiff() >= 24 ? (<SubComponent/>) : (<AnotherComponent/>) } </div> )
更严谨的写法:
const lastPlayed = localStorage.getItem("lastplayed"); return( <div> { (lastPlayed === null || lastPlayed === undefined || getTimeDiff() >= 24) ? (<SubComponent/>) : (<AnotherComponent/>) } </div> )
4. 为getTimeDiff添加容错处理
即使前面的条件都处理完毕,也可以给getTimeDiff加一层容错,避免意外的JSON解析错误:
function getTimeDiff() { let currentDay = new Date().toISOString(); let prevPlayStr = localStorage.getItem("lastplayed"); // 若值无效,直接返回24,满足显示SubComponent的条件 if (!prevPlayStr) return 24; let prevPlay = JSON.parse(prevPlayStr); let diff = differenceInHours(parseISO(currentDay), parseISO(prevPlay)); console.log(currentDay + " and " + prevPlay); return diff; }
内容的提问来源于stack exchange,提问作者afunnyworld
相关产品推荐
相关产品推荐

