docling-studio/e2e/ui/README.md
Pier-Jean Malandrino fdbab2f49e feat: add Karate UI e2e tests with data-e2e selectors (#124)
- Add e2e/ui/ as peer project to e2e/api/ (own pom.xml, runner, config)
- 5 critical UI journeys: upload, delete, analysis, batch-progress, rechunk
- 4 local-only tests: sidebar, i18n, error-states, pipeline-options
- 1 full happy path workflow covering all modes
- Add data-e2e attributes on all tested Vue components (decoupled from CSS)
- Add CONVENTIONS.md with 7 golden rules for writing Karate UI tests
- Update CI with dedicated e2e-ui job (Chrome headless, --no-sandbox)
- Update docs/contributing.md with UI test instructions

Closes #124
2026-04-08 17:53:52 +02:00

93 lines
3.3 KiB
Markdown

# E2E UI Tests — Karate UI
Browser-based end-to-end tests for Docling Studio using [Karate UI](https://karatelabs.github.io/karate/karate-core/#ui-automation) (Chrome headless).
## Prerequisites
- **JDK 17+** (e.g. `brew install openjdk@17`)
- **Maven 3.9+** (e.g. `brew install maven`)
- **Google Chrome** (headless, auto-detected)
- **Python 3.12+** (for test data generation)
- **Docker** (for running the full stack)
## Quick start
```bash
# 1. Generate test PDFs (from repo root)
python e2e/generate-test-data.py
# 2. Start the stack
docker compose up -d --wait
# 3. Run all UI tests
mvn test -f e2e/ui/pom.xml
# 4. Tear down
docker compose down
```
## Run by tag
```bash
# Critical only — CI scope (~1min30)
mvn test -f e2e/ui/pom.xml -Dkarate.options="--tags @critical"
# All UI tests — local scope (~3min)
mvn test -f e2e/ui/pom.xml -Dkarate.options="--tags @ui"
```
## Custom URLs
```bash
mvn test -f e2e/ui/pom.xml -DbaseUrl=http://your-host:8000 -DuiBaseUrl=http://your-host:3000
```
## Structure
```
e2e/ui/
├── pom.xml # Maven + Karate dependency
├── src/test/java/
│ └── UIRunner.java # JUnit5 Karate runner
└── src/test/resources/
├── karate-config.js # URLs, timeouts, Chrome driver config
├── common/helpers/
│ ├── upload.feature # API helper — upload (setup)
│ ├── analyze.feature # API helper — analyze (setup)
│ ├── cleanup.feature # API helper — delete (teardown)
│ ├── ui-upload.feature # UI helper — upload via file input
│ └── ui-wait-analysis.feature # UI helper — poll for completion
├── documents/ # @critical @ui
│ ├── upload.feature # Upload + preview
│ ├── delete.feature # Delete via hover + click
│ └── error-states.feature # Non-PDF rejection, hints
├── analyses/ # @critical @ui
│ ├── analysis.feature # Run analysis, verify tabs
│ ├── batch-progress.feature # Progress bar on multi-page
│ ├── rechunk.feature # Prepare mode, rechunk
│ └── pipeline-options.feature # OCR, table mode toggles
├── navigation/ # @ui
│ ├── sidebar.feature # Sidebar navigation
│ └── i18n.feature # FR/EN language switch
└── workflows/ # @ui
└── full-ui-path.feature # Complete happy path via browser
```
## Tags
| Tag | Scope | When |
|-----|-------|------|
| `@critical` | 5 features, 6 scenarios | CI on `main` branch |
| `@ui` | All UI features | Local development |
## Design patterns
- **Setup via API, verify via UI** — fast setup with API helpers, then browser assertions
- **Cleanup via API** — `cleanup.feature` deletes test data after each scenario
- **Polling with `optional()`** — graceful handling of fast completions (no `waitFor` on spinners that may flash)
- **`data-e2e` selectors** — `[data-e2e=doc-item]` instead of `.doc-item` — decoupled from CSS, never breaks on style refactors
- **`karate.sizeOf()` for counts** — `karate.sizeOf(locateAll('[data-e2e=xxx]'))` instead of raw `.length` or `script()`
## Reports
After a run, Karate HTML reports are in `e2e/ui/target/karate-reports/`.