- Add 'Twilight Velvet' color palette to globals.css with OKLCH values - Update SettingsPage headers, cards, and dialogs to use semantic theme variables - Update HistoryCard, HistoryFeed, and DraftContent to support dark mode - Update ProviderSelector and ProviderList to use custom card background (#2A2A3D) - Add ThemeToggle component with improved visibility - Ensure consistent use of 'bg-card', 'text-foreground', and 'text-muted-foreground'
89 lines
3.8 KiB
TypeScript
89 lines
3.8 KiB
TypeScript
import { test, expect } from '@playwright/test';
|
|
|
|
test.describe('The Venting Ritual', () => {
|
|
test.beforeEach(async ({ page }) => {
|
|
// Mock Auth
|
|
await page.context().addCookies([{
|
|
name: 'auth-token',
|
|
value: 'authenticated',
|
|
domain: 'localhost',
|
|
path: '/',
|
|
httpOnly: true,
|
|
secure: false,
|
|
sameSite: 'Lax'
|
|
}]);
|
|
|
|
// Mock Settings (Active Provider) via localStorage
|
|
// Since we are mocking network anyway, we just need the app to think it's configured
|
|
await page.goto('/settings');
|
|
// Actually, we can just use the UI to configure a dummy provider
|
|
await page.getByRole('button', { name: 'Add New Provider' }).click();
|
|
await page.fill('input[placeholder="My OpenAI Key"]', 'Test Provider');
|
|
await page.fill('input[placeholder="https://api.openai.com/v1"]', 'https://api.example.com/v1');
|
|
await page.fill('input[placeholder="gpt-4o"]', 'test-model');
|
|
await page.fill('input[placeholder="sk-..."]', 'sk-test-key');
|
|
|
|
// Mock Validation
|
|
await page.route('/api/llm', async route => {
|
|
const body = route.request().postDataJSON();
|
|
// Validation Check
|
|
if (body.messages.length === 1 && body.messages[0].content === 'hello') {
|
|
await route.fulfill({ json: { success: true, data: { text: 'Hello' } } });
|
|
return;
|
|
}
|
|
// Teacher Response
|
|
if (body.messages.some((m: any) => m.role === 'system' && m.content.includes('"Teacher"'))) {
|
|
await route.fulfill({ json: { success: true, data: { text: 'That sounds difficult. Tell me more.' } } });
|
|
return;
|
|
}
|
|
// Ghostwriter Response
|
|
if (body.messages.some((m: any) => m.role === 'system' && m.content.includes('"Ghostwriter"'))) {
|
|
await route.fulfill({
|
|
json: {
|
|
success: true, data: {
|
|
text: JSON.stringify({
|
|
title: "The Test Epiphany",
|
|
insight: "Testing is crucial for confidence.",
|
|
lesson: "Always verify your assumptions."
|
|
})
|
|
}
|
|
}
|
|
});
|
|
return;
|
|
}
|
|
});
|
|
|
|
await page.getByRole('button', { name: 'Save as New Provider' }).click();
|
|
});
|
|
|
|
test('should compare venting flow: Input -> Teacher -> Draft -> Insight', async ({ page }) => {
|
|
await page.goto('/chat?new=true');
|
|
|
|
// 1. User Vents
|
|
await page.fill('textarea', 'I am stressed about testing.');
|
|
await page.click('button:has-text("Send"), button:has(.lucide-send)');
|
|
// Note: Icon button might not have text, use selector for icon or aria-label if added
|
|
// The button has <Send> icon inside.
|
|
|
|
// 2. Teacher Responds
|
|
await expect(page.getByText('That sounds difficult. Tell me more.')).toBeVisible();
|
|
|
|
// 3. Contextual "Draft" button should appear (phase: elicitation)
|
|
// Wait for it because typing might take a moment (50ms per token simulation)
|
|
await expect(page.getByRole('button', { name: 'Summarize & Draft' })).toBeVisible();
|
|
|
|
// 4. Trigger Drafting
|
|
await page.click('button:has-text("Summarize & Draft")');
|
|
|
|
// 5. Draft Sheet appears
|
|
await expect(page.getByText('The Test Epiphany')).toBeVisible();
|
|
await expect(page.getByText('Testing is crucial for confidence.')).toBeVisible();
|
|
|
|
// 6. Keep It
|
|
await page.getByRole('button', { name: 'Keep It' }).click();
|
|
|
|
// Should reset or navigate (Story 4.1) - for now just check sheet closed
|
|
await expect(page.getByText('The Test Epiphany')).toBeHidden();
|
|
});
|
|
});
|