import { expect, test, type Page } from '@playwright/test' import { createFixtureVaultCopy, openFixtureVault, removeFixtureVaultCopy, } from '../helpers/fixtureVault' import { executeCommand, openCommandPalette } from './helpers' let tempVaultDir: string async function openNote(page: Page, title: string) { await page.locator('[data-testid="note-list-container"]').getByText(title, { exact: true }).click() await expect(page.locator('.bn-editor')).toBeVisible({ timeout: 5_000 }) } async function openRawMode(page: Page) { await openCommandPalette(page) await executeCommand(page, 'Toggle Raw') await expect(page.locator('.cm-content')).toBeVisible({ timeout: 5_000 }) } async function openBlockNoteMode(page: Page) { await openCommandPalette(page) await executeCommand(page, 'Toggle Raw') await expect(page.locator('.bn-editor')).toBeVisible({ timeout: 5_000 }) } async function getRawEditorContent(page: Page): Promise { return page.evaluate(() => { const el = document.querySelector('.cm-content') if (!el) return '' // eslint-disable-next-line @typescript-eslint/no-explicit-any -- CodeMirror view is attached to the DOM node. const view = (el as any).cmTile?.view if (!view) return el.textContent ?? '' return view.state.doc.toString() as string }) } async function setRawEditorContent(page: Page, content: string) { await page.evaluate((nextContent) => { const el = document.querySelector('.cm-content') if (!el) return // eslint-disable-next-line @typescript-eslint/no-explicit-any -- CodeMirror view is attached to the DOM node. const view = (el as any).cmTile?.view if (!view) return view.dispatch({ changes: { from: 0, to: view.state.doc.length, insert: nextContent, }, }) }, content) } async function appendPlainFilenameParagraph(page: Page, value: string) { const lastBlock = page.locator('.bn-block-content').last() await expect(lastBlock).toBeVisible({ timeout: 5_000 }) await lastBlock.click() await page.keyboard.press('End') await page.keyboard.press('Enter') await page.keyboard.type(`${value} `) await page.waitForTimeout(700) } test.beforeEach(async ({ page }, testInfo) => { testInfo.setTimeout(90_000) tempVaultDir = createFixtureVaultCopy() await openFixtureVault(page, tempVaultDir) }) test.afterEach(async () => { removeFixtureVaultCopy(tempVaultDir) }) test('plain filename-like text typed in BlockNote stays plain through raw-mode round trips', async ({ page }) => { await openNote(page, 'Note B') await appendPlainFilenameParagraph(page, 'AGENTS.md') await appendPlainFilenameParagraph(page, 'docs/README.md') await openRawMode(page) const raw = await getRawEditorContent(page) expect(raw).toContain('AGENTS.md') expect(raw).toContain('docs/README.md') expect(raw).not.toMatch(/\[AGENTS\.md\]\(/) expect(raw).not.toMatch(/\[docs\/README\.md\]\(/) }) test('explicit markdown links still render and round-trip intentionally', async ({ page }) => { await openNote(page, 'Note B') await openRawMode(page) const raw = await getRawEditorContent(page) const intentionalLink = '[Tolaria Docs](https://example.com/docs)' await setRawEditorContent(page, `${raw}\n\n${intentionalLink}\n`) await page.waitForTimeout(700) await openBlockNoteMode(page) await expect(page.locator('.bn-editor a[href="https://example.com/docs"]').last()).toContainText('Tolaria Docs') await openRawMode(page) await expect.poll(() => getRawEditorContent(page)).toContain(intentionalLink) })