process.env.VARIABLE возвращает string | undefined в TypeScript, поэтому тест с незаданной переменной окружения не падает с понятной ошибкой при старте: он падает в середине с криптовым сообщением от локатора или аутентификации. Решение: обёртка requireEnv() которая бросает исключение на старте с именем переменной. Отсутствующий TEST_USER_EMAIL останавливает сьют до первого теста и говорит что именно нужно задать. Эта статья разбирает настройку dotenv с .env и .env.local, паттерн типобезопасного объекта env, валидацию в глобальном setup и разницу между vars. и secrets. в GitHub Actions для несекретных и секретных значений.
Что куда
Вplaywright.config.ts (коммитится в репозиторий):
export default defineConfig({
timeout: 30000,
retries: process.env.CI ? 2 : 0,
workers: process.env.CI ? 4 : undefined,
reporter: [['html'], ['list']],
use: {
baseURL: process.env.BASE_URL || 'http://localhost:3000',
trace: 'on-first-retry',
screenshot: 'only-on-failure',
},
});.env-файлах или CI-секретах (секреты никогда не коммитятся):
BASE_URL=https://staging.myapp.com
API_KEY=sk-test-abc123
TEST_USER_EMAIL=testuser@example.com
TEST_USER_PASSWORD=SecurePass123!
DATABASE_URL=postgresql://localhost:5432/testdbНастройка dotenv
npm install -D dotenvСоздай .env с безопасными дефолтами (без реальных учётных данных):
# .env
BASE_URL=http://localhost:3000
TEST_USER_EMAIL=test@example.com
TEST_USER_PASSWORD=
DATABASE_URL=Создай .env.local с реальными локальными значениями (в .gitignore):
# .env.local — никогда не коммитится
TEST_USER_EMAIL=realtest@example.com
TEST_USER_PASSWORD=RealPassword123
DATABASE_URL=postgresql://localhost:5432/myapp_testЗагрузка в конфиге:
// playwright.config.ts
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',
},
});Добавь в .gitignore:
.env.local
playwright/.auth/
test-results/
playwright-report/Типобезопасные переменные окружения
process.env.VARIABLE возвращает string | undefined. Ловить отсутствующие переменные во время выполнения теста плохо. Лови при старте:
// utils/env.ts
function requireEnv(name: string): string {
const value = process.env[name];
if (!value) {
throw new Error(`Environment variable ${name} is required but not set`);
}
return value;
}
export const env = {
baseURL: process.env.BASE_URL || 'http://localhost:3000',
apiKey: requireEnv('API_KEY'),
testUser: {
email: requireEnv('TEST_USER_EMAIL'),
password: requireEnv('TEST_USER_PASSWORD'),
},
};Используй в тестах:
import { env } from '../utils/env';
test('login with test credentials', async ({ page }) => {
await page.goto('/login');
await page.getByLabel('Email').fill(env.testUser.email);
await page.getByLabel('Password').fill(env.testUser.password);
});Если TEST_USER_EMAIL не задан, получаешь понятную ошибку при старте: Environment variable TEST_USER_EMAIL is required but not set, а не загадочное падение в середине теста.
Конфигурация для нескольких окружений
Для нескольких тестовых окружений используй Playwright projects с разными настройками:
// playwright.config.ts
const environments = {
local: {
baseURL: 'http://localhost:3000',
apiURL: 'http://localhost:8000',
},
staging: {
baseURL: 'https://staging.myapp.com',
apiURL: 'https://api-staging.myapp.com',
},
production: {
baseURL: 'https://myapp.com',
apiURL: 'https://api.myapp.com',
},
};
const env = (process.env.TEST_ENV as keyof typeof environments) || 'local';
const config = environments[env];
export default defineConfig({
use: {
baseURL: config.baseURL,
extraHTTPHeaders: {
'X-API-Base': config.apiURL,
},
},
});Запуск:
TEST_ENV=staging npx playwright test
TEST_ENV=production npx playwright test --grep @smokeФлаги фич в тестах
Когда приложение использует флаги фич, тесты могут вести себя по-разному в зависимости от того что включено:
// проверяем включена ли фича через переменную окружения
const NEW_CHECKOUT = process.env.FEATURE_NEW_CHECKOUT === 'true';
test('checkout flow', async ({ page }) => {
await page.goto('/checkout');
if (NEW_CHECKOUT) {
// тестируем новый UI чекаута
await expect(page.getByTestId('new-checkout-form')).toBeVisible();
} else {
// тестируем legacy UI чекаута
await expect(page.getByTestId('legacy-checkout-form')).toBeVisible();
}
});Лучше: отдельные тест-файлы для каждого состояния флага, управляемые через Playwright projects:
projects: [
{
name: 'new-checkout',
testMatch: '**/checkout-new/**',
use: { extraHTTPHeaders: { 'X-Feature-New-Checkout': 'true' } },
},
{
name: 'legacy-checkout',
testMatch: '**/checkout-legacy/**',
},
],Переменные окружения в CI/CD
Пример GitHub Actions с правильной обработкой секретов:
# .github/workflows/tests.yml
env:
# несекретное — используй vars, видно в логах
BASE_URL: ${{ vars.STAGING_URL }}
TEST_ENV: staging
jobs:
test:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- name: Run tests
env:
# секретное — используй secrets, маскируется в логах
TEST_USER_EMAIL: ${{ secrets.TEST_USER_EMAIL }}
TEST_USER_PASSWORD: ${{ secrets.TEST_USER_PASSWORD }}
API_KEY: ${{ secrets.API_KEY }}
run: npx playwright testКлючевое различие: vars. это несекретная конфигурация, видна в логах воркфлоу. secrets. маскируется в логах, никогда не печатается, нужна для учётных данных и ключей.
Валидация конфигурации при старте сьюта
Используй глобальный setup для проверки окружения до запуска тестов:
// global-setup.ts
export default async function globalSetup() {
const required = ['TEST_USER_EMAIL', 'TEST_USER_PASSWORD', 'BASE_URL'];
const missing = required.filter(key => !process.env[key]);
if (missing.length > 0) {
throw new Error(
`Missing required environment variables:\n${missing.map(k => ` - ${k}`).join('\n')}\n\n` +
`Copy .env.example to .env.local and fill in the values.`
);
}
console.log(`Running tests against: ${process.env.BASE_URL}`);
}Падает быстро с понятным сообщением вместо того чтобы дать первому тесту упасть с загадочной ошибкой локатора.
→ See also: Файл конфигурации Playwright: все опции, которые нужно знать | Конфигурация окружений Playwright: локальная, стейджинг и продакшн | GitHub Actions для тестов Playwright: полная настройка (2026)