Vitest vs Jest: on a project built with Vite take Vitest, because it reuses the same settings, and if Jest already works, keep it. QUnit is enough when tests must run right in the browser with almost no setup. All three run automated JavaScript tests and differ in where they live and how much setup they need.
This article was born from another one: about formal models in Quint and formal verification. The names QUnit and Quint are similar and easy to mix up, so I decided to write about test frameworks separately too. How Quint differs from them is covered in the comparison of Quint with tests and TLA+.
What Jest, Vitest and QUnit have in common
Suppose there is a function that adds two numbers. A test records an expectation: for one and two the answer is three. The framework runs the function, compares the answer with the expected one and reports whether the check passed or failed. A project has hundreds of tests, so they run automatically after every edit: if an edit broke something that worked, a test fails and you see it at once. All three frameworks do exactly this for JavaScript code, that is, they run automated tests.
Three words will come up in the descriptions of the frameworks. A snapshot is a saved reference of a large result, for example the finished markup of a page, against which a new result is compared. A mock is a temporary replacement of real code with a stub, for example of a real email sending, so that the test does not reach outside. Coverage is a report of which lines of code a test ran at least once. So the choice between the frameworks rarely decides whether a project has tests. It decides how much has to be set up and where the tests run.
Jest or Vitest: how many places to edit for setup
Jest aims to work without configuration on most JavaScript projects. It understands projects on Babel, TypeScript, React, Angular and Vue. Snapshots and mocks are built in, and code coverage is switched on with one flag, --coverage, with no extra setup. It runs tests in parallel, each in its own process so they do not affect each other, and puts the ones that failed last time first. The style of checks is familiar: test describes a case, expect compares the answer.
Vitest does almost the same but is built on the Vite bundler. If the site is already built with Vite, Vitest takes the same settings and plugins, while Jest would need a second, separate configuration. The Vitest authors call this duplication of complexity. Compatibility with Jest is high: Vitest supports most of the Jest interface and its libraries, so in most projects it fits as a replacement.
Vitest also has a fast watch mode: when a file is edited, tests rerun instantly, on the same hot module replacement as in Vite itself. The documentation also lists a mode that runs tests in a real browser and a web interface with results. It has one price: it needs fairly recent Vite and Node.js, and the documentation today names Vite 6.4 and Node 22.12.
QUnit: when you need tests right in the browser
QUnit describes itself as a powerful, easy-to-use test framework. It needs no configuration for Node.js, and minimal setup is enough for the browser. It runs wherever there is JavaScript: in browsers, in Node.js, in the SpiderMonkey engine and in a background thread of a page. Jest and Vitest, unlike it, are most often run in Node.js.
Its style is its own. Related tests are grouped with QUnit.module, a single test is described with QUnit.test, and the answer is compared through assert. For tests that touch a page there is a fixture that returns the page to its original state after every test, and a separate check of the order of calls for events and delayed answers. You can extend QUnit to your needs: your own assertions, runners and reports. It also supports old browsers: version 2 works with Internet Explorer 9 and up.
Who has what: Jest, Vitest and QUnit point by point
| Jest | Vitest | QUnit | |
|---|---|---|---|
| Idea | the usual framework with a full set: snapshots, mocks, coverage | a next-generation framework built on Vite | a simple framework that runs anywhere |
| Setup | its own configuration | the same as Vite’s | almost none |
| Where it runs | most often in Node.js | most often in Node.js | browser, Node.js, other environments |
| How a check is written | test and expect | test and expect, as in Jest | QUnit.test and assert |
| When it fits | Jest is already there and works | the project is built with Vite | tests are needed in the browser without a build |
The table row by row. “Idea” says why the framework appeared. “Setup” shows how much work lies before the first test. “Where it runs” and “How a check is written” matter if you have many ready tests: the style of Jest and Vitest matches, so moving between them is simple, while on QUnit the checks would have to be rewritten.
What to choose: Jest, Vitest or QUnit
The choice is set by the project. The project is built with Vite: take Vitest, the settings are already there. Jest is already in the project and everything works: keep it. You need checks right in the browser without a build: take QUnit. Moving between Jest and Vitest is usually cheap, so a wrong choice will not be irreversible. If you need to check rules and the order of events rather than functions, see the articles Quint vs QUnit and TLA+ and on Quint models.
FAQ
On a project built with Vite, take Vitest: it reuses the same settings, so no second configuration is needed. If Jest already works and bothers nobody, moving rarely pays off.
Vitest is built on Vite, supports most of the Jest interface and restarts tests quickly when a file changes. It needs fairly recent Vite and Node.js.
When tests must run right in the browser without a build step. QUnit runs in browsers, in Node.js and in other JavaScript environments, and needs no setup for Node.js.
Usually not: both write checks with
test and expect, so moving between them is simple. Moving to QUnit means rewriting the checks.