This was a bit of a tricky one, and the solution from the Vitest docs didn't work for me.
Those docs suggested that I could do something like:
import * as Firestore from "firebase/firestore"
import { vi } from "vitest"
const onSnapshot = vi.spyOn(Firestore, "onSnapshot")
...
expect(onSnapshot).toHaveBeenCalled()
but that didn't work, Vitest complains that it can't redefine that propery:
TypeError: Cannot redefine property: onSnapshot
❯ lib/useDoc.test.ts:12:4
10| import type { Repo } from "~/test/helpers/factory"
11|
12| vi.spyOn(Firestore, "onSnapshot")
The solution
The answer wasn't too bad, but there are actually three steps:
1) Mock the import
2) Import the module in your test
3) Create the spy
Let's walk through each of those.
1) Mock the import
At the top level of my test file you need to mock the import using vi.mock
. In the factory you feed to vi.mock
you will replace the function you want to spy on with with a vi.fn
:
type FakeFirestore = { onSnapshot(this: void): void }
vi.mock("firebase/firestore", async (getModule) => {
const original: FakeFirestore = await getModule()
return {
...original,
onSnapshot: vi.fn().mockImplementation(original.onSnapshot),
}
})
Note that very useful importOriginal
function which lets me keep the Firestore module fully functional. This is because vi.mock
is really persnickety about referencing outside variables.
That factory function needs to be 100% self contained. Therefore you have to...
2) Import the module in your test
In order to have something to spy on, you'll need to import that same module directly in your test. This should be the mock object that you returned in your factory above, with the vi.fn
where you stuck it. That'll give us something to spy on...
import * as Firestore from "firebase/firestore"
3) Create the spy
Finally, we can create the spy, and place our expectations on it:
import { test, vi } from "vitest"
test("calls onSnapshot", () => {
const onSnapshot = vi.spyOn(Firestore, "onSnapshot")
/* trigger the onSnapshot call here in my code */
expect(onSnapshot).toHaveBeenCalled()
})
And that's it! My test passes.
Check out the complete source code here.
Follow me on Twitter if you want to see more Vite, Vitest, and Firestore tips!
Top comments (0)