Files
pablan/frontend/e2e/landing.spec.ts
T
ProfessorNovaandClaude Opus 5 784b76baf7 Pablan, as it stands
Self-hosted knowledge management for SMEs: a split-screen Markdown editor
whose sections an LLM refines while you write, and RAG question answering
over the documents that result. FastAPI + Postgres/pgvector on the back,
SvelteKit on the front, everything OpenAI-compatible and self-hostable.

Squashed into a single commit; the development history stays local.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01CA43ZJda8Rbp2hKXNy8f6b
2026-09-04 09:21:37 +02:00

59 lines
2.3 KiB
TypeScript

import { expect, test } from '@playwright/test';
import { login, logout } from './helpers';
// The landing is the front door: one input that starts a real conversation,
// and three chips.
test.setTimeout(120_000);
test.afterEach(async ({ page }) => {
await page.request.post('/api/auth/logout');
});
test('the landing input starts a conversation and streams an answer', async ({ page }) => {
await login(page, 'pablo@pablan.dev');
await page.getByTestId('landing-input').fill('Wie beantrage ich Urlaub?');
await page.getByTestId('landing-send').click();
// Hand-off to the chat page, which sends the question straight away.
await expect(page).toHaveURL(/\/chat/);
const assistant = page.getByTestId('assistant-message').last();
await expect(assistant).toBeVisible({ timeout: 45_000 });
// The turn is over once the stop button is gone.
await expect(page.getByTestId('stop-button')).toHaveCount(0, { timeout: 90_000 });
expect((await assistant.innerText()).trim().length).toBeGreaterThan(40);
// The conversation shows up in the sidebar.
await expect(page.getByTestId('conversation-list')).toContainText('Urlaub');
// Reloading reopens the same conversation instead of re-asking: the
// hand-off parameter is replaced by the conversation's own route.
const list = await (await page.request.get('/api/conversations')).json();
const created = list.find((c: { title: string }) => c.title?.includes('Urlaub'));
expect(created).toBeTruthy();
await expect(page).toHaveURL(`/chat/${created.id}`);
await page.reload();
await page.locator('body[data-hydrated]').waitFor();
await expect(page.getByTestId('assistant-message')).toHaveCount(1);
const after = await (await page.request.get(`/api/conversations/${created.id}`)).json();
expect(after.messages).toHaveLength(2); // still one question, one answer
await page.request.delete(`/api/conversations/${created.id}`);
});
test('the chips lead to capture and documents', async ({ page }) => {
await login(page, 'pablo@pablan.dev');
await page.getByTestId('chip-find').click();
await expect(page).toHaveURL(/\/documents$/);
await page.goBack();
await page.locator('body[data-hydrated]').waitFor();
await page.getByTestId('chip-capture').click();
await expect(page).toHaveURL(/\/documents\/new$/);
await expect(page.getByTestId('capture-template').first()).toBeVisible({ timeout: 15_000 });
await logout(page);
});