Files
brachnha-insight/tests/e2e/ghostwriter-flow.spec.ts
Max 3fbbb1a93b Initial commit: Brachnha Insight project setup
- Next.js 14+ with App Router and TypeScript
- Tailwind CSS and ShadCN UI styling
- Zustand state management
- Dexie.js for IndexedDB (local-first data)
- Auth.js v5 for authentication
- BMAD framework integration

Co-Authored-By: Claude <noreply@anthropic.com>
2026-01-26 12:28:43 +07:00

69 lines
3.5 KiB
TypeScript

import { test, expect } from '@playwright/test';
test.describe('Ghostwriter Flow', () => {
test('Scenario 2.3.2 (P0): Regeneration respects user critique', async ({ page }) => {
// GIVEN: A generated draft exists (mocked)
await page.goto('/session/chat');
// Mock the "Drafting" completion state by injecting state or ensuring mock network response
await page.route('**/api/llm/generate', async (route) => {
const json = { content: 'Draft Version 1' };
await route.fulfill({ json });
});
// Trigger generation (assuming UI state is ready or fast-track used)
// For E2E, we might need to simulate the chat flow or use a "Debug: Force Draft" button if available in dev mode
// Assuming we can start from a state where the draft sheet is open for this test, or we navigate through chat.
// Let's assume we simulate the chat end first.
await page.fill('[data-testid="chat-input"]', 'Fast track this');
await page.click('[data-testid="fast-track-btn"]');
await expect(page.locator('[data-testid="draft-sheet"]')).toBeVisible();
await expect(page.locator('[data-testid="markdown-content"]')).toContainText('Draft Version 1');
// WHEN: User clicks Thumbs Down and critiques
await page.click('[data-testid="thumbs-down-btn"]');
await expect(page.locator('[data-testid="critique-input"]')).toBeVisible();
await page.fill('[data-testid="critique-input"]', 'Make it shorter');
// Intercept the regeneration request
let critiqueSent = false;
await page.route('**/api/llm/regenerate', async (route) => {
critiqueSent = true;
const postData = route.request().postDataJSON();
expect(postData.critique).toBe('Make it shorter');
await route.fulfill({ json: { content: 'Draft Version 2 (Shorter)' } });
});
await page.click('[data-testid="regenerate-submit-btn"]');
// THEN: A new draft is requested with critique context
await expect(page.locator('[data-testid="markdown-content"]')).toContainText('Draft Version 2 (Shorter)');
expect(critiqueSent).toBe(true);
});
test('Scenario 2.4.1 (P0): Copy button places text in clipboard', async ({ page, context }) => {
// Grant clipboard permissions
await context.grantPermissions(['clipboard-read', 'clipboard-write']);
// GIVEN: A draft is visible
await page.goto('/session/chat');
// Mock generation
await page.route('**/api/llm/generate', async (route) => {
await route.fulfill({ json: { content: 'Final Draft Content' } });
});
await page.fill('[data-testid="chat-input"]', 'Fast track');
await page.click('[data-testid="fast-track-btn"]');
await expect(page.locator('[data-testid="draft-sheet"]')).toBeVisible();
// WHEN: User clicks Copy
await page.click('[data-testid="copy-btn"]');
// THEN: Clipboard contains text
// Note: Reading clipboard in headless might be tricky, checking for "Copied" toast is a good proxy for PWA checks
await expect(page.locator('[data-testid="toast-success"]')).toContainText('Copied to clipboard');
// Optional: layout check (R-2.5) - Verify rendering didn't break
await expect(page.locator('[data-testid="markdown-content"]')).toBeVisible();
await expect(page.locator('[data-testid="markdown-content"]')).not.toHaveCSS('overflow-x', 'hidden'); // Crude check for broken layout
});
});