docling-studio/e2e/ui/src/test/resources/workflows/full-ui-path.feature
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

79 lines
2.7 KiB
Gherkin

@ui
Feature: UI — Full happy path via browser
Background:
* url baseUrl
Scenario: Complete workflow — upload, analyze, verify results, rechunk, delete — all via UI
# Step 1: Open Studio page
* driver uiBaseUrl + '/studio'
* waitFor('[data-e2e=upload-zone]')
# Step 2: Upload a PDF via UI
* def filePath = karate.toAbsolutePath('classpath:common/data/generated/medium.pdf')
* driver.inputFile('input[type=file]', filePath)
# Step 3: Verify document appears in doc list
* waitFor('[data-e2e=doc-item]')
* match text('[data-e2e=doc-name]') contains 'medium.pdf'
# Step 4: Select the document
* click('[data-e2e=doc-item]')
* waitFor('[data-e2e=doc-item].selected')
# Step 5: Verify Configure mode is active
* waitFor('[data-e2e=toggle-btn].active')
# Step 6: Run the analysis
* click('[data-e2e=run-btn]')
# Step 7: Wait for analysis to complete
* call read('classpath:common/helpers/ui-wait-analysis.feature')
# Step 8: Verify results — tabs and content
* waitFor('[data-e2e=result-tabs]')
* match karate.sizeOf(locateAll('[data-e2e=tab-btn]')) == 3
# Check Elements tab has content
* def tabs = locateAll('[data-e2e=tab-btn]')
* tabs[0].click()
* waitFor('[data-e2e=elements-list]')
* assert karate.sizeOf(locateAll('[data-e2e=element-card]')) > 0
# Check Markdown tab has content
* tabs[1].click()
* waitFor('[data-e2e=raw-markdown]')
* match text('[data-e2e=raw-content]') != ''
# Step 9: Switch to Préparer mode and rechunk
* def toggleBtns = locateAll('[data-e2e=toggle-btn]')
* toggleBtns[karate.sizeOf(toggleBtns) - 1].click()
* waitFor('[data-e2e=chunk-panel]')
# Expand config if needed
* def chevronOpen = optional('[data-e2e=config-chevron].open')
* if (!chevronOpen.present) click('[data-e2e=config-toggle]')
* waitFor('[data-e2e=config-body]')
# Set max tokens and run chunking
* clear('[data-e2e=config-input]')
* input('[data-e2e=config-input]', '512')
* click('[data-e2e=chunk-btn]')
# Wait for chunks
* retry(30, 1000).waitFor('[data-e2e=chunk-card]')
* waitFor('[data-e2e=chunk-results]')
* assert karate.sizeOf(locateAll('[data-e2e=chunk-card]')) > 0
# Step 10: Delete the document via UI
* def toggleBtns2 = locateAll('[data-e2e=toggle-btn]')
* toggleBtns2[0].click()
* waitFor('[data-e2e=doc-item]')
# Hover and delete
* mouse('[data-e2e=doc-item]').go()
* waitFor('[data-e2e=doc-delete]')
* click('[data-e2e=doc-delete]')
# Verify document is gone from the list
* retry(10, 500).script("!document.querySelector('[data-e2e=doc-item]') || !document.querySelector('[data-e2e=doc-name]').textContent.includes('medium.pdf')")