144 lines
4.7 KiB
TypeScript
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)
|
|
})
|