cypress-io / cypress

Fast, easy and reliable testing for anything that runs in a browser.
https://cypress.io
MIT License
46.77k stars 3.17k forks source link

cy.session: Support IndexedDB #18350

Open nateroling opened 2 years ago

nateroling commented 2 years ago

What would you like?

The new cy.session API currently doesn't do anything with indexeddb. Is that likely to be supported in the future?

Why is this needed?

I'm testing an app that stores significants amounts of data in indexeddb to support offline use.

In the app, when a users choses to "Go Offline," data is downloaded from the server to indexeddb. I would like to cache/restore that data with cy.session so that each tests for offline functionality doesn't have to re-download that data.

Other

No response

dannyskoog commented 2 years ago

+1 👍

werlein commented 2 years ago

+1 👍

jaytavares commented 2 years ago

Any word on this? Firebase uses indexedDB for session storage. So cy.session() doesn't work to cache a logged in session in a Firebase app.

liquid1982 commented 1 year ago

+1

Has anyone tried manually saving and restoring IndexedDB using localforage or similar? I also am having challenge because of Firebase.

Would it be possible to coordinate efforts and put together a workaround? I'd love to help.

tianhuil commented 1 year ago

Facing a similar issue here and would love to work on a solution and publish it back here. I haven't been able to figure out how session actually stores data between sessions. Does anyone have pointers?

nicolassanmar commented 1 year ago

I found a workaround to circumvent this: You can store the contents of the IndexedDB in localstorage in the setup() function, and then restore them on the validate() function. The exportIDB and importIDB functions use the utilities provided by this gist: https://gist.github.com/loilo/ed43739361ec718129a15ae5d531095b

Cypress.Commands.add(
  'exportIDB',
  (dbName) =>
    new Cypress.Promise(async (resolve) => {
      indexedDB.open(dbName).onsuccess = async (event) => {
        const db = (event.target as IDBOpenDBRequest).result
        const json = await exportToJson(db)
        console.log(json)
        localStorage.setItem(dbName, json)
        resolve(json)
      }
    })
)

Cypress.Commands.add(
  'importIDB',
  (dbName) =>
    new Cypress.Promise(async (resolve) => {
      const json = localStorage.getItem(dbName)
      console.log(json)
      if (!json) {
        resolve()
        return
      }
      indexedDB.open(dbName).onsuccess = async (event) => {
        const db = (event.target as IDBOpenDBRequest).result
        await clearDatabase(db)
        await importFromJson(db, json.toString())
        resolve()
      }
    })
)

Cypress.Commands.add('fn', () => {
  cy.session(
    () => {
      /*regular session setup */

      // export the data to localStorage, as session does not persist the IndexedDB
      cy.exportIDB()
    },
    {
      validate: () => {
        // import the data from localstorage to the indexedDB
        cy.importIDB()

        /* validate extra stuff */
      },
      // if you want this session to be cached only for a single file, remove the following option
      cacheAcrossSpecs: true,
    }
  )
})
liquid1982 commented 1 year ago

This is brilliant! Will give it a try. Thanks for sharing!

cypress-app-bot commented 1 year ago

This issue has not had any activity in 180 days. Cypress evolves quickly and the reported behavior should be tested on the latest version of Cypress to verify the behavior is still occurring. It will be closed in 14 days if no updates are provided.

segevfiner commented 1 year ago

Still needed

asier-perez commented 1 year ago

Hi, I am in a JavaScript project and the workaround proposed by @nicolassanmar doesn't work for me. When importDB is executed, event is always empty. For this project I have replaced const db = (event.target as IDBOpenDBRequest).result with const db = event.target.result, because otherwise it was giving me a compilation error. Is this change correct for JavaScript? Or does anybody know why event could be empty?

Dale-777 commented 8 months ago

@jennifer-shehane @mike-plummer could you please see if this can be added to the roadmap?

It seems that cy.session() does not handle IndexedDB, this is used by Firebase for session storage. Therefore cy.session() does not work to cache a logged-in session in a Firebase app.

I know there's a viable workaround, but it seems to me to be a small fix for a big win...

https://github.com/cypress-io/cypress/issues/27155#issuecomment-1611419135

tinu-doit-intl commented 8 months ago

Same issue here as well. Good to have a fix than a work around.

jaytavares commented 8 months ago

Same issue. The workaround didn't work for me. 🤷‍♂️ The application stayed logged out and the session would need to be recreated every time.