Testing Auth in Playwright
Fri Mar 29 2024 00:00:00 GMT+0000 (Coordinated Universal Time)
Handling Authentication in Automated Tests
When procrastinating trying to hone my playwright skills, I’ll often go to the help-playwright channel on the Playwright Discord and try to help people with their questions. I find that it’s a good way to learn and to give back to the community. Today, one of the threads was about how to optimize authentication across tests. Variants of this question come up often, so I thought I’d write a bit about it and share my approaches and thoughts.
OP’s Question
Is there a way to access a webapp without typing in the username and password?
I know you can access some webapps by adding the username and password directly into the url, e.g. https://example.com/ but when I try it like that it simply takes me to the login page, where the username and password has to be typed in.
I also tried to cookies etc. but I didn’t manage to figure out how make that work.
I am fairly new to this kind of testing.
How do you guys access a webapp with username and password? (without typing in the credentials)
My Answer
It really depends on how your web application handles auth and sessions. In rough order of complexity, optimizing auth across tests can follow this order (IMO):
GUI > API
https://playwright.dev/docs/auth#authenticate-with-api-request
Call the auth API everywhere you would login with the GUI. This is usually the lowest hanging fruit, fairly easy to refactor, and can even be done incrementally. I’ll usually make a small auth module for a project that goes something like:
/**
* Authorizer
* @param page
* @example
* const page = new Page();
* const authorizer = authorizer(page);
* authorizer.loginWithGui(); // or...
* authorizer.loginViaApi();
*/
const authorizer = (page: Page) => {
const loginWithGui = async () => {
// login with GUI
};
const loginViaApi = async () => {
// login via API
};
return {
loginWithGui, // you will probably keep this to test that your login form works for users
loginViaApi, // this will ultimately replace the gui login and be used everywhere else.
};
};
You might be able to watch your devtools on your browser as you manually log in and identify the API call that does the auth to build the API function logic.
Cache auth
https://playwright.dev/docs/auth#session-storage This is the one the docs mostly focus on. This will be a bit faster per test than step 1, since you won’t need to do the API call for each test.
HOWEVER, if you DO make the auth call with every test, it is very unlikely that your cached session data will become stale, and that IS a potential risk here depending on your SUT timeouts and playwright test run duration.
Don’t…
This may seem facetious, and it’s more of a soapbox than an answer, but I’ll add it anyway.
This difficulty and others like it are good motivators of “shift-left” testing methodology and the “shape” of your test distribution. When looking at the distribution of your tests, you want tens of e2e UI tests, hundreds of integration/service tests, and thousands of unit tests in your SUT.
Stateful UI tests are expensive and complex. If you find yourself trying to implement auth boilerplate for dozens of tests with user state (or worse, multiple users), there’s a good possibility your pyramid is inverted. If you don’t have it already, try to get buy-in from your other QA engineers and the dev teams to put lower level coverage in place so you don’t HAVE to test EVERYTHING in the GUI.
While rare, it might also be the case that the playwright coverage you’re trying to add is ALREADY covered by unit and integ tests, and you/your team just didn’t know. Start the conversation with the devs as
“Hey, end-to-end tests with user auth is slow and expensive.
Do we already have enough coverage over [Feature x,y,z] in our lower level tests?
Might it be better to implement that coverage instead, and then only do user-state-less component testing of the GUI of [X,Y Z]? ”