I recently upgraded some functionality of our legacy codebase to fit our new Stack containing:
The feature that had to be rewritten was a scroll-depth tracking. It extensively uses
IntersectionObservers and some global properties like
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.
vi.spyOn(document, 'visibilityState', 'get').mockImplementationOnce(() => 'hidden');
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
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.
functions which observe the use of
methods. You can use them like so
vi.spyOn(object, "methodName"). They are usefull in cases where you check if calling a
method calls another
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.
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
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.