Перейти к основному контенту
Tech Path Finder
КурсыИнтервьюКод-ревьюБлог
Tech Path Finder

Персонализированный путеводитель в IT. Квизы, мок-интервью, код ревью и аналитика прогресса.

@potapov_me

Платформа

  • Курсы
  • Прогресс
  • Мок-интервью
  • Код ревью
  • Живое ревью с ИИ
  • Тренажёр переговоров
  • Закладки

Контент

  • Блог
  • Главная
  • Обратная связь

Компания

  • О проекте
  • Тарифы
  • Условия использования
  • Конфиденциальность
  • Согласие на обработку данных
  • Cookie
  • Реквизиты

Аккаунт

  • Войти
  • Зарегистрироваться
  • Профиль

© 2026 Tech Path Finder. Все права защищены.

·ИП Потапов К.С.·Политика конфиденциальности·
Сделано с ❤️ в России
  1. Аутентификация и авторизация
auth

Аутентификация и авторизация

Сохранение сессии, cookies, localStorage, обход login-формы, multi-factor auth

Аутентификация и авторизация

Большинство веб-приложений требуют авторизации. Повторный логин в каждом тесте замедляет прогон в 5-10 раз. Playwright предоставляет эффективные механизмы управления сессиями.

#1. Стандартный логин через UI

Простейший подход — заполнить форму логина:

def test_dashboard(logged_in_page): logged_in_page.goto('/dashboard') assert logged_in_page.get_by_role('heading', name='Добро пожаловать').is_visible() @pytest.fixture def logged_in_page(page): page.goto('/login') page.get_by_label('Email').fill('user@example.com') page.get_by_label('Пароль').fill('secret123') page.get_by_role('button', name='Войти').click() page.wait_for_url('**/dashboard') yield page

Проблема: каждый тест загружает страницу, заполняет поля, ждёт ответа сервера. Это медленно.

#2. Storage State — сохранение сессии

Решение: залогиниться один раз, сохранить cookies и localStorage, переиспользовать в тестах.

# conftest.py import pytest from pathlib import Path AUTH_FILE = Path('auth/user.json') @pytest.fixture(scope='session') def saved_auth(browser): """Логин один раз на сессию и сохранение состояния.""" context = browser.new_context() page = context.new_page() page.goto('/login') page.get_by_label('Email').fill('user@example.com') page.get_by_label('Пароль').fill('secret123') page.get_by_role('button', name='Войти').click() page.wait_for_url('**/dashboard') # Сохраняем cookies + localStorage + sessionStorage context.storage_state(path=AUTH_FILE) context.close() yield @pytest.fixture def user_page(page): """Каждый тест получает уже авторизованную страницу.""" # Пересоздаём контекст с сохранённой сессией page.context.storage_state(path=AUTH_FILE) yield page

Теперь тесты мгновенно получают авторизованную сессию:

def test_settings(user_page): user_page.goto('/settings') # Уже авторизован — редиректа на /login нет assert user_page.url.endswith('/settings')

#3. Что сохраняет storage_state?

Файл auth.json выглядит так:

{ "cookies": [ { "name": "session_id", "value": "abc123", "domain": ".example.com", "path": "/", "expires": 1735689600 } ], "origins": [ { "origin": "https://example.com", "localStorage": [ {"name": "auth_token", "value": "jwt-token-here"} ] } ] }

Сохраняются: cookies (включая httpOnly), localStorage, sessionStorage. Не сохраняется: состояние IndexedDB, кэш браузера.

#4. Авторизация через API (без UI)

Если у приложения есть login API — используйте его. Это ещё быстрее:

@pytest.fixture(scope='session') def api_auth(browser, base_url): """Авторизация через API, без загрузки страницы логина.""" context = browser.new_context() page = context.new_page() # Вызываем login API напрямую response = page.request.post(f'{base_url}/api/auth/login', data={ 'email': 'user@example.com', 'password': 'secret123', }) assert response.status == 200 # Сохраняем сессию (cookies уже установлены) context.storage_state(path=AUTH_FILE) context.close() yield

page.request — встроенный APIRequestContext Playwright. Он работает в контексте страницы, поэтому cookies автоматически сохраняются.

#5. JWT-авторизация

Если приложение использует JWT в localStorage:

@pytest.fixture def jwt_page(page): """Установка JWT-токена напрямую в localStorage.""" page.goto('/') # Нужно зайти на домен, чтобы localStorage был доступен page.evaluate(''' localStorage.setItem('auth_token', 'eyJhbGciOiJIUzI1NiIs...') ''') page.reload() # Перезагрузка для применения токена yield page

Важно: localStorage доступен только после навигации на домен. Сначала page.goto('/'), потом evaluate().

#6. Multi-role тестирование

Создайте auth-файл для каждой роли:

# conftest.py AUTH_FILES = { 'admin': Path('auth/admin.json'), 'manager': Path('auth/manager.json'), 'viewer': Path('auth/viewer.json'), } CREDENTIALS = { 'admin': ('admin@example.com', 'admin_pass'), 'manager': ('manager@example.com', 'manager_pass'), 'viewer': ('viewer@example.com', 'viewer_pass'), } @pytest.fixture def page_as(browser, base_url, request): """Фикстура с параметризованной ролью.""" role = request.param email, password = CREDENTIALS[role] auth_file = AUTH_FILES[role] context = browser.new_context() page = context.new_page() page.goto(f'{base_url}/login') page.get_by_label('Email').fill(email) page.get_by_label('Пароль').fill(password) page.get_by_role('button', name='Войти').click() page.wait_for_url('**/dashboard') context.storage_state(path=auth_file) context.close() # Новый контекст с auth auth_context = browser.new_context(storage_state=auth_file) auth_page = auth_context.new_page() yield auth_page auth_context.close() @pytest.mark.parametrize('page_as', ['admin', 'manager', 'viewer'], indirect=True) def test_dashboard_for_roles(page_as): page_as.goto('/dashboard') assert page_as.get_by_role('heading').is_visible()

#7. Истечение сессии

Для тестирования обработки expired token:

import json import time from pathlib import Path def expire_auth_file(auth_path: Path): """Устанавливает время истечения cookies в прошлое.""" data = json.loads(auth_path.read_text()) for cookie in data['cookies']: cookie['expires'] = int(time.time()) - 1000 # Истёк час назад auth_path.write_text(json.dumps(data)) def test_expired_token(page, base_url): expire_auth_file(Path('auth/user.json')) page.context.storage_state(path=Path('auth/user.json')) page.goto(base_url + '/dashboard') # Приложение должно показать форму логина assert '/login' in page.url

#8. Multi-factor Authentication (2FA)

Обход 2FA через сохранение сессии:

  1. Вручную пройдите 2FA один раз
  2. Сохраните storage_state
  3. Переиспользуйте файл — сервер не запрашивает 2FA повторно, пока сессия активна

Если сессия сбрасывается — используйте API для генерации TOTP-кодов:

import pyotp def get_totp_code(secret: str) -> str: """Генерирует текущий TOTP-код из секрета.""" totp = pyotp.TOTP(secret) return totp.now() # В тесте page.get_by_label('Код подтверждения').fill(get_totp_code('JBSWY3DPEHPK3PXP'))

#9. Очистка сессии

# Очистить cookies await context.clear_cookies() # Очистить localStorage await page.evaluate('localStorage.clear()') # Полная очистка — закрыть контекст await context.close()

#10. Типичные ошибки

❌ Использование одного auth.json для разных доменов. Cookies привязаны к домену. auth.json от staging.example.com не сработает на prod.example.com.

❌ Хранение auth.json в Git. Токены могут попасть в репозиторий. Добавьте auth/ в .gitignore и генерируйте файлы в CI.

❌ Попытка установить localStorage до навигации. page.evaluate('localStorage...') до page.goto() вызовет ошибку — нет origin.

✅ Правильный подход: storage_state для скорости, API-login для ещё большей скорости, отдельные файлы для каждой роли, очистка в teardown.


#Упражнения

  1. Создайте session-scoped фикстуру, которая логинится через UI и сохраняет auth.json.
  2. Напишите фикстуру, которая авторизуется через page.request.post() к login API.
  3. Протестируйте обработку истёкшего токена: измените expires в auth.json и проверьте редирект на /login.
  4. Создайте три auth-файла для ролей admin/manager/viewer и параметризуйте тест проверки контента.

#Что дальше?

Изучите визуальное тестирование, чтобы научиться сравнивать скриншоты с эталонами.

Далее: Визуальное тестирование