DEV Community

A better global setup in Playwright reusing login with project dependencies

Debbie O'Brien on March 15, 2023

Global setup is being used by many teams and companies to login to an application and then use this setup for tests that need to be in an authentic...
Collapse
 
r0nunes profile image
Renato O. Nunes

Hey @debs_obrien,

I tried to create a new project, using a site conduit to test here. But, for me it doesn't work.

Idk why, but the storage file is not created before the test, and when I run the command npx playwright test --headed --project=chromium the test fail.

I tried to follow the official documentation but got the same results. =(

Image description

Image description

Image description

Can you help me with this "feature"? I'm having a problem with some tests and I'm trying to find an alternative to login.

Collapse
 
r0nunes profile image
Renato O. Nunes

PS: If I put on the storage path into the test, the storage file is created.

e.g: await page.context().storageState({ path: './auth/user.json' });

Collapse
 
debs_obrien profile image
Debbie O'Brien

do you have a playwright-reuse-auth folder? change it to playwright and see if that works. if not can you add this a post in our discord server as much easier to get more eyes on it there for better help: aka.ms/playwright/discord

Collapse
 
victorneves profile image
Victor Neves

Hi @debs_obrien
We are starting implementing e2e tests on our project using Playwright and we have used this approach as it's also suggested on the documentation.
We only have one QA that doesn't have so much experience with Playwright (he has mostly worked with cypress and other existing projects that contain e2e tests are also done with cypress)
So after implementing the first basic suite of tests he got blocked because he wasn't able to make the group of test that checks if the user is able to access protected routes pass.
So I decided to do some tests in order to try to understand what could be the problem and I was able to make them pass but I'm not sure if what I did is correct.
Looking to Playwright's documentation fr me it's not totally clear the order where we should add the await page.context().storageState({ path: STORAGE_STATE }); and if when executing test that are defined on a external file that requires to access the data that saved on the JSON we always need to call it not.
Probably it's not too clear what I'm saying, so I'll gonna add some of the code to see if what I did, is correct or not

setup('authenticate', async ({ page }) => {
    await page.goto(urls.login);
    await page.locator(uiIdsCookies[envConfig.brand].cookieLayerAcceptBtn).click();
    // wait for cookie layer to disappear
    await page.waitForTimeout(customTimeout);

    await page.locator(uiIds[brand].loginButton).click();
    // wait for login form to appear
    await page.waitForTimeout(customTimeout);

    await page.locator(uiIds[brand].inputEmail).type(envConfig.username);
    await page.locator(uiIds[brand].inputPassword).type(envConfig.password);

    await page.locator(uiIds[brand].sendFormButton).click();
    // reads cookies from json file to be used to test pages that require authentication
    await page.context().storageState({ path: STORAGE_STATE });
    // the browser is closed

    // new browser is open
    await page.waitForURL(envConfig.devUrl); <-- this is a protected route that requires to be authenticated to access it
    await page.context().storageState({ path: STORAGE_STATE });
});
Enter fullscreen mode Exit fullscreen mode

My question is about the last storageState
Do we need to call it on every test that is executed on a new window that requires the user to be authenticated? If yes, it's not to clear for me why is called after and not before accessing the page. Is it because after the page is open, then it will make the browser read the cookies and so from the file? I would expect that we would define from where it would read the info, from he browser as it's the default behaviour or from the JSON

Hopefully with code I was able to be clear to my question.
Thanks in advance

Collapse
 
artem_qa profile image
AnewTranduil

There are line in the dependent project config which set the json. You don't need to call await page.context().storageState({ path: STORAGE_STATE }); again.

projects: [
    {
      name: 'setup',
      testMatch: '**/*.setup.ts',
    },
    {
      name: 'e2e tests logged in',
      dependencies: ['setup'],
      use: {
        storageState: STORAGE_STATE,
        ^^^^^^^^^^^^^^^^^^^^^^^
      },
    },
  ],
Enter fullscreen mode Exit fullscreen mode
Collapse
 
saurav_18_ profile image
Saurav Likhar

Hey @debs_obrien ,
I have 2 case scenarios.
First case - I have 2 type of users whose session data I want to use for different tests. Suppose I have 2 test suites A.spec.ts and B.spec.ts. First test file will use the login credentials of user1 and second test file will use the login credentials of user2. How can I store the 2 users login data using this new setup file?
In earlier version of globalSetup.ts file, I used to open two different contexts of browser and then two different pages to login the two types of users and then save the data of respective login in different state.json files.

Second case - In particular test file, I want to use the logged in data for some tests and not for all the tests. How can I do that in new version of project configurations? Earlier I used to write const context = await browser.newContext({storageState: undefined}); inside the tests in which I do not want the logged in state data.

Collapse
 
debs_obrien profile image
Debbie O'Brien

hi, can you post this to the Q&A on our discord server. would be much easier to answer/track and get others to look at it too. thanks

Collapse
 
philipfong profile image
Phil

I've found that making use of storage state in combination with playwright fixtures to be much more useful than coupling storage state with global setup. I've documented my experience with it in case anyone is interested.

Collapse
 
kolianas profile image
Anastasiia Kolianovska

Sounds interesting, could you please share your experience in more detail?

Collapse
 
philipfong profile image
Phil

Sure I posted here about it.

Collapse
 
raducybersec profile image
raducybersec

Hey @debs_obrien ,
I am wondering if I can use playwright test code with azure AD MFA. I have tried using TOTP instead and otpauth to generate the code for authentication but I failed dramatically with {"ResultValue": "AuthenticationThrottled",
"Message": "Authentication is throttled throttle.sas.user.authmethod.extended for tenant: 5ec97021-b760-441e-a67c-c2479291ad5d, user: b1ae5226-6cc6-4f88-a1dd-abea51a4dda4, auth method: PhoneAppOTP. Authentication limit reached: [Duration:01:00:36][Identifier:<PII-REDACTED>][Level:100][Reason:RequestCount].",
"AuthMethodId": "PhoneAppOTP",
"ErrCode": 500121,
}
is there any way to save my authentication?
Thank you

Collapse
 
debs_obrien profile image
Debbie O'Brien

hi, i havent used Azure AD personally. If you post this question in our discord server someone should be able to help you out

Collapse
 
jackbob2020110 profile image
jackbob2020110

Hey @debs_obrien

I followed the your github sample code (github.com/debs-obrien/playwright-...) to create M365 OWA test. the strange thing here is that when i tried to run 'npx playwright test' for all test, except login ok, other test will trigger to locate elelement timeout. but when I run each them one by one, it works without any issue. i'm curious what i was missing.

Test timeout of 30000ms exceeded.
Error: locator.click: Target closed
=========================== logs ===========================

waiting for getByPlaceholder('Search')

12 |
13 | await page.waitForLoadState();

14 | await page.getByPlaceholder('Search').click();
| ^
15 |

16 | await page.waitForTimeout(2000);
17 |

at C:\Users\vagrant\code\learn-playwright\tests\page-searchmail.spec.ts:14:41
Enter fullscreen mode Exit fullscreen mode

here is what run page-searchmail.spec.ts only, it works with out any issue.

Image description

thanks.
_Jun

Collapse
 
alice3105 profile image
Alice Huynh

Hey @debs_obrien
I wonder if I have two projects as dependencies then would they run at the same time or would they run in the order that they are listed?

Image description

Collapse
 
anandtiwari1 profile image
Anand Tiwari

Hi @debs_obrien, I'm having a problem where we want the results of the tests to be posted to our management system, and since we are sharding our tests, we are running the setup tests on each m/c, resulting in multiple test sets ids. Is there any way we can create a test set once and pass it on to all tests running on different m/c?

Collapse
 
Sloan, the sloth mascot
Comment deleted
Collapse
 
debs_obrien profile image
Debbie O'Brien

Can you file an issue with your operating system and version number etc. here is link to my repo with it working incase it helps: github.com/debs-obrien/playwright-...

Collapse
 
bandito profile image

"This page is not available for Python."
Would be a good approach to release the same feature for all available language, all at once...

Collapse
 
debs_obrien profile image
Debbie O'Brien

Project dependencies only work in Node.js. You will have to submit a feature request for Python. I am not sure if this can work with Pythons test runner etc so I can't answer on when, how, if etc but please fill a request on GitHub so the team can look into it

Collapse
 
bandito profile image
Maxi Bandito

Thank you Debbie, anyways, similar solution is possible with combination of
@pytest.fixture
and
yield

Collapse
 
hameethaahamed profile image
hameethaahamed

Hi , how to do the same in javascript, my global authentication keeps failing