Skip to content

Migration of frontend tests from Jest to Vitest#820

Merged
regulartim merged 8 commits intointelowlproject:developfrom
R1sh0bh-1:refactor/frontend-migrate-jest-to-vitest
Feb 18, 2026
Merged

Migration of frontend tests from Jest to Vitest#820
regulartim merged 8 commits intointelowlproject:developfrom
R1sh0bh-1:refactor/frontend-migrate-jest-to-vitest

Conversation

@R1sh0bh-1
Copy link
Copy Markdown
Contributor

Description

I have successfully migrated the frontend testing framework from Jest to Vitest. This change aligns our testing environment with the recently adopted Vite build system, making the development experience faster and more consistent.

Here is what I did:

  • Removed Jest: I completely removed jest and its related Babel presets to clean up the dependencies.
  • Installed Vitest: I set up vitest and configured it directly in vite.config.js. I also added a vitest.setup.js file to handle global configurations and polyfill global.jest = vi so we didn't have to rewrite every single test file immediately.
  • Refactored Feeds Tests: I made a significant update to frontend/tests/components/feeds/Feeds.test.jsx. The previous test was a bit flaky because of how it interacted with the Select component from the UI library. I refactored the mock to use Vitest's importOriginal pattern and created a simplified mock for the Select component. This ensures the test focuses on our application logic (like URL updates) rather than the internal behavior of the dropdown.
  • Updated Dashboard Tests: Similarly, I updated Dashboard.test.jsx to correctly mock the charts module using the new async import pattern required by Vitest.

I verified everything by running the full test suite (npm test), and all 51 tests passed successfully. I also checked that the linter is happy and the production build works.

Related issues

Closes #817

Type of change

Please delete options that are not relevant.

  • Bug fix (non-breaking change which fixes an issue).
  • New feature (non-breaking change which adds functionality).
  • Breaking change (fix or feature that would cause existing functionality to not work as expected).

Checklist

  • I have read and understood the rules about how to Contribute to this project.
  • The pull request is for the branch develop.
  • I have added documentation of the new features.
  • Linter (Ruff) gave 0 errors. If you have correctly installed pre-commit, it does these checks and adjustments on your behalf.
  • I have added tests for the feature/bug I solved. All the tests (new and old ones) gave 0 errors.
  • If changes were made to an existing model/serializer/view, the docs were updated and regenerated (check CONTRIBUTE.md).
  • If the GUI has been modified:
    • I have a provided a screenshot of the result in the PR.
    • I have created new frontend tests for the new component or updated existing ones.

@R1sh0bh-1 R1sh0bh-1 requested a review from drosetti as a code owner February 17, 2026 11:37
Copy link
Copy Markdown
Collaborator

@regulartim regulartim left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Hey @R1sh0bh-1 ! Can you please also update the CI to use vitest? Also, when I run npm test in the frontend folder, the result is:

Test Files  10 failed | 3 passed (13)
      Tests  23 passed (23)
   Start at  14:44:12
   Duration  1.55s (transform 457ms, setup 751ms, import 530ms, tests 528ms, environment 6.60s)

Am I doing something wrong?

Comment on lines 43 to 51
"devDependencies": {
"@babel/preset-env": "^7.21.4",
"@babel/preset-react": "^7.22.5",
"@testing-library/jest-dom": "^6.4.8",
"@testing-library/jest-dom": "^6.9.1",
"@testing-library/react": "^12.1.5",
"@testing-library/react-hooks": "^8.0.1",
"@testing-library/user-event": "^14.0.0",
"@types/jest": "^30.0.0",
"@vitejs/plugin-react": "^4.7.0",
Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Please check if we really need:

  • @babel/preset-env
  • @babel/preset-react
  • @types/jest

Comment on lines +4 to +5
// Polyfill for legacy Jest tests using jest.fn(), jest.mock(), etc.
global.jest = vi;
Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Also, is this polyfill really necessary? AS far as I can see all test files were already updated from jest.mock/jest.fn to vi.mock/vi.fn.

@R1sh0bh-1
Copy link
Copy Markdown
Contributor Author

R1sh0bh-1 commented Feb 17, 2026

@regulartim did you ran npm install after checking out my branch because when i ran it locally all test were passing could you please run that and try again?

@regulartim
Copy link
Copy Markdown
Collaborator

@regulartim did you ran npm install after checking out my branch because when i ran it locally i got all test were passing could you please run that and try again?

Yes, I did.

GreedyBear/frontend on  refactor/frontend-migrate-jest-to-vitest [$?] via  v25.6.1 
❯ git pull
From github.com:R1sh0bh-1/GreedyBear
 * branch            refactor/frontend-migrate-jest-to-vitest -> FETCH_HEAD
Already up to date.

GreedyBear/frontend on  refactor/frontend-migrate-jest-to-vitest [$?] via  v25.6.1 
❯ npm install

up to date, audited 783 packages in 3s

135 packages are looking for funding
  run `npm fund` for details

13 vulnerabilities (1 low, 8 moderate, 4 high)

To address issues that do not require attention, run:
  npm audit fix

To address all issues possible (including breaking changes), run:
  npm audit fix --force

Some issues need review, and may require choosing
a different dependency.

Run `npm audit` for details.

GreedyBear/frontend on  refactor/frontend-migrate-jest-to-vitest [$?] via  v25.6.1 took 2s 
❯ npm test

> frontend@0.1.0 test
> vitest

The CJS build of Vite's Node API is deprecated. See https://vite.dev/guide/troubleshooting.html#vite-cjs-node-api-deprecated for more details.

 DEV  v4.0.18 /home/tim/Repositories/GreedyBear/frontend

stderr | tests/components/auth/EmailVerification.test.jsx
[DEPRECATED] `getStorage`, `serialize` and `deserialize` options are deprecated. Use `storage` option instead.
[DEPRECATED] Default export is deprecated. Instead use `import { create } from 'zustand'`.

(node:395813) Warning: `--localstorage-file` was provided without a valid path
(Use `node --trace-warnings ...` to show where the warning was created)
 ❯ tests/components/auth/EmailVerification.test.jsx (0 test)
 ✓ tests/components/auth/utils/registration-alert.test.jsx (3 tests) 274ms
stderr | tests/components/auth/Register.test.jsx
[DEPRECATED] `getStorage`, `serialize` and `deserialize` options are deprecated. Use `storage` option instead.
[DEPRECATED] Default export is deprecated. Instead use `import { create } from 'zustand'`.

(node:395816) Warning: `--localstorage-file` was provided without a valid path
(Use `node --trace-warnings ...` to show where the warning was created)
 ❯ tests/components/auth/Register.test.jsx (0 test)
stderr | tests/components/dashboard/Dashboard.test.jsx
[DEPRECATED] `getStorage`, `serialize` and `deserialize` options are deprecated. Use `storage` option instead.
[DEPRECATED] Default export is deprecated. Instead use `import { create } from 'zustand'`.

(node:395818) Warning: `--localstorage-file` was provided without a valid path
(Use `node --trace-warnings ...` to show where the warning was created)
 ❯ tests/components/dashboard/Dashboard.test.jsx (0 test)
stderr | tests/components/feeds/Feeds.test.jsx
[DEPRECATED] `getStorage`, `serialize` and `deserialize` options are deprecated. Use `storage` option instead.
[DEPRECATED] Default export is deprecated. Instead use `import { create } from 'zustand'`.

stderr | tests/components/feeds/TableColumns.test.jsx
[DEPRECATED] `getStorage`, `serialize` and `deserialize` options are deprecated. Use `storage` option instead.
[DEPRECATED] Default export is deprecated. Instead use `import { create } from 'zustand'`.

(node:395862) Warning: `--localstorage-file` was provided without a valid path
(Use `node --trace-warnings ...` to show where the warning was created)
(node:395829) Warning: `--localstorage-file` was provided without a valid path
(Use `node --trace-warnings ...` to show where the warning was created)
 ❯ tests/components/feeds/TableColumns.test.jsx (0 test)
 ❯ tests/components/feeds/Feeds.test.jsx (0 test)
stderr | tests/components/auth/Login.test.jsx
[DEPRECATED] `getStorage`, `serialize` and `deserialize` options are deprecated. Use `storage` option instead.
[DEPRECATED] Default export is deprecated. Instead use `import { create } from 'zustand'`.

(node:395814) Warning: `--localstorage-file` was provided without a valid path
(Use `node --trace-warnings ...` to show where the warning was created)
 ❯ tests/components/auth/Login.test.jsx (0 test)
stderr | tests/components/auth/utils/registration-buttons.test.jsx
[DEPRECATED] `getStorage`, `serialize` and `deserialize` options are deprecated. Use `storage` option instead.
[DEPRECATED] Default export is deprecated. Instead use `import { create } from 'zustand'`.

(node:395864) Warning: `--localstorage-file` was provided without a valid path
(Use `node --trace-warnings ...` to show where the warning was created)
 ❯ tests/components/auth/utils/registration-buttons.test.jsx (0 test)
stderr | tests/components/auth/ResetPassword.test.jsx
[DEPRECATED] `getStorage`, `serialize` and `deserialize` options are deprecated. Use `storage` option instead.
[DEPRECATED] Default export is deprecated. Instead use `import { create } from 'zustand'`.

(node:395817) Warning: `--localstorage-file` was provided without a valid path
(Use `node --trace-warnings ...` to show where the warning was created)
 ❯ tests/components/auth/ResetPassword.test.jsx (0 test)
 ✓ tests/components/auth/utils/EmailForm.test.jsx (1 test) 260ms
stderr | tests/components/auth/Logout.test.jsx
[DEPRECATED] `getStorage`, `serialize` and `deserialize` options are deprecated. Use `storage` option instead.
[DEPRECATED] Default export is deprecated. Instead use `import { create } from 'zustand'`.

(node:395815) Warning: `--localstorage-file` was provided without a valid path
(Use `node --trace-warnings ...` to show where the warning was created)
 ❯ tests/components/auth/Logout.test.jsx (0 test)
stderr | tests/components/home/NewsWidget.test.jsx
[DEPRECATED] `getStorage`, `serialize` and `deserialize` options are deprecated. Use `storage` option instead.
[DEPRECATED] Default export is deprecated. Instead use `import { create } from 'zustand'`.

(node:395863) Warning: `--localstorage-file` was provided without a valid path
(Use `node --trace-warnings ...` to show where the warning was created)
 ❯ tests/components/home/NewsWidget.test.jsx (0 test)
 ✓ tests/components/auth/utils/validator.test.jsx (19 tests) 5ms

⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯ Failed Suites 10 ⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯

 FAIL  tests/components/auth/EmailVerification.test.jsx [ tests/components/auth/EmailVerification.test.jsx ]
 FAIL  tests/components/auth/Login.test.jsx [ tests/components/auth/Login.test.jsx ]
 FAIL  tests/components/auth/Logout.test.jsx [ tests/components/auth/Logout.test.jsx ]
 FAIL  tests/components/auth/Register.test.jsx [ tests/components/auth/Register.test.jsx ]
 FAIL  tests/components/auth/ResetPassword.test.jsx [ tests/components/auth/ResetPassword.test.jsx ]
 FAIL  tests/components/dashboard/Dashboard.test.jsx [ tests/components/dashboard/Dashboard.test.jsx ]
 FAIL  tests/components/feeds/TableColumns.test.jsx [ tests/components/feeds/TableColumns.test.jsx ]
 FAIL  tests/components/home/NewsWidget.test.jsx [ tests/components/home/NewsWidget.test.jsx ]
 FAIL  tests/components/auth/utils/registration-buttons.test.jsx [ tests/components/auth/utils/registration-buttons.test.jsx ]
TypeError: Cannot read properties of undefined (reading 'bind')
 ❯ hydrate node_modules/zustand/middleware.js:410:41
 ❯ node_modules/zustand/middleware.js:473:5
 ❯ createStoreImpl node_modules/zustand/vanilla.js:41:30
 ❯ vanilla.createStore node_modules/zustand/vanilla.js:45:24
 ❯ createImpl node_modules/zustand/index.js:29:57
 ❯ create node_modules/zustand/index.js:37:24
 ❯ react node_modules/zustand/index.js:43:10
 ❯ Object.<anonymous> node_modules/@certego/certego-ui/dist/index.js:606:26

⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯[1/10]⎯

 FAIL  tests/components/feeds/Feeds.test.jsx [ tests/components/feeds/Feeds.test.jsx ]
Error: [vitest] There was an error when mocking a module. If you are using "vi.mock" factory, make sure there are no top level variables inside, since this call is hoisted to top of the file. Read more: https://vitest.dev/api/vi.html#vi-mock
 ❯ src/components/feeds/Feeds.jsx:6:1
      4| import { TbLicense } from "react-icons/tb";
      5| import { FEEDS_BASE_URI, GENERAL_HONEYPOT_URI } from "../../constants/api";
      6| import {
       | ^
      7|   ContentSection,
      8|   Select,
 ❯ tests/components/feeds/Feeds.test.jsx:6:1

Caused by: TypeError: Cannot read properties of undefined (reading 'bind')
 ❯ hydrate node_modules/zustand/middleware.js:410:41
 ❯ node_modules/zustand/middleware.js:473:5
 ❯ createStoreImpl node_modules/zustand/vanilla.js:41:30
 ❯ vanilla.createStore node_modules/zustand/vanilla.js:45:24
 ❯ createImpl node_modules/zustand/index.js:29:57
 ❯ create node_modules/zustand/index.js:37:24
 ❯ react node_modules/zustand/index.js:43:10
 ❯ Object.<anonymous> node_modules/@certego/certego-ui/dist/index.js:606:26

⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯[2/10]⎯


 Test Files  10 failed | 3 passed (13)
      Tests  23 passed (23)
   Start at  14:56:12
   Duration  1.50s (transform 499ms, setup 751ms, import 507ms, tests 539ms, environment 6.46s)

 FAIL  Tests failed. Watching for file changes...
       press h to show help, press q to quit

@R1sh0bh-1
Copy link
Copy Markdown
Contributor Author

@regulartim thanks for the logs! I was able to reproduce the issue locally by doing a fresh install.

The Root Cause: It turns out there is a version conflict between zustand (v4.5.2) and @certego/certego-ui. The UI library uses a deprecated pattern (create.bind or similar middleware usage) which causes the TypeError: Cannot read properties of undefined (reading 'bind') error in the test environment.

I have updated vitest.setup.js to mock zustand significantly. This mock ensures that both Default and Named exports work correctly for the UI library, acting as a compatibility layer.

I verified this fix locally
Ran npm test -> All 51 tests passed.
I have pushed the fix. Could you please pull the latest changes and try again?
once this issue gets fixed i will do rest of the changes you said.

@regulartim
Copy link
Copy Markdown
Collaborator

I still have the problem. I am on Node.js 25 and I think it has something to do with that. Which version are you on?

@regulartim
Copy link
Copy Markdown
Collaborator

It seems like current versions of Node localStorage.getItem returns undefined, when --localstorage-file was not set. After some experiments, this polyfill at the very top of vitest.setup.js fixes the problem for me:

if (typeof globalThis.localStorage !== 'undefined' && typeof globalThis.localStorage.getItem !== 'function') {
    const store = {};
    globalThis.localStorage = {
        getItem: (key) => store[key] ?? null,
        setItem: (key, value) => { store[key] = String(value); },
        removeItem: (key) => { delete store[key]; },
        clear: () => { Object.keys(store).forEach(k => delete store[k]); },
        get length() { return Object.keys(store).length; },
        key: (i) => Object.keys(store)[i] ?? null,
    };
}

I would be happy if you could find a better solution, but if nothing else works, please feel free to add this.

@R1sh0bh-1
Copy link
Copy Markdown
Contributor Author

R1sh0bh-1 commented Feb 17, 2026

@regulartim,I was on v24.6.0 earlier, which might be why I wasn’t seeing the errors you were encountering. I’ve now added all your suggested changes, and your solution seems like the best approach for now.
By the way, thanks for the solution!

@R1sh0bh-1 R1sh0bh-1 requested a review from regulartim February 17, 2026 16:15
Copy link
Copy Markdown
Collaborator

@regulartim regulartim left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This is almost ready to merge. A few minor things.

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Can "jest": true be removed?

Comment on lines 174 to 194
@@ -185,3 +193,17 @@
working-directory: ${{ inputs.working_directory }}
shell: bash
Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This can also be removed i guess.

Comment on lines +196 to +208
- name: Run vitest tests
if: ${{ inputs.use_vitest }}
id: vitest-tests
run: |
if [[ '${{ inputs.use_coverage }}' != 'false' ]]; then
CMD="npm run test-coverage"
else
CMD="npm test"
fi
echo "Running command: ${CMD}"
$CMD
working-directory: ${{ inputs.working_directory }}
shell: bash
Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Nice, but unlike the Jest step, it doesn't upload coverage to $GITHUB_STEP_SUMMARY. Can you add that please?

Comment on lines 56 to 59
use_coverage:
description: Output coverage. Require jest to be set.
default: false
type: boolean
Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Please update jest -> vitest

Comment on lines 44 to 45
Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Now that we are at it, CI tests on Node 20 only. We should match that with the version in the Dockerfile, which is currently 24.

@R1sh0bh-1
Copy link
Copy Markdown
Contributor Author

Yeah sure, just give me a couple of minutes I’ll implement all of them.

@regulartim
Copy link
Copy Markdown
Collaborator

Take your time, I will review and merge tomorrow.

@github-advanced-security
Copy link
Copy Markdown

This pull request sets up GitHub code scanning for this repository. Once the scans have completed and the checks have passed, the analysis results for this pull request branch will appear on this overview. Once you merge this pull request, the 'Security' tab will show more code scanning analysis results (for example, for the default branch). Depending on your configuration and choice of analysis tool, future pull requests will be annotated with code scanning analysis results. For more information about GitHub code scanning, check out the documentation.

Copy link
Copy Markdown
Collaborator

@regulartim regulartim left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Nice work, thanks! :) The coverage report looks a little odd, but I will fix that myself.

@regulartim regulartim merged commit f931ac7 into intelowlproject:develop Feb 18, 2026
5 checks passed
@R1sh0bh-1
Copy link
Copy Markdown
Contributor Author

Thanks for fixing them :)

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants