smoke.spec.ts 5.0 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108
  1. /**
  2. * Playwright end-to-end smoke test
  3. *
  4. * Preconditions (operator must supply):
  5. * - The backend is running on port 8080 with the built UI served via --webui-dir
  6. * - SVAPI_ADMIN_KEY env var contains the admin API key (e.g. "e2eadmin")
  7. * - SVAPI_BASE env var (optional) overrides the base URL (default http://localhost:8080)
  8. *
  9. * Run sequence (example):
  10. * cmake --build build -j"$(nproc)"
  11. * SMARTBOTIC_VECTORAPI_KEY=e2eadmin ./build/src/smartbotic-vectorapi \
  12. * --config config/config.json --share-dir api --webui-dir build/webui/dist &
  13. * cd webui && SVAPI_ADMIN_KEY=e2eadmin SVAPI_BASE=http://localhost:8080 npx playwright test
  14. *
  15. * The test creates a collection "e2e_docs" and a document inside it, then
  16. * deletes the collection (cleanup) before logging out.
  17. */
  18. import { test, expect } from '@playwright/test'
  19. const ADMIN_KEY = process.env['SVAPI_ADMIN_KEY'] ?? 'e2eadmin'
  20. test('login → collections → documents → logout smoke', async ({ page }) => {
  21. // ── 1. Navigate to / → should redirect to /login ─────────────────────────
  22. await page.goto('/')
  23. await expect(page).toHaveURL(/\/login/)
  24. // ── 2. Fill API key and submit ────────────────────────────────────────────
  25. await page.locator('[data-testid="api-key-input"]').fill(ADMIN_KEY)
  26. await page.locator('[data-testid="login-submit-btn"]').click()
  27. // After login, should land on dashboard (root path)
  28. await expect(page).toHaveURL(/\/$/)
  29. // Project selector should be visible and show "default"
  30. const projectSelector = page.getByRole('combobox', { name: 'Select project' })
  31. await expect(projectSelector).toBeVisible()
  32. await expect(projectSelector).toHaveValue('default')
  33. // ── 3. Navigate to Collections ────────────────────────────────────────────
  34. await page.getByRole('link', { name: 'Collections' }).click()
  35. await expect(page).toHaveURL(/\/collections/)
  36. // Open "New collection" modal
  37. await page.locator('[data-testid="new-collection-btn"]').click()
  38. // Fill collection name
  39. const nameInput = page.locator('[data-testid="collection-name-input"]')
  40. await expect(nameInput).toBeVisible()
  41. await nameInput.fill('e2e_docs')
  42. // Kind is already "json" by default — just submit
  43. await page.locator('[data-testid="collection-create-btn"]').click()
  44. // Wait for modal to close and collection to appear
  45. await expect(page.locator('[data-testid="collection-row-e2e_docs"]')).toBeVisible({ timeout: 10_000 })
  46. // ── 4. Navigate to Documents ──────────────────────────────────────────────
  47. await page.getByRole('link', { name: 'Documents' }).click()
  48. await expect(page).toHaveURL(/\/documents/)
  49. // Collection picker should auto-select e2e_docs (it will be in the list)
  50. const collPicker = page.locator('[data-testid="collection-picker"]')
  51. await expect(collPicker).toBeVisible()
  52. // Select e2e_docs in the collection picker
  53. await collPicker.selectOption('e2e_docs')
  54. // Click "New document"
  55. const newDocBtn = page.locator('[data-testid="new-doc-btn"]')
  56. await expect(newDocBtn).toBeEnabled({ timeout: 5_000 })
  57. await newDocBtn.click()
  58. // Monaco editor: wait for it to load and type the document
  59. // Monaco renders a contenteditable div; we use keyboard to replace the default "{}"
  60. const monacoEditor = page.locator('.monaco-editor').first()
  61. await expect(monacoEditor).toBeVisible({ timeout: 15_000 })
  62. // Click into the editor, select all and type our JSON
  63. await monacoEditor.click()
  64. await page.keyboard.press('Control+a')
  65. await page.keyboard.type('{"name":"e2e"}')
  66. // Save button
  67. const saveBtn = page.locator('[data-testid="doc-save-btn"]')
  68. await expect(saveBtn).toBeEnabled({ timeout: 5_000 })
  69. await saveBtn.click()
  70. // Document should appear in the list
  71. await expect(page.locator('[data-testid="doc-row"]').first()).toBeVisible({ timeout: 10_000 })
  72. // ── 5. Delete the collection (cleanup) ────────────────────────────────────
  73. await page.getByRole('link', { name: 'Collections' }).click()
  74. await expect(page).toHaveURL(/\/collections/)
  75. // Click Delete button for e2e_docs row
  76. await page.getByRole('button', { name: 'Delete e2e_docs' }).click()
  77. // Confirm deletion
  78. await page.locator('[data-testid="confirm-dialog-confirm-btn"]').click()
  79. // Collection should be gone
  80. await expect(page.locator('[data-testid="collection-row-e2e_docs"]')).not.toBeVisible({ timeout: 10_000 })
  81. // ── 6. Logout ──────────────────────────────────────────────────────────────
  82. await page.locator('[data-testid="logout-btn"]').click()
  83. await expect(page).toHaveURL(/\/login/)
  84. })