diff --git a/.github/workflows/quality.yml b/.github/workflows/quality.yml index d50cd23..9604402 100644 --- a/.github/workflows/quality.yml +++ b/.github/workflows/quality.yml @@ -68,9 +68,9 @@ jobs: working-directory: web run: pnpm install --frozen-lockfile - - name: Install Chromium + - name: Install Playwright browsers working-directory: web - run: pnpm exec playwright install --with-deps chromium + run: pnpm exec playwright install --with-deps chromium firefox webkit - name: Run E2E working-directory: web diff --git a/AGENTS.md b/AGENTS.md index c168c52..715ee53 100644 --- a/AGENTS.md +++ b/AGENTS.md @@ -18,6 +18,12 @@ (docs) + `pnpm --dir web exec prettier --check .` (код). - Полный быстрый gate: `pnpm verify`; подробная матрица команд и CI — `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:all` (ESLint + stylelint + токен-аудит). Каждый шаг выполняется, даже если предыдущий упал. Новые изменения не должны добавлять @@ -42,6 +48,10 @@ - `test.fixme` допускается только для зарегистрированной задачи в backlog или checklist; после исправления тест и ссылку обновляют вместе. - Полные переводы проверяются в unit-тестах; e2e проверяет поведение. +- Playwright-прогоны запускаются только по явной команде пользователя, по одному + прогону, без циклов повторов и без фонового запуска: локально matrix идёт с + `workers: 1`. Отзывчивость компьютера пользователя важнее скорости проверки — + подробности в `docs/agent-workflow.md`. ### Сначала искать @@ -56,7 +66,8 @@ Описание нового визуального языка — в `docs/plan-redesign.md`. Общие правила, которые линтер не проверяет: -- Новый дизайн живёт в `web/src/app.css` и применяется ко всем production-маршрутам. +- Новый дизайн живёт в `web/src/app.css` и применяется ко всем + production-маршрутам. - Все повторяющиеся визуальные элементы — отдельные компоненты в `web/src/lib/components/`, даже «просто div с двумя стилями». - Дизайн-токены (цвета, размеры, длительности, z-index) — только из diff --git a/docs/README.md b/docs/README.md index adf9b07..16d81a1 100644 --- a/docs/README.md +++ b/docs/README.md @@ -51,9 +51,9 @@ только если темы нет в существующем документе; иначе обновляется источник истины. -## Текущий baseline Q6f.2 +## Текущий baseline Q6f.3 -На момент фиксации Q6f.2: +На момент фиксации Q6f.3: - production registry содержит 122 инструмента; - `pnpm --dir web check` проходит без ошибок и предупреждений; @@ -61,7 +61,10 @@ - `pnpm --dir web test:rules` — 4 test files / 74 tests; - `pnpm --dir web lint:all` — 0 errors и 0 i18n warnings; остаются 4 unused 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`. diff --git a/docs/agent-workflow.md b/docs/agent-workflow.md index 4fbb97a..5d13b8b 100644 --- a/docs/agent-workflow.md +++ b/docs/agent-workflow.md @@ -49,6 +49,25 @@ E2E запускается отдельно от быстрых проверок статический сервер. Для UI-изменений сначала выбирается минимальный пользовательский поток, затем при необходимости расширяется smoke. +### Нагрузка на машину + +Агент работает на компьютере пользователя, поэтому тяжёлые прогоны не +запускаются «по умолчанию»: + +- Playwright-прогоны запускаются только по явной команде пользователя: один + прогон за раз, без циклов повторов и без фонового запуска. +- Локально `workers: 1` (`web/playwright.config.ts`). Browser matrix из четырёх + проектов проходит медленно, зато не забирает память и не мешает работе + пользователя. Скорость проверки уступает отзывчивости компьютера. +- Нельзя запускать тяжёлый прогон параллельно с другим прогоном или в момент, + когда пользователь работает с приложением. +- Диагностика флаков идёт от меньшего к большему: один spec, один проект, + `--workers=1`, и только затем полный прогон. +- Таймауты не подбираются под конкретную машину. Если проверка падает из-за + нехватки ресурсов, это фиксируется как ограничение окружения, а не лечится + увеличением `expect.timeout`. +- При необходимости повторного прогона сначала спрашивается пользователь. + ## 4. Работа с тестами - Поведенческий тест проверяет пользовательский контракт, а не текущую @@ -102,4 +121,10 @@ E2E запускается отдельно от быстрых проверок 4. отдельно перечисляет warnings, fixme, долги и вопросы; 5. ждёт подтверждения на продолжение. +Коммит и пуш делает разработчик. После пуша агент проверяет результат CI и +сообщает его вместе с локальными проверками, включая случай, когда нужный job не +запускался: `Quality` workflow с browser matrix живёт на `pull_request` и +`workflow_dispatch`, поэтому прямой пуш в `main` проверяет только быстрый gate. +Процедура описана в `docs/quality-gates.md`. + Следующий шаг начинается только после ревью текущего изменения. diff --git a/docs/backlog.md b/docs/backlog.md index 4c6b0f0..c68a18b 100644 --- a/docs/backlog.md +++ b/docs/backlog.md @@ -107,8 +107,9 @@ ## Качество production UI -Q5–Q6f.2 закрывают известные preview-проблемы, special fixtures, smoke и -layout/view-model инварианты; активных `test.fixme` в e2e больше нет. +Q5–Q6f.3 закрывают известные preview-проблемы, special fixtures, smoke, +layout/view-model инварианты и browser matrix; активных `test.fixme` в e2e +больше нет. - [x] Генераторы auto-run без кнопки Generate — `web/e2e/generators.spec.ts`. - [x] `resize-png` и `crop-png` используют размеры текущего source через общий @@ -126,6 +127,13 @@ layout/view-model инварианты; активных `test.fixme` в e2e б unit-тестами; `SchemaFields.svelte` использует общий seam. - [x] `SchemaPreview` view-model вынесена в `buildSchemaPreviewModel` и покрыта 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` требуют отдельного решения: node Vitest не имеет DOM/canvas, а e2e уже покрывает поведение. - [ ] Ошибка декодирования изображения из `createImageBitmap` пока показывается diff --git a/docs/checklist-manual-testing.md b/docs/checklist-manual-testing.md index f5cb703..3f40f68 100644 --- a/docs/checklist-manual-testing.md +++ b/docs/checklist-manual-testing.md @@ -96,10 +96,10 @@ корректный (не «кракозябры»). - [ ] 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-проблемы закрыты автоматическими тестами; для -> ручной проверки остаются субъективные сценарии разделов A–F. +> Q5/Q6b/Q6c/Q6d/Q6e/Q6f.1/Q6f.2/Q6f.3-проблемы закрыты автоматическими тестами; +> для ручной проверки остаются субъективные сценарии разделов A–F. - [x] **Генераторы:** auto-run по дефолтам, результат и изменение параметра без кнопки Generate. `web/e2e/generators.spec.ts`. @@ -124,6 +124,9 @@ группировка полей использует тот же seam. - [x] **Preview model:** `buildSchemaPreviewModel` покрывает source/result 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`. ## Как долго diff --git a/docs/plan-codebase-quality.md b/docs/plan-codebase-quality.md index 6550820..ea9e1ec 100644 --- a/docs/plan-codebase-quality.md +++ b/docs/plan-codebase-quality.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-тестов и -> инфраструктурных скриптов. 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` нет. - `ToolError` хранится как key/vars и переводится только при выводе; смена локали обновляет уже видимый alert. +- E2E гоняется в четырёх Playwright-проектах: полный Chromium, Firefox и WebKit + для browser-critical спецификаций и mobile Chromium 390×844. Job остаётся + non-blocking, число воркеров ограничено из-за памяти. ## 3. Этапы выполнения @@ -253,7 +256,12 @@ CRC/truncated отклоняются без падения, ancillary CRC и х - `web/e2e/helpers/fixtures.ts` собирает indexed, 16-bit, CRC-mutation, 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-контракта, а не самостоятельного PNG-парсера product-кода. - Сырое сообщение браузера при decode-ошибке не локализуется в Q6d; это @@ -298,9 +306,34 @@ image→image, image→text, text→image, generator input→image и verdict. F - image/text/verdict/files и пустые результаты покрыты в `pnpm verify`. - Новые зависимости, 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. Не применять один одинаковый smoke-сценарий к image-, text-, generator- и diff --git a/docs/quality-gates.md b/docs/quality-gates.md index 13a7f03..5b5c3e8 100644 --- a/docs/quality-gates.md +++ b/docs/quality-gates.md @@ -40,6 +40,12 @@ download, темы или локализации. Изменения runtime fix `tests/fixtures/` не входят в `verify`. В текущем CI это отдельный non-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 запускает тот же `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`. + ## Локальная диагностика При медленном полном прогоне сначала запускай минимальную команду из таблицы, а diff --git a/docs/testing-strategy.md b/docs/testing-strategy.md index a0909b3..55e0d39 100644 --- a/docs/testing-strategy.md +++ b/docs/testing-strategy.md @@ -54,10 +54,14 @@ CSS-классы и конкретный формат временного URL Изображения создаются воспроизводимыми helpers в `web/e2e/helpers/fixtures.ts`. Тесты не добавляют большие бинарные файлы и не зависят от локальных пользовательских файлов. Runtime-fixtures для malformed/special PNG проверяют -browser-контракт: critical CRC и truncated отклоняются, ancillary CRC и хвост -после `IEND` допускаются, palette/16-bit декодируются. `toPass()` допускается -только для ограниченного ожидания hydration или асинхронного результата; он не -должен превращать проверку продукта в бесконечный retry. +browser-контракт: critical CRC и truncated отклоняются движком, ancillary CRC и +хвост после `IEND` допускаются, palette/16-bit декодируются. Отказ декодера — +свойство движка, поэтому ожидание задаётся per-engine в +`web/e2e/png-fixtures.spec.ts`, а не через skip. Общее требование для всех +движков: битый файл не роняет страницу, отказ показывается alert-ом, а успешный +декод даёт результат без ошибки. `toPass()` допускается только для ограниченного +ожидания hydration или асинхронного результата; он не должен превращать проверку +продукта в бесконечный retry. Чистая логика схемы, layout и preview-модели (defaults, sanitization, `resolveLayoutGroups`, `buildSchemaPreviewModel`) проверяется в @@ -78,6 +82,11 @@ text — `renderText` + результат, generator — auto-run без upload checklist. В комментарии указывается ссылка на неё. После исправления тест и ссылка обновляются вместе; в текущем Q6e baseline активных fixme нет. +Если тест сравнивает два состояния одного элемента, он ждёт изменения значения +(`not.toHaveText`, `not.toHaveAttribute`), а не его видимости. Пересчёт идёт +через debounce, поэтому `toBeVisible()` после второго ввода проходит на старом +значении. Такой тест флакает по таймингу и обычно ловится на CI, а не локально. + ## 6. Проверки Для изменений e2e выполняются: @@ -95,3 +104,38 @@ pnpm verify `verify` не включает Playwright: E2E остаётся отдельным тяжёлым gate. В CI non-blocking E2E не считается заменой локальному smoke; перед ревью фиксируются число 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). diff --git a/web/e2e/png-fixtures.spec.ts b/web/e2e/png-fixtures.spec.ts index 6536b61..8123283 100644 --- a/web/e2e/png-fixtures.spec.ts +++ b/web/e2e/png-fixtures.spec.ts @@ -39,31 +39,34 @@ async function expectAccepted(page: Page, file: SourceFile): Promise { expectNoErrors(sink); } -const rejectedFixtures = [ - crcBadIdatPng, - truncatedHeaderPng, - truncatedNoIendPng, - idatCutPng, -]; +type DecodeContract = { + file: SourceFile; + rejectedIn: readonly string[]; +}; -const acceptedFixtures = [ - crcBadAncillaryPng, - garbageTailPng, - palette4Png, - palette256Png, - sixteenBitPng, +const decodeContracts: readonly DecodeContract[] = [ + { file: crcBadIdatPng, rejectedIn: ["chromium", "firefox"] }, + { file: truncatedHeaderPng, rejectedIn: ["chromium", "firefox", "webkit"] }, + { file: truncatedNoIendPng, rejectedIn: ["chromium"] }, + { file: idatCutPng, rejectedIn: ["chromium"] }, + { file: crcBadAncillaryPng, rejectedIn: [] }, + { file: garbageTailPng, rejectedIn: [] }, + { file: palette4Png, rejectedIn: [] }, + { file: palette256Png, rejectedIn: [] }, + { file: sixteenBitPng, rejectedIn: [] }, ]; test.describe("PNG special fixtures", () => { - for (const file of rejectedFixtures) { - test(`${file.name}: shows an error without a result`, async ({ page }) => { - await expectRejected(page, file); - }); - } - - for (const file of acceptedFixtures) { - test(`${file.name}: decodes without an error`, async ({ page }) => { - await expectAccepted(page, file); + for (const { file, rejectedIn } of decodeContracts) { + test(`${file.name}: matches the engine decode contract`, async ({ + browserName, + page, + }) => { + if (rejectedIn.includes(browserName)) { + await expectRejected(page, file); + } else { + await expectAccepted(page, file); + } }); } }); diff --git a/web/e2e/text-and-verdicts.spec.ts b/web/e2e/text-and-verdicts.spec.ts index 8a3b6f2..6b03488 100644 --- a/web/e2e/text-and-verdicts.spec.ts +++ b/web/e2e/text-and-verdicts.spec.ts @@ -68,9 +68,7 @@ test("verify-is-png renders different verdicts for valid and invalid input", asy const validText = await verdict.textContent(); await renderText(page, "aGVsbG8="); - await expect(verdict).toBeVisible(); - const invalidText = await verdict.textContent(); - expect(invalidText).not.toBe(validText); + await expect(verdict).not.toHaveText(validText ?? ""); }); test("png-is-transparent: opaque image renders a verdict", async ({ page }) => { diff --git a/web/playwright.config.ts b/web/playwright.config.ts index f0236b7..6df7cb4 100644 --- a/web/playwright.config.ts +++ b/web/playwright.config.ts @@ -1,11 +1,25 @@ 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({ testDir: "./e2e", outputDir: "./e2e-results", fullyParallel: true, timeout: 60_000, retries: 0, + workers: process.env.CI ? 2 : 1, reporter: [["list"], ["html", { open: "never" }]], use: { baseURL: "http://127.0.0.1:4173", @@ -19,6 +33,31 @@ export default defineConfig({ 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: { command: "pnpm build && node scripts/serve-static.mjs --port 4173",