Files
Xen-Orchestra-xen-orchestra…/@xen-orchestra/web/docs/tests/mocking.md
Olivier Floch 1667ed2a16 test(web): seed every V2V list pool and list VMs through the shared helpers
- seedV2vListPool takes partial offers and the other pool, and sets the collections itself: seedChoices is gone
- the wizard, pool name and source-and-destination tests seed the list pool through it
- createV2vMigrationListVmsOf builds the list VMs of given ids, replacing the hand-written ones; V2vMappingStep reads the stored VM through readV2vStoredListVm
2026-11-09 12:43:34 +01:00

4.7 KiB

Mocking dependencies

Keep the mock boundary tight: mock only the remote-resource collections / stores a composable depends on, and let pure utilities and icon helpers run for real.

Use the typed mock form — vi.mock(import('<module>'), …) — so a rename breaks type-check instead of silently leaving a stale mock. Create the stub functions with vi.hoisted (a plain const fn = vi.fn() referenced in the factory throws, because the mock is hoisted above imports), and reset them in beforeEach:

const { getHostById, isMasterHost } = vi.hoisted(() => ({
  getHostById: vi.fn(),
  isMasterHost: vi.fn(),
}))

vi.mock(import('@/modules/host/remote-resources/use-xo-host-collection.ts'), () => ({
  useXoHostCollection: (() => ({ getHostById, isMasterHost })) as unknown as typeof useXoHostCollection,
}))

beforeEach(() => {
  getHostById.mockReset()
  isMasterHost.mockReset()
})

Note the cast: the typed form checks the factory return against the whole module, so a partial mock of a large export needs as unknown as typeof useX (with an import type { useX }).

When several test files mock the same remote resource (a collection or a single resource) with the same shape, the mock lives once in src/test/ and the test file only points vi.mock to it; its exported state is read and changed by the tests, and reset in beforeEach:

vi.mock(
  import('@/modules/vm/remote-resources/use-xo-vm-collection.ts'),
  () => import('@/test/mock-xo-vm-collection.ts')
)

beforeEach(() => {
  vmCollectionMock.reset()
})

vmCollectionMock.areVmsReady is true after a reset; set it to false to hold the collection as still loading.

Collections always read together share one mock module exporting each of their composables: mock-xo-collections.ts stands for the pool, host, SR, network, PBD, PIF and VM template collections. Each vi.mock of these modules points to it (vi.mock is hoisted, it cannot be wrapped in a helper), and xoCollectionsMock.reset() resets them all. Its pool collection also answers getPoolById, hasPoolById and useGetPoolById from pools, its host collection getHostById from hosts, its SR and network collections getSrById and getNetworkById, its PBD collection pbdsBySr from pbds, and arePoolsReady, areSrsReady, areNetworksReady and areTemplatesReady (true after a reset) let a test hold that collection as still loading. seedV2vListPool (seed-v2v-list-pool.ts) seeds the pool of a V2V list and what it offers.

The same goes for mock-xo-v2v-vm-rows-collections.ts, the VM, task and VM snapshot collections the V2V VM rows are built from: v2vVmRowsCollectionsMock holds vms, tasks, snapshots and their are…Ready flags (true after a reset; set one to false to hold that collection as still loading).

mock-delete-modal.ts stands for useDeleteModal, whose overlay a unit test cannot answer: deleteModalMock.answer('onConfirm' | 'onCancel') sets how the next confirmation is answered, deleteModalMock.confirm() runs the onConfirm event of the last confirmation for a caller that passes its events instead of awaiting the answer, deleteModalMock.open is the spy to read the props it was opened with, and deleteModalMock.reset() goes in beforeEach.

mock-overlay.ts stands for useOverlay, whose overlays a unit test cannot open: each call is recorded in order, as the options it was given (its component, its events) and the open spy it got back; overlayMock.getOverlay<TOptions>(index = 0) / overlayMock.getOverlays<TOptions>() read them back, TOptions typing the events for the payload they take, and overlayMock.reset() goes in beforeEach.

mock-v2v-vm-actions.ts stands for use-v2v-vm-actions.composable.ts, whose composables open the settings drawer or delete an import VM: each v2vVmActionsMock.useV2v*VmActions spy returns fresh fake actions of its kind (read them back from mock.results), and v2vVmActionsMock.reset() goes in beforeEach.

mock-xo-vm-device-collections.ts stands for the VBD, VDI and VIF collections: vmDeviceCollectionsMock holds vbds, vdis, vifs and their are…Ready flags (true after a reset), and its collections answer getVbdsByIds and getVifsByIds.

mock-xo-routes.ts stands for useXoRoutes, the XO 5 routes the app fetches: an XO 5 link reads https://xo5.example.com/#<path>.

Network

src/test/setup.ts stubs the global fetch with a never-settling promise before each test, so composables that trigger remote requests on use never hit the network in unit tests. When a test needs a real response, stubFetchResponse(status, body) from src/test/stub-fetch-response.ts overrides it for that test only and returns the mock, to assert the request when the request is the contract (a job).