test: stabilize untitled draft title regression

This commit is contained in:
Test
2026-04-07 22:45:55 +02:00
parent 9308493326
commit e1771ed7e6

View File

@@ -1,85 +1,58 @@
import { test, expect } from '@playwright/test'
import { sendShortcut } from './helpers'
import fs from 'fs'
import path from 'path'
import os from 'os'
/** Known BlockNote/ProseMirror error that fires during editor re-mount after rename. */
const KNOWN_EDITOR_ERRORS = ['isConnected']
const FIXTURE_VAULT = path.resolve('tests/fixtures/test-vault')
function isKnownEditorError(msg: string): boolean {
return KNOWN_EDITOR_ERRORS.some(k => msg.includes(k))
function copyDirSync(src: string, dest: string): void {
fs.mkdirSync(dest, { recursive: true })
for (const item of fs.readdirSync(src, { withFileTypes: true })) {
const s = path.join(src, item.name)
const d = path.join(dest, item.name)
if (item.isDirectory()) copyDirSync(s, d)
else fs.copyFileSync(s, d)
}
}
test.describe('H1 decoupled from title + non-blocking rename', () => {
test.beforeEach(async ({ page }) => {
await page.goto('/')
await page.waitForLoadState('networkidle')
await page.waitForTimeout(2500)
})
let tempVaultDir: string
test('editing H1 in editor does NOT update TitleField', async ({ page }) => {
const errors: string[] = []
page.on('pageerror', (err) => { if (!isKnownEditorError(err.message)) errors.push(err.message) })
test.beforeEach(async ({ page }) => {
tempVaultDir = fs.mkdtempSync(path.join(os.tmpdir(), 'laputa-test-vault-'))
copyDirSync(FIXTURE_VAULT, tempVaultDir)
// Create a new note
await page.locator('body').click()
await sendShortcut(page, 'n', ['Control'])
await expect(page.getByText(/Untitled note/).first()).toBeVisible({ timeout: 3000 })
await page.addInitScript((vaultPath: string) => {
// eslint-disable-next-line @typescript-eslint/no-explicit-any
let ref: any = null
Object.defineProperty(window, '__mockHandlers', {
set(val) {
ref = val
ref.load_vault_list = () => ({
vaults: [{ label: 'Test Vault', path: vaultPath }],
active_vault: vaultPath,
})
ref.check_vault_exists = () => true
ref.get_last_vault_path = () => vaultPath
ref.get_default_vault_path = () => vaultPath
ref.save_vault_list = () => null
},
get() { return ref },
configurable: true,
})
}, tempVaultDir)
// Note the initial TitleField value
const titleInput = page.getByTestId('title-field-input')
await titleInput.waitFor({ timeout: 3000 })
const initialTitle = await titleInput.inputValue()
// Type an H1 in the editor body
const heading = page.locator('[data-content-type="heading"] h1')
if (await heading.isVisible()) {
await heading.click({ clickCount: 3 })
} else {
// Click into the editor and type an H1
const editor = page.locator('.bn-editor')
await editor.click()
}
await page.keyboard.type('My Custom H1 Heading', { delay: 15 })
// Wait well past the old debounce time (500ms)
await page.waitForTimeout(1500)
// TitleField should NOT have changed from its initial value
const titleAfterH1 = await titleInput.inputValue()
expect(titleAfterH1).toBe(initialTitle)
expect(errors).toEqual([])
})
test('TitleField rename is non-blocking (no freeze)', async ({ page }) => {
const errors: string[] = []
page.on('pageerror', (err) => { if (!isKnownEditorError(err.message)) errors.push(err.message) })
// Create a new note
await page.locator('body').click()
await sendShortcut(page, 'n', ['Control'])
await expect(page.getByText(/Untitled note/).first()).toBeVisible({ timeout: 3000 })
// Focus the TitleField and type a new title
const titleInput = page.getByTestId('title-field-input')
await titleInput.waitFor({ timeout: 3000 })
await titleInput.click()
await titleInput.fill('Responsive Rename Test')
// Measure time for blur (commit) — should be near-instant
const start = Date.now()
await titleInput.press('Enter')
const elapsed = Date.now() - start
// The blur/commit should complete in under 500ms (no blocking rename)
expect(elapsed).toBeLessThan(500)
// TitleField should show the new title optimistically
await expect(titleInput).toHaveValue('Responsive Rename Test', { timeout: 1000 })
// Wait for rename to complete in background
const toast = page.locator('.fixed.bottom-8')
await expect(toast).toContainText('Renamed', { timeout: 5000 })
expect(errors).toEqual([])
})
await page.goto('/')
await page.getByText('Alpha Project', { exact: true }).first().waitFor({ timeout: 10_000 })
})
test.afterEach(async () => {
fs.rmSync(tempVaultDir, { recursive: true, force: true })
})
test('creating an untitled draft hides the legacy title section in the editor', async ({ page }) => {
await page.locator('button[title="Create new note"]').click()
await expect(page.getByRole('textbox').last()).toBeVisible({ timeout: 5_000 })
await expect(page.getByTestId('title-field-input')).toHaveCount(0)
await expect(page.locator('.title-section[data-title-ui-visible]')).toHaveCount(0)
})