Захардкодить baseURL в playwright.config.ts: проверенный способ запустить тесты не в том окружении. Кто-то меняет URL, забывает откатить, тесты зеленеют на устаревших данных. Эта статья разбирает: чтение base URL и учётных данных из переменных окружения, загрузку .env-файлов локально, передачу секретов через GitHub Actions и упаковку учётных данных в фикстуры, чтобы отсутствующая переменная падала на старте, а не в середине теста.

Проблема с захардкоженными URL

// плохо — жёстко задан, никакой гибкости
use: {
  baseURL: 'https://staging.myapp.com',
},

Нужно запустить локально: меняешь URL вручную. CI должен проверить фича-ветку: кто-то вспоминает откатить, кто-то нет. Тесты проходят, но против не того окружения. Ошибка незаметна: всё зелёное, просто данные устаревшие.

Переменные окружения

Берём base URL из переменной окружения:

// playwright.config.ts
import { defineConfig } from '@playwright/test';

export default defineConfig({
  use: {
    baseURL: process.env.BASE_URL || 'http://localhost:3000',
  },
});

Запуск:

# локально
npx playwright test

# на staging
BASE_URL=https://staging.myapp.com npx playwright test

# продакшн (только smoke-тесты)
BASE_URL=https://myapp.com npx playwright test --grep @smoke

Никаких изменений в коде при смене окружения. Только другая переменная.

dotenv для локальной разработки

Каждый раз писать BASE_URL=... неудобно. Используй .env-файл:

# .env.local
BASE_URL=http://localhost:3000
API_TOKEN=dev-token-abc123
TEST_USER_EMAIL=test@example.com
TEST_USER_PASSWORD=testpass123

Загружаем в конфиге:

npm install -D dotenv

// playwright.config.ts
import { defineConfig } from '@playwright/test';
import dotenv from 'dotenv';
import path from 'path';

// загружаем .env.local если есть, затем .env как запасной
dotenv.config({ path: path.resolve(__dirname, '.env.local') });
dotenv.config({ path: path.resolve(__dirname, '.env') });

export default defineConfig({
  use: {
    baseURL: process.env.BASE_URL || 'http://localhost:3000',
  },
});

.env.local добавь в .gitignore. .env коммить с безопасными дефолтами, без секретов. Каждый в команде создаёт свой .env.local с локальными учётными данными.

Несколько конфигов под окружения

Когда у окружений принципиально разные настройки, удобны отдельные конфиг-файлы:

playwright.config.ts           # базовый конфиг, общие настройки
playwright.config.staging.ts   # настройки для staging
playwright.config.prod.ts      # продакшн (только smoke)

// playwright.config.staging.ts
import { defineConfig } from '@playwright/test';
import baseConfig from './playwright.config';

export default defineConfig({
  ...baseConfig,
  use: {
    ...baseConfig.use,
    baseURL: 'https://staging.myapp.com',
    video: 'on-first-retry',
  },
  retries: 2,
});

Запуск:

npx playwright test --config=playwright.config.staging.ts

Схема хорошо работает в CI-пайплайнах, где разные стадии требуют разного количества повторов, настроек видео или репортеров.

Переменные окружения в тестах

Не обращайся к переменным окружения напрямую из тестовых файлов. Это привязывает тестовую логику к инфраструктуре. Оборачивай в фикстуры:

// fixtures/env.ts
import { test as base } from '@playwright/test';

type EnvFixtures = {
  testUser: { email: string; password: string };
  apiToken: string;
};

export const test = base.extend<EnvFixtures>({
  testUser: async ({}, use) => {
    const email = process.env.TEST_USER_EMAIL;
    const password = process.env.TEST_USER_PASSWORD;

    if (!email || !password) {
      throw new Error('TEST_USER_EMAIL and TEST_USER_PASSWORD must be set');
    }

    await use({ email, password });
  },

  apiToken: async ({}, use) => {
    const token = process.env.API_TOKEN;
    if (!token) throw new Error('API_TOKEN must be set');
    await use(token);
  },
});

Тесты используют фикстуру, а не process.env напрямую:

import { test } from '../fixtures/env';
import { expect } from '@playwright/test';

test('user can log in', async ({ page, testUser }) => {
  await page.goto('/login');
  await page.getByLabel('Email').fill(testUser.email);
  await page.getByLabel('Password').fill(testUser.password);
  await page.getByRole('button', { name: 'Log in' }).click();
  await expect(page).toHaveURL('/dashboard');
});

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

Переменные окружения в CI/CD

В GitHub Actions секреты настраиваются в настройках репозитория, затем передаются в тесты:

# .github/workflows/tests.yml
jobs:
  test:
    runs-on: ubuntu-latest
    env:
      BASE_URL: ${{ vars.STAGING_URL }}
      API_TOKEN: ${{ secrets.API_TOKEN }}
      TEST_USER_EMAIL: ${{ secrets.TEST_USER_EMAIL }}
      TEST_USER_PASSWORD: ${{ secrets.TEST_USER_PASSWORD }}

    steps:
      - uses: actions/checkout@v4
      - uses: actions/setup-node@v4
        with:
          node-version: '20'
      - run: npm ci
      - run: npx playwright install --with-deps
      - run: npx playwright test

vars (не secrets) используй для нечувствительных значений вроде staging URL: они видны в логах CI, что помогает при отладке. secrets используй для учётных данных, токенов и паролей.

Тест-данные под конкретные окружения

Некоторые тесты должны запускаться только в определённых окружениях. Используй теги и проверки окружения:

test('payment flow smoke test', {
  tag: '@smoke',
  annotation: { type: 'env', description: 'staging and production only' },
}, async ({ page }) => {
  // пропускаем при локальной разработке — не нужен sandbox оплаты
  test.skip(
    process.env.BASE_URL?.includes('localhost') === true,
    'Payment tests require staging or production environment'
  );

  // тело теста...
});

Или через фикстуру которая определяет текущее окружение:

const currentEnv = process.env.BASE_URL?.includes('staging')
  ? 'staging'
  : process.env.BASE_URL?.includes('localhost')
  ? 'local'
  : 'production';

Это избавляет от разбросанных по тест-файлам if (process.env.BASE_URL === '...').

Что в переменные, что в конфиг

| Настройка | Где должна быть |

|-----------|-----------------|

| Base URL | Переменная окружения |

| API-токены, пароли | Переменная окружения (секрет) |

| Тип браузера | Конфиг-файл |

| Количество повторов | Конфиг-файл (можно разное для окружений) |

| Таймауты | Конфиг-файл |

| Тест-данные | Фикстуры |

| Флаги фич для поведения тестов | Переменная окружения |

Правило простое: всё что отличается между окружениями идёт в переменную окружения. Всё что остаётся стабильной настройкой фреймворка идёт в конфиг-файл.

→ See also: Файл конфигурации Playwright: все опции, которые нужно знать | Переменные окружения в тестах Playwright: полное руководство | GitHub Actions для тестов Playwright: полная настройка (2026)