From 4ad32faa7b9a3e2b6c0b75201c6b7dc7667fdb0d Mon Sep 17 00:00:00 2001 From: lucaronin Date: Thu, 23 Apr 2026 22:10:02 +0200 Subject: [PATCH] test: simplify main entrypoint setup --- src/main.test.ts | 20 +++++----- tests/smoke/arrow-ligatures.spec.ts | 58 +++++++++++++++++++++++++++++ 2 files changed, 69 insertions(+), 9 deletions(-) create mode 100644 tests/smoke/arrow-ligatures.spec.ts diff --git a/src/main.test.ts b/src/main.test.ts index 4e6b8075..a5b61cdf 100644 --- a/src/main.test.ts +++ b/src/main.test.ts @@ -1,6 +1,8 @@ -import { describe, expect, it, vi, beforeEach } from 'vitest' +import { describe, expect, it, vi, beforeAll, beforeEach } from 'vitest' import { createElement, type ReactNode } from 'react' +const MAIN_ENTRYPOINT_TEST_TIMEOUT_MS = 30_000 + type ReactRootErrorInfo = { componentStack?: string } type ReactRootOptions = { onCaughtError?: (error: unknown, errorInfo: ReactRootErrorInfo) => void @@ -52,15 +54,17 @@ function rootOptions(): ReactRootOptions { } describe('main entrypoint', () => { - beforeEach(() => { - vi.resetModules() + beforeAll(async () => { vi.clearAllMocks() document.body.innerHTML = '
' + await importEntrypoint() + }, MAIN_ENTRYPOINT_TEST_TIMEOUT_MS) + + beforeEach(() => { + mocks.sentryHandler.mockClear() }) - it('captures React root errors through Sentry with component stack context', async () => { - await importEntrypoint() - + it('captures React root errors through Sentry with component stack context', () => { expect(mocks.reactErrorHandler).toHaveBeenCalledOnce() expect(mocks.createRoot).toHaveBeenCalledWith( document.getElementById('root'), @@ -77,9 +81,7 @@ describe('main entrypoint', () => { expect(mocks.sentryHandler).toHaveBeenCalledWith(error, { componentStack: '\n in App' }) }) - it('normalizes missing React component stacks before handing errors to Sentry', async () => { - await importEntrypoint() - + it('normalizes missing React component stacks before handing errors to Sentry', () => { const error = new Error('recoverable render error') rootOptions().onRecoverableError?.(error, {}) diff --git a/tests/smoke/arrow-ligatures.spec.ts b/tests/smoke/arrow-ligatures.spec.ts new file mode 100644 index 00000000..a732c642 --- /dev/null +++ b/tests/smoke/arrow-ligatures.spec.ts @@ -0,0 +1,58 @@ +import { test, expect, type Page } from '@playwright/test' +import { executeCommand, openCommandPalette } from './helpers' + +const AI_AGENTS_ONBOARDING_DISMISSED_KEY = 'tolaria:ai-agents-onboarding-dismissed' +const CLAUDE_CODE_ONBOARDING_DISMISSED_KEY = 'tolaria:claude-code-onboarding-dismissed' + +async function createNote(page: Page) { + await page.waitForSelector('[data-testid="sidebar-top-nav"]', { timeout: 10000 }) + await page.locator('button[title="Create new note"]').first().click() + await expect(page.getByTestId('breadcrumb-filename-trigger')).toContainText(/untitled-note-\d+/i, { + timeout: 5_000, + }) + await expect(page.locator('.bn-editor')).toBeVisible({ timeout: 5_000 }) + await page.waitForTimeout(500) + await page.keyboard.press('Enter') +} + +async function toggleRawEditor(page: Page) { + await openCommandPalette(page) + await executeCommand(page, 'Toggle Raw') +} + +async function getRawEditorContent(page: Page) { + return page.locator('[data-testid="raw-editor-codemirror"]').evaluate((element) => { + // eslint-disable-next-line @typescript-eslint/no-explicit-any + const view = (element as any).__cmView + return view?.state?.doc?.toString?.() ?? element.textContent ?? '' + }) +} + +test('typing keeps arrow ligatures aligned between rich and raw editors', async ({ page }) => { + await page.setViewportSize({ width: 1600, height: 900 }) + await page.addInitScript(({ aiAgentsKey, claudeKey }: { aiAgentsKey: string; claudeKey: string }) => { + localStorage.clear() + localStorage.setItem(aiAgentsKey, '1') + localStorage.setItem(claudeKey, '1') + }, { + aiAgentsKey: AI_AGENTS_ONBOARDING_DISMISSED_KEY, + claudeKey: CLAUDE_CODE_ONBOARDING_DISMISSED_KEY, + }) + await page.goto(process.env.BASE_URL ?? 'http://localhost:5201', { waitUntil: 'domcontentloaded' }) + + await createNote(page) + await page.keyboard.type('-> <- <-> \\<->') + + await expect(page.locator('.bn-editor')).toContainText('→ ← ↔ <->', { timeout: 5_000 }) + + await toggleRawEditor(page) + await expect(page.locator('[data-testid="raw-editor-codemirror"]')).toBeVisible({ timeout: 5_000 }) + await expect.poll(() => getRawEditorContent(page)).toContain('→ ← ↔ <->') + + await page.locator('[data-testid="raw-editor-codemirror"]').click() + await page.keyboard.type('\n-> <- <-> \\<->') + await expect.poll(() => getRawEditorContent(page)).toMatch(/→ ← ↔ <->\s+→ ← ↔ <->/u) + + await toggleRawEditor(page) + await expect(page.locator('.bn-editor')).toContainText('→ ← ↔ <->', { timeout: 5_000 }) +})