cc-haha/desktop/electron/services/__electronMock.ts
你的姓名 acb288aa51 fix(ci): repair server/adapter/desktop-native PR checks
- ci: install adapter deps in server-checks job so the server route's
  static import of @whiskeysockets/baileys (via whatsapp adapter) resolves,
  fixing the 34 fail + 7 errors A-group in server-checks
- adapters(ws-bridge): keep a no-op 'error' listener when detaching a
  discarded socket so a pending socket's async ECONNREFUSED can't surface
  as an unhandled exception (was 9 "errors" -> exit 1 in adapter-checks)
- desktop(electron): share one electron module mock across tray/menu tests
  so bun's single-process, last-registered-wins vi.mock('electron') no
  longer leaves tray with menu's mock (missing nativeImage/Tray)

Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
2026-06-11 10:03:50 +08:00

91 lines
2.9 KiB
TypeScript

import { vi } from 'vitest'
/**
* Shared Electron module mock.
*
* `check:electron` runs the whole suite through a single `bun test` process.
* `vi.mock('electron', factory)` registers a *process-global* mock keyed by the
* specifier `'electron'`, and bun keeps only one factory per specifier — the
* last one registered wins. `tray.test.ts` and `menu.test.ts` both mock
* `'electron'`, so whichever factory loses still has to satisfy the other
* file's runtime `await import('electron')`.
*
* To stay correct regardless of file load order, every factory returns the
* *union* of the Electron surface both files need (Menu, Tray, nativeImage),
* all backed by this single shared store.
*/
const electronMockKey = '__electronServiceMocks'
export type ElectronServiceMocks = {
handlers: Map<string, () => void>
buildFromTemplate: ReturnType<typeof vi.fn>
setApplicationMenu: ReturnType<typeof vi.fn>
createFromPath: ReturnType<typeof vi.fn>
tray: {
setToolTip: ReturnType<typeof vi.fn>
setContextMenu: ReturnType<typeof vi.fn>
on: ReturnType<typeof vi.fn>
destroy: ReturnType<typeof vi.fn>
}
Tray: ReturnType<typeof vi.fn>
}
function createElectronServiceMocks(): ElectronServiceMocks {
const handlers = new Map<string, () => void>()
return {
handlers,
buildFromTemplate: vi.fn((template: unknown) => ({ template })),
setApplicationMenu: vi.fn(),
createFromPath: vi.fn((iconPath: string) => ({ iconPath })),
tray: {
setToolTip: vi.fn(),
setContextMenu: vi.fn(),
on: vi.fn((event: string, handler: () => void) => {
handlers.set(event, handler)
}),
destroy: vi.fn(),
},
Tray: vi.fn(),
}
}
/** Returns the shared mock store, lazily creating it on first access. */
export function getElectronServiceMocks(): ElectronServiceMocks {
const store = globalThis as Record<string, unknown>
const existing = store[electronMockKey] as ElectronServiceMocks | undefined
if (existing) return existing
const created = createElectronServiceMocks()
store[electronMockKey] = created
return created
}
/** Resets every mock fn between tests without tearing down the shared store. */
export function resetElectronServiceMocks(): void {
const mocks = getElectronServiceMocks()
mocks.buildFromTemplate.mockClear()
mocks.setApplicationMenu.mockClear()
mocks.createFromPath.mockClear()
mocks.Tray.mockClear()
mocks.tray.setToolTip.mockClear()
mocks.tray.setContextMenu.mockClear()
mocks.tray.on.mockClear()
mocks.tray.destroy.mockClear()
mocks.handlers.clear()
}
/** Builds the mocked `electron` module exports from the shared store. */
export function buildElectronModuleMock() {
const mocks = getElectronServiceMocks()
return {
Menu: {
buildFromTemplate: mocks.buildFromTemplate,
setApplicationMenu: mocks.setApplicationMenu,
},
Tray: mocks.Tray.mockImplementation(() => mocks.tray),
nativeImage: {
createFromPath: mocks.createFromPath,
},
}
}