test: stabilize the smoke lane
This commit is contained in:
@@ -13,7 +13,7 @@
|
||||
"test": "vitest run",
|
||||
"test:watch": "vitest",
|
||||
"test:e2e": "playwright test",
|
||||
"playwright:smoke": "playwright test --config playwright.smoke.config.ts tests/smoke/example.spec.ts tests/smoke/fix-ai-chat-empty-body-v3.spec.ts tests/smoke/raw-editor-sync-to-blocknote.spec.ts tests/integration/vault-workflows.spec.ts",
|
||||
"playwright:smoke": "playwright test --config playwright.smoke.config.ts tests/smoke/example.spec.ts tests/smoke/fix-ai-chat-empty-body-v3.spec.ts tests/smoke/create-note-crash.spec.ts tests/smoke/raw-editor-sync-to-blocknote.spec.ts tests/smoke/rename-wikilink-update.spec.ts",
|
||||
"playwright:regression": "playwright test tests/smoke/",
|
||||
"playwright:integration": "playwright test --config playwright.integration.config.ts",
|
||||
"test:coverage": "vitest run --coverage",
|
||||
|
||||
82
tests/helpers/fixtureVault.ts
Normal file
82
tests/helpers/fixtureVault.ts
Normal file
@@ -0,0 +1,82 @@
|
||||
import { expect, type Page } from '@playwright/test'
|
||||
import fs from 'fs'
|
||||
import os from 'os'
|
||||
import path from 'path'
|
||||
|
||||
const FIXTURE_VAULT = path.resolve('tests/fixtures/test-vault')
|
||||
|
||||
function copyDirSync(src: string, dest: string): void {
|
||||
fs.mkdirSync(dest, { recursive: true })
|
||||
for (const item of fs.readdirSync(src, { withFileTypes: true })) {
|
||||
const sourcePath = path.join(src, item.name)
|
||||
const destinationPath = path.join(dest, item.name)
|
||||
if (item.isDirectory()) {
|
||||
copyDirSync(sourcePath, destinationPath)
|
||||
continue
|
||||
}
|
||||
fs.copyFileSync(sourcePath, destinationPath)
|
||||
}
|
||||
}
|
||||
|
||||
export function createFixtureVaultCopy(): string {
|
||||
const tempVaultDir = fs.mkdtempSync(path.join(os.tmpdir(), 'laputa-test-vault-'))
|
||||
copyDirSync(FIXTURE_VAULT, tempVaultDir)
|
||||
return tempVaultDir
|
||||
}
|
||||
|
||||
export function removeFixtureVaultCopy(tempVaultDir: string | null | undefined): void {
|
||||
if (!tempVaultDir) return
|
||||
fs.rmSync(tempVaultDir, { recursive: true, force: true })
|
||||
}
|
||||
|
||||
export async function openFixtureVault(
|
||||
page: Page,
|
||||
vaultPath: string,
|
||||
): Promise<void> {
|
||||
await page.addInitScript((resolvedVaultPath: string) => {
|
||||
localStorage.clear()
|
||||
|
||||
const nativeFetch = window.fetch.bind(window)
|
||||
window.fetch = (input: RequestInfo | URL, init?: RequestInit) => {
|
||||
const requestUrl = typeof input === 'string'
|
||||
? input
|
||||
: input instanceof Request
|
||||
? input.url
|
||||
: input.toString()
|
||||
|
||||
if (requestUrl.endsWith('/api/vault/ping') || requestUrl.includes('/api/vault/ping?')) {
|
||||
return Promise.resolve(new Response(JSON.stringify({ ok: true }), {
|
||||
status: 200,
|
||||
headers: { 'Content-Type': 'application/json' },
|
||||
}))
|
||||
}
|
||||
|
||||
return nativeFetch(input, init)
|
||||
}
|
||||
|
||||
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
||||
let ref: any = null
|
||||
Object.defineProperty(window, '__mockHandlers', {
|
||||
configurable: true,
|
||||
set(value) {
|
||||
ref = value
|
||||
ref.load_vault_list = () => ({
|
||||
vaults: [{ label: 'Test Vault', path: resolvedVaultPath }],
|
||||
active_vault: resolvedVaultPath,
|
||||
hidden_defaults: [],
|
||||
})
|
||||
ref.check_vault_exists = () => true
|
||||
ref.get_last_vault_path = () => resolvedVaultPath
|
||||
ref.get_default_vault_path = () => resolvedVaultPath
|
||||
ref.save_vault_list = () => null
|
||||
},
|
||||
get() {
|
||||
return ref
|
||||
},
|
||||
})
|
||||
}, vaultPath)
|
||||
|
||||
await page.goto('/')
|
||||
await page.locator('[data-testid="note-list-container"]').waitFor({ timeout: 15_000 })
|
||||
await expect(page.getByText('Alpha Project', { exact: true }).first()).toBeVisible({ timeout: 15_000 })
|
||||
}
|
||||
@@ -8,58 +8,18 @@
|
||||
import { test, expect } from '@playwright/test'
|
||||
import fs from 'fs'
|
||||
import path from 'path'
|
||||
import os from 'os'
|
||||
|
||||
const FIXTURE_VAULT = path.resolve('tests/fixtures/test-vault')
|
||||
|
||||
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)
|
||||
}
|
||||
}
|
||||
import { createFixtureVaultCopy, openFixtureVault, removeFixtureVaultCopy } from '../helpers/fixtureVault'
|
||||
|
||||
let tempVaultDir: string
|
||||
|
||||
test.beforeEach(async ({ page }) => {
|
||||
// Fresh vault copy for each test
|
||||
tempVaultDir = fs.mkdtempSync(path.join(os.tmpdir(), 'laputa-test-vault-'))
|
||||
copyDirSync(FIXTURE_VAULT, tempVaultDir)
|
||||
|
||||
// Intercept window.__mockHandlers assignment to override vault path handlers.
|
||||
// The Object.defineProperty setter fires when mock-tauri/index.ts sets
|
||||
// window.__mockHandlers = mockHandlers, letting us patch the same object
|
||||
// reference that mockInvoke reads from.
|
||||
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)
|
||||
|
||||
await page.goto('/')
|
||||
// Wait until the real vault entries are loaded in the sidebar
|
||||
await page.getByText('Alpha Project', { exact: true }).first().waitFor({ timeout: 10_000 })
|
||||
test.beforeEach(async ({ page }, testInfo) => {
|
||||
testInfo.setTimeout(60_000)
|
||||
tempVaultDir = createFixtureVaultCopy()
|
||||
await openFixtureVault(page, tempVaultDir)
|
||||
})
|
||||
|
||||
test.afterEach(async () => {
|
||||
fs.rmSync(tempVaultDir, { recursive: true, force: true })
|
||||
removeFixtureVaultCopy(tempVaultDir)
|
||||
})
|
||||
|
||||
/** Helper: locate the note-list container. */
|
||||
|
||||
@@ -5,7 +5,7 @@ function isCrashError(msg: string): boolean {
|
||||
return msg.includes('Maximum update depth') || msg.includes('Invalid hook call') || msg.includes('#185')
|
||||
}
|
||||
|
||||
test('create note via Cmd+N does not crash', async ({ page }) => {
|
||||
test('create note via Cmd+N does not crash @smoke', async ({ page }) => {
|
||||
const errors: string[] = []
|
||||
page.on('pageerror', (err) => { if (isCrashError(err.message)) errors.push(err.message) })
|
||||
|
||||
@@ -17,7 +17,9 @@ test('create note via Cmd+N does not crash', async ({ page }) => {
|
||||
await page.waitForTimeout(2000)
|
||||
|
||||
expect(errors).toHaveLength(0)
|
||||
await expect(page.locator('[data-testid="title-field-input"]')).toBeVisible()
|
||||
const noteList = page.locator('[data-testid="note-list-container"]')
|
||||
await expect(noteList.getByText(/Untitled Note/i).first()).toBeVisible({ timeout: 5000 })
|
||||
await expect(page.getByRole('textbox').last()).toBeVisible()
|
||||
})
|
||||
|
||||
test('create note via sidebar + button does not crash', async ({ page }) => {
|
||||
|
||||
@@ -1,52 +1,16 @@
|
||||
import { test, expect } from '@playwright/test'
|
||||
import fs from 'fs'
|
||||
import path from 'path'
|
||||
import os from 'os'
|
||||
|
||||
const FIXTURE_VAULT = path.resolve('tests/fixtures/test-vault')
|
||||
|
||||
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)
|
||||
}
|
||||
}
|
||||
import { createFixtureVaultCopy, openFixtureVault, removeFixtureVaultCopy } from '../helpers/fixtureVault'
|
||||
|
||||
let tempVaultDir: string
|
||||
|
||||
test.beforeEach(async ({ page }) => {
|
||||
tempVaultDir = fs.mkdtempSync(path.join(os.tmpdir(), 'laputa-test-vault-'))
|
||||
copyDirSync(FIXTURE_VAULT, tempVaultDir)
|
||||
|
||||
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)
|
||||
|
||||
await page.goto('/')
|
||||
await page.getByText('Alpha Project', { exact: true }).first().waitFor({ timeout: 10_000 })
|
||||
test.beforeEach(async ({ page }, testInfo) => {
|
||||
testInfo.setTimeout(60_000)
|
||||
tempVaultDir = createFixtureVaultCopy()
|
||||
await openFixtureVault(page, tempVaultDir)
|
||||
})
|
||||
|
||||
test.afterEach(async () => {
|
||||
fs.rmSync(tempVaultDir, { recursive: true, force: true })
|
||||
removeFixtureVaultCopy(tempVaultDir)
|
||||
})
|
||||
|
||||
test('creating an untitled draft hides the legacy title section in the editor', async ({ page }) => {
|
||||
|
||||
@@ -7,7 +7,7 @@ test.describe('Renaming a note updates wikilinks across the vault', () => {
|
||||
await page.waitForLoadState('networkidle')
|
||||
})
|
||||
|
||||
test('title field rename triggers rename flow and shows toast', async ({ page }) => {
|
||||
test('title field rename triggers rename flow and shows toast @smoke', async ({ page }) => {
|
||||
// 1. Click the first note in the list to open it
|
||||
const noteListContainer = page.locator('[data-testid="note-list-container"]')
|
||||
await noteListContainer.waitFor({ timeout: 5000 })
|
||||
|
||||
Reference in New Issue
Block a user