Files
crumbs/tests/e2e/sharing.spec.ts
T
Frederic CabassutandClaude Opus 4.6 0b417bef0e test: consolidate E2E tests — remove duplicates, fix timeouts, parallelize sharing
- 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>
2026-03-10 10:14:09 +01:00

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();
});
});