From 534d84224d253309d050a5a83b7491268deb7701 Mon Sep 17 00:00:00 2001 From: Arkaprava Gaine Date: Tue, 4 Aug 2026 20:44:21 +0530 Subject: [PATCH] tests for formating and note linking --- tests/e2e/formatting.spec.ts | 10 +++ tests/e2e/note-linking.spec.ts | 110 +++++++++++++++++++++++++++++++++ 2 files changed, 120 insertions(+) create mode 100644 tests/e2e/note-linking.spec.ts diff --git a/tests/e2e/formatting.spec.ts b/tests/e2e/formatting.spec.ts index c866956..588d2ee 100644 --- a/tests/e2e/formatting.spec.ts +++ b/tests/e2e/formatting.spec.ts @@ -13,6 +13,14 @@ async function runTiptapCommand(page: Page, commandFn: string) { ); } +async function waitForTiptapEditor(page: Page) { + await page.getByTestId('tiptap-editor').waitFor({ state: 'visible' }); + await page.waitForFunction(() => { + const el = document.querySelector('[data-testid="tiptap-editor"]'); + return el && (el as any).__tiptapEditor != null; + }); +} + /** * Read the `checked` attribute of the first task item from the live ProseMirror * document. This reflects the editor's document state, not just the native @@ -57,6 +65,7 @@ test.describe('Rich text formatting', () => { const editor = page.getByTestId('tiptap-editor').locator('.tiptap'); // When the user selects "world" and applies bold formatting + await waitForTiptapEditor(page); await runTiptapCommand(page, 'editor.chain().focus().setTextSelection({from:7,to:12}).toggleBold().run()'); // Then the selected text appears bold in the editor @@ -99,6 +108,7 @@ test.describe('Rich text formatting', () => { // Given the user is editing a note with selected text await page.getByTestId('new-note-btn').click(); await typeViaMarkdown(page, 'visit example'); + await waitForTiptapEditor(page); await runTiptapCommand(page, 'editor.chain().focus().setTextSelection({from:7,to:14}).run()'); // When the user opens the link popover and enters a URL diff --git a/tests/e2e/note-linking.spec.ts b/tests/e2e/note-linking.spec.ts new file mode 100644 index 0000000..d678aa0 --- /dev/null +++ b/tests/e2e/note-linking.spec.ts @@ -0,0 +1,110 @@ +import { test, expect, createNote, noteCard } from './helpers/fixtures.js'; + +test.describe('Note Linking', () => { + test('Scenario: Linking to a note renders a live chip and clicking it opens that note', async ({ authenticatedPage: page }) => { + await createNote(page, 'Target Note', 'target content'); + await createNote(page, 'Source Note', 'source content'); + + await page.getByTestId('new-note-btn').click(); + await page.getByTestId('note-title-input').fill('Linker Note'); + const editor = page.getByTestId('tiptap-editor').locator('.tiptap'); + await editor.click(); + await page.getByTestId('format-link').click(); + await page.getByTestId('format-link-input').fill('Target'); + await page.getByTestId('format-link-note-result').filter({ hasText: 'Target Note' }).click(); + + await expect(page.getByTestId('tiptap-editor').locator('[data-note-id]')).toBeVisible(); + await page.getByTestId('tiptap-editor').locator('[data-note-id]').click(); + + await expect(page.getByTestId('note-title-input').first()).toHaveValue('Target Note'); + }); + + test('Scenario: Renaming a linked note updates the displayed link text', async ({ authenticatedPage: page }) => { + await createNote(page, 'Original Title', ''); + await page.getByTestId('new-note-btn').click(); + await page.getByTestId('note-title-input').fill('Linker Note'); + const editor = page.getByTestId('tiptap-editor').locator('.tiptap'); + await editor.click(); + await page.getByTestId('format-link').click(); + await page.getByTestId('format-link-input').fill('Original'); + await page.getByTestId('format-link-note-result').filter({ hasText: 'Original Title' }).click(); + await page.getByTestId('close-editor-btn').click(); + + await noteCard(page, 'Original Title').click(); + await page.getByTestId('note-title-input').fill('Renamed Title'); + await page.getByTestId('close-editor-btn').click(); + + await noteCard(page, 'Linker Note').click(); + await expect(editor.getByText('Renamed Title')).toBeVisible(); + await expect(editor.getByText('Original Title')).not.toBeVisible(); + }); + + test('Scenario: A link to a trashed note renders inert and does not navigate', async ({ authenticatedPage: page }) => { + await createNote(page, 'Doomed Note', ''); + await page.getByTestId('new-note-btn').click(); + await page.getByTestId('note-title-input').fill('Linker Note'); + const editor = page.getByTestId('tiptap-editor').locator('.tiptap'); + await editor.click(); + await page.getByTestId('format-link').click(); + await page.getByTestId('format-link-input').fill('Doomed'); + await page.getByTestId('format-link-note-result').filter({ hasText: 'Doomed Note' }).click(); + await page.getByTestId('close-editor-btn').click(); + + await noteCard(page, 'Doomed Note').click(); + await page.getByTestId('overflow-menu-btn').click(); + await page.getByTestId('trash-note-btn').click(); + await expect(page.getByTestId('note-editor-overlay')).toHaveCount(0); + + await noteCard(page, 'Linker Note').click(); + await expect(editor.getByText('Note not found')).toBeVisible(); + await editor.getByText('Note not found').click(); + await expect(page.getByTestId('note-title-input').first()).toHaveValue('Linker Note'); + }); + + test('Scenario: The linked-to note shows a Referenced by backlink', async ({ authenticatedPage: page }) => { + await createNote(page, 'Popular Note', ''); + await page.getByTestId('new-note-btn').click(); + await page.getByTestId('note-title-input').fill('Referencing Note'); + const editor = page.getByTestId('tiptap-editor').locator('.tiptap'); + await editor.click(); + await page.getByTestId('format-link').click(); + await page.getByTestId('format-link-input').fill('Popular'); + await page.getByTestId('format-link-note-result').filter({ hasText: 'Popular Note' }).click(); + await page.getByTestId('close-editor-btn').click(); + + await noteCard(page, 'Popular Note').click(); + + await expect(page.getByTestId('backlink-chip').filter({ hasText: 'Referencing Note' })).toBeVisible(); + }); + + test('Scenario: The note-picker excludes the currently-open note from its own search results', async ({ authenticatedPage: page }) => { + await page.getByTestId('new-note-btn').click(); + await page.getByTestId('note-title-input').fill('Self Reference Test'); + const editor = page.getByTestId('tiptap-editor').locator('.tiptap'); + await editor.click(); + + await page.getByTestId('format-link').click(); + await page.getByTestId('format-link-input').fill('Self Reference'); + + await expect(page.getByTestId('format-link-note-result').filter({ hasText: 'Self Reference Test' })).toHaveCount(0); + }); + + test('Scenario: Hovering a note-link chip reveals a remove button that deletes it without navigating', async ({ authenticatedPage: page }) => { + await createNote(page, 'Removable Target', ''); + await page.getByTestId('new-note-btn').click(); + await page.getByTestId('note-title-input').fill('Has A Link'); + const editor = page.getByTestId('tiptap-editor').locator('.tiptap'); + await editor.click(); + await page.getByTestId('format-link').click(); + await page.getByTestId('format-link-input').fill('Removable'); + await page.getByTestId('format-link-note-result').filter({ hasText: 'Removable Target' }).click(); + + const chip = page.getByTestId('tiptap-editor').locator('[data-note-id]'); + await expect(chip).toBeVisible(); + await chip.hover(); + await page.getByRole('button', { name: 'Remove note link' }).click(); + + await expect(chip).toHaveCount(0); + await expect(page.getByTestId('note-title-input').first()).toHaveValue('Has A Link'); + }); +});