Private side effects

As a rule of thumb, you should always strive toward mocking at the lowest possible level. Module mocking, however, lies on the higher spectrum of things. But that's not a bad thing in itself. In fact, if module mocking is justified, it gives you full control over that module's values and behaviors.
I am going to utilize that power to both exclude the telemetry side effect and mock the implementation of the queryTable function exported from @workshop/epic-sdk.
In the beforeAll() hook, I will use vi.mock() function to mock a module.
vi.mock(import('@workshop/epic-sdk'), async () => {
  return {
    queryTable: queryTableMock,
  }
})
The vi.mock() function accepts two arguments:
  • The module import to mock (import('@workshop/epic-sdk')).;
  • An optional factory function to implement the module.
Using a dynamic import() here allows proper type inference from the mocked module as well as makes the mock proof to renaming or deleting the module.
I will also provide the factory function to control the exact exports returned from the mocked module. In this case, I will swap the actual queryTable function with the queryTableMock introduced earlier:
import { authorize, User } from './authorize.js'

const queryTableMock = vi.hoisted(() => vi.fn<() => Promise<User>>())

vi.mock(import('@workshop/epic-sdk'), async () => {
  return {
    queryTable: queryTableMock,
  }
})
πŸ¦‰ Since vi.mock() function is hoisted (gets evaluated as the first thing no matter where it's defined), it won't be able to reference any values in the test's scope, like the queryTableMock function. To solve this, I am wrapping the mock function in the vi.hoisted() utility:
const queryTableMock = vi.hoisted(() => vi.fn<() => Promise<User>>())
This will expose the queryTableMock function to the vi.mock() factory correctly so it could use it as the value of the queryTable export. Nice!
And since I am using a mock function, to begin with, I need to make sure its call information and implementation are reset between tests:
afterEach(() => {
  vi.resetAllMocks()
})
By mocking the entire @workshop/epic-sdk module, my test becomes in full control over its exports, but also over what gets evaluated at its root level (which, in this case, is nothing). This gives me two for the price of one: I am mocking the behavior I need (queryTable) while also excluding the side effects I don't (telemetry).
From this point on, the rest of the test is not much different from using mock functions you've practiced earlier. Using the .mockResolvedValue and .mockRejectedValue() built-in methods in Vitest, I will model different behavior scenarios of the queryTable function to test my authorize() function:
test('returns the authorized user', async () => {
  queryTableMock.mockResolvedValue({
    id: 'abc-123',
    name: 'Kody Koala',
  })

  await expect(authorize('abc-123')).resolves.toEqual({
    id: 'abc-123',
    name: 'Kody Koala',
  })
})

test('returns null if no user was found', async () => {
  queryTableMock.mockResolvedValue(null)

  await expect(authorize('abc-123')).resolves.toBeNull()
})

test('throws an error if querying the user failed', async () => {
  queryTableMock.mockRejectedValue(new Error('Original error'))

  await expect(authorize('abc-123')).rejects.toThrow(
    'Failed to fetch user by id "abc-123"',
  )
})

vi.mock() vs vi.doMock()

Vitest ships two main APIs to mock modules:
They may look similar on the surface, but the way they behave is drastically different.

vi.mock()

vi.mock() function is hoisted. It means that no matter where you write it in your test file, it will always be evaluated as the first thing in that test module. This makes it useful for mocking module dependencies of the code you import in test, since imports are also hoisted, and would otherwise be subjected to import order issues:
import { something } from 'dependency'
import { behavior } './tested-code'

vi.mock(import('dependency'))
Despite the vi.mock() call happening after the import to dependency (visually), it actually appears before it (hoisted) so the mock could take effect.
This affects any dependencies vi.mock() itself has as well. For example, if you wish to reference a variable in the vi.mock() factory function, you have to wrap that variable in vi.hoisted(), otherwise it will not be defined by the moment your factory runs.

vi.doMock()

vi.doMock() is the unhoisted alternative to vi.mock(). Unlike its sibling, vi.doMock() calls are not hoisted, which ...
import { something } from 'dependency'
// `something` has the original value here.

vi.doMock(import('dependency'))

import { something } from 'dependency'
// `something` has the mocked value from now on.
This gives you more control over the import order in exchange for requiring you to import your tested code dynamically to circumvent the standard imports hoisting and have the module mock take effect.
beforeAll(() => {
  vi.doMock(import('dependency'))
})

test('validates the behavior', () => {
  // The "./tested-code" MUST be imported dynamically in the test's scope
  // because otherwise it will be hoisted to the top of the file,
  // evaluating BEFORE `vi.doMock()` takes effect.
  const { behavior } = await import('./tested-code')
})