{"id":51740007,"url":"https://github.com/trurl-master/jsdom-testing-mocks","last_synced_at":"2026-07-18T11:42:26.005Z","repository":{"id":36363183,"uuid":"223790942","full_name":"trurl-master/jsdom-testing-mocks","owner":"trurl-master","description":"A set of tools for emulating browser behavior in jsdom environment","archived":false,"fork":false,"pushed_at":"2025-09-13T12:58:33.000Z","size":1592,"stargazers_count":128,"open_issues_count":5,"forks_count":7,"subscribers_count":3,"default_branch":"master","last_synced_at":"2026-04-30T13:27:02.445Z","etag":null,"topics":["intersectionobserver","javascript","jsdom","matchmedia","mocks","react-testing-library","reactjs","resizeobserver","testing","viewport","vitest","waapi","web-animations-api"],"latest_commit_sha":null,"homepage":"","language":"TypeScript","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"mit","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/trurl-master.png","metadata":{"files":{"readme":"README.md","changelog":null,"contributing":null,"funding":null,"license":"LICENSE","code_of_conduct":"CODE_OF_CONDUCT.md","threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null,"governance":null,"roadmap":null,"authors":null,"dei":null,"publiccode":null,"codemeta":null}},"created_at":"2019-11-24T18:31:37.000Z","updated_at":"2026-04-01T21:56:07.000Z","dependencies_parsed_at":"2024-02-26T20:30:25.978Z","dependency_job_id":"2ff6653f-ca88-4cb8-be77-1477ddc6eac8","html_url":"https://github.com/trurl-master/jsdom-testing-mocks","commit_stats":{"total_commits":48,"total_committers":5,"mean_commits":9.6,"dds":"0.16666666666666663","last_synced_commit":"6c018a5cf7c22e2a16fb62445cce0d3b4c6fdcf9"},"previous_names":[],"tags_count":36,"template":false,"template_full_name":null,"purl":"pkg:github/trurl-master/jsdom-testing-mocks","repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/trurl-master%2Fjsdom-testing-mocks","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/trurl-master%2Fjsdom-testing-mocks/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/trurl-master%2Fjsdom-testing-mocks/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/trurl-master%2Fjsdom-testing-mocks/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/trurl-master","download_url":"https://codeload.github.com/trurl-master/jsdom-testing-mocks/tar.gz/refs/heads/master","sbom_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/trurl-master%2Fjsdom-testing-mocks/sbom","scorecard":{"id":899958,"data":{"date":"2025-08-11","repo":{"name":"github.com/trurl-master/jsdom-testing-mocks","commit":"5e8d618bd033ecfa60bbb04ed020752bad4ab95a"},"scorecard":{"version":"v5.2.1-40-gf6ed084d","commit":"f6ed084d17c9236477efd66e5b258b9d4cc7b389"},"score":5.4,"checks":[{"name":"Code-Review","score":2,"reason":"Found 3/11 approved changesets -- score normalized to 2","details":null,"documentation":{"short":"Determines if the project requires human code review before pull requests (aka merge requests) are merged.","url":"https://github.com/ossf/scorecard/blob/f6ed084d17c9236477efd66e5b258b9d4cc7b389/docs/checks.md#code-review"}},{"name":"Maintained","score":10,"reason":"24 commit(s) and 1 issue activity found in the last 90 days -- score normalized to 10","details":null,"documentation":{"short":"Determines if the project is \"actively maintained\".","url":"https://github.com/ossf/scorecard/blob/f6ed084d17c9236477efd66e5b258b9d4cc7b389/docs/checks.md#maintained"}},{"name":"Dangerous-Workflow","score":10,"reason":"no dangerous workflow patterns detected","details":null,"documentation":{"short":"Determines if the project's GitHub Action workflows avoid dangerous patterns.","url":"https://github.com/ossf/scorecard/blob/f6ed084d17c9236477efd66e5b258b9d4cc7b389/docs/checks.md#dangerous-workflow"}},{"name":"Token-Permissions","score":0,"reason":"detected GitHub workflow tokens with excessive permissions","details":["Info: jobLevel 'contents' permission set to 'read': .github/workflows/claude-code-review.yml:23","Info: jobLevel 'pull-requests' permission set to 'read': .github/workflows/claude-code-review.yml:24","Info: jobLevel 'issues' permission set to 'read': .github/workflows/claude-code-review.yml:25","Info: jobLevel 'actions' permission set to 'read': .github/workflows/claude.yml:26","Info: jobLevel 'contents' permission set to 'read': .github/workflows/claude.yml:22","Info: jobLevel 'pull-requests' permission set to 'read': .github/workflows/claude.yml:23","Info: jobLevel 'issues' permission set to 'read': .github/workflows/claude.yml:24","Warn: no topLevel permission defined: .github/workflows/bump.yml:1","Warn: no topLevel permission defined: .github/workflows/claude-code-review.yml:1","Warn: no topLevel permission defined: .github/workflows/claude.yml:1","Warn: no topLevel permission defined: .github/workflows/main.yml:1","Warn: no topLevel permission defined: .github/workflows/publish.yml:1","Info: no jobLevel write permissions found"],"documentation":{"short":"Determines if the project's workflows follow the principle of least privilege.","url":"https://github.com/ossf/scorecard/blob/f6ed084d17c9236477efd66e5b258b9d4cc7b389/docs/checks.md#token-permissions"}},{"name":"Packaging","score":-1,"reason":"packaging workflow not detected","details":["Warn: no GitHub/GitLab publishing workflow detected."],"documentation":{"short":"Determines if the project is published as a package that others can easily download, install, easily update, and uninstall.","url":"https://github.com/ossf/scorecard/blob/f6ed084d17c9236477efd66e5b258b9d4cc7b389/docs/checks.md#packaging"}},{"name":"Binary-Artifacts","score":10,"reason":"no binaries found in the repo","details":null,"documentation":{"short":"Determines if the project has generated executable (binary) artifacts in the source repository.","url":"https://github.com/ossf/scorecard/blob/f6ed084d17c9236477efd66e5b258b9d4cc7b389/docs/checks.md#binary-artifacts"}},{"name":"Pinned-Dependencies","score":5,"reason":"dependency not pinned by hash detected -- score normalized to 5","details":["Warn: GitHub-owned GitHubAction not pinned by hash: .github/workflows/bump.yml:21: update your workflow using https://app.stepsecurity.io/secureworkflow/trurl-master/jsdom-testing-mocks/bump.yml/master?enable=pin","Warn: GitHub-owned GitHubAction not pinned by hash: .github/workflows/bump.yml:26: update your workflow using https://app.stepsecurity.io/secureworkflow/trurl-master/jsdom-testing-mocks/bump.yml/master?enable=pin","Warn: GitHub-owned GitHubAction not pinned by hash: .github/workflows/claude-code-review.yml:30: update your workflow using https://app.stepsecurity.io/secureworkflow/trurl-master/jsdom-testing-mocks/claude-code-review.yml/master?enable=pin","Warn: third-party GitHubAction not pinned by hash: .github/workflows/claude-code-review.yml:36: update your workflow using https://app.stepsecurity.io/secureworkflow/trurl-master/jsdom-testing-mocks/claude-code-review.yml/master?enable=pin","Warn: GitHub-owned GitHubAction not pinned by hash: .github/workflows/claude.yml:29: update your workflow using https://app.stepsecurity.io/secureworkflow/trurl-master/jsdom-testing-mocks/claude.yml/master?enable=pin","Warn: third-party GitHubAction not pinned by hash: .github/workflows/claude.yml:35: update your workflow using https://app.stepsecurity.io/secureworkflow/trurl-master/jsdom-testing-mocks/claude.yml/master?enable=pin","Warn: GitHub-owned GitHubAction not pinned by hash: .github/workflows/main.yml:12: update your workflow using https://app.stepsecurity.io/secureworkflow/trurl-master/jsdom-testing-mocks/main.yml/master?enable=pin","Warn: GitHub-owned GitHubAction not pinned by hash: .github/workflows/main.yml:15: update your workflow using https://app.stepsecurity.io/secureworkflow/trurl-master/jsdom-testing-mocks/main.yml/master?enable=pin","Warn: GitHub-owned GitHubAction not pinned by hash: .github/workflows/main.yml:21: update your workflow using https://app.stepsecurity.io/secureworkflow/trurl-master/jsdom-testing-mocks/main.yml/master?enable=pin","Warn: GitHub-owned GitHubAction not pinned by hash: .github/workflows/main.yml:31: update your workflow using https://app.stepsecurity.io/secureworkflow/trurl-master/jsdom-testing-mocks/main.yml/master?enable=pin","Warn: GitHub-owned GitHubAction not pinned by hash: .github/workflows/publish.yml:14: update your workflow using https://app.stepsecurity.io/secureworkflow/trurl-master/jsdom-testing-mocks/publish.yml/master?enable=pin","Warn: GitHub-owned GitHubAction not pinned by hash: .github/workflows/publish.yml:17: update your workflow using https://app.stepsecurity.io/secureworkflow/trurl-master/jsdom-testing-mocks/publish.yml/master?enable=pin","Warn: GitHub-owned GitHubAction not pinned by hash: .github/workflows/publish.yml:40: update your workflow using https://app.stepsecurity.io/secureworkflow/trurl-master/jsdom-testing-mocks/publish.yml/master?enable=pin","Warn: GitHub-owned GitHubAction not pinned by hash: .github/workflows/publish.yml:43: update your workflow using https://app.stepsecurity.io/secureworkflow/trurl-master/jsdom-testing-mocks/publish.yml/master?enable=pin","Info:   0 out of  12 GitHub-owned GitHubAction dependencies pinned","Info:   0 out of   2 third-party GitHubAction dependencies pinned","Info:   5 out of   5 npmCommand dependencies pinned"],"documentation":{"short":"Determines if the project has declared and pinned the dependencies of its build process.","url":"https://github.com/ossf/scorecard/blob/f6ed084d17c9236477efd66e5b258b9d4cc7b389/docs/checks.md#pinned-dependencies"}},{"name":"CII-Best-Practices","score":0,"reason":"no effort to earn an OpenSSF best practices badge detected","details":null,"documentation":{"short":"Determines if the project has an OpenSSF (formerly CII) Best Practices Badge.","url":"https://github.com/ossf/scorecard/blob/f6ed084d17c9236477efd66e5b258b9d4cc7b389/docs/checks.md#cii-best-practices"}},{"name":"Security-Policy","score":0,"reason":"security policy file not detected","details":["Warn: no security policy file detected","Warn: no security file to analyze","Warn: no security file to analyze","Warn: no security file to analyze"],"documentation":{"short":"Determines if the project has published a security policy.","url":"https://github.com/ossf/scorecard/blob/f6ed084d17c9236477efd66e5b258b9d4cc7b389/docs/checks.md#security-policy"}},{"name":"Fuzzing","score":0,"reason":"project is not fuzzed","details":["Warn: no fuzzer integrations found"],"documentation":{"short":"Determines if the project uses fuzzing.","url":"https://github.com/ossf/scorecard/blob/f6ed084d17c9236477efd66e5b258b9d4cc7b389/docs/checks.md#fuzzing"}},{"name":"License","score":10,"reason":"license file detected","details":["Info: project has a license file: LICENSE:0","Info: FSF or OSI recognized license: MIT License: LICENSE:0"],"documentation":{"short":"Determines if the project has defined a license.","url":"https://github.com/ossf/scorecard/blob/f6ed084d17c9236477efd66e5b258b9d4cc7b389/docs/checks.md#license"}},{"name":"Signed-Releases","score":-1,"reason":"no releases found","details":null,"documentation":{"short":"Determines if the project cryptographically signs release artifacts.","url":"https://github.com/ossf/scorecard/blob/f6ed084d17c9236477efd66e5b258b9d4cc7b389/docs/checks.md#signed-releases"}},{"name":"Branch-Protection","score":-1,"reason":"internal error: error during branchesHandler.setup: internal error: githubv4.Query: Resource not accessible by integration","details":null,"documentation":{"short":"Determines if the default and release branches are protected with GitHub's branch protection settings.","url":"https://github.com/ossf/scorecard/blob/f6ed084d17c9236477efd66e5b258b9d4cc7b389/docs/checks.md#branch-protection"}},{"name":"SAST","score":0,"reason":"SAST tool is not run on all commits -- score normalized to 0","details":["Warn: 0 commits out of 30 are checked with a SAST tool"],"documentation":{"short":"Determines if the project uses static code analysis.","url":"https://github.com/ossf/scorecard/blob/f6ed084d17c9236477efd66e5b258b9d4cc7b389/docs/checks.md#sast"}},{"name":"Vulnerabilities","score":10,"reason":"0 existing vulnerabilities detected","details":null,"documentation":{"short":"Determines if the project has open, known unfixed vulnerabilities.","url":"https://github.com/ossf/scorecard/blob/f6ed084d17c9236477efd66e5b258b9d4cc7b389/docs/checks.md#vulnerabilities"}}]},"last_synced_at":"2025-08-24T15:12:03.610Z","repository_id":36363183,"created_at":"2025-08-24T15:12:03.610Z","updated_at":"2025-08-24T15:12:03.610Z"},"host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":286080680,"owners_count":35616737,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2026-05-26T15:22:16.424Z","status":"online","status_checked_at":"2026-07-18T02:00:07.223Z","response_time":61,"last_error":null,"robots_txt_status":"success","robots_txt_updated_at":"2025-07-24T06:49:26.215Z","robots_txt_url":"https://github.com/robots.txt","online":true,"can_crawl_api":true,"host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":["intersectionobserver","javascript","jsdom","matchmedia","mocks","react-testing-library","reactjs","resizeobserver","testing","viewport","vitest","waapi","web-animations-api"],"created_at":"2026-07-18T11:42:18.863Z","updated_at":"2026-07-18T11:42:25.989Z","avatar_url":"https://github.com/trurl-master.png","language":"TypeScript","funding_links":[],"categories":[],"sub_categories":[],"readme":"# jsdom-testing-mocks\n\nA set of tools for emulating browser behavior in jsdom environment\n\n[![Build status][build-status-badge]][build-status]\n[![version][version-badge]][package]\n[![PRs Welcome][prs-badge]][prs]\n[![downloads][downloads-badge]][npmtrends]\n[![MIT License][license-badge]][license]\n[![Code of Conduct][coc-badge]][coc]\n\n[![GitHub Repo stars][star-badge]][star]\n[![Twitter URL][twitter-badge]][twitter]\n\n[![Stand With Ukraine](https://raw.githubusercontent.com/vshymanskyy/StandWithUkraine/main/banner2-direct.svg)](https://stand-with-ukraine.pp.ua)\n\n### Mocks\n\n[matchMedia](#mock-viewport)  \n[Intersection Observer](#mock-intersectionobserver)  \n[Resize Observer](#mock-resizeobserver)  \n[Web Animations API](#mock-web-animations-api)  \n[CSS Typed OM](#mock-css-typed-om)\n\n## Installation\n\n```sh\nnpm i -D jsdom-testing-mocks\n```\n\n```sh\nyarn add -D jsdom-testing-mocks\n```\n\n## Setup\n\n### With `react`\n\nTo avoid having to wrap everything in `act` calls, you can pass `act` to `configMocks`:\n\n```jsx\nimport { configMocks } from 'jsdom-testing-mocks';\nimport { act } from '...';\n\nconfigMocks({ act });\n```\n\nIt can be done in a setup file, or in a test file, before rendering the component.\n\n### With `vitest`\n\nSome 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](https://vitest.dev/config/#globals). If you don't want to do that you can pass it manually using `configMocks`.\n\nAlso, 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:\n\n```js\nvi.useFakeTimers({\n  toFake: [\n    // vitests defaults\n    'setTimeout',\n    'clearTimeout',\n    'setInterval',\n    'clearInterval',\n    'setImmediate',\n    'clearImmediate',\n    'Date',\n    // required for mocks\n    'performance',\n    'requestAnimationFrame',\n    'cancelAnimationFrame',\n  ],\n});\n```\n\n[vitest defaults](https://github.com/vitest-dev/vitest/blob/190c25f902a8c32859c9f62407040dedf5a72cb9/packages/vitest/src/defaults.ts)\n\n## Testing framework support\n\nWe 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](https://jestjs.io/), [@swc/jest](https://swc.rs/docs/usage/jest) and [vitest](https://vitest.dev/) (with [some setup](#with-vitest)). If you encounter any problems with other testing frameworks, please open an issue.\n\n## Mock viewport\n\nMocks `matchMedia`, allows testing of component's behavior depending on the viewport description (supports all of the [Media Features](http://www.w3.org/TR/css3-mediaqueries/#media1)). `mockViewport` must be called before rendering the component\n\nExample, using `React Testing Library`:\n\n```jsx\nimport { mockViewport } from 'jsdom-testing-mocks';\n\nit('shows the right lines on desktop and mobile', () =\u003e {\n  const viewport = mockViewport({ width: '320px', height: '568px' });\n\n  render(\u003cTestComponent /\u003e);\n\n  expect(\n    screen.getByText('Content visible only on small screens')\n  ).toBeInTheDocument();\n\n  expect(\n    screen.queryByText('Content visible only on large screens')\n  ).not.toBeInTheDocument();\n\n  act(() =\u003e {\n    viewport.set({ width: '1440px', height: '900px' });\n  });\n\n  expect(\n    screen.queryByText('Content visible only on small screens')\n  ).not.toBeInTheDocument();\n\n  expect(\n    screen.getByText('Content visible only on large screens')\n  ).toBeInTheDocument();\n\n  viewport.cleanup();\n});\n```\n\nAlso, you can mock the viewport for a group of tests, using `mockViewportForTestGroup`:\n\n```jsx\nimport { mockViewportForTestGroup } from 'jsdom-testing-mocks'\n\ndescribe('Desktop specific tests', () =\u003e {\n  mockViewportForTestGroup({ width: '1440px', height: '900px' })\n\n  test('this', () = {\n    // ...\n  })\n\n  test('that', () = {\n    // ...\n  })\n})\n```\n\n## Mock IntersectionObserver\n\nProvides a way of triggering intersection observer events\n\nExample, using `React Testing Library`:\n\n```jsx\nimport { mockIntersectionObserver } from 'jsdom-testing-mocks';\n\nconst io = mockIntersectionObserver();\n\n/*\nAssuming html:\n\u003cdiv data-testid=\"container\"\u003e\n  \u003cimg src=\"...\" alt=\"alt text\" /\u003e\n\u003c/div\u003e\n\nAnd an IntersectionObserver, observing the container\n*/\nit('loads the image when the component is in the viewport', () =\u003e {\n  const { container } = render(\u003cTestComponent /\u003e);\n\n  expect(screen.queryByAltText('alt text')).not.toBeInTheDocument();\n\n  // when the component's observed node is in the viewport - show the image\n  act(() =\u003e {\n    io.enterNode(screen.getByTestId('container'));\n  });\n\n  expect(screen.getByAltText('alt text')).toBeInTheDocument();\n});\n```\n\n### API\n\n`mockIntersectionObserver` returns an object, that has several useful methods:\n\n#### .enterNode(node, desc)\n\nTriggers 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`\n\n#### .leaveNode(node, desc)\n\nTriggers 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`\n\n#### .enterNodes(nodeDescriptions)\n\nTriggers all IntersectionObservers observing the nodes in `nodeDescriptions` with multiple nodes entering at once. Each IntersectionObserver callback will receive only the nodes it's observing:\n\n```js\nio.enterNodes([\n  // you can pass multiple nodes each with its own state\n  { node: screen.getByText('First Node'), desc: { intersectionRatio: 0.5 } },\n  // description is optional:\n  { node: screen.getByText('Second Node') },\n  // or you can use a shorthand:\n  screen.getByText('Third Node'),\n]);\n```\n\n#### .leaveNodes(nodeDescriptions)\n\nTriggers all IntersectionObservers observing the nodes in `nodeDescriptions` with multiple nodes leaving at once. Each IntersectionObserver callback will receive only the nodes it's observing.\n\n#### .triggerNodes(nodeDescriptions)\n\nTriggers 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\n\n#### .enterAll(desc) and .leaveAll(desc)\n\nTriggers all IntersectionObservers for each of the observed nodes\n\n## Mock ResizeObserver\n\nMocks `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`](#mockelementsizeelement-htmlelement-size-size) or `mockElementBoundingClientRect`)\n\nExample, using `React Testing Library`:\n\n```jsx\nimport { mockResizeObserver } from 'jsdom-testing-mocks';\n\nconst DivWithSize = () =\u003e {\n  const [size, setSize] = useState({ width: 0, height: 0 });\n  const ref = useRef(null);\n\n  useEffect(() =\u003e {\n    const observer = new ResizeObserver((entries) =\u003e {\n      setSize({\n        width: entries[0].contentRect.width,\n        height: entries[0].contentRect.height,\n      });\n    });\n\n    observer.observe(ref.current);\n\n    return () =\u003e {\n      observer.disconnect();\n    };\n  }, []);\n\n  return (\n    \u003cdiv data-testid=\"theDiv\" ref={ref}\u003e\n      {size.width} x {size.height}\n    \u003c/div\u003e\n  );\n};\n\nconst resizeObserver = mockResizeObserver();\n\nit('prints the size of the div', () =\u003e {\n  render(\u003cDivWithSize /\u003e);\n\n  const theDiv = screen.getByTestId('theDiv');\n\n  expect(screen.getByText('0 x 0')).toBeInTheDocument();\n\n  resizeObserver.mockElementSize(theDiv, {\n    contentBoxSize: { inlineSize: 300, blockSize: 200 },\n  });\n\n  act(() =\u003e {\n    // on the first run you don't have to pass the element,\n    // it will be included in the list of entries automatically\n    // because of the call to .observe\n    resizeObserver.resize();\n  });\n\n  expect(screen.getByText('300 x 200')).toBeInTheDocument();\n\n  resizeObserver.mockElementSize(theDiv, {\n    contentBoxSize: { inlineSize: 200, blockSize: 500 },\n  });\n\n  act(() =\u003e {\n    // on subsequent calls to `resize` you have to include it\n    // explicitly, unless observe has been called on it again\n    resizeObserver.resize(theDiv);\n  });\n\n  expect(screen.getByText('200 x 500')).toBeInTheDocument();\n});\n```\n\n### Caveats\n\n#### Triggering the callback on observe\n\nAlthough 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`\n\n#### Mocking element's size\n\nThe 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`\n\n### API\n\n`mockResizeObserver` returns an object, that has several methods:\n\n#### .resize(elements?: HTMLElement | HTMLElement[], options: ResizeOptions)\n\nTriggers 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).\n\nIn this example the resize callback will be triggered with all observed elements from within `TestedComponent`:\n\n```jsx\n// a component that begins to observe elements in a useEffect\nrender(\u003cTestedComponent /\u003e);\n\n// ...don't forget to mock sizes\n\nact(() =\u003e {\n  // triggers the `resize` callback with the elements for which `observe` has been called\n  resizeObserver.resize();\n});\n```\n\n##### ResizeOptions.ignoreImplicit (`false` by default)\n\nIf `true`, do not include imlicit elements in the resize callback entries array\n\n#### .mockElementSize(element: HTMLElement, size: Size)\n\nMocks `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`).\n\nExample:\n\n```jsx\nmockElementSize(myDiv, {\n  // both contentBoxSize and borderBoxSize accept plain objects instead of arrays\n  contentBoxSize: { inlineSize: 400, blockSize: 200 },\n});\n\nmockElementSize(myOtherDiv, {\n  // only one dimension is required, the other one will be assumed to be 0\n  borderBoxSize: { inlineSize: 200 },\n});\n```\n\n#### .getObservers(element?: HTMLElement)\n\nReturns all observers (observing the `element` if passed)\n\n#### .getObservedElements(observer?: ResizeObserver)\n\nReturns all observed elements (of the `observer` if passed)\n\n## Mock Web Animations API\n\n_Warning: **experimental**, bug reports, tests and feedback are greatly appreciated_\n\nMocks 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](https://www.w3.org/TR/web-animations-1/) it should support the majority of cases, but the test suite is far from complete, so _here be dragons_\n\nExample, using `React Testing Library`:\n\n```jsx\nimport { mockAnimationsApi } from 'jsdom-testing-mocks';\n\nconst TestComponent = () =\u003e {\n  const [isShown, setIsShown] = useState(false);\n\n  return (\n    \u003cdiv\u003e\n      {/* AnimatePresence is a component that adds its children in the dom\n          and fades it in using WAAPI, with 2 keyframes: [{ opacity: 0 }, { opacity: 1 }],\n          also adding a div with the word \"Done!\" after the animation has finished\n          You can find implementation in examples\n       */}\n      \u003cAnimatePresence\u003e{isShown \u0026\u0026 \u003cdiv\u003eHehey!\u003c/div\u003e}\u003c/AnimatePresence\u003e\n      \u003cbutton\n        onClick={() =\u003e {\n          setIsShown(true);\n        }}\n      \u003e\n        Show\n      \u003c/button\u003e\n    \u003c/div\u003e\n  );\n};\n\nmockAnimationsApi();\n\nit('adds an element into the dom and fades it in', async () =\u003e {\n  render(\u003cTestComponent /\u003e);\n\n  expect(screen.queryByText('Hehey!')).not.toBeInTheDocument();\n\n  await userEvent.click(screen.getByText('Show'));\n\n  // assume there's only one animation present in the document at this point\n  // in practice it's better to get the running animation from the element itself\n  const element = screen.getByText('Hehey!');\n  const animation = document.getAnimations()[0];\n\n  // our AnimatePresence implementation has 2 keyframes: opacity: 0 and opacity: 1\n  // which allows us to test the visibility of the element, the first keyframe\n  // is applied right after the animation is ready\n  await animation.ready;\n\n  expect(element).not.toBeVisible();\n\n  // this test will pass right after 50% of the animation is complete\n  // because this mock doesn't interpolate keyframes values,\n  // but chooses the closest one at each frame\n  await waitFor(() =\u003e {\n    expect(element).toBeVisible();\n  });\n\n  // AnimatePresence will also add a div with the text 'Done!' after animation is complete\n  await waitFor(() =\u003e {\n    expect(screen.getByText('Done!')).toBeInTheDocument();\n  });\n});\n```\n\n## Using with fake timers\n\nIt's perfectly usable with fake timers, except for the [issue with promises](https://github.com/facebook/jest/issues/2157). 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.\n\n## Mock CSS Typed OM\n\nProvides a complete implementation of the CSS Typed Object Model Level 1 specification for testing CSS numeric values and calculations. While primarily used internally by the Web Animations API mock, it's available as a standalone feature supporting all major CSS units, mathematical operations, and type checking.\n\n```jsx\nimport { mockCSSTypedOM } from 'jsdom-testing-mocks';\n\nmockCSSTypedOM();\n\nit('performs CSS calculations correctly', () =\u003e {\n  const width = CSS.px(100);\n  const height = CSS.px(200);\n  \n  expect(width.add(CSS.px(50)).toString()).toBe('150px');\n  expect(width.mul(height).toString()).toBe('calc(100px * 200px)');\n  expect(CSS.cm(2.54).to('in').toString()).toBe('1in');\n  expect(CSS.px(100).min(CSS.px(200), CSS.px(50)).toString()).toBe('50px');\n});\n\nit('enforces type safety', () =\u003e {\n  // Cannot add incompatible units or use raw numbers\n  expect(() =\u003e CSS.px(10).add(CSS.em(5))).toThrow();\n  expect(() =\u003e CSS.px(10).add(5)).toThrow();\n  \n  // Use CSS.number() for dimensionless values\n  expect(CSS.px(10).add(CSS.number(5)).toString()).toBe('calc(10px + 5)');\n});\n```\n\nSupports all CSS units (length, angle, time, frequency, resolution, flex, percentage), mathematical operations, and enforces type compatibility rules as defined in the [W3C specification](https://www.w3.org/TR/css-typed-om-1/).\n\n## Current issues\n\n- Needs more tests\n\n\u003c!-- prettier-ignore-start --\u003e\n\n[version-badge]: https://img.shields.io/npm/v/jsdom-testing-mocks.svg?style=flat-square\n[package]: https://www.npmjs.com/package/jsdom-testing-mocks\n[downloads-badge]: https://img.shields.io/npm/dm/jsdom-testing-mocks.svg?style=flat-square\n[npmtrends]: http://www.npmtrends.com/jsdom-testing-mocks\n[license-badge]: https://img.shields.io/npm/l/jsdom-testing-mocks.svg?style=flat-square\n[license]: https://github.com/trurl-master/jsdom-testing-mocks/blob/master/LICENSE\n[build-status-badge]: https://img.shields.io/github/actions/workflow/status/trurl-master/jsdom-testing-mocks/main.yml?branch=master\u0026style=flat-square\n[build-status]: https://github.com/trurl-master/jsdom-testing-mocks/actions/workflows/main.yml\n[prs-badge]: https://img.shields.io/badge/PRs-welcome-brightgreen.svg?style=flat-square\n[prs]: http://makeapullrequest.com\n[coc-badge]: https://img.shields.io/badge/code%20of-conduct-ff69b4.svg?style=flat-square\n[coc]: https://github.com/trurl-master/jsdom-testing-mocks/blob/master/CODE_OF_CONDUCT.md\n[star-badge]: https://img.shields.io/github/stars/trurl-master/jsdom-testing-mocks?style=social\n[star]: https://github.com/trurl-master/jsdom-testing-mocks/stargazers\n[twitter-badge]: https://img.shields.io/twitter/url?style=social\u0026url=https%3A%2F%2Fgithub.com%2Ftrurl-master%2Fjsdom-testing-mocks\n[twitter]: https://twitter.com/intent/tweet?text=Check%20out%20jsdom-testing-mocks%20by%20@ivangaliatin%20https%3A%2F%2Fgithub.com%2Ftrurl-master%2Fjsdom-testing-mocks\n\n\u003c!-- prettier-ignore-end --\u003e\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Ftrurl-master%2Fjsdom-testing-mocks","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Ftrurl-master%2Fjsdom-testing-mocks","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Ftrurl-master%2Fjsdom-testing-mocks/lists"}