- 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>
69 lines
3.5 KiB
TypeScript
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
|
|
});
|
|
});
|