Cypress测试登录后打开IndexedDB连接报错,该如何解决?
问题原因
- 上下文错误:你代码中直接调用的
window是Cypress测试脚本运行的Node环境全局对象,并非被测应用所在的浏览器窗口对象,操作该对象下的IndexedDB不会对应用生效。 - 执行时机错误:IndexedDB与源地址绑定,你在
cy.visit执行前操作IndexedDB时,还未加载http://localhost:3000的页面上下文,操作的IndexedDB不属于目标源,应用无法读取。 - 异步未等待:IndexedDB打开、读写以及localforage的操作都是异步逻辑,你未等待操作完成就触发页面加载,会导致首页读取数据时写入还未完成。
解决方案
推荐使用cy.visit的onBeforeLoad回调,该回调会在页面资源加载前触发,此时已经可以拿到目标源的浏览器window对象,且在回调中返回Promise可以让Cypress等待异步操作完成后再继续加载页面,完美适配你的需求。
基于localforage的实现代码
beforeEach(() => { // 先完成登录请求 cy.request({ method: 'POST', url: 'http://localhost:3000/api/auth/login', body: { email: "email", password: "password" } }).then(() => { cy.visit('http://localhost:3000/', { // 页面加载前的回调,此处拿到的是被测应用的浏览器window onBeforeLoad(window) { // 若你的应用全局挂载了localforage直接取用即可,未挂载可手动注入 const localforage = window.localforage; localforage.config({ driver: [localforage.INDEXEDDB], name: 'testDB', storeName: 'testDB', version: '1.0', }); // 返回Promise让Cypress等待所有操作完成再加载页面 return new Cypress.Promise((resolve) => { localforage.clear().then(() => { localforage.setItem('jobs', [{name: 'fdf'}]).then(() => resolve()); }); }); } }) }) })
基于原生IndexedDB的实现代码
// 封装成自定义Cypress命令复用逻辑 Cypress.Commands.add('initTestDB', (window) => { return new Cypress.Promise((resolve, reject) => { const request = window.indexedDB.open("testDB", 1); request.onerror = (event) => reject(event); request.onsuccess = (event) => { const db = event.target.result; const transaction = db.transaction("jobs", "readwrite"); const store = transaction.objectStore("jobs"); store.put({name: 'fsdf'}); transaction.oncomplete = () => { db.close(); resolve(); }; transaction.onerror = (err) => reject(err); }; request.onupgradeneeded = (event) => { const db = event.target.result; // 避免重复创建存储报错 if (!db.objectStoreNames.contains('jobs')) { const objectStore = db.createObjectStore("jobs", { keyPath: "name" }); objectStore.createIndex("name", "name", { unique: false }); } }; }) }) describe('The Login Page', () => { beforeEach(() => { cy.request({ method: 'POST', url: 'http://localhost:3000/api/auth/login', body: { email: "gfdgfdg", password: "gdfgfdg" } }).then(() => { cy.visit('http://localhost:3000/', { onBeforeLoad(window) { // 等待IndexedDB初始化完成再加载页面 return cy.initTestDB(window); } }) }) }) })
内容的提问来源于stack exchange,提问作者DevOverflow
相关产品推荐
相关产品推荐

