| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108 |
- /**
- * Playwright end-to-end smoke test
- *
- * Preconditions (operator must supply):
- * - The backend is running on port 8080 with the built UI served via --webui-dir
- * - SVAPI_ADMIN_KEY env var contains the admin API key (e.g. "e2eadmin")
- * - SVAPI_BASE env var (optional) overrides the base URL (default http://localhost:8080)
- *
- * Run sequence (example):
- * cmake --build build -j"$(nproc)"
- * SMARTBOTIC_VECTORAPI_KEY=e2eadmin ./build/src/smartbotic-vectorapi \
- * --config config/config.json --share-dir api --webui-dir build/webui/dist &
- * cd webui && SVAPI_ADMIN_KEY=e2eadmin SVAPI_BASE=http://localhost:8080 npx playwright test
- *
- * The test creates a collection "e2e_docs" and a document inside it, then
- * deletes the collection (cleanup) before logging out.
- */
- import { test, expect } from '@playwright/test'
- const ADMIN_KEY = process.env['SVAPI_ADMIN_KEY'] ?? 'e2eadmin'
- test('login → collections → documents → logout smoke', async ({ page }) => {
- // ── 1. Navigate to / → should redirect to /login ─────────────────────────
- await page.goto('/')
- await expect(page).toHaveURL(/\/login/)
- // ── 2. Fill API key and submit ────────────────────────────────────────────
- await page.locator('[data-testid="api-key-input"]').fill(ADMIN_KEY)
- await page.locator('[data-testid="login-submit-btn"]').click()
- // After login, should land on dashboard (root path)
- await expect(page).toHaveURL(/\/$/)
- // Project selector should be visible and show "default"
- const projectSelector = page.getByRole('combobox', { name: 'Select project' })
- await expect(projectSelector).toBeVisible()
- await expect(projectSelector).toHaveValue('default')
- // ── 3. Navigate to Collections ────────────────────────────────────────────
- await page.getByRole('link', { name: 'Collections' }).click()
- await expect(page).toHaveURL(/\/collections/)
- // Open "New collection" modal
- await page.locator('[data-testid="new-collection-btn"]').click()
- // Fill collection name
- const nameInput = page.locator('[data-testid="collection-name-input"]')
- await expect(nameInput).toBeVisible()
- await nameInput.fill('e2e_docs')
- // Kind is already "json" by default — just submit
- await page.locator('[data-testid="collection-create-btn"]').click()
- // Wait for modal to close and collection to appear
- await expect(page.locator('[data-testid="collection-row-e2e_docs"]')).toBeVisible({ timeout: 10_000 })
- // ── 4. Navigate to Documents ──────────────────────────────────────────────
- await page.getByRole('link', { name: 'Documents' }).click()
- await expect(page).toHaveURL(/\/documents/)
- // Collection picker should auto-select e2e_docs (it will be in the list)
- const collPicker = page.locator('[data-testid="collection-picker"]')
- await expect(collPicker).toBeVisible()
- // Select e2e_docs in the collection picker
- await collPicker.selectOption('e2e_docs')
- // Click "New document"
- const newDocBtn = page.locator('[data-testid="new-doc-btn"]')
- await expect(newDocBtn).toBeEnabled({ timeout: 5_000 })
- await newDocBtn.click()
- // Monaco editor: wait for it to load and type the document
- // Monaco renders a contenteditable div; we use keyboard to replace the default "{}"
- const monacoEditor = page.locator('.monaco-editor').first()
- await expect(monacoEditor).toBeVisible({ timeout: 15_000 })
- // Click into the editor, select all and type our JSON
- await monacoEditor.click()
- await page.keyboard.press('Control+a')
- await page.keyboard.type('{"name":"e2e"}')
- // Save button
- const saveBtn = page.locator('[data-testid="doc-save-btn"]')
- await expect(saveBtn).toBeEnabled({ timeout: 5_000 })
- await saveBtn.click()
- // Document should appear in the list
- await expect(page.locator('[data-testid="doc-row"]').first()).toBeVisible({ timeout: 10_000 })
- // ── 5. Delete the collection (cleanup) ────────────────────────────────────
- await page.getByRole('link', { name: 'Collections' }).click()
- await expect(page).toHaveURL(/\/collections/)
- // Click Delete button for e2e_docs row
- await page.getByRole('button', { name: 'Delete e2e_docs' }).click()
- // Confirm deletion
- await page.locator('[data-testid="confirm-dialog-confirm-btn"]').click()
- // Collection should be gone
- await expect(page.locator('[data-testid="collection-row-e2e_docs"]')).not.toBeVisible({ timeout: 10_000 })
- // ── 6. Logout ──────────────────────────────────────────────────────────────
- await page.locator('[data-testid="logout-btn"]').click()
- await expect(page).toHaveURL(/\/login/)
- })
|