// Shared fixtures for the per-theme bridge-action tests. // // Each action test file mocks `../src/bridge/bridge-oidb` and (where // needed) `../src/bridge/highway/*` so we can assert what the action // asked the OIDB / Highway layer to do without booting a real Bridge. // // `mockBridge()` returns a minimal stand-in: enough state for the // actions to thread but no real packet/event machinery. // // As the #6 Api-on-ctx refactor moves business methods OFF Bridge and // onto `bridge.apis..method()`, the mock grows an `apis` block // matching the ApiHub shape. Each Api gets its own stub helper // (e.g. `mockMessageApi()`) and tests can override individual entries // via `mockBridge({ apis: { message: ... } })`. import { vi } from 'vitest'; import type { SendPacketResult } from '@snowluma/common/packet-sender'; /** Default receipt returned by sendGroup / sendPrivate / sendC2cFile mocks. */ const STUB_RECEIPT = { messageId: 1, sequence: 1, clientSequence: 0, random: 1, timestamp: 0 }; export interface MockMessageApi { sendGroup: ReturnType; sendPrivate: ReturnType; sendC2cFile: ReturnType; recallGroup: ReturnType; recallPrivate: ReturnType; markGroupRead: ReturnType; markPrivateRead: ReturnType; markAllRead: ReturnType; } export function mockMessageApi(): MockMessageApi { return { sendGroup: vi.fn(async () => STUB_RECEIPT), sendPrivate: vi.fn(async () => STUB_RECEIPT), sendC2cFile: vi.fn(async () => STUB_RECEIPT), recallGroup: vi.fn(async () => undefined), recallPrivate: vi.fn(async () => undefined), markGroupRead: vi.fn(async () => undefined), markPrivateRead: vi.fn(async () => undefined), markAllRead: vi.fn(async () => undefined), }; } export interface MockContactsApi { fetchFriendList: ReturnType; fetchGroupList: ReturnType; fetchGroupMemberList: ReturnType; fetchUserProfile: ReturnType; fetchGroupRequests: ReturnType; fetchDownloadRKeys: ReturnType; } export function mockContactsApi(): MockContactsApi { return { fetchFriendList: vi.fn(async () => []), fetchGroupList: vi.fn(async () => []), fetchGroupMemberList: vi.fn(async () => []), fetchUserProfile: vi.fn(async () => ({ uid: 'profile-uid' })), fetchGroupRequests: vi.fn(async () => []), fetchDownloadRKeys: vi.fn(async () => []), }; } export interface MockGroupFileApi { upload: ReturnType; uploadPrivate: ReturnType; publish: ReturnType; trans: ReturnType; getCount: ReturnType; list: ReturnType; getUrl: ReturnType; getPrivateUrl: ReturnType; getPttUrl: ReturnType; getPrivatePttUrl: ReturnType; getVideoUrl: ReturnType; getPrivateVideoUrl: ReturnType; delete: ReturnType; move: ReturnType; createFolder: ReturnType; deleteFolder: ReturnType; renameFolder: ReturnType; } export function mockGroupFileApi(): MockGroupFileApi { return { upload: vi.fn(async () => ({ fileId: 'stub-fid' })), uploadPrivate: vi.fn(async () => ({ fileId: 'stub-pfid', fileHash: 'stub-hash' })), publish: vi.fn(async () => undefined), trans: vi.fn(async () => ({ saveBusId: 102, saveFilePath: '/stub-path' })), getCount: vi.fn(async () => ({ fileCount: 0, maxCount: 10000 })), list: vi.fn(async () => ({ files: [], folders: [] })), getUrl: vi.fn(async () => 'stub://url'), getPrivateUrl: vi.fn(async () => 'stub://private-url'), getPttUrl: vi.fn(async () => 'stub://ptt-url'), getPrivatePttUrl: vi.fn(async () => 'stub://private-ptt-url'), getVideoUrl: vi.fn(async () => 'stub://video-url'), getPrivateVideoUrl: vi.fn(async () => 'stub://private-video-url'), delete: vi.fn(async () => undefined), move: vi.fn(async () => undefined), createFolder: vi.fn(async () => undefined), deleteFolder: vi.fn(async () => undefined), renameFolder: vi.fn(async () => undefined), }; } export interface MockApiHub { message: MockMessageApi; contacts: MockContactsApi; groupFile: MockGroupFileApi; // additional Apis added commit-by-commit as #6 progresses } export function mockApiHub(overrides: Partial = {}): MockApiHub { return { message: overrides.message ?? mockMessageApi(), contacts: overrides.contacts ?? mockContactsApi(), groupFile: overrides.groupFile ?? mockGroupFileApi(), }; } export interface MockBridge { identity: { uin: string; selfUid: string; nickname: string; findUidByUin: ReturnType; findUinByUid: ReturnType; resolveUin: ReturnType; findGroupMember: ReturnType; updateFriendRemark: ReturnType; updateGroupRemark: ReturnType; forgetGroup: ReturnType; }; events: { emit: ReturnType }; apis: MockApiHub; sendRawPacket: ReturnType; fetchFriendList: ReturnType; fetchGroupMemberList: ReturnType; fetchUserProfile: ReturnType; resolveUserUid: ReturnType; // Uploaded-file metadata cache helpers — GroupFileApi.upload / // uploadPrivate call these to remember the upload, so tests // covering those code paths get a default-no-op shim. rememberUploadedFile: ReturnType; recallUploadedFile: ReturnType; } export function mockBridge(overrides: Partial = {}): MockBridge { const defaultResp: SendPacketResult = { success: true, gotResponse: true, errorCode: 0, errorMessage: '', responseData: Buffer.alloc(0), }; return { identity: { uin: '10001', selfUid: 'self-uid', nickname: 'self-nick', findUidByUin: vi.fn(() => 'cached-uid'), findUinByUid: vi.fn(() => 0), resolveUin: vi.fn(async () => null), findGroupMember: vi.fn(() => null), updateFriendRemark: vi.fn(() => true), updateGroupRemark: vi.fn(() => true), forgetGroup: vi.fn(), ...(overrides.identity ?? {}), } as MockBridge['identity'], events: overrides.events ?? { emit: vi.fn(async () => undefined) }, apis: overrides.apis ?? mockApiHub(), sendRawPacket: vi.fn(async () => defaultResp), fetchFriendList: vi.fn(async () => []), fetchGroupMemberList: vi.fn(async () => []), fetchUserProfile: vi.fn(async () => ({ uid: 'profile-uid' })), resolveUserUid: vi.fn(async () => 'resolved-uid'), rememberUploadedFile: vi.fn(), recallUploadedFile: vi.fn(() => undefined), ...overrides, }; }