Gathering detailed insights and metrics for jsdom-testing-mocks
Gathering detailed insights and metrics for jsdom-testing-mocks
Gathering detailed insights and metrics for jsdom-testing-mocks
Gathering detailed insights and metrics for jsdom-testing-mocks
npm install jsdom-testing-mocks
98.1
Supply Chain
99.2
Quality
78.2
Maintenance
100
Vulnerability
99.5
License
Module System
Min. Node Version
Typescript Support
Node Version
NPM Version
116 Stars
79 Commits
7 Forks
4 Watching
16 Branches
5 Contributors
Updated on 25 Nov 2024
Minified
Minified + Gzipped
TypeScript (99.71%)
JavaScript (0.29%)
Cumulative downloads
Total Downloads
Last day
2%
25,100
Compared to previous day
Last week
0.5%
126,403
Compared to previous week
Last month
36%
519,440
Compared to previous month
Last year
213.8%
4,408,425
Compared to previous year
2
23
A set of tools for emulating browser behavior in jsdom environment
matchMedia
Intersection Observer
Resize Observer
Web Animations API
1npm i -D jsdom-testing-mocks
1yarn add -D jsdom-testing-mocks
react
To avoid having to wrap everything in act
calls, you can pass act
to configMocks
:
1import { configMocks } from 'jsdom-testing-mocks'; 2import { act } from '...'; 3 4configMocks({ act });
It can be done in a setup file, or in a test file, before rendering the component.
vitest
Some mocks require lifecycle hooks to be defined on the global object. To make it work with vitest, you need to enable globals in your config. If you don't want to do that you can pass it manually using configMocks
.
Also, if you're using fake timers, at the time of writing this, vitest doesn't enable faking performance.now
, requestAnimationFrame
and cancelAnimationFrame
by default, so you need to do it manually:
1vi.useFakeTimers({ 2 toFake: [ 3 // vitests defaults 4 'setTimeout', 5 'clearTimeout', 6 'setInterval', 7 'clearInterval', 8 'setImmediate', 9 'clearImmediate', 10 'Date', 11 // required for mocks 12 'performance', 13 'requestAnimationFrame', 14 'cancelAnimationFrame', 15 ], 16});
We aim to support all major testing frameworks that support jsdom. Internally, there are no dependencies on any of them, so it's likely that it will work out of the box. Currently tested and confirmed to work with jest, @swc/jest and vitest (with some setup). If you encounter any problems with other testing frameworks, please open an issue.
Mocks matchMedia
, allows testing of component's behavior depending on the viewport description (supports all of the Media Features). mockViewport
must be called before rendering the component
Example, using React Testing Library
:
1import { mockViewport } from 'jsdom-testing-mocks'; 2 3it('shows the right lines on desktop and mobile', () => { 4 const viewport = mockViewport({ width: '320px', height: '568px' }); 5 6 render(<TestComponent />); 7 8 expect( 9 screen.getByText('Content visible only on small screens') 10 ).toBeInTheDocument(); 11 12 expect( 13 screen.queryByText('Content visible only on large screens') 14 ).not.toBeInTheDocument(); 15 16 act(() => { 17 viewport.set({ width: '1440px', height: '900px' }); 18 }); 19 20 expect( 21 screen.queryByText('Content visible only on small screens') 22 ).not.toBeInTheDocument(); 23 24 expect( 25 screen.getByText('Content visible only on large screens') 26 ).toBeInTheDocument(); 27 28 viewport.cleanup(); 29});
Also, you can mock the viewport for a group of tests, using mockViewportForTestGroup
:
1import { mockViewportForTestGroup } from 'jsdom-testing-mocks' 2 3describe('Desktop specific tests', () => { 4 mockViewportForTestGroup({ width: '1440px', height: '900px' }) 5 6 test('this', () = { 7 // ... 8 }) 9 10 test('that', () = { 11 // ... 12 }) 13})
Provides a way of triggering intersection observer events
Example, using React Testing Library
:
1import { mockIntersectionObserver } from 'jsdom-testing-mocks'; 2 3const io = mockIntersectionObserver(); 4 5/* 6Assuming html: 7<div data-testid="container"> 8 <img src="..." alt="alt text" /> 9</div> 10 11And an IntersectionObserver, observing the container 12*/ 13it('loads the image when the component is in the viewport', () => { 14 const { container } = render(<TestComponent />); 15 16 expect(screen.queryByAltText('alt text')).not.toBeInTheDocument(); 17 18 // when the component's observed node is in the viewport - show the image 19 act(() => { 20 io.enterNode(screen.getByTestId('container')); 21 }); 22 23 expect(screen.getByAltText('alt text')).toBeInTheDocument(); 24});
mockIntersectionObserver
returns an object, that has several useful methods:
Triggers all IntersectionObservers observing the node
, with isIntersected
set to true
and intersectionRatio
set to 1
. Other IntersectionObserverEntry
params can be passed as desc
argument, you can override any parameter except isIntersected
Triggers all IntersectionObservers observing the node
, with isIntersected
set to false
and intersectionRatio
set to 0
. Other IntersectionObserverEntry
params can be passed as desc
argument, you can override any parameter except isIntersected
Triggers all IntersectionObservers observing the nodes in nodeDescriptions
with multiple nodes entering at once. Each IntersectionObserver callback will receive only the nodes it's observing:
1io.enterNodes([
2 // you can pass multiple nodes each with its own state
3 { node: screen.getByText('First Node'), desc: { intersectionRatio: 0.5 } },
4 // description is optional:
5 { node: screen.getByText('Second Node') },
6 // or you can use a shorthand:
7 screen.getByText('Third Node'),
8]);
Triggers all IntersectionObservers observing the nodes in nodeDescriptions
with multiple nodes leaving at once. Each IntersectionObserver callback will receive only the nodes it's observing.
Triggers all IntersectionObservers observing the nodes in nodeDescriptions
with multiple nodes at once with custom descriptions (isIntersected
is not enforced). Each IntersectionObserver callback will receive only the nodes it's observing
Triggers all IntersectionObservers for each of the observed nodes
Mocks ResizeObserver
class. Resize callbacks are triggered manually using resize
method returned by the mock. Elements' size must not be 0 (at least on one axis) for the element to appear in the list of callback entries (you can mock the size using mockElementSize
or mockElementBoundingClientRect
)
Example, using React Testing Library
:
1import { mockResizeObserver } from 'jsdom-testing-mocks';
2
3const DivWithSize = () => {
4 const [size, setSize] = useState({ width: 0, height: 0 });
5 const ref = useRef(null);
6
7 useEffect(() => {
8 const observer = new ResizeObserver((entries) => {
9 setSize({
10 width: entries[0].contentRect.width,
11 height: entries[0].contentRect.height,
12 });
13 });
14
15 observer.observe(ref.current);
16
17 return () => {
18 observer.disconnect();
19 };
20 }, []);
21
22 return (
23 <div data-testid="theDiv" ref={ref}>
24 {size.width} x {size.height}
25 </div>
26 );
27};
28
29const resizeObserver = mockResizeObserver();
30
31it('prints the size of the div', () => {
32 render(<DivWithSize />);
33
34 const theDiv = screen.getByTestId('theDiv');
35
36 expect(screen.getByText('0 x 0')).toBeInTheDocument();
37
38 resizeObserver.mockElementSize(theDiv, {
39 contentBoxSize: { inlineSize: 300, blockSize: 200 },
40 });
41
42 act(() => {
43 // on the first run you don't have to pass the element,
44 // it will be included in the list of entries automatically
45 // because of the call to .observe
46 resizeObserver.resize();
47 });
48
49 expect(screen.getByText('300 x 200')).toBeInTheDocument();
50
51 resizeObserver.mockElementSize(theDiv, {
52 contentBoxSize: { inlineSize: 200, blockSize: 500 },
53 });
54
55 act(() => {
56 // on subsequent calls to `resize` you have to include it
57 // explicitly, unless observe has been called on it again
58 resizeObserver.resize(theDiv);
59 });
60
61 expect(screen.getByText('200 x 500')).toBeInTheDocument();
62});
Although the mock doesn't call the resize callback on its own, it keeps track of all the cases when it should be implicitly called (like when the element first begins being observed), and it auto-adds them to the list of elements when resize
is called. You can disable this in ResizeOptions
The mock uses the size provided by mockElementSize
if present and fallbacks to getBoundingClientRect
(that you can mock using mockElementBoundingClientRect
). The issue with getBoundingClientRect
however is that in the real world the value it returns takes CSS Transforms into account, while the values returned in the observer callback don't. It doesn't really matter because it is you who mocks sizes, but for consistency it is preferred that you use mockElementSize
mockResizeObserver
returns an object, that has several methods:
Triggers all resize observer callbacks for all observers that observe the passed elements. Some elements are implicitly resized by the Resize Observer itself, for example when they first attached using observe
. This mock doesn't call the callback by itself. Instead, it adds them to the list of entries
when the next resize
is called (it happens only once per observe
per element).
In this example the resize callback will be triggered with all observed elements from within TestedComponent
:
1// a component that begins to observe elements in a useEffect 2render(<TestedComponent />); 3 4// ...don't forget to mock sizes 5 6act(() => { 7 // triggers the `resize` callback with the elements for which `observe` has been called 8 resizeObserver.resize(); 9});
false
by default)If true
, do not include imlicit elements in the resize callback entries array
Mocks element
's size only for the ResizeObserver. size
accepts 2 properties: contentBoxSize
and borderBoxSize
they're both similar to what you see in the ResizeObserver's callback entry. At least one of them must be present (if the other isn't it is set to be equal to the one present), and the other entry properties are derived from these two (and window.devicePixelRatio
).
Example:
1mockElementSize(myDiv, {
2 // both contentBoxSize and borderBoxSize accept plain objects instead of arrays
3 contentBoxSize: { inlineSize: 400, blockSize: 200 },
4});
5
6mockElementSize(myOtherDiv, {
7 // only one dimension is required, the other one will be assumed to be 0
8 borderBoxSize: { inlineSize: 200 },
9});
Returns all observers (observing the element
if passed)
Returns all observed elements (of the observer
if passed)
Warning: experimental, bug reports, tests and feedback are greatly appreciated
Mocks WAAPI functionality using requestAnimationFrame
. With one important limitation — there are no style interpolations. Each frame applies the closest keyframe from list of passed keyframes or a generated "initial keyframe" if only one keyframe is passed (initial keyframe removes/restores all the properties set by the one keyframe passed). As the implementation is based on the official spec it should support the majority of cases, but the test suite is far from complete, so here be dragons
Example, using React Testing Library
:
1import { mockAnimationsApi } from 'jsdom-testing-mocks'; 2 3const TestComponent = () => { 4 const [isShown, setIsShown] = useState(false); 5 6 return ( 7 <div> 8 {/* AnimatePresence is a component that adds its children in the dom 9 and fades it in using WAAPI, with 2 keyframes: [{ opacity: 0 }, { opacity: 1 }], 10 also adding a div with the word "Done!" after the animation has finished 11 You can find implementation in examples 12 */} 13 <AnimatePresence>{isShown && <div>Hehey!</div>}</AnimatePresence> 14 <button 15 onClick={() => { 16 setIsShown(true); 17 }} 18 > 19 Show 20 </button> 21 </div> 22 ); 23}; 24 25mockAnimationsApi(); 26 27it('adds an element into the dom and fades it in', async () => { 28 render(<TestComponent />); 29 30 expect(screen.queryByText('Hehey!')).not.toBeInTheDocument(); 31 32 await userEvent.click(screen.getByText('Show')); 33 34 // assume there's only one animation present in the document at this point 35 // in practice it's better to get the running animation from the element itself 36 const element = screen.getByText('Hehey!'); 37 const animation = document.getAnimations()[0]; 38 39 // our AnimatePresence implementation has 2 keyframes: opacity: 0 and opacity: 1 40 // which allows us to test the visibility of the element, the first keyframe 41 // is applied right after the animation is ready 42 await animation.ready; 43 44 expect(element).not.toBeVisible(); 45 46 // this test will pass right after 50% of the animation is complete 47 // because this mock doesn't interpolate keyframes values, 48 // but chooses the closest one at each frame 49 await waitFor(() => { 50 expect(element).toBeVisible(); 51 }); 52 53 // AnimatePresence will also add a div with the text 'Done!' after animation is complete 54 await waitFor(() => { 55 expect(screen.getByText('Done!')).toBeInTheDocument(); 56 }); 57});
It's perfectly usable with fake timers, except for the issue with promises. Also note that you would need to manually advance timers by the duration of the animation taking frame duration (which currently is set to 16ms in jest
/sinon.js
) into account. So if you, say, have an animation with a duration of 300ms
, you will need to advance your timers by the value that is at least the closest multiple of the frame duration, which in this case is 304ms
(19
frames * 16ms
). Otherwise the last frame may not fire and the animation won't finish.
No vulnerabilities found.
Reason
no binaries found in the repo
Reason
no dangerous workflow patterns detected
Reason
license file detected
Details
Reason
Found 3/15 approved changesets -- score normalized to 2
Reason
0 commit(s) and 0 issue activity found in the last 90 days -- score normalized to 0
Reason
detected GitHub workflow tokens with excessive permissions
Details
Reason
no effort to earn an OpenSSF best practices badge detected
Reason
security policy file not detected
Details
Reason
dependency not pinned by hash detected -- score normalized to 0
Details
Reason
project is not fuzzed
Details
Reason
SAST tool is not run on all commits -- score normalized to 0
Details
Reason
40 existing vulnerabilities detected
Details
Score
Last Scanned on 2024-11-18
The Open Source Security Foundation is a cross-industry collaboration to improve the security of open source software (OSS). The Scorecard provides security health metrics for open source projects.
Learn Morecssstyle
CSSStyleDeclaration Object Model implementation
jsdom
A JavaScript implementation of many web standards
ng-mocks
An Angular testing library for creating mock services, components, directives, pipes and modules in unit tests. It provides shallow rendering, precise stubs to fake child dependencies. ng-mocks works with Angular 5 6 7 8 9 10 11 12 13 14 15 16 17 18, jasm
node-mocks-http
Mock 'http' objects for testing Express, Next.js and Koa routing functions