如何在Playwright中Mock chrome.storage.sync.get完成扩展测试?
解决Playwright中Mock chrome.storage.sync.get无效的问题
问题根源
你的mock代码未生效,核心原因是页面上下文与扩展上下文相互隔离:page.addInitScript是注入到普通页面的执行上下文,但你的扩展代码(比如内容脚本)运行在独立的扩展沙箱上下文中,导致mock无法覆盖到扩展里的chrome.storage对象。
解决方案
方案1:针对内容脚本上下文注入Mock
如果你的业务代码是扩展的内容脚本,需要将mock注入到内容脚本的专属上下文,可通过context.addInitScript指定target: 'content'实现:
test('MyTest', async ({ context, page }) => { // 向所有内容脚本上下文注入mock逻辑 await context.addInitScript({ target: 'content', content: ` const mockStorageData = { data: 'storedData' }; // 对齐原生chrome.storage.sync.get的参数逻辑 chrome.storage.sync.get = (keys, callback) => { let result = {}; // 处理不同类型的keys参数 if (typeof keys === 'string') { result[keys] = mockStorageData[keys]; } else if (Array.isArray(keys)) { keys.forEach(key => { result[key] = mockStorageData[key]; }); } else if (typeof keys === 'object') { Object.keys(keys).forEach(key => { result[key] = mockStorageData[key] ?? keys[key]; }); } else { result = mockStorageData; } // 同时支持回调和Promise两种调用方式 if (typeof callback === 'function') { callback(result); return; } return Promise.resolve(result); }; ` }); await page.goto('https://www.myWebsite.com/'); const result = page.locator("#data"); await expect(result).toContainText('storedData'); });
方案2:模拟完整的Chrome Storage API
如果你的代码依赖chrome.storage的更多特性(比如存储修改、监听变化),可以模拟更完整的API实现:
await context.addInitScript({ target: 'content', content: ` const mockStorage = { sync: { data: 'storedData', get: function(keys, callback) { let res = {}; // 兼容各种参数场景 if (keys === null || keys === undefined) { res = { ...this }; } else if (typeof keys === 'string') { res[keys] = this[keys]; } else if (Array.isArray(keys)) { keys.forEach(k => res[k] = this[k]); } else if (typeof keys === 'object') { for (const k in keys) { res[k] = this[k] ?? keys[k]; } } // 支持回调和Promise if (callback) { callback(res); return; } return Promise.resolve(res); }, // 可选:模拟set方法 set: function(data, callback) { Object.assign(this, data); if (callback) callback(); return Promise.resolve(); } } }; // 替换全局chrome.storage对象 chrome.storage = mockStorage; ` });
方案3:针对后台脚本的Mock
如果你的chrome.storage调用是在扩展后台脚本中,需要通过Playwright的extension fixture获取后台页面,再注入mock:
test('MyTest', async ({ extension, page }) => { const backgroundPage = await extension.backgroundPage(); await backgroundPage.addInitScript(() => { const mockData = { data: 'storedData' }; chrome.storage.sync.get = async (keys) => { if (keys === 'data') return mockData; return {}; }; }); await page.goto('https://www.myWebsite.com/'); const result = page.locator("#data"); await expect(result).toContainText('storedData'); });
关键注意事项
- 确保mock的
get函数完全对齐原生API的参数规则:支持字符串、数组、对象作为keys,同时兼容回调和Promise两种调用方式,否则业务代码可能因参数不匹配无法获取数据。 - 明确代码运行的上下文:页面上下文、内容脚本上下文、后台脚本上下文相互隔离,mock必须注入到对应上下文才会生效。
- 确认扩展已正确加载:使用Playwright Web扩展夹具时,需保证启动上下文时已正确加载扩展,避免因
chrome对象不存在导致的异常。
内容的提问来源于stack exchange,提问作者XenonOverflow
相关产品推荐
相关产品推荐

