I am exploring Cypress for e2e testing, looks like great software. The problem is Authentication, the Cypress documentation explains why using the UI is very bad here.
So I tried looking at the network tap of my application, to see if I could create a POST request to the firebase API, and authenticate without using the GUI. But I can see that there at least 2 request fired, and token saved to application storage.
So what approach should I use?
- Authenticate with the UI of my application, and instruct Cybress not to touch the local storage
- Keep experimenting with a way of sending the correct POST requests, and save the values to local storage.
- Make Cypress run custom JS code, and then use the Firebase SDK to login.
I am really looking for some advice here :)
This is certainly a hack but to get around the login part for the app I am working on I use the
beforeEach
hook to login to the application.Which is derived from my helper functions.
What I would like to know is how the information coming back from
firebase
ultimately gets saved tolocalStorage
. I don't really have an answer to this but it works. Also, the app uses.signInWithPopup(new firebase.auth.GoogleAuthProvider())
whereas above it signs in with email and password. So I am kind of shortcutting the signin process only becausecypress
has the CORS limitation.Ok after much trial and error, I tried solution path 2 and it worked.
So my auth flow looks like this:
Send POST request (using cybress.request) to
https://www.googleapis.com/identitytoolkit/v3/relyingparty/verifyPassword
, and parse the response. Create an object:response1 = response.body
Send POST request (using cybress.request) to
https://www.googleapis.com/identitytoolkit/v3/relyingparty/getAccountInfo
, use the idToken from the prev request. Create an object:user = response2.body.users[0];
Combine the response in an object, with the following properties:
Then in cybress, I simply save this object in local storag, in the before hook:
localStorage.setItem(
firebase:authUser:${apiKey}:[DEFAULT], authObject);
Maybe not perfect, but it solves the problem. Let me know if you interested in the code, and if you have any knowledge about how to build the "authObject", or solve this problem in another way.
When doing this myself I made custom commands (like
cy.login
for auth thency.callRtdb
andcy.callFirestore
for verifying data). After getting tired of repeating the logic it took to build them, I wrapped it up into a library called cypress-firebase. It includes custom commands and a cli to generate a custom auth token.Setup mostly just consists of adding the custom commands in
cypress/support/commands.js
:And adding the plugin to
cypress/plugins/index.js
:But there full details on setup are available in the setup docs.
Disclosure, I am the author of cypress-firebase, which is the whole answer.
I took the approach of using automated UI to obtain the contents of localStorage used by Firebase JS SDK. I also wanted to do this only once per whole Cypress run so I did it before the Cypress start.
Helper script which obtains contents of localStorage:
Since there were problem with sending JSON as environment variables to Cypress I use tmp file to pass the data between the script and the Cypress process.
In Cypress I read it from the file system and set it to the localStorage