mirror of
https://github.com/Ku6epXBOCTuK/easy-png-tools.git
synced 2026-11-13 17:08:20 +00:00
test: update fixtures flow, add different browsers
This commit is contained in:
@@ -68,9 +68,9 @@ jobs:
|
|||||||
working-directory: web
|
working-directory: web
|
||||||
run: pnpm install --frozen-lockfile
|
run: pnpm install --frozen-lockfile
|
||||||
|
|
||||||
- name: Install Chromium
|
- name: Install Playwright browsers
|
||||||
working-directory: web
|
working-directory: web
|
||||||
run: pnpm exec playwright install --with-deps chromium
|
run: pnpm exec playwright install --with-deps chromium firefox webkit
|
||||||
|
|
||||||
- name: Run E2E
|
- name: Run E2E
|
||||||
working-directory: web
|
working-directory: web
|
||||||
|
|||||||
@@ -18,6 +18,12 @@
|
|||||||
(docs) + `pnpm --dir web exec prettier --check .` (код).
|
(docs) + `pnpm --dir web exec prettier --check .` (код).
|
||||||
- Полный быстрый gate: `pnpm verify`; подробная матрица команд и CI —
|
- Полный быстрый gate: `pnpm verify`; подробная матрица команд и CI —
|
||||||
`docs/quality-gates.md`.
|
`docs/quality-gates.md`.
|
||||||
|
- После пуша результат CI проверяется явно: смотреть и blocking `verify`, и
|
||||||
|
non-blocking `e2e` — если тот job вообще запускался. `Quality` workflow живёт
|
||||||
|
на `pull_request` и `workflow_dispatch`, поэтому при прямом пуше в `main`
|
||||||
|
выполняется только `Deploy to GitHub Pages` со своим `verify`, а browser
|
||||||
|
matrix проверяется на PR или ручным запуском. Красный `e2e` не блокирует PR,
|
||||||
|
но остаётся падением — сообщать его фактический статус.
|
||||||
- Линтинг: `pnpm --dir web lint` (ESLint). Полный прогон дизайн-проверок:
|
- Линтинг: `pnpm --dir web lint` (ESLint). Полный прогон дизайн-проверок:
|
||||||
`pnpm --dir web lint:all` (ESLint + stylelint + токен-аудит). Каждый шаг
|
`pnpm --dir web lint:all` (ESLint + stylelint + токен-аудит). Каждый шаг
|
||||||
выполняется, даже если предыдущий упал. Новые изменения не должны добавлять
|
выполняется, даже если предыдущий упал. Новые изменения не должны добавлять
|
||||||
@@ -42,6 +48,10 @@
|
|||||||
- `test.fixme` допускается только для зарегистрированной задачи в backlog или
|
- `test.fixme` допускается только для зарегистрированной задачи в backlog или
|
||||||
checklist; после исправления тест и ссылку обновляют вместе.
|
checklist; после исправления тест и ссылку обновляют вместе.
|
||||||
- Полные переводы проверяются в unit-тестах; e2e проверяет поведение.
|
- Полные переводы проверяются в unit-тестах; e2e проверяет поведение.
|
||||||
|
- Playwright-прогоны запускаются только по явной команде пользователя, по одному
|
||||||
|
прогону, без циклов повторов и без фонового запуска: локально matrix идёт с
|
||||||
|
`workers: 1`. Отзывчивость компьютера пользователя важнее скорости проверки —
|
||||||
|
подробности в `docs/agent-workflow.md`.
|
||||||
|
|
||||||
### Сначала искать
|
### Сначала искать
|
||||||
|
|
||||||
@@ -56,7 +66,8 @@
|
|||||||
Описание нового визуального языка — в `docs/plan-redesign.md`. Общие правила,
|
Описание нового визуального языка — в `docs/plan-redesign.md`. Общие правила,
|
||||||
которые линтер не проверяет:
|
которые линтер не проверяет:
|
||||||
|
|
||||||
- Новый дизайн живёт в `web/src/app.css` и применяется ко всем production-маршрутам.
|
- Новый дизайн живёт в `web/src/app.css` и применяется ко всем
|
||||||
|
production-маршрутам.
|
||||||
- Все повторяющиеся визуальные элементы — отдельные компоненты в
|
- Все повторяющиеся визуальные элементы — отдельные компоненты в
|
||||||
`web/src/lib/components/`, даже «просто div с двумя стилями».
|
`web/src/lib/components/`, даже «просто div с двумя стилями».
|
||||||
- Дизайн-токены (цвета, размеры, длительности, z-index) — только из
|
- Дизайн-токены (цвета, размеры, длительности, z-index) — только из
|
||||||
|
|||||||
+6
-3
@@ -51,9 +51,9 @@
|
|||||||
только если темы нет в существующем документе; иначе обновляется источник
|
только если темы нет в существующем документе; иначе обновляется источник
|
||||||
истины.
|
истины.
|
||||||
|
|
||||||
## Текущий baseline Q6f.2
|
## Текущий baseline Q6f.3
|
||||||
|
|
||||||
На момент фиксации Q6f.2:
|
На момент фиксации Q6f.3:
|
||||||
|
|
||||||
- production registry содержит 122 инструмента;
|
- production registry содержит 122 инструмента;
|
||||||
- `pnpm --dir web check` проходит без ошибок и предупреждений;
|
- `pnpm --dir web check` проходит без ошибок и предупреждений;
|
||||||
@@ -61,7 +61,10 @@
|
|||||||
- `pnpm --dir web test:rules` — 4 test files / 74 tests;
|
- `pnpm --dir web test:rules` — 4 test files / 74 tests;
|
||||||
- `pnpm --dir web lint:all` — 0 errors и 0 i18n warnings; остаются 4 unused
|
- `pnpm --dir web lint:all` — 0 errors и 0 i18n warnings; остаются 4 unused
|
||||||
design tokens от token audit;
|
design tokens от token audit;
|
||||||
- `pnpm verify` проходит; production E2E — 161 passed, 0 skipped.
|
- `pnpm verify` проходит;
|
||||||
|
- `pnpm --dir web test:e2e` — 276 тестов в четырёх проектах: 276 passed, 0
|
||||||
|
skipped, 0 failed. Отказ декодера битого PNG зафиксирован per-engine в
|
||||||
|
`web/e2e/png-fixtures.spec.ts`.
|
||||||
|
|
||||||
Baseline и следующий шаг поддерживаются в `docs/plan-codebase-quality.md`.
|
Baseline и следующий шаг поддерживаются в `docs/plan-codebase-quality.md`.
|
||||||
|
|
||||||
|
|||||||
@@ -49,6 +49,25 @@ E2E запускается отдельно от быстрых проверок
|
|||||||
статический сервер. Для UI-изменений сначала выбирается минимальный
|
статический сервер. Для UI-изменений сначала выбирается минимальный
|
||||||
пользовательский поток, затем при необходимости расширяется smoke.
|
пользовательский поток, затем при необходимости расширяется smoke.
|
||||||
|
|
||||||
|
### Нагрузка на машину
|
||||||
|
|
||||||
|
Агент работает на компьютере пользователя, поэтому тяжёлые прогоны не
|
||||||
|
запускаются «по умолчанию»:
|
||||||
|
|
||||||
|
- Playwright-прогоны запускаются только по явной команде пользователя: один
|
||||||
|
прогон за раз, без циклов повторов и без фонового запуска.
|
||||||
|
- Локально `workers: 1` (`web/playwright.config.ts`). Browser matrix из четырёх
|
||||||
|
проектов проходит медленно, зато не забирает память и не мешает работе
|
||||||
|
пользователя. Скорость проверки уступает отзывчивости компьютера.
|
||||||
|
- Нельзя запускать тяжёлый прогон параллельно с другим прогоном или в момент,
|
||||||
|
когда пользователь работает с приложением.
|
||||||
|
- Диагностика флаков идёт от меньшего к большему: один spec, один проект,
|
||||||
|
`--workers=1`, и только затем полный прогон.
|
||||||
|
- Таймауты не подбираются под конкретную машину. Если проверка падает из-за
|
||||||
|
нехватки ресурсов, это фиксируется как ограничение окружения, а не лечится
|
||||||
|
увеличением `expect.timeout`.
|
||||||
|
- При необходимости повторного прогона сначала спрашивается пользователь.
|
||||||
|
|
||||||
## 4. Работа с тестами
|
## 4. Работа с тестами
|
||||||
|
|
||||||
- Поведенческий тест проверяет пользовательский контракт, а не текущую
|
- Поведенческий тест проверяет пользовательский контракт, а не текущую
|
||||||
@@ -102,4 +121,10 @@ E2E запускается отдельно от быстрых проверок
|
|||||||
4. отдельно перечисляет warnings, fixme, долги и вопросы;
|
4. отдельно перечисляет warnings, fixme, долги и вопросы;
|
||||||
5. ждёт подтверждения на продолжение.
|
5. ждёт подтверждения на продолжение.
|
||||||
|
|
||||||
|
Коммит и пуш делает разработчик. После пуша агент проверяет результат CI и
|
||||||
|
сообщает его вместе с локальными проверками, включая случай, когда нужный job не
|
||||||
|
запускался: `Quality` workflow с browser matrix живёт на `pull_request` и
|
||||||
|
`workflow_dispatch`, поэтому прямой пуш в `main` проверяет только быстрый gate.
|
||||||
|
Процедура описана в `docs/quality-gates.md`.
|
||||||
|
|
||||||
Следующий шаг начинается только после ревью текущего изменения.
|
Следующий шаг начинается только после ревью текущего изменения.
|
||||||
|
|||||||
+10
-2
@@ -107,8 +107,9 @@
|
|||||||
|
|
||||||
## Качество production UI
|
## Качество production UI
|
||||||
|
|
||||||
Q5–Q6f.2 закрывают известные preview-проблемы, special fixtures, smoke и
|
Q5–Q6f.3 закрывают известные preview-проблемы, special fixtures, smoke,
|
||||||
layout/view-model инварианты; активных `test.fixme` в e2e больше нет.
|
layout/view-model инварианты и browser matrix; активных `test.fixme` в e2e
|
||||||
|
больше нет.
|
||||||
|
|
||||||
- [x] Генераторы auto-run без кнопки Generate — `web/e2e/generators.spec.ts`.
|
- [x] Генераторы auto-run без кнопки Generate — `web/e2e/generators.spec.ts`.
|
||||||
- [x] `resize-png` и `crop-png` используют размеры текущего source через общий
|
- [x] `resize-png` и `crop-png` используют размеры текущего source через общий
|
||||||
@@ -126,6 +127,13 @@ layout/view-model инварианты; активных `test.fixme` в e2e б
|
|||||||
unit-тестами; `SchemaFields.svelte` использует общий seam.
|
unit-тестами; `SchemaFields.svelte` использует общий seam.
|
||||||
- [x] `SchemaPreview` view-model вынесена в `buildSchemaPreviewModel` и покрыта
|
- [x] `SchemaPreview` view-model вынесена в `buildSchemaPreviewModel` и покрыта
|
||||||
unit-тестами для всех input/result-типов.
|
unit-тестами для всех input/result-типов.
|
||||||
|
- [x] Browser matrix: полный Chromium, Firefox/WebKit для browser-critical
|
||||||
|
спецификаций и mobile Chromium 390×844 — `web/playwright.config.ts`.
|
||||||
|
- [x] Расхождение декодеров зафиксировано как ожидаемое поведение: Firefox и
|
||||||
|
WebKit декодируют `truncated-no-iend` и `idat-cut`, а WebKit ещё и
|
||||||
|
`crc-bad-idat`. Таблица движков живёт в `web/e2e/png-fixtures.spec.ts`,
|
||||||
|
продукт не ужесточается, и любая выгрузка битого файла обязана давать
|
||||||
|
alert, а не падение или «пустой» результат.
|
||||||
- [ ] Component-тесты `SchemaToolView`/`SchemaPreview` требуют отдельного
|
- [ ] Component-тесты `SchemaToolView`/`SchemaPreview` требуют отдельного
|
||||||
решения: node Vitest не имеет DOM/canvas, а e2e уже покрывает поведение.
|
решения: node Vitest не имеет DOM/canvas, а e2e уже покрывает поведение.
|
||||||
- [ ] Ошибка декодирования изображения из `createImageBitmap` пока показывается
|
- [ ] Ошибка декодирования изображения из `createImageBitmap` пока показывается
|
||||||
|
|||||||
@@ -96,10 +96,10 @@
|
|||||||
корректный (не «кракозябры»).
|
корректный (не «кракозябры»).
|
||||||
- [ ] remove-background на сложной полупрозрачности — края не «звенят».
|
- [ ] remove-background на сложной полупрозрачности — края не «звенят».
|
||||||
|
|
||||||
## G. Закрытые Q5/Q6b/Q6c/Q6d/Q6e/Q6f.1/Q6f.2-проблемы
|
## G. Закрытые Q5/Q6b/Q6c/Q6d/Q6e/Q6f.1/Q6f.2/Q6f.3-проблемы
|
||||||
|
|
||||||
> Q5/Q6b/Q6c/Q6d/Q6e/Q6f.1/Q6f.2-проблемы закрыты автоматическими тестами; для
|
> Q5/Q6b/Q6c/Q6d/Q6e/Q6f.1/Q6f.2/Q6f.3-проблемы закрыты автоматическими тестами;
|
||||||
> ручной проверки остаются субъективные сценарии разделов A–F.
|
> для ручной проверки остаются субъективные сценарии разделов A–F.
|
||||||
|
|
||||||
- [x] **Генераторы:** auto-run по дефолтам, результат и изменение параметра без
|
- [x] **Генераторы:** auto-run по дефолтам, результат и изменение параметра без
|
||||||
кнопки Generate. `web/e2e/generators.spec.ts`.
|
кнопки Generate. `web/e2e/generators.spec.ts`.
|
||||||
@@ -124,6 +124,9 @@
|
|||||||
группировка полей использует тот же seam.
|
группировка полей использует тот же seam.
|
||||||
- [x] **Preview model:** `buildSchemaPreviewModel` покрывает source/result
|
- [x] **Preview model:** `buildSchemaPreviewModel` покрывает source/result
|
||||||
values, формат и `hasResult` для image/text/verdict/files.
|
values, формат и `hasResult` для image/text/verdict/files.
|
||||||
|
- [x] **Browser matrix:** pipeline, verdicts и PNG-fixtures проходят в Firefox и
|
||||||
|
WebKit, mobile viewport 390×844 — в Chromium; отказ декодера битого PNG
|
||||||
|
зафиксирован per-engine. См. раздел 7 `docs/testing-strategy.md`.
|
||||||
|
|
||||||
## Как долго
|
## Как долго
|
||||||
|
|
||||||
|
|||||||
@@ -1,9 +1,9 @@
|
|||||||
# План: линтеры, тесты и качество кодовой базы
|
# План: линтеры, тесты и качество кодовой базы
|
||||||
|
|
||||||
> Статус: **draft — Q0–Q5 и Q6a–Q6f.2 готовы к ревью; Q6f.3 — следующий этап**.
|
> Статус: **draft — Q0–Q5 и Q6a–Q6f.3 готовы к ревью; Q6f.4 — следующий этап**.
|
||||||
>
|
>
|
||||||
> Источник: `docs/backlog.md`, аудит конфигурации `web/`, e2e-тестов и
|
> Источник: `docs/backlog.md`, аудит конфигурации `web/`, e2e-тестов и
|
||||||
> инфраструктурных скриптов. Q0–Q5 и Q6a–Q6f.2 выполнены; Q6f.3–Q8 выполняются
|
> инфраструктурных скриптов. Q0–Q5 и Q6a–Q6f.3 выполнены; Q6f.4–Q8 выполняются
|
||||||
> отдельными атомарными шагами.
|
> отдельными атомарными шагами.
|
||||||
>
|
>
|
||||||
> Цель: сделать качество кодовой базы воспроизводимым, убрать ложную «зелёность»
|
> Цель: сделать качество кодовой базы воспроизводимым, убрать ложную «зелёность»
|
||||||
@@ -49,6 +49,9 @@
|
|||||||
resolver; активных known-issue `test.fixme` нет.
|
resolver; активных known-issue `test.fixme` нет.
|
||||||
- `ToolError` хранится как key/vars и переводится только при выводе; смена
|
- `ToolError` хранится как key/vars и переводится только при выводе; смена
|
||||||
локали обновляет уже видимый alert.
|
локали обновляет уже видимый alert.
|
||||||
|
- E2E гоняется в четырёх Playwright-проектах: полный Chromium, Firefox и WebKit
|
||||||
|
для browser-critical спецификаций и mobile Chromium 390×844. Job остаётся
|
||||||
|
non-blocking, число воркеров ограничено из-за памяти.
|
||||||
|
|
||||||
## 3. Этапы выполнения
|
## 3. Этапы выполнения
|
||||||
|
|
||||||
@@ -253,7 +256,12 @@ CRC/truncated отклоняются без падения, ancillary CRC и х
|
|||||||
|
|
||||||
- `web/e2e/helpers/fixtures.ts` собирает indexed, 16-bit, CRC-mutation,
|
- `web/e2e/helpers/fixtures.ts` собирает indexed, 16-bit, CRC-mutation,
|
||||||
truncation и tail-варианты из уже существующих `crc32`/`chunk`.
|
truncation и tail-варианты из уже существующих `crc32`/`chunk`.
|
||||||
- Проверки выполняются в Chromium; browser matrix остаётся Q6f.
|
- Отклонение битых файлов — свойство декодера движка, а не единый продуктовый
|
||||||
|
контракт: Q6f.3 зафиксировал, что Firefox и WebKit декодируют `idat-cut` и
|
||||||
|
`truncated-no-iend`, а WebKit ещё и `crc-bad-idat`. Это ожидаемое поведение,
|
||||||
|
которое закреплено per-engine в `web/e2e/png-fixtures.spec.ts`.
|
||||||
|
- Обязательное требование при любом исходе: файл не роняет страницу, ошибка
|
||||||
|
показывается alert-ом, а не «пустым» результатом.
|
||||||
- Поведение `createImageBitmap` является частью browser-контракта, а не
|
- Поведение `createImageBitmap` является частью browser-контракта, а не
|
||||||
самостоятельного PNG-парсера product-кода.
|
самостоятельного PNG-парсера product-кода.
|
||||||
- Сырое сообщение браузера при decode-ошибке не локализуется в Q6d; это
|
- Сырое сообщение браузера при decode-ошибке не локализуется в Q6d; это
|
||||||
@@ -298,9 +306,34 @@ image→image, image→text, text→image, generator input→image и verdict. F
|
|||||||
- image/text/verdict/files и пустые результаты покрыты в `pnpm verify`.
|
- image/text/verdict/files и пустые результаты покрыты в `pnpm verify`.
|
||||||
- Новые зависимости, vitest-конфиг и browser matrix не добавлялись.
|
- Новые зависимости, vitest-конфиг и browser matrix не добавлялись.
|
||||||
|
|
||||||
#### Q6f.3–Q6f.4. Оставшиеся направления
|
#### Q6f.3. Browser matrix и mobile viewport
|
||||||
|
|
||||||
- browser matrix, mobile viewport, visual snapshots и coverage thresholds;
|
**Статус:** выполнен. Playwright запускает четыре проекта: полный Chromium,
|
||||||
|
Firefox и WebKit для browser-critical спецификаций и mobile Chromium 390×844 с
|
||||||
|
`hasTouch` для навигации, каталога, генераторов и pipeline.
|
||||||
|
|
||||||
|
- `web/playwright.config.ts`: `browserContractTests` — `pipeline.spec.ts`,
|
||||||
|
`png-fixtures.spec.ts`, `text-and-verdicts.spec.ts`; `mobileTests` —
|
||||||
|
`navigation.spec.ts`, `catalog.spec.ts`, `generators.spec.ts`,
|
||||||
|
`pipeline.spec.ts`.
|
||||||
|
- `workers` — 1 локально и 2 в CI. Browser matrix ограничена памятью: при 12
|
||||||
|
воркерах на машине с 16 GB RAM браузеры не успевают поднять worker, и тесты
|
||||||
|
падают без ошибок (проверено и в Chromium). Локально matrix поэтому медленная,
|
||||||
|
но почти не нагружает компьютер. Per-project лимита воркеров в Playwright нет.
|
||||||
|
- Per-project `expect.timeout` не задаётся: Firefox и WebKit отдают результат
|
||||||
|
так же быстро, а расхождения объясняются памятью, а не скоростью движка.
|
||||||
|
- Декодеры движков расходятся, и это зафиксировано как ожидаемое поведение:
|
||||||
|
`png-fixtures.spec.ts` хранит список движков, отклоняющих каждый битый файл, и
|
||||||
|
не пропускает проверки. В любом браузере файл не должен ронять страницу, а
|
||||||
|
отказ декодера показывается alert-ом.
|
||||||
|
- CI устанавливает `chromium firefox webkit`; job остаётся non-blocking.
|
||||||
|
- Локальный прогон: 276 passed, 0 skipped, 0 failed. Visual snapshots и coverage
|
||||||
|
thresholds не добавлялись — это Q6f.4.
|
||||||
|
|
||||||
|
#### Q6f.4. Оставшиеся направления
|
||||||
|
|
||||||
|
- visual snapshots для kit/критичных экранов;
|
||||||
|
- coverage thresholds для `web/src/lib/`;
|
||||||
- при необходимости отдельное решение по DOM-тестам `SchemaToolView`/controls.
|
- при необходимости отдельное решение по DOM-тестам `SchemaToolView`/controls.
|
||||||
|
|
||||||
Не применять один одинаковый smoke-сценарий к image-, text-, generator- и
|
Не применять один одинаковый smoke-сценарий к image-, text-, generator- и
|
||||||
|
|||||||
@@ -40,6 +40,12 @@ download, темы или локализации. Изменения runtime fix
|
|||||||
`tests/fixtures/` не входят в `verify`. В текущем CI это отдельный non-blocking
|
`tests/fixtures/` не входят в `verify`. В текущем CI это отдельный non-blocking
|
||||||
baseline; после закрытия известных ошибок его можно сделать blocking.
|
baseline; после закрытия известных ошибок его можно сделать blocking.
|
||||||
|
|
||||||
|
Локально прогон идёт с `workers: 1` и заметно медленнее: это осознанный размен,
|
||||||
|
экономит память и оставляет компьютер отзывчивым. Playwright не умеет
|
||||||
|
per-project лимит воркеров, а browser matrix упирается в память, а не CPU.
|
||||||
|
Тяжёлые прогоны запускаются по команде пользователя — по одному, без фонового
|
||||||
|
запуска и циклов повторов; детали в `docs/agent-workflow.md`.
|
||||||
|
|
||||||
## Быстрые подмножества
|
## Быстрые подмножества
|
||||||
|
|
||||||
| Изменение | Команда |
|
| Изменение | Команда |
|
||||||
@@ -75,6 +81,52 @@ baseline; после закрытия известных ошибок его м
|
|||||||
`.github/workflows/deploy.yml` перед production build запускает тот же
|
`.github/workflows/deploy.yml` перед production build запускает тот же
|
||||||
`pnpm verify`, поэтому deploy не должен проходить при ошибке быстрых проверок.
|
`pnpm verify`, поэтому deploy не должен проходить при ошибке быстрых проверок.
|
||||||
|
|
||||||
|
### Что и когда запускается
|
||||||
|
|
||||||
|
| Workflow | Триггер | Jobs |
|
||||||
|
| ------------------------ | ------------------------ | --------------------------- |
|
||||||
|
| `Deploy to GitHub Pages` | push в `main`, dispatch | `verify`, `build`, `deploy` |
|
||||||
|
| `Quality` | `pull_request`, dispatch | `verify`, `e2e` |
|
||||||
|
|
||||||
|
Следствие: при прямом пуше в `main` выполняется только быстрый gate — `verify`
|
||||||
|
внутри deploy-workflow. Browser matrix из четырёх проектов на этом прогоне не
|
||||||
|
запускается вообще, поэтому зелёный deploy-run нельзя читать как «e2e прошёл».
|
||||||
|
|
||||||
|
### Проверка результатов CI после пуша
|
||||||
|
|
||||||
|
Первый реальный прогон browser matrix происходит на runner, а не на локальной
|
||||||
|
машине: локально Firefox и WebKit проходят на 1 воркере, но состав, скорость и
|
||||||
|
память Linux-раннера отличаются. Поэтому после пуша разработчика:
|
||||||
|
|
||||||
|
1. дождаться завершения workflow и посмотреть, какие job вообще запустились;
|
||||||
|
2. отдельно открыть non-blocking `e2e`, если он был в прогоне: его красный
|
||||||
|
статус не блокирует PR, но остаётся падением, и его нельзя выдавать за
|
||||||
|
«зелёный по умолчанию»;
|
||||||
|
3. если `e2e` не запускался (прямой пуш в `main`), сказать это прямо: matrix на
|
||||||
|
раннере ещё не проверена, и её можно прогнать через PR или
|
||||||
|
`gh workflow run quality.yml`;
|
||||||
|
4. сообщить фактический результат (passed, failed, skipped) в отчёте агента.
|
||||||
|
|
||||||
|
Красный `e2e` только из-за ресурсов раннера фиксируется как ограничение
|
||||||
|
окружения: сначала проверяется один проект и один spec, а не увеличиваются
|
||||||
|
таймауты под конкретную машину.
|
||||||
|
|
||||||
|
### Измеренная стоимость прогона
|
||||||
|
|
||||||
|
Замер на ручном запуске `quality.yml` (276 e2e-тестов, 4 проекта,
|
||||||
|
ubuntu-latest):
|
||||||
|
|
||||||
|
| Этап | Время |
|
||||||
|
| ----------------- | -------- |
|
||||||
|
| `verify` job | ~1 мин |
|
||||||
|
| `e2e` job целиком | ~3.1 мин |
|
||||||
|
| из них сами тесты | ~2.2 мин |
|
||||||
|
| весь run | ~4.2 мин |
|
||||||
|
|
||||||
|
Browser matrix стоит около трёх минут, поэтому её дешёво держать на каждом PR.
|
||||||
|
Полный прогон локально на 1 воркере — заметно дольше (~7 мин), и именно поэтому
|
||||||
|
локальные правила нагрузки описаны в `docs/agent-workflow.md`.
|
||||||
|
|
||||||
## Локальная диагностика
|
## Локальная диагностика
|
||||||
|
|
||||||
При медленном полном прогоне сначала запускай минимальную команду из таблицы, а
|
При медленном полном прогоне сначала запускай минимальную команду из таблицы, а
|
||||||
|
|||||||
@@ -54,10 +54,14 @@ CSS-классы и конкретный формат временного URL
|
|||||||
Изображения создаются воспроизводимыми helpers в `web/e2e/helpers/fixtures.ts`.
|
Изображения создаются воспроизводимыми helpers в `web/e2e/helpers/fixtures.ts`.
|
||||||
Тесты не добавляют большие бинарные файлы и не зависят от локальных
|
Тесты не добавляют большие бинарные файлы и не зависят от локальных
|
||||||
пользовательских файлов. Runtime-fixtures для malformed/special PNG проверяют
|
пользовательских файлов. Runtime-fixtures для malformed/special PNG проверяют
|
||||||
browser-контракт: critical CRC и truncated отклоняются, ancillary CRC и хвост
|
browser-контракт: critical CRC и truncated отклоняются движком, ancillary CRC и
|
||||||
после `IEND` допускаются, palette/16-bit декодируются. `toPass()` допускается
|
хвост после `IEND` допускаются, palette/16-bit декодируются. Отказ декодера —
|
||||||
только для ограниченного ожидания hydration или асинхронного результата; он не
|
свойство движка, поэтому ожидание задаётся per-engine в
|
||||||
должен превращать проверку продукта в бесконечный retry.
|
`web/e2e/png-fixtures.spec.ts`, а не через skip. Общее требование для всех
|
||||||
|
движков: битый файл не роняет страницу, отказ показывается alert-ом, а успешный
|
||||||
|
декод даёт результат без ошибки. `toPass()` допускается только для ограниченного
|
||||||
|
ожидания hydration или асинхронного результата; он не должен превращать проверку
|
||||||
|
продукта в бесконечный retry.
|
||||||
|
|
||||||
Чистая логика схемы, layout и preview-модели (defaults, sanitization,
|
Чистая логика схемы, layout и preview-модели (defaults, sanitization,
|
||||||
`resolveLayoutGroups`, `buildSchemaPreviewModel`) проверяется в
|
`resolveLayoutGroups`, `buildSchemaPreviewModel`) проверяется в
|
||||||
@@ -78,6 +82,11 @@ text — `renderText` + результат, generator — auto-run без upload
|
|||||||
checklist. В комментарии указывается ссылка на неё. После исправления тест и
|
checklist. В комментарии указывается ссылка на неё. После исправления тест и
|
||||||
ссылка обновляются вместе; в текущем Q6e baseline активных fixme нет.
|
ссылка обновляются вместе; в текущем Q6e baseline активных fixme нет.
|
||||||
|
|
||||||
|
Если тест сравнивает два состояния одного элемента, он ждёт изменения значения
|
||||||
|
(`not.toHaveText`, `not.toHaveAttribute`), а не его видимости. Пересчёт идёт
|
||||||
|
через debounce, поэтому `toBeVisible()` после второго ввода проходит на старом
|
||||||
|
значении. Такой тест флакает по таймингу и обычно ловится на CI, а не локально.
|
||||||
|
|
||||||
## 6. Проверки
|
## 6. Проверки
|
||||||
|
|
||||||
Для изменений e2e выполняются:
|
Для изменений e2e выполняются:
|
||||||
@@ -95,3 +104,38 @@ pnpm verify
|
|||||||
`verify` не включает Playwright: E2E остаётся отдельным тяжёлым gate. В CI
|
`verify` не включает Playwright: E2E остаётся отдельным тяжёлым gate. В CI
|
||||||
non-blocking E2E не считается заменой локальному smoke; перед ревью фиксируются
|
non-blocking E2E не считается заменой локальному smoke; перед ревью фиксируются
|
||||||
число passed, skipped и известные fixme.
|
число passed, skipped и известные fixme.
|
||||||
|
|
||||||
|
## 7. Browser matrix
|
||||||
|
|
||||||
|
`web/playwright.config.ts` запускает четыре проекта:
|
||||||
|
|
||||||
|
| Проект | Движок | Спецификации |
|
||||||
|
| ----------------- | -------- | ---------------------------------------------------------------------- |
|
||||||
|
| `chromium` | Chromium | все e2e |
|
||||||
|
| `firefox` | Firefox | `pipeline`, `png-fixtures`, `text-and-verdicts` |
|
||||||
|
| `webkit` | WebKit | `pipeline`, `png-fixtures`, `text-and-verdicts` |
|
||||||
|
| `mobile-chromium` | Chromium | `navigation`, `catalog`, `generators`, `pipeline`, 390×844, `hasTouch` |
|
||||||
|
|
||||||
|
- Новые engine-специфичные фичи сначала добавляются в `chromium`, потом
|
||||||
|
решается, попадает ли spec в `browserContractTests`.
|
||||||
|
- Расхождения декодеров не ужесточаются и не скрываются skip-ом: они описаны в
|
||||||
|
тесте как ожидаемое поведение движка.
|
||||||
|
|
||||||
|
| Fixture | Отклоняют |
|
||||||
|
| ------------------------------------ | ------------------------- |
|
||||||
|
| `crc-bad-idat.png` | Chromium, Firefox |
|
||||||
|
| `truncated-header.png` | Chromium, Firefox, WebKit |
|
||||||
|
| `truncated-no-iend.png` | Chromium |
|
||||||
|
| `idat-cut.png` | Chromium |
|
||||||
|
| ancillary CRC, tail, palette, 16-bit | ни один движок |
|
||||||
|
|
||||||
|
- Firefox и WebKit работают с теми же таймаутами, что и Chromium: движок не
|
||||||
|
причина расхождений, поэтому per-project `expect.timeout` не задаётся.
|
||||||
|
- `workers` — 1 локально и 2 в CI. Playwright не умеет per-project лимит
|
||||||
|
воркеров, а browser matrix ограничена памятью, а не CPU: при высокой
|
||||||
|
параллельности браузеры на машине с 16 GB RAM не успевают поднять worker, и
|
||||||
|
тесты падают без ошибок. Локальный matrix поэтому медленный, но не нагружает
|
||||||
|
компьютер.
|
||||||
|
- Локальный baseline: 276 тестов, 276 passed, 0 skipped, 0 failed.
|
||||||
|
- Visual snapshots и coverage thresholds не часть matrix; они вынесены в
|
||||||
|
`docs/plan-codebase-quality.md` (Q6f.4).
|
||||||
|
|||||||
@@ -39,31 +39,34 @@ async function expectAccepted(page: Page, file: SourceFile): Promise<void> {
|
|||||||
expectNoErrors(sink);
|
expectNoErrors(sink);
|
||||||
}
|
}
|
||||||
|
|
||||||
const rejectedFixtures = [
|
type DecodeContract = {
|
||||||
crcBadIdatPng,
|
file: SourceFile;
|
||||||
truncatedHeaderPng,
|
rejectedIn: readonly string[];
|
||||||
truncatedNoIendPng,
|
};
|
||||||
idatCutPng,
|
|
||||||
];
|
|
||||||
|
|
||||||
const acceptedFixtures = [
|
const decodeContracts: readonly DecodeContract[] = [
|
||||||
crcBadAncillaryPng,
|
{ file: crcBadIdatPng, rejectedIn: ["chromium", "firefox"] },
|
||||||
garbageTailPng,
|
{ file: truncatedHeaderPng, rejectedIn: ["chromium", "firefox", "webkit"] },
|
||||||
palette4Png,
|
{ file: truncatedNoIendPng, rejectedIn: ["chromium"] },
|
||||||
palette256Png,
|
{ file: idatCutPng, rejectedIn: ["chromium"] },
|
||||||
sixteenBitPng,
|
{ file: crcBadAncillaryPng, rejectedIn: [] },
|
||||||
|
{ file: garbageTailPng, rejectedIn: [] },
|
||||||
|
{ file: palette4Png, rejectedIn: [] },
|
||||||
|
{ file: palette256Png, rejectedIn: [] },
|
||||||
|
{ file: sixteenBitPng, rejectedIn: [] },
|
||||||
];
|
];
|
||||||
|
|
||||||
test.describe("PNG special fixtures", () => {
|
test.describe("PNG special fixtures", () => {
|
||||||
for (const file of rejectedFixtures) {
|
for (const { file, rejectedIn } of decodeContracts) {
|
||||||
test(`${file.name}: shows an error without a result`, async ({ page }) => {
|
test(`${file.name}: matches the engine decode contract`, async ({
|
||||||
await expectRejected(page, file);
|
browserName,
|
||||||
});
|
page,
|
||||||
}
|
}) => {
|
||||||
|
if (rejectedIn.includes(browserName)) {
|
||||||
for (const file of acceptedFixtures) {
|
await expectRejected(page, file);
|
||||||
test(`${file.name}: decodes without an error`, async ({ page }) => {
|
} else {
|
||||||
await expectAccepted(page, file);
|
await expectAccepted(page, file);
|
||||||
|
}
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|||||||
@@ -68,9 +68,7 @@ test("verify-is-png renders different verdicts for valid and invalid input", asy
|
|||||||
const validText = await verdict.textContent();
|
const validText = await verdict.textContent();
|
||||||
|
|
||||||
await renderText(page, "aGVsbG8=");
|
await renderText(page, "aGVsbG8=");
|
||||||
await expect(verdict).toBeVisible();
|
await expect(verdict).not.toHaveText(validText ?? "");
|
||||||
const invalidText = await verdict.textContent();
|
|
||||||
expect(invalidText).not.toBe(validText);
|
|
||||||
});
|
});
|
||||||
|
|
||||||
test("png-is-transparent: opaque image renders a verdict", async ({ page }) => {
|
test("png-is-transparent: opaque image renders a verdict", async ({ page }) => {
|
||||||
|
|||||||
@@ -1,11 +1,25 @@
|
|||||||
import { defineConfig } from "playwright/test";
|
import { defineConfig } from "playwright/test";
|
||||||
|
|
||||||
|
const browserContractTests = [
|
||||||
|
"**/pipeline.spec.ts",
|
||||||
|
"**/png-fixtures.spec.ts",
|
||||||
|
"**/text-and-verdicts.spec.ts",
|
||||||
|
];
|
||||||
|
|
||||||
|
const mobileTests = [
|
||||||
|
"**/navigation.spec.ts",
|
||||||
|
"**/catalog.spec.ts",
|
||||||
|
"**/generators.spec.ts",
|
||||||
|
"**/pipeline.spec.ts",
|
||||||
|
];
|
||||||
|
|
||||||
export default defineConfig({
|
export default defineConfig({
|
||||||
testDir: "./e2e",
|
testDir: "./e2e",
|
||||||
outputDir: "./e2e-results",
|
outputDir: "./e2e-results",
|
||||||
fullyParallel: true,
|
fullyParallel: true,
|
||||||
timeout: 60_000,
|
timeout: 60_000,
|
||||||
retries: 0,
|
retries: 0,
|
||||||
|
workers: process.env.CI ? 2 : 1,
|
||||||
reporter: [["list"], ["html", { open: "never" }]],
|
reporter: [["list"], ["html", { open: "never" }]],
|
||||||
use: {
|
use: {
|
||||||
baseURL: "http://127.0.0.1:4173",
|
baseURL: "http://127.0.0.1:4173",
|
||||||
@@ -19,6 +33,31 @@ export default defineConfig({
|
|||||||
viewport: { width: 1440, height: 900 },
|
viewport: { width: 1440, height: 900 },
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
|
{
|
||||||
|
name: "firefox",
|
||||||
|
testMatch: browserContractTests,
|
||||||
|
use: {
|
||||||
|
browserName: "firefox",
|
||||||
|
viewport: { width: 1440, height: 900 },
|
||||||
|
},
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: "webkit",
|
||||||
|
testMatch: browserContractTests,
|
||||||
|
use: {
|
||||||
|
browserName: "webkit",
|
||||||
|
viewport: { width: 1440, height: 900 },
|
||||||
|
},
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: "mobile-chromium",
|
||||||
|
testMatch: mobileTests,
|
||||||
|
use: {
|
||||||
|
browserName: "chromium",
|
||||||
|
viewport: { width: 390, height: 844 },
|
||||||
|
hasTouch: true,
|
||||||
|
},
|
||||||
|
},
|
||||||
],
|
],
|
||||||
webServer: {
|
webServer: {
|
||||||
command: "pnpm build && node scripts/serve-static.mjs --port 4173",
|
command: "pnpm build && node scripts/serve-static.mjs --port 4173",
|
||||||
|
|||||||
Reference in New Issue
Block a user