Files
tolaria/tests/smoke/missing-string-metadata-open-note.spec.ts
2026-05-07 22:40:33 +02:00

144 lines
4.7 KiB
TypeScript

import { test, expect, type Locator, type Page } from '@playwright/test'
import {
createFixtureVaultCopy,
openFixtureVaultDesktopHarness,
removeFixtureVaultCopy,
} from '../helpers/fixtureVault'
import { executeCommand, openCommandPalette } from './helpers'
let tempVaultDir: string
function isMissingStringMetadataCrash(message: string): boolean {
return (
message.includes("Cannot read properties of undefined (reading 'replace')") ||
message.includes('undefined is not an object') ||
/undefined.*\.replace|\.replace.*undefined/.test(message)
)
}
function collectMissingMetadataCrashes(page: Page): string[] {
const errors: string[] = []
page.on('pageerror', (error) => {
if (isMissingStringMetadataCrash(error.message)) errors.push(error.message)
})
page.on('console', (message) => {
if (message.type() === 'error' && isMissingStringMetadataCrash(message.text())) {
errors.push(message.text())
}
})
return errors
}
function removeAlphaProjectStringMetadata(entries: Array<Record<string, unknown>>) {
return entries.map((entry) => {
const entryPath = typeof entry.path === 'string' ? entry.path : ''
const title = typeof entry.title === 'string' ? entry.title : ''
if (title !== 'Alpha Project' && !entryPath.endsWith('/alpha-project.md')) return entry
return {
...entry,
title: undefined,
filename: undefined,
aliases: undefined,
outgoingLinks: undefined,
relationships: undefined,
properties: undefined,
snippet: undefined,
}
})
}
function appendMalformedReloadEntry(entries: Array<Record<string, unknown>>) {
return entries.concat({
filename: 'phantom-from-reload.md',
title: 'Phantom From Reload',
aliases: [],
outgoingLinks: [],
relationships: {},
properties: {},
snippet: '',
})
}
function readRouteJsonBody(route: { request: () => { postDataJSON: () => unknown } }): Record<string, unknown> {
try {
const body = route.request().postDataJSON()
return body && typeof body === 'object' && !Array.isArray(body)
? body as Record<string, unknown>
: {}
} catch {
return {}
}
}
async function reloadVaultFromCommandPalette(page: Page): Promise<void> {
await openCommandPalette(page)
await executeCommand(page, 'Reload Vault')
await expect(page.locator('input[placeholder="Type a command..."]')).not.toBeVisible()
}
async function openNoteFromList(noteList: Locator, title: string): Promise<void> {
await noteList.getByText(title, { exact: true }).click()
}
async function expectAlphaProjectHeading(page: Page): Promise<void> {
await expect(page.getByRole('heading', { name: 'Alpha Project', level: 1 })).toBeVisible({ timeout: 5_000 })
}
async function switchFromNoteBBackToAlpha(page: Page, noteList: Locator): Promise<void> {
await openNoteFromList(noteList, 'Note B')
await openNoteFromList(noteList, 'alpha-project')
await expectAlphaProjectHeading(page)
}
test.beforeEach(async ({ page }, testInfo) => {
testInfo.setTimeout(60_000)
tempVaultDir = createFixtureVaultCopy()
await page.route('**/*', async (route) => {
const requestUrl = new URL(route.request().url())
if (!requestUrl.pathname.endsWith('/api/vault/list')) {
await route.continue()
return
}
const response = await route.fetch()
const entries = await response.json() as Array<Record<string, unknown>>
const scrubbedEntries = removeAlphaProjectStringMetadata(entries)
const body = readRouteJsonBody(route)
const isReload = requestUrl.searchParams.get('reload') === '1' || body.reload === true
await route.fulfill({
response,
json: isReload ? appendMalformedReloadEntry(scrubbedEntries) : scrubbedEntries,
})
})
await openFixtureVaultDesktopHarness(page, tempVaultDir, {
expectedReadyTitle: 'alpha-project',
})
await page.setViewportSize({ width: 1180, height: 760 })
})
test.afterEach(() => {
removeFixtureVaultCopy(tempVaultDir)
})
test('@smoke note open tolerates missing string metadata from the vault scan', async ({ page }) => {
const errors = collectMissingMetadataCrashes(page)
const noteList = page.getByTestId('note-list-container')
await openNoteFromList(noteList, 'alpha-project')
await expectAlphaProjectHeading(page)
await switchFromNoteBBackToAlpha(page, noteList)
expect(errors).toHaveLength(0)
})
test('@smoke note open after vault reload tolerates missing suggestion metadata', async ({ page }) => {
const errors = collectMissingMetadataCrashes(page)
const noteList = page.getByTestId('note-list-container')
await reloadVaultFromCommandPalette(page)
await expect(noteList.getByText('Phantom From Reload', { exact: true })).toHaveCount(0)
await switchFromNoteBBackToAlpha(page, noteList)
expect(errors).toHaveLength(0)
})