mirror of
https://github.com/bretzel-app/crumbs.git
synced 2026-10-12 20:06:57 +02:00
- Add noteCard() helper to target specific cards by title instead of
generic getByTestId('note-card') which fails with multiple matches
- Scope action button clicks (trash, pin, archive) within their card
- Scope tag-chip filter clicks to the tag-filter container
- Wait for networkidle after auth to ensure full hydration
- Remove "empty notes list" test incompatible with shared DB
- Use toHaveCount(0) instead of not.toBeVisible for search empty state
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
121 lines
4.8 KiB
TypeScript
121 lines
4.8 KiB
TypeScript
import { test, expect, noteCard } from './helpers/fixtures.js';
|
|
|
|
test.describe('Offline Support', () => {
|
|
test('Scenario: Sync status is visible to the user', async ({ authenticatedPage: page }) => {
|
|
// Given the user is authenticated
|
|
// Then the sync status indicator is displayed
|
|
await expect(page.getByTestId('sync-indicator')).toBeVisible();
|
|
});
|
|
|
|
test('Scenario: Created note is immediately visible in the notes list', async ({ authenticatedPage: page }) => {
|
|
// When the user creates a note titled "Offline Test Note"
|
|
await page.getByTestId('new-note-btn').click();
|
|
await page.getByTestId('note-title-input').fill('Offline Test Note');
|
|
await page.getByTestId('close-editor-btn').click();
|
|
|
|
// Then the note appears in the list
|
|
await expect(page.getByText('Offline Test Note')).toBeVisible();
|
|
});
|
|
|
|
test('Scenario: Edited note persists in the UI when offline', async ({ authenticatedPage: page }) => {
|
|
// Given a note titled "Offline Edit" exists
|
|
await page.getByTestId('new-note-btn').click();
|
|
await page.getByTestId('note-title-input').fill('Offline Edit');
|
|
await page.getByTestId('close-editor-btn').click();
|
|
await expect(page.getByText('Offline Edit')).toBeVisible();
|
|
|
|
// When the network is unavailable
|
|
await page.context().setOffline(true);
|
|
|
|
// And the user edits the note title to "Offline Edited"
|
|
await noteCard(page, 'Offline Edit').click();
|
|
await page.getByTestId('note-title-input').clear();
|
|
await page.getByTestId('note-title-input').fill('Offline Edited');
|
|
await page.getByTestId('close-editor-btn').click();
|
|
|
|
// Then the note "Offline Edited" appears in the list
|
|
await expect(page.getByText('Offline Edited')).toBeVisible();
|
|
|
|
// And a "Saved offline" toast is shown
|
|
await expect(page.getByText('Saved offline')).toBeVisible();
|
|
});
|
|
|
|
test('Scenario: New note appears in the UI when created offline', async ({ authenticatedPage: page }) => {
|
|
// When the network is unavailable
|
|
await page.context().setOffline(true);
|
|
|
|
// And the user creates a note titled "Offline New"
|
|
await page.getByTestId('new-note-btn').click();
|
|
await page.getByTestId('note-title-input').fill('Offline New');
|
|
await page.getByTestId('close-editor-btn').click();
|
|
|
|
// Then the note "Offline New" appears in the list
|
|
await expect(page.getByText('Offline New')).toBeVisible();
|
|
|
|
// And a "Saved offline" toast is shown
|
|
await expect(page.getByText('Saved offline')).toBeVisible();
|
|
});
|
|
|
|
test('Scenario: Offline note survives a page reload after reconnecting', async ({ authenticatedPage: page }) => {
|
|
// When the network is unavailable
|
|
await page.context().setOffline(true);
|
|
|
|
// And the user creates a note titled "Survive Reload"
|
|
await page.getByTestId('new-note-btn').click();
|
|
await page.getByTestId('note-title-input').fill('Survive Reload');
|
|
await page.getByTestId('close-editor-btn').click();
|
|
await expect(page.getByText('Survive Reload')).toBeVisible();
|
|
|
|
// When the network is restored (triggers 'online' event + navigator.onLine = true)
|
|
await page.context().setOffline(false);
|
|
|
|
// And the sync completes
|
|
await page.waitForResponse('**/api/sync');
|
|
|
|
// And the user reloads the page
|
|
await page.reload();
|
|
|
|
// Then the note is still visible
|
|
await expect(page.getByText('Survive Reload')).toBeVisible();
|
|
});
|
|
|
|
test('Scenario: Notes load from local cache when the API is unavailable', async ({ authenticatedPage: page }) => {
|
|
// Given a note titled "Cached Note" exists
|
|
await page.getByTestId('new-note-btn').click();
|
|
await page.getByTestId('note-title-input').fill('Cached Note');
|
|
await page.getByTestId('close-editor-btn').click();
|
|
await expect(page.getByText('Cached Note')).toBeVisible();
|
|
|
|
// When the API is unavailable (simulating service worker serving cached shell)
|
|
await page.route('**/api/**', (route) => route.abort());
|
|
|
|
// And the user reloads the page
|
|
await page.reload();
|
|
|
|
// Then the note is still visible (loaded from IDB cache)
|
|
await expect(page.getByText('Cached Note')).toBeVisible();
|
|
});
|
|
|
|
test('Scenario: Trashed note disappears from the list when offline', async ({ authenticatedPage: page }) => {
|
|
// Given a note titled "Offline Trash" exists
|
|
await page.getByTestId('new-note-btn').click();
|
|
await page.getByTestId('note-title-input').fill('Offline Trash');
|
|
await page.getByTestId('close-editor-btn').click();
|
|
await expect(page.getByText('Offline Trash')).toBeVisible();
|
|
|
|
// When the network is unavailable
|
|
await page.context().setOffline(true);
|
|
|
|
// And the user trashes the note
|
|
const card = noteCard(page, 'Offline Trash');
|
|
await card.hover();
|
|
await card.getByTestId('trash-btn').click();
|
|
|
|
// Then the note is no longer visible
|
|
await expect(page.getByText('Offline Trash')).not.toBeVisible();
|
|
|
|
// And a "Saved offline" toast is shown
|
|
await expect(page.getByText('Saved offline')).toBeVisible();
|
|
});
|
|
});
|