I recently upgraded some functionality of our legacy codebase to fit our new Stack containing:
- Vue3/Nuxt3
- Vite
- Vitest
- Typescript
The feature that had to be rewritten was a scroll-depth tracking. It extensively uses IntersectionObservers
and some global properties like innerWidth
or document.visibilityState
to do some checks. As I had a hard time testing changes on document.visibilityState
changes, I write this post so you won't have to deal with them.
TLDR;
vi.spyOn(document, 'visibilityState', 'get').mockImplementationOnce(() => 'hidden');
First approach: simply setting it
Does not work as document.visibilityState
is defined as read-only
. It is, however a solution if you want to manipulate window.innerWidth
as shown in the docs
Second Approach: Using global stubs
The first idea I had was to use global stubs. With these you can overwrite a global property or object and provide Mock to use instead. I used this to stub the IntersectionObservers
as suggested in the docs.
Unfortunately, if you need the functionality of the original object somewhere else this won't work as it apparently gets hoisted, meaning it is not scoped to your current test. For me, this did not work. vi.unstubAllGlobals()
did not reset the stubs which may have prevented this issue as we use JSDOM.
Third Approach: Using a spy
spy
s are function
s which observe the use of method
s. You can use them like so vi.spyOn(object, "methodName")
. They are usefull in cases where you check if calling a function
or method
calls another function
or method
. This helped me to find out if the function
I was testing was called. However, I needed to now if it was called with the correct argument.
Solution: mocking the return of a getter
you spy
on
After a bit of tinkering I found out, that vi.spy
accepts a third argument and allows me to provide a mockImplementation
for that setter/getter
. The third parameter describes if the property - instead of being a method - is a getter
or setter
.
Hence I ended up with the following solution:
vi.spyOn(document, 'visibilityState', 'get').mockImplementationOnce(() => 'hidden');
// and later
vi.spyOn(document, 'visibilityState', 'get').mockImplementationOnce(() => 'visible');
If you have questions, better ideas or find errors, please leave a comment.
Cheers!
Top comments (0)