Playwright e2e testing issues with log in

I’m attempting to write e2e tests for my app using Playwright but am unable to get past the login screen with my tests as the Continue with email button remains disabled viewing a screenshot capture.

If I’m accessing the login page manually, I notice that the button is also disabled briefly before I start to interact with the page so I suspect there’s some anti-bot protection at play.

To fake a real user I’ve tried things like:

await page.mouse.move(100, 100);
await page.waitForTimeout(3000);

but no joy.

I note that the Shopify documentation explicitly mentions Playwright as a way for store owners to test their stores so I would have though e2e testing like this should be possible.

Any ideas how I can get my Playwright tests to work?

Here’s a screenshot capture showing the issue:

I experienced the same issue. Unfortunately not a lot of resources are available for this. Here’s what’s my temporary solution:
Create a spec file for login:

import { test, expect } from '@playwright/test';

test('test', async ({ page, context }) => {
  await page.goto('https://admin.shopify.com/store/your-store/apps/your-app');
  await page.locator('body').click();
  await page.getByLabel('Email').fill('your@email.com');
  await page.getByRole('button', { name: 'Continue with email' }).click();
  await page.getByLabel('Password', { exact: true }).fill('your-password');
  await page.getByRole('button', { name: 'Log in' }).click();
  await page.getByRole('link', { name: 'Use the authentication app' }).click();
  await page.getByPlaceholder('000000').click();
  await page.getByPlaceholder('000000').fill('your-authenticator-token-number');
  await page.getByRole('button', { name: 'Log in' }).click();
  await page.context().storageState({ path: 'cookies.json' });
});

Fill in your details (the authenticator token needs to be up to date) and run it to generate a cookies.json

Now, in your other test files import the cookie file:

import cookies from '../cookies.json';

and the first thing within your tests, load the cookies:

  await page.context().addCookies(cookies.cookies);

You should now be able to await page.goto() both to the storefront and the admin pages.

1 Like

Thank you for sharing that, it’s very much appreciated!

It seem the await page.locator('body').click(); part was the immediate missing part of my puzzle, though I am still hitting other issues getting through the process.

Evan though I don’t have a passkey setup for the e2e account I get the following error message showing on screenshots:

We’ve encountered an error accessing your passkey. Please try again or log in using a different method.

Update:

Using this blog post as a guide:

I managed to get further and though I was making progress, using the input locator methods this example used. The for some reason this technique stop working and I started getting the passkey message again. I feel like there’s probably some active bot protection at play making the process of e2e testing very flakey?

Have you tried generating the script by using interactive mode? That’s how I created my in the first place, and then I added the cookies stuff.
npx playwright test --ui

This way you’ll actually see what’s on screen and click where you need to click to go through the login process.
The debug mode might actually help too with your current script, so you can see what’s happening.

Yes, I did try that process which seemed quite promising but subsequent runs of the tests resulted in the issues reported above. Quite a good tool! Though it did seem to struggle with selecting anything in the embedded app iframe.

It seems that I have much more success running the tests when I allow them to pop open a browser so I can watch them happen, rather than going headless.

It seems the login process / environment changes slightly when the tests are running in headless mode with the chromium browser.

I had a quick try with the webkit browser but kept hitting Cloudflare I’m-not-a-robot challenges.

Now on to the next bit of run… figuring out the best way to deal with iframe for the embedded app.