Разделы портала

Онлайн-тренинги

.
Простые рецепты аутентификации в Playwright: кулинарная книга тестировщика
24.02.2026 00:00

Автор: Cуатика Визань (Swathika Visagn)
Оригинал статьи
Перевод: Ольга Алифанова

Что общего у кулинарии и автоматизации тестирования?

Что общего у кулинарии и автоматизации тестирования, спросите вы? Можно провести красивые параллели между программированием и готовкой: автоматизаторы тестирования как шеф-повара, скрипты автоматизации как рецепты, фреймворки автоматизации как кастрюли и сковородки, а кулинарная книга — как эта статья! Эта статья посвящена всем тестировщикам, которые ищут новые рецепты аутентификации с использованием Playwright.

Статья предназначена для автоматизаторов тестирования, которые уже знакомы с Playwright или используют его в своей работе. Для демонстрации я буду использовать учебный магазин Book Cart, на который я наткнулась в статье Сары Дири на сайте Ministry of Testing.

Для этой «поваренной книги» я отобрала четыре рецепта аутентификации, варьирующиеся от базового до среднего уровня сложности. Эти рецепты используют сочетание методов аутентификации через UI и API, с объяснением реальных сценариев применения для каждого из них.

Предварительные требования: ингредиенты, общие для всех рецептов

  • Playwright должен быть установлен и запущен на вашей системе.
  • Необходимо знать основы TypeScript.
  • Необходимо быть знакомым с общими сценариями аутентификации как для API, так и для графических интерфейсов.
  • Необходимо знать информацию из разделов Playwright Installation и Playwright Authentication.

Что дадут эти рецепты вашему тестированию?

Независимо от того, какой инструмент автоматизации тестирования вы используете, хорошей практикой всегда будет повторное использование состояния входа для ваших тестов, если это возможно. Другими словами, каждый раз, когда вы запускаете тест для конкретного пользователя, вы повторно используете его состояние входа. Это похоже на покупку годовой подписки на Netflix один раз вместо того, чтобы покупать месячную подписку 12 раз в году.

Все методы аутентификации Playwright, описанные ниже, позволяют залогиниться один раз и эффективно переприменять это состояние входа во всех тестах. Это сэкономит время выполнения, уменьшит нестабильность и избавит от ненужного повторения: работайте умнее, а не тяжелее.

Рецепт 1: Однократная аутентификация через UI и повторное использование состояния логина

Если взглянуть на сайт Book Cart, то у него хороший фронтэнд, который мы можем использовать для значимых тестов - входа в систему, добавления товаров в корзину, добавления в избранное и оформления заказов. Также он оснащён документацией Swagger, которую можно применять для API-тестов.

Вы МОЖЕТЕ использовать этот рецепт, когда все ваши тесты могут выполняться параллельно с использованием одной и той же учётной записи без влияния друг на друга. Например, его можно применить, добавляя книги в избранное пользователя. В таком случае имеет смысл войти один раз и повторно использовать состояние входа во всех тестах.

Существуют ситуации, когда этот рецепт использовать нельзя. Например, представьте, что на нашем учебном сайте Bookcart у вас есть тест, проверяющий страницу истории заказов, и другой тест, который проверяет элементы страницы, когда список заказов пуст (см. скриншоты ниже). В таких случаях необходимо использовать разные учётные записи для тестов, а это значит, что рецепт здесь НЕ ПОДХОДИТ. Однако для этого случая вы можете использовать Рецепт 2.


Шаг 1: Создайте файл setup.spec

Создайте файл tests/setup.spec.ts, который будет содержать шаги входа в систему и сохранять состояние хранилища пользователя по указанному пути.

Убедитесь, что вы добавили auth.json в .gitignore, чтобы не загружать этот файл в репозиторий.

import { test as setup, expect } from "@playwright/test";
 
setup("authenticate", async ({ page }) => {
await page.goto("https://bookcart.azurewebsites.net/");
await page.getByRole("button", { name: " Login " }).click();
await page.getByLabel("Username").fill("username");
await page.getByLabel("Password").fill("password");
await page
.locator("mat-card-actions")
.getByRole("button", { name: "Login" })
.click();
// Ждём, пока страница получит cookies.
// Иногда поток входа устанавливает cookies в процессе нескольких перенаправлений.
// Ждём окончательный URL, чтобы убедиться, что cookies действительно установлены.
await page.waitForURL("https://bookcart.azurewebsites.net/");
// Конец шагов аутентификации.
await page.context().storageState({ path: "playwright/.auth.json" });
});

Шаг 2: Добавьте setup как проект

В playwright.config.ts добавьте наш setup как проект и сделайте его зависимостью для всех проектов. Файл setup.ts будет выполняться перед запуском любых тестов.

import { defineConfig, devices } from "@playwright/test";
 
export default defineConfig({
testDir: "./tests",
projects: [
// Проект Setup
{ name: "setup", testMatch: /.*\.setup\.ts/ },
 
{
name: "chromium",
use: {
...devices["Desktop Chrome"],
// Используем подготовленное состояние аутентификации.
storageState: "./playwright/.auth.json",
},
dependencies: ["setup"],
},
],
});

Результат рецепта 1

Playwright сначала выполнит файл setup.ts перед любыми тестами и зафиксирует состояние хранения (storage state). Любые тесты, выполняющиеся после этого, будут использовать состояние хранения из файла auth.json.

Пример запуска 2 тестов с 1 воркером:
 
   ✓  1 [setup] > tests/auth.setup.ts:3:6 > authenticate (2.7s)
✓  2 [chromium] > tests/first_test.spec.ts:3:5 > first test (1.6s)
 
2 passed (5.0s)

Рецепт 2: Аутентификация через UI с разными аккаунтами и использование уникальных storage state для каждого параллельного воркера

В случаях, когда необходимо войти под двумя или более разными пользователями, на помощь приходит рецепт 2. Вы можете проверять такие сценарии, используя уникальный аккаунт пользователя для каждого параллельного воркера.

Ознакомьтесь с документацией Playwright, чтобы понять, как реализован этот рецепт. Я использовала этот шаблон для проведения своего эксперимента.

Шаг 1: Создайте файл фикстур

  • Создайте файл фикстур, который переопределяет фикстуру для storage state, что означает отсутствие необходимости объявлять какую-либо зависимость в конфиге, как это делалось в рецепте 1.
  • Объект test расширяет baseTest и добавляет storage state, уникальное для каждого параллельного воркера.
  • workerStorageState — это фикстура настройки, действующая для каждого параллельного воркера.
  • Storage states сохраняются в уникальных файлах auth0.json и auth1.json в папке playwright. Не забудьте добавить эти файлы в .gitignore.
  • Функция acquireAccount назначает учетные данные для входа из переменных окружения на основе ID воркеров.

Например, я выполнила вход как swathika и snithik, по одному разу на пользователя, используя файл фикстуры. Затем код сохраняет их storage states, которые можно использовать для всех воркеров. Таким образом, мы аутентифицируемся один раз на воркер, каждый с уникальным аккаунтом: воркер 1 как swathika, другой как snithik.

Ниже приведён пример файла фикстур:

import { test as baseTest, expect } from "@playwright/test";
export * from "@playwright/test";
import fs from "fs";
 
let account: { username: any; password: any };
// Определяем функцию для получения учетных данных аккаунта на основе ID
async function acquireAccount(id: number) {
// Для демонстрации определяем два аккаунта
if (id === 0) {
account = {
username: process.env.username0,
password: process.env.password0,
};
} else if (id === 1) {
account = {
username: process.env.username1,
password: process.env.password1,
};
}
return account;
}
export const test = baseTest.extend<{}, { workerStorageState: string }>({
// Используем одно и то же состояние хранения для всех тестов в этом воркере
storageState: ({ workerStorageState }, use) => use(workerStorageState),
// Аутентификация один раз на воркер с использованием фикстуры для воркера
workerStorageState: [
async ({ browser }, use) => {
// Используем parallelIndex как уникальный идентификатор для каждого воркера
const id = test.info().parallelIndex;
const fileName = `playwright/.auth${id}.json`;
 
if (fs.existsSync(fileName)) {
// Повторное использование существующего состояния аутентификации, если оно есть
await use(fileName);
return;
}
// Важно: убедиться, что аутентификация выполняется в чистой среде, обнуляя storage state
const page = await browser.newPage({ storageState: undefined });
 
// Можно иметь список заранее созданных аккаунтов для тестирования
account = await acquireAccount(id);
// Выполняем шаги аутентификации. Замените эти действия на свои собственные
await page.goto("https://bookcart.azurewebsites.net/");
await page.getByRole("button", { name: " Login " }).click();
await page.getByLabel("Username").fill(account.username);
await page.getByLabel("Password").fill(account.password);
await page
.locator("mat-card-actions")
.getByRole("button", { name: "Login" }).click();
// Ждем финальный URL, чтобы убедиться, что cookies действительно установлены
await page.waitForURL("https://bookcart.azurewebsites.net/");
// Конец шагов аутентификации
await page.context().storageState({ path: `playwright/.auth${id}.json` });
await page.close();
await use(fileName);},
{ scope: "worker" },
],
});

Шаг 2: создаем тестовые файлы в папке tests

Теперь создайте пару тестов, которые будут проверять вход в систему с уникальными состояниями хранения, созданными в auth0.json и auth1.json.

Например, это простой тест для проверки URL главной страницы после входа под swathika:

import { test, expect } from "../playwright/fixtures";
 
test("first test", async ({ page }) => {
await page.goto("https://bookcart.azurewebsites.net/");
await page.waitForURL("https://bookcart.azurewebsites.net/");
// продолжайте с любым пользовательским сценарием, например, добавлением книг в корзину или в список желаемого, и выполнением проверок
// Если тест выполняется под воркером 1, он будет выполнен как 'swathika', так как auth0.json будет сохранен с состоянием хранения для 'swathika'
});

Результат рецепта 2

После выполнения тестов создаются файлы состояния хранения auth0.json и auth1.json. Каждый из них будет использоваться своим параллельным воркером.

Ниже видно, что оба теста прошли успешно, и каждый процесс воркера использовал уникальное состояние хранения из auth0.json и auth1.json.

Рецепт 3: Аутентификация через API для нескольких аккаунтов и использование полученных состояний хранения

Все знают, что в тестировании API-эндпойнты быстрее, чем UI. Особенно это актуально при работе с несколькими учетными записями пользователей.

Тестирование с учетом ролей критично, когда нужно проверять действия, которые разрешены определенной категории пользователей. Этот рецепт идеально подходит, когда необходимо войти под несколькими пользователями и выполнять действия с разными уровнями авторизации.

Для демонстрации представим, что у вас два пользователя: один админ, другой читатель/покупатель. (Сайт Book Cart не поддерживает разные роли, только читателя: мы просто воображаем это.) Посмотрим, как войти как админ и как читатель, чтобы использовать их состояния хранения в тестах.

Я опиралась на документацию на сайте Playwright. Рассмотрим реализацию.

Шаг 1: создаем setup.spec файл

Создайте файл tests/setup.spec.ts с шагами аутентификации через API для админа и читателя, а также сохранением их состояний хранения в соответствующих json-файлах: admin.json и reader.json.

Обязательно добавьте admin.json и reader.json в .gitignore, чтобы случайно не залить их в репозиторий.

import { test as setup, expect } from "@playwright/test";
 
const adminFile = "playwright/.auth/admin.json";
 
setup("authenticate as admin", async ({ request }) => {
// аутентификация
await request.post("https://bookcart.azurewebsites.net/api/login", {
form: {
user: "BookcartAdmin",
password: process.env.password1,
},
});
await request.storageState({ path: adminFile });
});
 
const readerFile = "playwright/.auth/reader.json";
 
setup("authenticate as reader", async ({ request }) =>
// аутентификация
await request.post("https://bookcart.azurewebsites.net/api/login", {
form: {
user: "BookcartReader",
password: process.env.password2,
},
});
await request.storageState({ path: readerFile });
});

Шаг 2: Создаем тесты, использующие состояния хранения для админа и читателя

Мы можем использовать состояние хранения для группы тестов или для каждого теста отдельно, в зависимости от требований теста. Давайте создадим два отдельных теста: один для «админа», другой для «читателя».

Я создала файл теста adminTest.spec.ts, где использую состояние хранения для админа, и readerTest.spec.ts для читателя. Это похоже на предыдущие рецепты, за исключением того, что я буду использовать состояние хранения непосредственно внутри теста, а не настраивать его глобально в конфиге.

В обоих файлах теста я сразу перехожу на страницу «Мои заказы» сайта Book Cart и проверяю, отображается ли определенный текст. Так мы убеждаемся, что состояние хранения позволило нам зайти как админ или как читатель.

Ниже пример adminTest.spec.ts, использующего состояние хранения из admin.json:

import { test } from "@playwright/test";
 
test.use({ storageState: "./playwright/.auth/admin.json" });
 
test("admin test", async ({ page }) => {
await page.goto("https://bookcart.azurewebsites.net/myorders");
await page.waitForURL("https://bookcart.azurewebsites.net/myorders");
// проверяем, что состояние хранения сработало и вход выполнен успешно
// страница «Мои заказы»
await page.getByPlaceholder(" Start shopping ").isVisible();
// дополнительные проверки для админа
//......
});

И файл readerTest.spec.ts, использующий состояние хранения из reader.json:

import { test } from "@playwright/test";
 
test.use({ storageState: "./playwright/.auth/reader.json" });
 
test("reader test", async ({ page }) => {
await page.goto("https://bookcart.azurewebsites.net/myorders");
await page.waitForURL("https://bookcart.azurewebsites.net/myorders");
// проверяем, что состояние хранения сработало и вход выполнен успешно
// страница «Мои заказы»
await page.getByPlaceholder(" Start shopping ").isVisible();
// дополнительные проверки для читателя
//......
});

Результат рецепта 3

После выполнения тестов будут созданы два файла состояния хранения: один для админа, другой для читателя. Тесты будут использовать соответствующие файлы состояния хранения.


Ниже приведено подтверждение состояния хранения, зафиксированного в одном из json-файлов.


Рецепт 4: Аутентификация через API для нескольких аккаунтов и использование их в одном тесте

В этом рецепте мы повторяем те же шаги, что и в рецепте 3. Но на этот раз вместо того, чтобы использовать состояния хранения «админа» и «читателя» в разных тестах, мы используем их в одном тесте. Этот рецепт подходит, когда нужно протестировать, как взаимодействуют несколько аутентифицированных ролей.

Шаг 1: Создайте файл setup.spec

Следуйте тем же шагам, что и в Рецепте 3: создайте файл setup.ts, который сохраняет API-аутентификацию для админа и читателя.

Шаг 2: Создайте файл теста

Создайте тестовый файл, чтобы использовать аутентифицированные состояния как для админа, так и для читателя:

import { test } from "@playwright/test";
test("admin and user", async ({ browser }) => {
// adminContext и все страницы внутри, включая adminPage, залогинены как "admin".
const adminContext = await browser.newContext({
storageState: "playwright/.auth/admin.json",
});
const adminPage = await adminContext.newPage();
// readerContext и все страницы внутри, включая readerPage, залогинены как "reader".
const readerContext = await browser.newContext({
storageState: "playwright/.auth/reader.json",
});
const readerPage = await readerContext.newPage();
// ... взаимодействие с adminPage и readerPage ...
await adminPage.goto("https://bookcart.azurewebsites.net/myorders");
await adminPage.waitForURL("https://bookcart.azurewebsites.net/myorders");
await readerPage.goto("https://bookcart.azurewebsites.net/myorders");
await readerPage.waitForURL("https://bookcart.azurewebsites.net/myorders");
// дальнейшие тесты.....
await adminContext.close();
await readerContext.close();
});

Результат рецепта 4

После выполнения тестов, как и в рецепте 3, будут созданы два файла состояния хранения: один для админа, другой для читателя. Каждый тест будет использовать соответствующее состояние хранения.

Единственное отличие в том, что в рецепте 4 мы используем состояния хранения обоих пользователей в одном тесте, тогда как в рецепте 3 состояния использовались в разных тестах.

Подводя итог

Мы рассмотрели несколько техник аутентификации, которые можно реализовать с помощью Playwright. По моему опыту, каждая система уникальна, и стратегия автоматизации тестирования также зависит от приложения.

Например, если ваше приложение не включает различные роли и права доступа, вы можете выбрать метод аутентификации соответственно. С другой стороны, если приложение поддерживает роли с разными уровнями авторизации, методы аутентификации и способы их использования в тестах будут существенно различаться.

Надеюсь, эта статья дала вам ясное представление о том, как повторно использовать состояния аутентификации. Это экономит время выполнения на пайплайнах, что особенно важно при масштабируемости автоматизационной инфраструктуры!

Я добавила эти рецепты в своё портфолио на GitHub, и они доступны на соответствующих ветках, чтобы избежать путаницы. Вы можете клонировать мой практический репозиторий и попробовать все примеры самостоятельно. Официальный сайт Playwright также предоставляет массу полезной информации и примеров кода, которые можно адаптировать под свои нужды.

Приятного аппетита!

Дополнительная информация