mirror of
https://github.com/bretzel-app/crumbs.git
synced 2026-10-12 20:06:57 +02:00
- Remove duplicate bold formatting test from notes-crud.spec.ts - Trim formatting.spec.ts from 9 to 5 tests (remove italic, inline code, toolbar bold, toolbar visibility — same mechanism as bold shortcut) - Remove hardcoded waitForTimeout(500) from search.spec.ts (Playwright assertions already retry with built-in timeouts) - Restructure sharing.spec.ts: 9 serial tests → 5 parallel self-contained tests using collabPage fixture and API-based setup - Add collabPage fixture to helpers/fixtures.ts for sharing tests Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
158 lines
5.6 KiB
TypeScript
158 lines
5.6 KiB
TypeScript
import { test, expect, noteCard } from './helpers/fixtures.js';
|
|
import type { Page } from '@playwright/test';
|
|
|
|
/**
|
|
* Create a note via API and share it with the collaborator.
|
|
* Returns the note object (with id).
|
|
*/
|
|
async function createSharedNote(
|
|
ownerPage: Page,
|
|
collabPage: Page,
|
|
title: string,
|
|
content = 'Shared content'
|
|
) {
|
|
// Create note
|
|
const res = await ownerPage.request.post('/api/notes', {
|
|
data: { title, content }
|
|
});
|
|
const note = await res.json();
|
|
|
|
// Find the collab user ID
|
|
const usersRes = await ownerPage.request.get('/api/users/search?q=collab');
|
|
const users = await usersRes.json();
|
|
const collabUser = users[0];
|
|
|
|
// Share the note
|
|
await ownerPage.request.post(`/api/notes/${note.id}/collaborators`, {
|
|
data: { userId: collabUser.id }
|
|
});
|
|
|
|
return note;
|
|
}
|
|
|
|
test.describe('Note Sharing', () => {
|
|
test('Scenario: Owner shares a note via UI and collaborator sees it', async ({
|
|
authenticatedPage: page,
|
|
collabPage
|
|
}) => {
|
|
// When the owner creates a note titled "Share Test"
|
|
await page.getByTestId('new-note-btn').click();
|
|
await page.getByTestId('note-title-input').fill('Share Test');
|
|
const editor = page.getByTestId('tiptap-editor').locator('.tiptap');
|
|
await editor.click();
|
|
await editor.pressSequentially('Shared content');
|
|
await page.getByTestId('close-editor-btn').click();
|
|
await expect(noteCard(page, 'Share Test')).toBeVisible();
|
|
|
|
// And the owner opens the share dialog and adds the collaborator
|
|
await noteCard(page, 'Share Test').click();
|
|
await page.getByTestId('share-toggle').click();
|
|
await expect(page.getByTestId('share-dialog')).toBeVisible();
|
|
await page.getByTestId('share-search-input').fill('collab');
|
|
await expect(page.getByTestId('share-user-result').first()).toBeVisible({ timeout: 5000 });
|
|
await page.getByTestId('share-user-result').first().click();
|
|
await expect(page.getByTestId('share-collaborator')).toBeVisible();
|
|
await page.getByTestId('share-dialog-overlay').click({ position: { x: 10, y: 10 } });
|
|
await page.getByTestId('close-editor-btn').click();
|
|
|
|
// Then the owner sees a collaborator indicator
|
|
await expect(noteCard(page, 'Share Test').getByTestId('collaborator-indicator')).toBeVisible();
|
|
|
|
// And the collaborator sees the shared note in their list
|
|
await collabPage.reload();
|
|
await collabPage.waitForLoadState('networkidle');
|
|
await expect(noteCard(collabPage, 'Share Test')).toBeVisible({ timeout: 10000 });
|
|
});
|
|
|
|
test('Scenario: Collaborator can edit shared note and owner sees changes', async ({
|
|
authenticatedPage: page,
|
|
collabPage
|
|
}) => {
|
|
// Given a shared note exists
|
|
const note = await createSharedNote(page, collabPage, 'Collab Edit Test');
|
|
|
|
// When the collaborator edits the note via API
|
|
await collabPage.request.patch(`/api/notes/${note.id}`, {
|
|
data: { content: 'Edited by collaborator' }
|
|
});
|
|
|
|
// Then the owner sees the updated content
|
|
const ownerRes = await page.request.get(`/api/notes/${note.id}`);
|
|
const ownerNote = await ownerRes.json();
|
|
expect(ownerNote.content).toBe('Edited by collaborator');
|
|
});
|
|
|
|
test('Scenario: Owner and collaborator have independent per-user state', async ({
|
|
authenticatedPage: page,
|
|
collabPage
|
|
}) => {
|
|
// Given a shared note exists
|
|
const note = await createSharedNote(page, collabPage, 'Pin Independence Test');
|
|
|
|
// When the collaborator pins the note
|
|
await collabPage.request.patch(`/api/notes/${note.id}`, {
|
|
data: { pinned: true }
|
|
});
|
|
|
|
// Then the collaborator sees it as pinned
|
|
const collabRes = await collabPage.request.get(`/api/notes/${note.id}`);
|
|
const collabNote = await collabRes.json();
|
|
expect(collabNote.pinned).toBeTruthy();
|
|
|
|
// But the owner does not see it as pinned
|
|
const ownerRes = await page.request.get(`/api/notes/${note.id}`);
|
|
const ownerNote = await ownerRes.json();
|
|
expect(ownerNote.pinned).toBeFalsy();
|
|
});
|
|
|
|
test('Scenario: Sync returns correct data for both owner and collaborator', async ({
|
|
authenticatedPage: page,
|
|
collabPage
|
|
}) => {
|
|
// Given a shared note exists
|
|
const note = await createSharedNote(page, collabPage, 'Sync Round-trip Test');
|
|
|
|
// When the owner updates the content
|
|
await page.request.patch(`/api/notes/${note.id}`, {
|
|
data: { content: 'Owner sync update' }
|
|
});
|
|
|
|
// Then the collaborator sees the change via sync endpoint
|
|
const syncRes = await collabPage.request.get(`/api/sync?since=0`);
|
|
const syncedNotes = await syncRes.json();
|
|
const syncedNote = syncedNotes.find((n: { id: string }) => n.id === note.id);
|
|
expect(syncedNote).toBeDefined();
|
|
expect(syncedNote.content).toBe('Owner sync update');
|
|
});
|
|
|
|
test('Scenario: Collaborator sees leave action and can leave a shared note', async ({
|
|
authenticatedPage: page,
|
|
collabPage
|
|
}) => {
|
|
// Given a shared note exists
|
|
const note = await createSharedNote(page, collabPage, 'Leave Test Note');
|
|
|
|
// When the collaborator views their notes
|
|
await collabPage.reload();
|
|
await collabPage.waitForLoadState('networkidle');
|
|
await expect(noteCard(collabPage, 'Leave Test Note')).toBeVisible({ timeout: 10000 });
|
|
|
|
// Then the collaborator's card shows a leave button, not trash
|
|
const card = noteCard(collabPage, 'Leave Test Note');
|
|
await card.hover();
|
|
await expect(card.getByTestId('leave-btn')).toBeVisible();
|
|
await expect(card.getByTestId('trash-btn')).not.toBeVisible();
|
|
|
|
// When the collaborator leaves
|
|
await card.getByTestId('leave-btn').click({ force: true });
|
|
|
|
// Then the note disappears from the collaborator's list
|
|
await expect(noteCard(collabPage, 'Leave Test Note')).not.toBeVisible({ timeout: 5000 });
|
|
|
|
// But the owner still has it
|
|
await page.reload();
|
|
await page.waitForLoadState('networkidle');
|
|
await expect(noteCard(page, 'Leave Test Note')).toBeVisible();
|
|
});
|
|
});
|