docs(web-test): BrowserContext вместо sequential reconnect для мульти-контекста

Один процесс браузера, несколько изолированных BrowserContext'ов.
Мгновенное переключение между пользователями, состояние каждой
сессии сохраняется. Не требует полного рефакторинга createContext().

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
This commit is contained in:
Nick Shirokov
2026-04-05 14:47:26 +03:00
parent 2347859bdd
commit f39a0d9c5e
+82 -23
View File
@@ -46,9 +46,10 @@ In-process (не через HTTP). Раннер:
3. Импортирует каждый модуль, извлекает метаданные
4. Фильтрует по тегам/grep/only
5. Группирует по контексту, сортирует по алфавиту внутри группы
6. Подключается к 1С (`browser.connect(url)`)
7. Выполняет тесты последовательно
8. Отключается, выводит результаты
6. Запускает браузер (`chromium.launch()`)
7. Создаёт BrowserContext + page для каждого используемого контекста (лениво)
8. Выполняет тесты последовательно, переключая активный контекст
9. Закрывает все контексты и браузер, выводит результаты
---
@@ -280,19 +281,21 @@ assert.noErrors(state, msg)
### Порядок выполнения
```
prepare() // без браузера
browser.connect(url)
beforeAll(ctx) // браузер готов
prepare() // без браузера (восстановление БД, публикация)
browser.launch() // запуск процесса браузера
создание BrowserContext'ов // по одному на каждый используемый контекст
beforeAll(ctx) // браузер готов, контексты созданы
beforeEach(ctx)
test.setup(ctx) // подготовка теста
test.default(ctx) // тело теста
test.teardown(ctx) // очистка теста (всегда)
afterEach(ctx) // всегда
[встроенный сброс] // всегда
test.setup(ctx) // подготовка теста
test.default(ctx) // тело теста
test.teardown(ctx) // очистка теста (всегда)
afterEach(ctx) // всегда
[встроенный сброс] // всегда (для каждого активного контекста)
...следующий тест...
afterAll(ctx)
browser.disconnect()
cleanup() // без браузера
закрытие всех BrowserContext'ов
browser.close()
cleanup() // без браузера (удаление публикации)
```
### Встроенный сброс состояния
@@ -372,9 +375,30 @@ export default {
## 8. Контексты
### Механизм: Playwright BrowserContext
Один процесс браузера (`chromium.launch()`), несколько изолированных контекстов.
Каждый контекст -- отдельная сессия (куки, авторизация, состояние страницы).
```
browser (один процесс chromium)
├─ BrowserContext "кладовщик" → page → http://localhost/app-clerk/ru_RU
├─ BrowserContext "менеджер" → page → http://localhost/app-mgr/ru_RU
└─ BrowserContext "админ" → page → http://localhost/app-admin/ru_RU
```
Преимущества:
- **Мгновенное переключение** между пользователями (смена активного `page`)
- **Состояние сохраняется** -- переключились на менеджера и обратно, у кладовщика
все формы остались открытыми, ничего не потеряно
- **Нет переподключений** -- каждая сессия живёт независимо
- **Один процесс** -- экономия ресурсов по сравнению с несколькими браузерами
- **Стандартный паттерн** Playwright для мульти-пользовательских сценариев
### Одиночный контекст (по умолчанию)
Большинство тестов. Один браузер, один пользователь. Тест получает плоский контекст со всем API.
Большинство тестов. Один BrowserContext, один пользователь.
Тест получает плоский контекст со всем API.
```js
export const context = 'кладовщик'; // необязательно, используется defaultContext
@@ -383,10 +407,13 @@ export default async function({ clickElement, fillFields, ... }) { }
### Группировка по контексту
Раннер группирует тесты по значению `context`, минимизирует переподключения:
1. Собрать все тесты, сгруппировать по имени контекста
2. Для каждой группы: подключиться -> выполнить тесты -> отключиться
3. Внутри группы тесты выполняются по алфавиту
Раннер группирует тесты по значению `context`:
1. Собрать все тесты, определить набор уникальных контекстов
2. Создать BrowserContext + page для каждого используемого контекста
3. Для каждой группы тестов: переключить активный context, выполнить тесты
4. Внутри группы тесты выполняются по алфавиту
Контексты создаются лениво (при первом обращении) и живут до конца прогона.
### Мульти-контекст (процессные тесты)
@@ -395,11 +422,43 @@ export const contexts = ['кладовщик', 'менеджер'];
export default async function({ кладовщик, менеджер, step, assert }) { }
```
Каждый именованный контекст -- полноценный объект API. Тест оркестрирует переключение.
Каждый именованный контекст -- полноценный объект API со своим `page`.
Тест оркестрирует переключение между пользователями.
Состояние каждого пользователя сохраняется между переключениями:
**Этапы реализации:**
- Этап 1: последовательное переподключение (отключиться от одного URL, подключиться к другому)
- Этап 2: параллельные браузеры (после рефакторинга browser.mjs в `createContext()`)
```js
await step('Кладовщик создаёт документ', async () => {
await кладовщик.openCommand('Приходные накладные');
await кладовщик.clickElement('Создать');
await кладовщик.fillFields({ 'Контрагент': 'ООО Поставщик' });
await кладовщик.clickElement('Записать');
// кладовщик стоит на форме документа
});
await step('Менеджер утверждает', async () => {
await менеджер.navigateSection('Согласование');
await менеджер.clickElement('Утвердить');
});
await step('Кладовщик проверяет статус', async () => {
// страница кладовщика ТА ЖЕ -- форма открыта, навигация не нужна
const state = await кладовщик.getFormState();
assert.equal(state.fields['Статус']?.value, 'Утверждён');
});
```
### Влияние на browser.mjs
Текущий browser.mjs хранит `page`, `browser`, `session` как module-level переменные.
Для мульти-контекста необходимо:
- Уметь создавать несколько `BrowserContext` + `page` в одном `browser`
- Хранить карту контекстов `{ name → { context, page, session } }`
- Переключать текущий `page` при смене активного контекста
- API-функции рабтают с текущим активным `page`
Это промежуточный шаг к полному `createContext()` из Фазы 3 роадмапа,
но значительно проще -- не требует рефакторинга всех функций browser.mjs,
только управление текущим page.
---
@@ -723,7 +782,7 @@ function buildContext({ noRecord = false } = {}) -> object
| 3 | Ядро cmdTest() | run.mjs: обнаружение, импорт, выполнение, консольный вывод, JSON-отчёт | #2 |
| 4 | Утверждения + обёртка step() | run.mjs: assert.*, step(name, fn) | #3 |
| 5 | Хуки (prepare/cleanup + before/after) | run.mjs: поддержка _hooks.mjs | #3 |
| 6 | Файл конфигурации + контексты | run.mjs: webtest.config.mjs, маршрутизация контекстов | #3 |
| 6 | Файл конфигурации + контексты | run.mjs: webtest.config.mjs, BrowserContext'ы, маршрутизация | #3 |
| 7 | Форматы отчётов (Allure, JUnit) | run.mjs: --format=allure/junit | #3 |
| 8 | Синтетическая конфигурация | integration/build-webtest-config.test.mjs | спека |
| 9 | Smoke-тесты (01-06) | tests/web-test/01-06*.test.mjs | #3, #8 |