-
Notifications
You must be signed in to change notification settings - Fork 3.2k
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Cypress should clear indexeddb state between test runs #1208
Comments
Big thanks for making a nice demo. Cleaning everything between the tests is important, and we will invest more time, track #686 for the overall theme. For now, can you clear the DB in |
hi @bahmutov yes we currently use the below workaround in our tests. had to strip out some of our project specific code from it but hopefully it works for other people facing this issue. ps: thanks for cypress, it's a breath of fresh air from the days of selenium testing. // ./cypress/integration/common/index.js
// loads an external script
export function loadScript(src) {
return new Promise((resolve, reject) => {
const script = document.createElement('script');
script.onload = () => resolve();
script.onerror = err => reject(err);
script.src = src;
document.head.appendChild(script);
});
}
// clears IndexedDb storage
export function clearIndexedDb() {
return new Promise(resolve => {
// we clear the indexeddb state ourselves for now
// @see https://github.com/cypress-io/cypress/issues/1208
it(`load localforage script`, () =>
loadScript('https://unpkg.com/localforage@1.5.5/dist/localforage.js').then(() => {
localforage.config({
driver: [localforage.INDEXEDDB],
name: 'MyDb',
storeName: 'my_store',
version: '1.0',
});
}));
it(`clear INDEXEDDB storage`, () => {
cy.visit('/');
localforage.clear();
});
});
} // ./cypress/integration/mytest.js
import { clearIndexedDb } from './common';
describe('Create Group Chat', () => {
before(() => {
clearIndexedDb();
});
it('does something on a clean indexeddb state', () => {
//
});
}); |
@andreiashu why couldn't you clear this yourself as per this comment: #1383 (comment) |
That's what we actually do in our tests and it works alright. |
Firebase is now storing their auth data in indexedDB, so this will likely cause some people a few headaches. Clearing in |
found this at https://gist.github.com/innerdaze/2fe0c6a23ed4aee0f94a0302f9de7e6c
It does the job too |
Thanks @abumalick! As we use redux-persist with a localForage adapter, we need to clear this between tests. I used this code inside Cypress.on("window:before:load", win => {
win.indexedDB.deleteDatabase("localforage");
}); |
This also works great for clearing the local Firebase storage ( |
I believe I was also able to find a workaround for this issue by just disabling local storage completely. This may not be a viable solution for everyone, though. This config was added to the module.exports = (on, config) => {
// `on` is used to hook into various events Cypress emits
// `config` is the resolved Cypress config
on('before:browser:launch', (browser = {}, args) => {
if(browser.name === 'chrome') {
args.push('--disable-local-storage')
//
return args
}
})
} |
If anyone has tried the above solutions and it's still not working this is what I came up with after a lot of failed attempts. This implementation so far is the most consistent with CI. //commands.js
let firebase = require('firebase');
Cypress.Commands.add("clearAuth", () => {
return new Cypress.Promise(async (resolve) => {
const config = {
apiKey: Cypress.env('FIREBASE_API_KEY'),
authDomain: Cypress.env('FIREBASE_AUTH_DOMAIN'),
databaseURL: Cypress.env('FIREBASE_DATABASE_URL'),
projectId: Cypress.env('FIREBASE_PROJECT_ID'),
storageBucket: Cypress.env('FIREBASE_STORAGE_BUCKET'),
messagingSenderId: Cypress.env('FIREBASE_MESSAGING_SENDER_ID')
};
await firebase.auth().signOut();
await firebase.app().delete();
firebase.initializeApp(config);
resolve();
});
}); //test.js
describe('Login', function() {
before(() => {
cy.visit('/login', {timeout: 100000});
});
beforeEach(() => {
cy.clearAuth();
cy.reload(true);
});
it(`should login`, function() {
//login code here
}); |
Re: firebase, |
Going to make one more suggestion on here if you do not have access to the firebase web api locally //commands.js
Cypress.Commands.add(
'clearFirebaseAuth',
() =>
new Cypress.Promise(async resolve => {
const req = indexedDB.deleteDatabase('firebaseLocalStorageDb');
req.onsuccess = function() {
resolve();
};
})
) //test.spec.js
beforeEach(() => {
cy.clearFirebaseAuth();
}); The promise ensures the delete happens before the cypress chain continues |
hehe good to see firebase mentioned above, as thats why im here. |
Turns out Cypress.on("window:before:load", win => {
win.indexedDB.deleteDatabase("firebaseLocalStorageDb");
}) is no good if I want to visit another page in the same test, but I like it because I don't have to use beforeEach(() => {
cy.clearFirebaseAuth();
}); everywhere |
I'm currently using Firebase Auth (which, as pointed out above, now uses indexedDB to store its auth data), but I didn't want to depend on their implementation (I don't want my tests to break if Firebase decides to change their indexedDB name), so I went for a more generic solution that clears all the available indexedDB databases:
So now in my tests I just do:
|
Have you tried the new auth emulator? |
For anyone else who is running Jest tests in Cypress (i.e., so that your unit tests can run against a real IndexedDB implementation), I found that the main issue with deleting the database before each test was making sure the database connection is closed first. const TODOS_DB = 'todos-db';
const TODOS_STORE = 'todos-store';
let dbPromise: Promise<IDBDatabase> | null = null;
context('IndexedDB test', () => {
beforeEach(async () => {
if (dbPromise) {
// indexedDB.deleteDatabase() will be blocked unless we ensure the db conn is closed first.
(await dbPromise).close(); // 👈👈👈
dbPromise = null;
}
return new Promise((resolve, reject) => {
const deleteDbReq = indexedDB.deleteDatabase(TODOS_DB);
deleteDbReq.onsuccess = () => resolve();
deleteDbReq.onerror = reject;
deleteDbReq.onblocked = reject;
});
});
it(`onupgradeneeded() creates expected object stores.`, async () => {
const db = await getDb();
expect(db.name).to.equal(TODOS_DB);
expect(db.objectStoreNames.contains(TODOS_STORE)).equals(true);
});
it(`test something else...`, async () => {
const db = await getDb();
const txReq = db.transaction(TODOS_STORE, 'readonly');
const store = txReq.objectStore(TODOS_STORE);
const addReq = store.add({ id: 123, name: 'Buy more cookies'});
// ...
});
});
async function getDb(): Promise<IDBDatabase> {
if (!dbPromise) {
dbPromise = new Promise((resolve, reject) => {
const openreq = indexedDB.open(TODOS_DB, 1);
openreq.onblocked = reject;
openreq.onerror = reject;
openreq.onsuccess = () => resolve(openreq.result);
openreq.onupgradeneeded = (event) => {
const db = openreq.result;
db.createObjectStore(TODOS_STORE, { keyPath: 'id' });
};
});
}
return dbPromise;
} |
This solved most of my problems too. There is a discussion here about support in Firefox & Safari |
This would fit well with the new This means that if |
I second what @EtienneBruines is saying above, the application that I'm testing uses an IndexedDB to store the access token. However since |
New to Cypress and was really surprised this wasn't a standard part of the framework. Seems like a pretty obvious win to implement. This is sort of a deal breaker and we can't get this to work as a command. |
So, the current status of this issue is that we're waiting for a way to clear indexedDB (without knowing the db name) on Firefox? In the meantime, I don't see why we can't already implement this already while waiting for Firefox to catch up. Simply: if (window.indexedDB.databases) {
const dbs = await window.indexedDB.databases();
dbs.forEach(db => { window.indexedDB.deleteDatabase(db.name) });
} Source: https://gist.github.com/rmehner/b9a41d9f659c9b1c3340 |
Related: cypress-io#1208
Current behavior:
Cypress does not clean the indexeddb state between test runs
Desired behavior:
Cypress should clean the indexeddb state between tests
How to reproduce:
I've created a spec that reproduces this behaviour in a fork of cypress-test-tiny. Just clone, run the spec here and open the console: https://github.com/andreiashu/cypress-test-tiny
The text was updated successfully, but these errors were encountered: