From a779edd08a52bbca1dcbadd947f53bb9341683e3 Mon Sep 17 00:00:00 2001 From: Danila Poyarkov Date: Thu, 10 Sep 2026 14:26:36 +0300 Subject: [PATCH] refactor: scope browser test instrumentation and global types (#667) --- AGENTS.md | 6 +- packages/vue/src/global.d.ts | 12 ---- src/app/browser-bridge.ts | 6 -- src/global.d.ts | 19 +----- tests/e2e/editor/drag-performance.spec.ts | 44 +------------ tests/e2e/editor/resize-performance.spec.ts | 40 +----------- tests/e2e/fonts/picker.spec.ts | 70 +++------------------ tests/e2e/layers/drop-indicator.spec.ts | 26 ++------ tests/e2e/perf/large-document.spec.ts | 34 ++-------- tests/helpers/fonts/google.ts | 30 +++++++++ tests/helpers/performance/hit-testing.ts | 34 ++++++++++ tests/helpers/performance/interaction.ts | 45 +++++++++++++ tests/helpers/tauri/clipboard-mock.ts | 10 ++- tests/helpers/tauri/fig-export-fixture.ts | 8 +-- tests/helpers/tauri/mocks.ts | 8 +-- tsconfig.json | 4 +- 16 files changed, 153 insertions(+), 243 deletions(-) create mode 100644 tests/helpers/fonts/google.ts create mode 100644 tests/helpers/performance/hit-testing.ts create mode 100644 tests/helpers/performance/interaction.ts diff --git a/AGENTS.md b/AGENTS.md index e5b6a536d..0b84afee8 100644 --- a/AGENTS.md +++ b/AGENTS.md @@ -139,7 +139,11 @@ Private tooling belongs under `tools//{src,tests}`, with kebab-case doma - Use `@/` for app cross-directory imports. Package aliases are `#vue/*`, `#cli/*`, `#dom-css/*`, `#mcp/*`, and `#core/*`; prefer clear relative imports nearby. - No `any`, non-null assertions, or `Math.random()`; use precise types, guards, and `crypto.getRandomValues()`. - Reuse named types and primitives from `@open-pencil/scene-graph`; do not respell `Color`, `Vector`, `SceneNode`, `Effect`, `Fill`, or `Stroke` shapes. -- Window API declarations belong in `src/global.d.ts` or `packages/core/src/global.d.ts`. +- Window API augmentations belong in the owning compilation boundary: app declarations in `src/global.d.ts`, package DOM gaps in the owning package's `global.d.ts`, and native-test declarations in `tests/helpers/tauri/native-global.d.ts`. Never put `declare global` in specs or implementation modules. Include canonical declarations through tsconfig instead of duplicating them. +- Keep app API contracts named and owned by their implementation domain; declaration files import those types. Derive vendor API types from top-level type imports rather than hand-copying signatures. Optional runtime globals remain optional and require a runtime guard. +- Native tests centralize invocation in a guarded test helper using vendor-derived types; do not import packages inside serialized WebView callbacks or repeat direct Tauri-global access in specs. Never expand production Window declarations just to accommodate test fixtures. +- Prefer test-runner-owned fixtures and request/route counters over browser globals. For in-page performance instrumentation, return a scoped `JSHandle` from `evaluateHandle()`; restore patched methods/listeners and dispose the handle in `finally`. Handles do not survive navigation. Assert transient DOM state with locators before the interaction ends when possible. Do not create a catch-all test Window interface or add ad-hoc counter properties to window. +- In Bun tests, prefer injected dependencies or scoped spies with explicit cleanup. `mock.restore()` restores spies but does not undo `mock.module()` overrides; do not assume module mocks are isolated by cleanup hooks. Read the installed runner's current lifecycle/mocking docs before introducing global or module-level instrumentation. - Use `culori` for color conversion and existing dependencies before custom implementations. - Prefer VueUse for common browser, event, focus, clipboard, storage, and timer behavior, but keep one-shot rAF or explicit service-owned timers when clearer. - Components must not hold module-level mutable state. Share repeated logic/constants rather than copying it. diff --git a/packages/vue/src/global.d.ts b/packages/vue/src/global.d.ts index 0ded8a35f..6afa97ac0 100644 --- a/packages/vue/src/global.d.ts +++ b/packages/vue/src/global.d.ts @@ -1,15 +1,3 @@ -interface FontData { - family: string - fullName: string - postscriptName: string - style: string - blob(): Promise -} - -interface Window { - queryLocalFonts?(): Promise -} - interface GestureEvent extends UIEvent { scale: number rotation: number diff --git a/src/app/browser-bridge.ts b/src/app/browser-bridge.ts index 93c2c24cf..4ca7146bc 100644 --- a/src/app/browser-bridge.ts +++ b/src/app/browser-bridge.ts @@ -28,12 +28,6 @@ export interface OpenPencilWindowAPI { test?: OpenPencilTestHooks } -declare global { - interface Window { - openPencil?: OpenPencilWindowAPI - } -} - let activeStore: EditorStore | null = null function windowAPI(): OpenPencilWindowAPI { diff --git a/src/global.d.ts b/src/global.d.ts index bd7d8b684..ab6c59985 100644 --- a/src/global.d.ts +++ b/src/global.d.ts @@ -1,13 +1,8 @@ +import type { OpenPencilWindowAPI } from './app/browser-bridge' + export {} declare global { - interface GestureEvent extends UIEvent { - scale: number - rotation: number - clientX: number - clientY: number - } - interface FilePickerAcceptType { description: string accept: Record @@ -20,17 +15,9 @@ declare global { } interface Window { + openPencil?: OpenPencilWindowAPI showOpenFilePicker?(options?: FilePickerOptions): Promise showSaveFilePicker?(options?: FilePickerOptions): Promise - queryLocalFonts?(): Promise< - { - family: string - fullName: string - style: string - postscriptName: string - blob(): Promise - }[] - > mockWindowOpen?(url: string): void } } diff --git a/tests/e2e/editor/drag-performance.spec.ts b/tests/e2e/editor/drag-performance.spec.ts index 76bd8ebc1..7064c5560 100644 --- a/tests/e2e/editor/drag-performance.spec.ts +++ b/tests/e2e/editor/drag-performance.spec.ts @@ -1,6 +1,7 @@ import { expect, test } from '@playwright/test' import { CanvasHelper } from '#tests/helpers/canvas' +import { measureInteraction } from '#tests/helpers/performance/interaction' test('dragging a nested card uses repaint-only position previews', async ({ page }) => { await page.goto('/') @@ -46,48 +47,7 @@ test('dragging a nested card uses repaint-only position previews', async ({ page }) await canvas.waitForRender() - await page.evaluate(() => { - const store = window.openPencil?.getStore?.() - if (!store) throw new Error('OpenPencil store not initialized') - const originalStoreUpdate = store.updateNode.bind(store) - const originalGraphUpdate = store.graph.updateNode.bind(store.graph) - let storeUpdateCount = 0 - let graphUpdateCount = 0 - let repaintCount = 0 - store.updateNode = ((id, changes) => { - storeUpdateCount++ - return originalStoreUpdate(id, changes) - }) as typeof store.updateNode - store.graph.updateNode = ((id, changes) => { - graphUpdateCount++ - return originalGraphUpdate(id, changes) - }) as typeof store.graph.updateNode - store.onEditorEvent('repaint:requested', () => { - repaintCount++ - }) - Object.assign(window, { - __openPencilDragCounters: () => ({ - storeUpdateCount, - graphUpdateCount, - repaintCount - }) - }) - }) - - await canvas.drag(110, 110, 210, 150, 20) - - const counters = await page.evaluate(() => { - const getCounters = ( - window as typeof window & { - __openPencilDragCounters?: () => { - storeUpdateCount: number - graphUpdateCount: number - repaintCount: number - } - } - ).__openPencilDragCounters - return getCounters?.() ?? null - }) + const counters = await measureInteraction(page, () => canvas.drag(110, 110, 210, 150, 20)) expect(counters?.storeUpdateCount).toBeLessThanOrEqual(1) expect(counters?.graphUpdateCount).toBeLessThanOrEqual(25) diff --git a/tests/e2e/editor/resize-performance.spec.ts b/tests/e2e/editor/resize-performance.spec.ts index bdcf66655..f38646344 100644 --- a/tests/e2e/editor/resize-performance.spec.ts +++ b/tests/e2e/editor/resize-performance.spec.ts @@ -1,6 +1,7 @@ import { expect, test } from '@playwright/test' import { CanvasHelper } from '#tests/helpers/canvas' +import { measureInteraction } from '#tests/helpers/performance/interaction' test('resizing uses repaint-only previews until mouseup', async ({ page }) => { await page.goto('/') @@ -39,44 +40,7 @@ test('resizing uses repaint-only previews until mouseup', async ({ page }) => { }) await canvas.waitForRender() - await page.evaluate((selectedId) => { - const store = window.openPencil?.getStore?.() - if (!store) throw new Error('OpenPencil store not initialized') - const originalStoreUpdate = store.updateNode.bind(store) - const originalGraphUpdate = store.graph.updateNode.bind(store.graph) - let storeUpdateCount = 0 - let graphUpdateCount = 0 - let repaintCount = 0 - store.updateNode = ((nodeId, changes) => { - if (nodeId === selectedId) storeUpdateCount++ - return originalStoreUpdate(nodeId, changes) - }) as typeof store.updateNode - store.graph.updateNode = ((nodeId, changes) => { - if (nodeId === selectedId) graphUpdateCount++ - return originalGraphUpdate(nodeId, changes) - }) as typeof store.graph.updateNode - store.onEditorEvent('repaint:requested', () => { - repaintCount++ - }) - Object.assign(window, { - __openPencilResizeCounters: () => ({ storeUpdateCount, graphUpdateCount, repaintCount }) - }) - }, id) - - await canvas.drag(340, 240, 420, 290, 12) - - const counters = await page.evaluate(() => { - const getCounters = ( - window as typeof window & { - __openPencilResizeCounters?: () => { - storeUpdateCount: number - graphUpdateCount: number - repaintCount: number - } - } - ).__openPencilResizeCounters - return getCounters?.() ?? null - }) + const counters = await measureInteraction(page, () => canvas.drag(340, 240, 420, 290, 12), id) const node = await page.evaluate((nodeId) => { const store = window.openPencil?.getStore?.() if (!store) throw new Error('OpenPencil store not initialized') diff --git a/tests/e2e/fonts/picker.spec.ts b/tests/e2e/fonts/picker.spec.ts index 5377cea2d..2e221796c 100644 --- a/tests/e2e/fonts/picker.spec.ts +++ b/tests/e2e/fonts/picker.spec.ts @@ -1,6 +1,7 @@ import { expect, test, type Page } from '@playwright/test' import { CanvasHelper } from '#tests/helpers/canvas' +import { mockGoogleFonts } from '#tests/helpers/fonts/google' async function openTypographyForText(page: Page) { await page.goto('/') @@ -25,51 +26,8 @@ async function searchFonts(page: Page, query: string) { await page.getByRole('combobox', { name: 'Search fonts…' }).fill(query) } -async function installGoogleFontsMock(page: Page, families = ['Inter', 'OpenPencil Google Font']) { - await page.addInitScript((googleFamilies) => { - const win = window as Window & { - __googleFontsFetchCount?: number - __googleFontPreviewFetchCount?: number - } - win.__googleFontsFetchCount = 0 - win.__googleFontPreviewFetchCount = 0 - const originalFetch = window.fetch.bind(window) - window.fetch = async (input, init) => { - let url: string - if (typeof input === 'string') url = input - else if (input instanceof URL) url = input.href - else url = input.url - if (url.startsWith('https://fonts.openpencil.test/')) { - win.__googleFontPreviewFetchCount = (win.__googleFontPreviewFetchCount ?? 0) + 1 - return new Response(new ArrayBuffer(8), { status: 200 }) - } - if (url.startsWith('https://fonts.google.com/metadata/fonts')) { - win.__googleFontsFetchCount = (win.__googleFontsFetchCount ?? 0) + 1 - return new Response( - JSON.stringify({ - familyMetadataList: googleFamilies.map((family) => ({ - family, - axes: [], - fonts: { '400': {} } - })) - }), - { status: 200, headers: { 'content-type': 'application/json' } } - ) - } - if (url.startsWith('https://fonts.googleapis.com/css2')) { - const family = new URL(url).searchParams.get('family')?.split(':')[0] ?? 'Inter' - return new Response( - `@font-face { font-family: '${family}'; font-style: normal; font-weight: 400; src: url(https://fonts.openpencil.test/${encodeURIComponent(family)}.ttf) format('truetype'); }`, - { status: 200, headers: { 'content-type': 'text/css' } } - ) - } - return originalFetch(input, init) - } - }, families) -} - test('font picker selects local fonts without browser web-font access', async ({ page }) => { - await installGoogleFontsMock(page) + const fonts = await mockGoogleFonts(page) await page.addInitScript(() => { Object.defineProperty(window, 'queryLocalFonts', { configurable: true, @@ -109,17 +67,13 @@ test('font picker selects local fonts without browser web-font access', async ({ }, textId) ) .toBe('OpenPencil Local Font') - expect( - await page.evaluate( - () => (window as Window & { __googleFontsFetchCount?: number }).__googleFontsFetchCount - ) - ).toBe(0) + expect(fonts.counts.metadata).toBe(0) }) test('font picker keeps bundled fonts when local and web fonts are unavailable', async ({ page }) => { - await installGoogleFontsMock(page) + const fonts = await mockGoogleFonts(page) await page.addInitScript(() => { Reflect.deleteProperty(window, 'queryLocalFonts') }) @@ -134,15 +88,11 @@ test('font picker keeps bundled fonts when local and web fonts are unavailable', await expect( page.getByTestId('font-picker-item').filter({ hasText: 'OpenPencil Google Font' }) ).toHaveCount(0) - expect( - await page.evaluate( - () => (window as Window & { __googleFontsFetchCount?: number }).__googleFontsFetchCount - ) - ).toBe(0) + expect(fonts.counts.metadata).toBe(0) }) test('font picker keeps bundled fonts when local font permission is rejected', async ({ page }) => { - await installGoogleFontsMock(page) + const fonts = await mockGoogleFonts(page) await page.addInitScript(() => { Object.defineProperty(window, 'queryLocalFonts', { configurable: true, @@ -162,17 +112,13 @@ test('font picker keeps bundled fonts when local font permission is rejected', a await expect( page.getByTestId('font-picker-item').filter({ hasText: 'OpenPencil Google Font' }) ).toHaveCount(0) - expect( - await page.evaluate( - () => (window as Window & { __googleFontsFetchCount?: number }).__googleFontsFetchCount - ) - ).toBe(0) + expect(fonts.counts.metadata).toBe(0) }) test('font picker keeps bundled Inter available when local and Google fonts are unavailable', async ({ page }) => { - await installGoogleFontsMock(page, []) + await mockGoogleFonts(page, []) await page.addInitScript(() => { Reflect.deleteProperty(window, 'queryLocalFonts') }) diff --git a/tests/e2e/layers/drop-indicator.spec.ts b/tests/e2e/layers/drop-indicator.spec.ts index c0c711f69..6aba0f1f2 100644 --- a/tests/e2e/layers/drop-indicator.spec.ts +++ b/tests/e2e/layers/drop-indicator.spec.ts @@ -10,19 +10,6 @@ async function dragLayerAndObserveIndicator( targetId: string, targetPosition: Vector ) { - await page.evaluate(() => { - const positions: string[] = [] - new MutationObserver(() => { - for (const element of document.querySelectorAll( - '[data-slot="drop-indicator"]' - )) { - const position = element.dataset.dropPosition - if (position) positions.push(position) - } - }).observe(document.body, { subtree: true, childList: true, attributes: true }) - Object.assign(window, { __layerDropPositions: positions }) - }) - const source = page.locator(`[data-node-id="${sourceId}"]`) const target = page.locator(`[data-node-id="${targetId}"]`) const sourceBox = await source.boundingBox() @@ -35,12 +22,11 @@ async function dragLayerAndObserveIndicator( await page.mouse.move(targetBox.x + targetPosition.x, targetBox.y + targetPosition.y, { steps: 20 }) - await expect(target.locator('[data-slot="drop-indicator"]')).toBeVisible() + const indicator = target.locator('[data-slot="drop-indicator"]') + await expect(indicator).toBeVisible() + const position = await indicator.getAttribute('data-drop-position') await page.mouse.up() - - return page.evaluate( - () => (window as typeof window & { __layerDropPositions?: string[] }).__layerDropPositions ?? [] - ) + return position } test('layer reorder exposes a visible drop indicator before dropping', async ({ page }) => { @@ -67,7 +53,7 @@ test('layer reorder exposes a visible drop indicator before dropping', async ({ y: 2 }) - expect(positions).toContain('above') + expect(positions).toBe('above') canvas.assertNoErrors() }) @@ -98,6 +84,6 @@ test('layer child drop exposes a visible container highlight before dropping', a y: 12 }) - expect(positions).toContain('child') + expect(positions).toBe('child') canvas.assertNoErrors() }) diff --git a/tests/e2e/perf/large-document.spec.ts b/tests/e2e/perf/large-document.spec.ts index fd126f68a..80edd2d38 100644 --- a/tests/e2e/perf/large-document.spec.ts +++ b/tests/e2e/perf/large-document.spec.ts @@ -2,6 +2,7 @@ import { expect, test } from '@playwright/test' import { CanvasHelper } from '#tests/helpers/canvas' import { seedLargeDocument } from '#tests/helpers/large-document' +import { measureHitTesting } from '#tests/helpers/performance/hit-testing' type TimingSummary = { hitTestMissMs: number @@ -31,36 +32,13 @@ test.describe.serial('large-document performance', () => { const fixture = await seedLargeDocument(page, nodeCount) await canvas.waitForRender() - await page.evaluate(() => { - const store = window.openPencil?.getStore?.() - if (!store) throw new Error('OpenPencil store not initialized') - const originalHitTest = store.graph.hitTest.bind(store.graph) - let calls = 0 - let totalMs = 0 - store.graph.hitTest = ((...args) => { - const startedAt = performance.now() - const result = originalHitTest(...args) - totalMs += performance.now() - startedAt - calls++ - return result - }) as typeof store.graph.hitTest - Object.assign(window, { - __largeDocumentPointerProfile: () => ({ calls, totalMs }) - }) - }) const bounds = await canvas.canvas.boundingBox() if (!bounds) throw new Error('Canvas bounds unavailable') - await page.mouse.move(bounds.x + 10, bounds.y + 10) - await page.mouse.move(bounds.x + bounds.width - 10, bounds.y + bounds.height - 10, { - steps: 40 - }) - const pointerProfile = await page.evaluate(() => { - const profile = ( - window as typeof window & { - __largeDocumentPointerProfile?: () => { calls: number; totalMs: number } - } - ).__largeDocumentPointerProfile - return profile?.() ?? { calls: 0, totalMs: 0 } + const pointerProfile = await measureHitTesting(page, async () => { + await page.mouse.move(bounds.x + 10, bounds.y + 10) + await page.mouse.move(bounds.x + bounds.width - 10, bounds.y + bounds.height - 10, { + steps: 40 + }) }) const result = await page.evaluate((profile): Promise => { diff --git a/tests/helpers/fonts/google.ts b/tests/helpers/fonts/google.ts new file mode 100644 index 000000000..a40d700e5 --- /dev/null +++ b/tests/helpers/fonts/google.ts @@ -0,0 +1,30 @@ +import type { Page, Route } from '@playwright/test' + +/** Route-owned counts live in the runner, not on window or in a patched fetch. */ +export async function mockGoogleFonts(page: Page, families = ['Inter', 'OpenPencil Google Font']) { + const counts = { metadata: 0, previews: 0 } + const pattern = + /^https:\/\/(fonts\.openpencil\.test\/|fonts\.google\.com\/metadata\/fonts|fonts\.googleapis\.com\/css2)/ + async function handle(route: Route) { + const url = new URL(route.request().url()) + if (url.hostname === 'fonts.openpencil.test') { + counts.previews++ + await route.fulfill({ status: 200, body: Buffer.alloc(8) }) + } else if (url.hostname === 'fonts.google.com') { + counts.metadata++ + await route.fulfill({ + json: { + familyMetadataList: families.map((family) => ({ family, axes: [], fonts: { '400': {} } })) + } + }) + } else { + const family = url.searchParams.get('family')?.split(':')[0] ?? 'Inter' + await route.fulfill({ + contentType: 'text/css', + body: `@font-face { font-family: '${family}'; font-style: normal; font-weight: 400; src: url(https://fonts.openpencil.test/${encodeURIComponent(family)}.ttf) format('truetype'); }` + }) + } + } + await page.route(pattern, handle) + return { counts, dispose: () => page.unroute(pattern, handle) } +} diff --git a/tests/helpers/performance/hit-testing.ts b/tests/helpers/performance/hit-testing.ts new file mode 100644 index 000000000..2b80e40e2 --- /dev/null +++ b/tests/helpers/performance/hit-testing.ts @@ -0,0 +1,34 @@ +import type { Page } from '@playwright/test' + +export async function measureHitTesting(page: Page, run: () => Promise) { + const probe = await page.evaluateHandle(() => { + const graph = window.openPencil?.getStore?.().graph + if (!graph) throw new Error('OpenPencil graph not initialized') + const original = graph.hitTest + let calls = 0 + let totalMs = 0 + graph.hitTest = (...args) => { + const start = performance.now() + const result = original.apply(graph, args) + totalMs += performance.now() - start + calls++ + return result + } + return { + read: () => ({ calls, totalMs }), + dispose: () => { + graph.hitTest = original + } + } + }) + try { + await run() + return await probe.evaluate((probe) => probe.read()) + } finally { + try { + await probe.evaluate((probe) => probe.dispose()) + } finally { + await probe.dispose() + } + } +} diff --git a/tests/helpers/performance/interaction.ts b/tests/helpers/performance/interaction.ts new file mode 100644 index 000000000..27d71bcf1 --- /dev/null +++ b/tests/helpers/performance/interaction.ts @@ -0,0 +1,45 @@ +import type { Page } from '@playwright/test' + +/** Own the instrumentation and remote handle for exactly one interaction. */ +export async function measureInteraction( + page: Page, + run: () => Promise, + selectedId?: string +) { + const probe = await page.evaluateHandle((selectedId) => { + const store = window.openPencil?.getStore?.() + if (!store) throw new Error('OpenPencil store not initialized') + const update = store.updateNode + const graphUpdate = store.graph.updateNode + const counts = { storeUpdateCount: 0, graphUpdateCount: 0, repaintCount: 0 } + store.updateNode = (id, changes) => { + if (!selectedId || id === selectedId) counts.storeUpdateCount++ + return update.call(store, id, changes) + } + store.graph.updateNode = (id, changes) => { + if (!selectedId || id === selectedId) counts.graphUpdateCount++ + return graphUpdate.call(store.graph, id, changes) + } + const unsubscribe = store.onEditorEvent('repaint:requested', () => { + counts.repaintCount++ + }) + return { + read: () => ({ ...counts }), + dispose() { + store.updateNode = update + store.graph.updateNode = graphUpdate + unsubscribe() + } + } + }, selectedId) + try { + await run() + return await probe.evaluate((probe) => probe.read()) + } finally { + try { + await probe.evaluate((probe) => probe.dispose()) + } finally { + await probe.dispose() + } + } +} diff --git a/tests/helpers/tauri/clipboard-mock.ts b/tests/helpers/tauri/clipboard-mock.ts index 74ba09174..23e77116d 100644 --- a/tests/helpers/tauri/clipboard-mock.ts +++ b/tests/helpers/tauri/clipboard-mock.ts @@ -57,12 +57,10 @@ export async function installTauriClipboardMock(page: Page): Promise { - const invoke = ( - globalThis as typeof globalThis & { - [key: string]: (cmd: string, args?: Record) => Promise - } - )[bindingName] - if (!invoke) throw new Error(`Playwright binding not found: ${bindingName}`) + const binding: unknown = Reflect.get(globalThis, bindingName) + if (typeof binding !== 'function') + throw new Error(`Playwright binding not found: ${bindingName}`) + const invoke = binding as (cmd: string, args?: Record) => Promise let callbackId = 1 const callbacks = new Map() diff --git a/tests/helpers/tauri/fig-export-fixture.ts b/tests/helpers/tauri/fig-export-fixture.ts index 1cba85d6e..24e3eab36 100644 --- a/tests/helpers/tauri/fig-export-fixture.ts +++ b/tests/helpers/tauri/fig-export-fixture.ts @@ -1,10 +1,8 @@ import { mockIPC } from '@tauri-apps/api/mocks' -const windowLike = globalThis as typeof globalThis & { - __TAURI_INTERNALS__?: unknown - __TAURI_EVENT_PLUGIN_INTERNALS__?: unknown -} -Object.assign(globalThis, { window: windowLike }) +import { installTauriMockWindow } from './mocks' + +installTauriMockWindow() mockIPC((cmd, args) => { if (cmd !== 'build_fig_file') throw new Error(`Unexpected command: ${cmd}`) diff --git a/tests/helpers/tauri/mocks.ts b/tests/helpers/tauri/mocks.ts index 620992432..5ec3da391 100644 --- a/tests/helpers/tauri/mocks.ts +++ b/tests/helpers/tauri/mocks.ts @@ -1,9 +1,5 @@ export function installTauriMockWindow() { - const windowLike = globalThis as typeof globalThis & { - __TAURI_INTERNALS__?: unknown - __TAURI_EVENT_PLUGIN_INTERNALS__?: unknown - } - Object.assign(globalThis, { window: windowLike }) + Object.assign(globalThis, { window: globalThis }) } export async function mockTauriIPC( @@ -26,5 +22,5 @@ export async function clearTauriMocks() { clearMocks() Reflect.deleteProperty(window, '__TAURI_INTERNALS__') Reflect.deleteProperty(window, '__TAURI_EVENT_PLUGIN_INTERNALS__') - delete (globalThis as typeof globalThis & { window?: unknown }).window + Reflect.deleteProperty(globalThis, 'window') } diff --git a/tsconfig.json b/tsconfig.json index 8e25f00da..1284339ff 100644 --- a/tsconfig.json +++ b/tsconfig.json @@ -89,7 +89,9 @@ }, "include": [ "src/**/*.ts", - "src/**/*.vue" + "src/**/*.vue", + "packages/core/src/global.d.ts", + "packages/vue/src/global.d.ts" ], "references": [ {