Skip to content

Commit

Permalink
feat(examples): add example for reusing login with playwright (#2398)
Browse files Browse the repository at this point in the history
  • Loading branch information
bernardobridge committed Jan 12, 2024
1 parent db60c0d commit 65f36d3
Show file tree
Hide file tree
Showing 4 changed files with 132 additions and 0 deletions.
50 changes: 50 additions & 0 deletions examples/browser-playwright-reuse-authentication/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,50 @@
# Reuse Authentication in Playwright tests

Playwright allows you to use `sessionStorage` to reuse authentication in your tests. This can be especially useful in Load Testing, where you might be interested in testing other parts of the application at scale, without having to exercise the login backend (which is sometimes third-party) with every VU.

This example shows you how to do that.

## Pre-requisites

Before running the example, install Artillery:

```sh
npm install artillery
```

## Example

The example leverages [`storageState`] similarly to [Playwright documentation](https://playwright.dev/docs/auth#basic-shared-account-in-all-tests). It's simple to set this up with Artillery, but there are some small differences:

* You set the `storageState` path in [`config.engines.playwright.contextOptions`](https://www.artillery.io/docs/reference/engines/playwright#configuration), instead of a Playwright config file.
* A [before hook](https://www.artillery.io/docs/reference/test-script#before-and-after-sections) will run the setup function (`loginUserAndSaveStorage` in this example), rather than referencing it as a Playwright project.
* You will need to create the storageState JSON (`storage.json` in this example) file first as an empty object (`{}`), in the same directory where you run the test from. This is because the first time Artillery runs, it will run the `before` hook, and the file referenced in `config` won't be available.

That's it!

To run the fully configured example, run:

```sh
npx artillery run scenario.yml
```

*Note: this example runs with headless disabled, so you can easily observe the login being reused.*

## Running the example in Fargate

Want to run 1,000 browsers at the same time? 10,000? more? Run your load tests on AWS Fargate with [built-in support in Artillery](https://www.artillery.io/docs/load-testing-at-scale/aws-fargate). Just make sure to tell Artillery to include the `storage.json` file. For example:

```yaml
config:
...
includeFiles:
- ./storage.json
```
This ensures the file is bundled to Fargate workers correctly. You will also need to make sure the test is running using headless mode. Then, run the test:
```sh
npx artillery run:fargate scenario.yml --count 2
```

*Note: `before` hooks run once per Fargate worker, so the authentication step will run as many times as the `--count` you set.*
55 changes: 55 additions & 0 deletions examples/browser-playwright-reuse-authentication/flow.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,55 @@
const { expect } = require('@playwright/test');
const fs = require('fs');

async function loginUserAndSaveStorage(page, context) {
const storageState = JSON.parse(fs.readFileSync('./storage.json', 'utf8'));
if (Object.keys(storageState).length > 0) {
console.log('Already logged in. Skipping login.');
return;
}

//1. navigate to page and assert that we are not logged in
await page.goto(context.vars.target);
await expect(page.getByText('Authentication example')).toBeVisible();

//2. click login button and make sure we are redirected to `/login`
await page.getByRole('link', { name: 'Login' }).click();
await page.waitForURL('**/login');

//3. fill in your github username and click login button
await page.getByLabel('username').fill(context.vars.githubUsername);
await page.getByRole('button', { name: 'Login' }).click();

//4. ensure we are redirected to profile page and logged in
await page.waitForURL('**/profile-sg');
await expect(page.getByText('Your GitHub profile')).toBeVisible();

//5. save iron session cookie to storage.json
await page.context().storageState({ path: './storage.json' });
}

async function goToProfilePageAndLogout(page, context, events, test) {
const { step } = test;
const profileHeaderText = 'Profile (Static Generation, recommended)';

await step('go_to_page', async () => {
await page.goto(context.vars.target);
await expect(page.getByText(profileHeaderText)).toBeVisible();
});

await step('go_to_profile_page', async () => {
await page.getByRole('link', { name: profileHeaderText }).click();
await page.waitForURL('**/profile-sg');
await expect(page.getByText('Your Github Profile')).toBeVisible();
});

await step('logout', async () => {
await page.getByRole('link', { name: 'Logout' }).click();
await page.waitForURL('**/login');
});
}

module.exports = {
loginUserAndSaveStorage,
goToProfilePageAndLogout
};
26 changes: 26 additions & 0 deletions examples/browser-playwright-reuse-authentication/scenario.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,26 @@
config:
target: https://iron-session-example.vercel.app/
phases:
- arrivalRate: 1
duration: 10
engines:
playwright:
launchOptions:
headless: false
contextOptions:
storageState: './storage.json'
processor: ./flow.js
variables:
githubUsername: "bernardobridge"
# NOTE: add this if you want to run the test in fargate. make sure to remove headless:false too
# includeFiles:
# - ./storage.json

before:
engine: playwright
flowFunction: loginUserAndSaveStorage

scenarios:
- name: go_to_profile_page_and_logout
engine: playwright
flowFunction: goToProfilePageAndLogout
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
{}

0 comments on commit 65f36d3

Please sign in to comment.