- Unified localStorage key to 'theme-preference' across all components
- Fixed header.tsx using wrong localStorage key ('theme' instead of 'theme-preference')
- Added localStorage hybrid persistence for instant theme changes
- Removed router.refresh() which was causing stale data revert
- Replaced Blue theme with Sepia
- Consolidated auth() calls to prevent race conditions
- Updated UserSettingsData types to include all themes
228 lines
9.0 KiB
TypeScript
228 lines
9.0 KiB
TypeScript
import { test, expect } from '@playwright/test';
|
|
|
|
/**
|
|
* E2E Test: Auto-Labeling Bug Fix (Story 7.1)
|
|
*
|
|
* This test verifies that auto-labeling works correctly when creating a new note.
|
|
*
|
|
* Acceptance Criteria:
|
|
* 1. Given a user creates a new note with content
|
|
* 2. When the note is saved
|
|
* 3. Then the system should:
|
|
* - Automatically analyze the note content for relevant labels
|
|
* - Assign suggested labels to the note
|
|
* - Display the note in the UI with labels visible
|
|
* - NOT require a page refresh to see labels
|
|
*/
|
|
|
|
test.describe('Auto-Labeling Bug Fix', () => {
|
|
test.beforeEach(async ({ page }) => {
|
|
// Login
|
|
await page.goto('/');
|
|
await page.waitForURL('**/sign-in', { timeout: 5000 });
|
|
|
|
// Fill login form
|
|
await page.fill('input[type="email"]', 'test@example.com');
|
|
await page.fill('input[type="password"]', 'password123');
|
|
await page.click('button[type="submit"]');
|
|
|
|
// Wait for navigation to home page
|
|
await page.waitForURL('/', { timeout: 5000 });
|
|
});
|
|
|
|
test('should auto-label a note about programming', async ({ page }) => {
|
|
// Create a new note about programming
|
|
const noteContent = 'Need to learn React and TypeScript for web development';
|
|
|
|
// Click "New Note" button
|
|
await page.click('[data-testid="new-note-button"], button:has-text("New Note"), .create-note-btn');
|
|
|
|
// Wait for note to be created
|
|
await page.waitForSelector('.note-card, [data-testid^="note-"]', { timeout: 3000 });
|
|
|
|
// Find the newly created note (first one in the list)
|
|
const firstNote = page.locator('.note-card, [data-testid^="note-"]').first();
|
|
await expect(firstNote).toBeVisible();
|
|
|
|
// Click on the note to edit it
|
|
await firstNote.click();
|
|
|
|
// Wait for note editor to appear
|
|
await page.waitForSelector('[data-testid="note-editor"], textarea.note-content, .note-editor', { timeout: 3000 });
|
|
|
|
// Type content about programming
|
|
const textarea = page.locator('[data-testid="note-editor"] textarea, textarea.note-content, .note-editor textarea');
|
|
await textarea.fill(noteContent);
|
|
|
|
// Wait a moment for auto-labeling to process
|
|
await page.waitForTimeout(1000);
|
|
|
|
// Find labels in the note
|
|
const labels = page.locator('.label-badge, .tag, [data-testid*="label"]');
|
|
|
|
// Verify that labels appear (auto-labeling should have assigned them)
|
|
await expect(labels.first()).toBeVisible({ timeout: 5000 });
|
|
|
|
// Verify the label text contains relevant keywords (like "code", "development", "programming", etc.)
|
|
const labelText = await labels.first().textContent();
|
|
expect(labelText?.toLowerCase()).toMatch(/code|development|programming|react|typescript|web/);
|
|
|
|
console.log('✓ Auto-labeling applied relevant labels:', labelText);
|
|
});
|
|
|
|
test('should auto-label a note about meetings', async ({ page }) => {
|
|
// Create a note about a meeting
|
|
const noteContent = 'Team meeting scheduled for tomorrow at 2pm to discuss project roadmap';
|
|
|
|
// Click "New Note" button
|
|
await page.click('[data-testid="new-note-button"], button:has-text("New Note"), .create-note-btn');
|
|
|
|
// Wait for note to be created
|
|
await page.waitForSelector('.note-card, [data-testid^="note-"]', { timeout: 3000 });
|
|
|
|
// Find the newly created note
|
|
const firstNote = page.locator('.note-card, [data-testid^="note-"]').first();
|
|
await expect(firstNote).toBeVisible();
|
|
|
|
// Click on the note to edit it
|
|
await firstNote.click();
|
|
|
|
// Wait for note editor
|
|
await page.waitForSelector('[data-testid="note-editor"], textarea.note-content, .note-editor', { timeout: 3000 });
|
|
|
|
// Type content about meeting
|
|
const textarea = page.locator('[data-testid="note-editor"] textarea, textarea.note-content, .note-editor textarea');
|
|
await textarea.fill(noteContent);
|
|
|
|
// Wait for auto-labeling
|
|
await page.waitForTimeout(1000);
|
|
|
|
// Check for labels
|
|
const labels = page.locator('.label-badge, .tag, [data-testid*="label"]');
|
|
await expect(labels.first()).toBeVisible({ timeout: 5000 });
|
|
|
|
// Verify meeting-related label
|
|
const labelText = await labels.first().textContent();
|
|
expect(labelText?.toLowerCase()).toMatch(/meeting|team|project|roadmap|discussion/);
|
|
|
|
console.log('✓ Auto-labeling applied meeting-related labels:', labelText);
|
|
});
|
|
|
|
test('should display labels immediately without page refresh', async ({ page }) => {
|
|
// This test verifies the critical requirement: labels should be visible WITHOUT refreshing
|
|
|
|
const noteContent = 'Need to buy groceries: milk, bread, eggs, and vegetables';
|
|
|
|
// Click "New Note"
|
|
await page.click('[data-testid="new-note-button"], button:has-text("New Note"), .create-note-btn');
|
|
|
|
// Wait for note creation
|
|
await page.waitForSelector('.note-card, [data-testid^="note-"]', { timeout: 3000 });
|
|
|
|
// Click on the note
|
|
const firstNote = page.locator('.note-card, [data-testid^="note-"]').first();
|
|
await firstNote.click();
|
|
|
|
// Wait for editor
|
|
await page.waitForSelector('[data-testid="note-editor"], textarea.note-content, .note-editor', { timeout: 3000 });
|
|
|
|
// Type content
|
|
const textarea = page.locator('[data-testid="note-editor"] textarea, textarea.note-content, .note-editor textarea');
|
|
await textarea.fill(noteContent);
|
|
|
|
// CRITICAL: Wait for labels to appear WITHOUT refreshing
|
|
const labels = page.locator('.label-badge, .tag, [data-testid*="label"]');
|
|
|
|
// Labels should appear within 5 seconds (optimistic update + server processing)
|
|
await expect(labels.first()).toBeVisible({ timeout: 5000 });
|
|
|
|
console.log('✓ Labels appeared immediately without page refresh');
|
|
});
|
|
|
|
test('should handle auto-labeling failure gracefully', async ({ page }) => {
|
|
// This test verifies error handling: if auto-labeling fails, the note should still be created
|
|
|
|
const noteContent = 'Test note with very short content';
|
|
|
|
// Click "New Note"
|
|
await page.click('[data-testid="new-note-button"], button:has-text("New Note"), .create-note-btn');
|
|
|
|
// Wait for note creation
|
|
await page.waitForSelector('.note-card, [data-testid^="note-"]', { timeout: 3000 });
|
|
|
|
// Click on the note
|
|
const firstNote = page.locator('.note-card, [data-testid^="note-"]').first();
|
|
await firstNote.click();
|
|
|
|
// Wait for editor
|
|
await page.waitForSelector('[data-testid="note-editor"], textarea.note-content, .note-editor', { timeout: 3000 });
|
|
|
|
// Type very short content (may not generate labels)
|
|
const textarea = page.locator('[data-testid="note-editor"] textarea, textarea.note-content, .note-editor textarea');
|
|
await textarea.fill(noteContent);
|
|
|
|
// Wait for processing
|
|
await page.waitForTimeout(2000);
|
|
|
|
// Note should still be visible even if no labels are assigned
|
|
await expect(firstNote).toBeVisible();
|
|
|
|
console.log('✓ Note created successfully even if auto-labeling fails or returns no suggestions');
|
|
});
|
|
|
|
test('should auto-label in notebook context', async ({ page }) => {
|
|
// Test that auto-labeling uses notebook context for suggestions
|
|
|
|
const noteContent = 'Planning a trip to Japan next month';
|
|
|
|
// Create a notebook first (if not exists)
|
|
const notebookExists = await page.locator('.notebook-item:has-text("Travel")').count();
|
|
if (notebookExists === 0) {
|
|
await page.click('[data-testid="create-notebook-button"], button:has-text("Create Notebook")');
|
|
await page.fill('input[placeholder*="notebook name"], input[placeholder*="name"]', 'Travel');
|
|
await page.click('button:has-text("Create"), button[type="submit"]');
|
|
}
|
|
|
|
// Navigate to Travel notebook
|
|
await page.click('.notebook-item:has-text("Travel")');
|
|
|
|
// Wait for navigation
|
|
await page.waitForTimeout(500);
|
|
|
|
// Click "New Note"
|
|
await page.click('[data-testid="new-note-button"], button:has-text("New Note"), .create-note-btn');
|
|
|
|
// Wait for note creation
|
|
await page.waitForSelector('.note-card, [data-testid^="note-"]', { timeout: 3000 });
|
|
|
|
// Click on the note
|
|
const firstNote = page.locator('.note-card, [data-testid^="note-"]').first();
|
|
await firstNote.click();
|
|
|
|
// Wait for editor
|
|
await page.waitForSelector('[data-testid="note-editor"], textarea.note-content, .note-editor', { timeout: 3000 });
|
|
|
|
// Type travel-related content
|
|
const textarea = page.locator('[data-testid="note-editor"] textarea, textarea.note-content, .note-editor textarea');
|
|
await textarea.fill(noteContent);
|
|
|
|
// Wait for auto-labeling
|
|
await page.waitForTimeout(1000);
|
|
|
|
// Check for labels (should be travel-related)
|
|
const labels = page.locator('.label-badge, .tag, [data-testid*="label"]');
|
|
const labelCount = await labels.count();
|
|
|
|
// At least one label should appear (or note should still be visible if no labels)
|
|
if (labelCount > 0) {
|
|
const labelText = await labels.first().textContent();
|
|
console.log('✓ Auto-labeling in notebook context applied labels:', labelText);
|
|
} else {
|
|
console.log('✓ Note created in notebook context (no labels generated for this content)');
|
|
}
|
|
|
|
// Note should be visible regardless
|
|
await expect(firstNote).toBeVisible();
|
|
});
|
|
});
|