Remix.run Logo
Vitest vs. Jest(speakeasy.com)
42 points by ritzaco 17 hours ago | 35 comments
mythz 16 hours ago | parent | next [-]

I prefer using bun:test [1] where possible, super fast to run, all built-in no need to install any packages, supports watch mode, also TypeScript tests just works out of the box without additional deps or steps. You'll also get all the benefits of bun which is a breath of fresh air over npm.

[1] https://bun.sh/docs/cli/test

loevborg 16 hours ago | parent | next [-]

Yes, same with node:test https://nodejs.org/api/test.html

It's an excellent test runner and much, much faster than the others, especially if you set the "isolation" flag to "none".

fastball 16 hours ago | parent | prev [-]

Testing with Bun would only make sense if you're running it with Bun (or targeting Safari), right?

neallindsay 14 hours ago | parent | next [-]

The JavaScript language is extremely standardized—the differences between Safari, Chrome, and Firefox are almost 100% down to browser APIs like Bluetooth and MIDI support and such. Those things don't come up in the JavaScript engine.

The only exception I can think of is proper tail calls, which Google explicitly removed and I don't know if Mozilla ever tried to implement: https://compat-table.github.io/compat-table/es6/#test-proper... https://chromestatus.com/feature/5516876633341952

fastball 11 hours ago | parent [-]

There is a language spec, but the browsers implement that standard at different rates. I know up until recently negative look-behind didn't work in Safari but did work in Chrome, and RegEx is clearly a language feature rather than an API.

mythz 16 hours ago | parent | prev | next [-]

It's my preferred js runtime for developing/testing *any* new TypeScript/JS libs since I prefer writing JS libraries with TypeScript and Bun had the best UX for running TS out of the box (also big fan of their built-in SQLite and $ shell support). It only doesn't make sense if you're testing a library requiring node, otherwise it's my preferred choice for testing my js libs.

Even when testing libraries requiring node in which case I'll run the tests with node:test but still use bun's built-in bundler [1] to build & bundle the typescript code base.

Basically Bun's my first choice, but will still use node if I have to.

[1] https://bun.sh/docs/bundler

WorldMaker 15 hours ago | parent | prev [-]

If your JS tests are dependent on specifics in JavaScriptCore or V8 are you really writing unit tests?

If you want the extra confidence, run it with bun:test and node:test to cover JSC and V8. But JS should be JS and for unit tests feeling a need to test on multiple JS engines is a possible code smell.

MrJohz 11 hours ago | parent | next [-]

Neither of the test libraries are specific to unit tests, so I don't quite understand that comment.

That said, there are a lot more issues than just the differences between JSC and V8 - the Bun and NodeJS runtimes, while theoretically exposing the same modules, have a lot of practical differences that are visible in userland code, such as different exceptions, different orderings of queue events, etc. I imagine quite a lot of more complex code depends in some way on platform behaviours like these.

jitl 13 hours ago | parent | prev [-]

Tests are about catching bugs, not playing no-true-Scotsman about what is or is not “unit test-y enough” to be a valid test.

WorldMaker 13 hours ago | parent [-]

If you have a bug that acts different on JSC than V8 or vice versa that's not necessarily a bug in your code. It maybe implies that your code is doing something wrong and should take a more web platform "standard" approach. It generally implies that you are relying on browser specifics that you'd likely be better off testing directly in those browsers in functional/integration tests.

The point about saying "those aren't unit tests" is that it is a "wrong tool for the wrong job" problem. Of course I don't expect Node or Bun to act like any specific browser. The things I want to test in Node or Bun are "universals" that should work in any JS environment, no matter what. If I need to catch V8-specific bugs or JSC-specific bugs, I want to use a smarter integration testing tool like Cypress or Playwright for that, not slow down my unit test suite trying to make a unit test harness pretend to be browsers.

jitl 5 hours ago | parent [-]

I misinterpreted what you mean –– I thought what you meant was "even if your software runs in NodeJS, you can test in Bun, and mock out all the Node modules since otherwise it's not a unit test". Agree that for testing code intended to run in a browser, either of Node or Bun is fine.

OptionOfT 16 hours ago | parent | prev | next [-]

Vitest does not support CommonJS mocking as of today.

I switched to Vitest because Jest was giving me flaky coverage results: https://github.com/nodejs/node/issues/51251

And while Vitest' coverage is stable, I had to add an indirection layer to change how I mock out calls to GitHub's API (@github/octokit).

Oh, side note: vite-node's --watch functionality does not restart the process. It does hot reloading which is different enough that it requires some rework at how you set up your app structure and callbacks.

pcb-rework 16 hours ago | parent [-]

The problem is jest is run by megacorp Meta, so it won't be fixed in any reasonable timeframe because they're all about new features to make "impact". Its FOSS contributors are typically slow and working primarily to keep their jobs. Also, with node > 20.9.0 being broken and node = 20.9.0 not being a viable option by being insecure, so it's worth having a look at alternatives like bun or deno because it does seem to have lost its way too. I'm currently pinned to 20.9.0 for system dependencies, but use bun for new dev.

cowsandmilk 15 hours ago | parent [-]

As described in the article, Jest is no longer run by Meta and its primary maintainers don’t work there.

I also would argue Jest development slowed down after Meta transferred the project to OpenJS, so…

pcb-rework 5 hours ago | parent [-]

> Please don't comment on whether someone read an article.

https://news.ycombinator.com/newsguidelines.html

A rotten apple doesn't roll far from the tree. The vast majority of Meta projects and former projects are garbage. If you need to ask why, because it's experience.

britches11 15 hours ago | parent | prev | next [-]

We switched from Jest to Vitest this summer as part of the effort to migrate a large node repository to ESM. Jest presented a lot of issues after switching to ESM. Vitest was compatible with our existing jest code, minus a couple altered method signatures. It was also compatible with custom matchers we had implemented with jest-extend.

Most of the migration effort was spent on configuration for our needs. Vitest is quite flexible so it was just a matter of nailing down what worked for us.

streptomycin 14 hours ago | parent | prev | next [-]

FWIW I tried switching a fairly large project from Jest to Vitest, hoping for performance improvements. Instead I got some inscrutable errors about circular dependencies.

More generally this is one of the really annoying things about Node.js. You might have some circular dependency that works everywhere, but it fails when you use some specific bundler or test runner. Cause they all handle things slightly differently.

mst 12 hours ago | parent [-]

Circular dependencies almost always end up causing trouble *eventually* because the body of one of the modules involved has to be evaluated first (when the other participants in the cycle aren't a fully operational battlestation yet).

I've used p3rl.org/circular::require on perl projects before now to root out such dependencies and kill them with fire, and "figure out how to get equivalent technology in TS/JS codebases" is on my list of things to do.

Fundamentally, a circular dependency that currently (apparently) "works everywhere" should still be treated as an unexploded footbomb.

Excising them can absolutely be annoying and inconvenient, but IME not nearly as much as having the damn thing go off when a future maintainer makes an innocuous change an indeterminate amount of time later.

tl;dr: HUMBUG (and sorry I don't have a better answer yet)

thecopy 16 hours ago | parent | prev | next [-]

Im interested if anyone has experience using node's native test runner in a non-trivial project?

We are not using the module mocks from Jest in our project and a quick PoC showed significant (3x) speed improvement, but i am worried about the battle-tested:ness.

ilkkao 16 hours ago | parent | next [-]

I just started to use nodejs test runner in a new project. All configuration is basically:

node --experimental-transform-types --experimental-test-module-mocks --env-file test/test.env --test

It then automatically runs all my test/*.tests.ts files.

So nice to get rid of all that extra config. As this is still a tiny project, I can tolerate some API changes in these experimental features.

jitl 13 hours ago | parent | prev | next [-]

My experience using built in node:test and other rapidly evolving things is frustration around getting improvements. I test one of my projects with the oldest supported NodeJS version, and simply can’t use node:test there because the old node:test in Node 18 is missing a lot of features. It’s similar to building for Apple’s platforms - great stuff happens every new major version, but there’s no way to use new libraries with older OS versions. Gotta wait for all your users (and yourself) to update your whole runtime to get those new features.

Maybe if you are on Node 23 and you absolutely have everything you need, then node:test is okay, but I DO NOT recommend it.

WorldMaker 15 hours ago | parent | prev | next [-]

I've been very happy with node:test (and deno:test), but also I migrated from mostly mocha as jest I found difficult to configure, especially without unnecessary bundling configurations as the ESM support among other things was broken for far too long (but mocha delivered it well). Most of my successful uses of jest were out-of-the-box configs in create-react-app and the Angular tools to strip uses of karma and replace them with jest. (Side rant: Seriously whoever thought that karma was a good idea for a test runner? "I love V8 so much I'm using Node's V8 to spin up another headless Chromium's V8 so I can V8 from inside V8." lolsob)

loevborg 16 hours ago | parent | prev [-]

Yes we're using the built-in test runner and it's much better than jest.

Jest is full of unneeded magic (= complexity), whereas node:test is straightforward and has a better design. Highly recommended. You can turn off process isolation for extra speedup!

thecopy 15 hours ago | parent | next [-]

How large is your project?

Without process isolation we got 6x speedup vs. jest! But it is difficult to ensure a clean slate between our test suites (~40 suites which all use a test DB)

We are also using some helpers to mock, e.g https://github.com/marchaos/jest-mock-extended - its such helper libraries im concerned about.

jitl 13 hours ago | parent | prev [-]

Process isolation is an absolute non-negotiable must for any seriously sized project (>50 developers) I’ve worked on

lscharen 16 hours ago | parent | prev | next [-]

I just recently did a website conversion that used vite and took a look at both vitest and playwright.

Ended up going with playwright for the “batteries included” browser support and because we use .Net Core for the backend.

dotnet doesn’t always get the best support from pure JS/TS projects, so it seemed like a reasonable hedge.

mst 12 hours ago | parent [-]

I was under the impression that playwright was (a very good) how your code behaves when actually running in a browser testing library, and vitest was a how your code behaves on its own testing library.

But I'd tend to have relatively independent test suites for my frontend model/state layer and the "how it behaves live in a browser" stuff because that way if I'm not currently iterating on my view components I can test the rest of my frontend code changes without having to faff with headless browser instances.

(obviously you'd then want to run both before committing, and again under CI before merge, but still)

Depending on how thin your model/state layer is (and if you have a Sufficiently Rich Backend then it can probably be very thin without that being an issue) your situation may not match mine, of course.

But y'know, free data point, worth exactly what you paid :D

craftoman 14 hours ago | parent | prev | next [-]

Why not use Node’s built-in testing platform with node --test for server-side purposes or small projects? You can run typescript too. The only drawback is the lack of an expect function, but you can easily built your own or use mine, it’s called tinyexpect.

catlifeonmars 16 hours ago | parent | prev | next [-]

What is meant by “interactive snapshot testing”? If this is the ability to generate and update snapshots in watch mode, Vitest supports this, even though the feature matrix in the article indicates that it does not. I know because I used this feature last month.

ndimares 15 hours ago | parent [-]

Hi, I work at Speakeasy. Thanks for this. I'll look into this and correct the post. Thanks :)

hadskasfs 13 hours ago | parent [-]

Also "Multi-project runner" is supported, Vitest has workspaces feature.

brianzelip 16 hours ago | parent | prev | next [-]

Good write up that helps you get started if you haven't used either lib.

petesergeant 16 hours ago | parent | prev | next [-]

It’s fair to say I will never use Jest again where possible, instead preferring vitest

16 hours ago | parent | prev | next [-]
[deleted]
draw_down 16 hours ago | parent | prev [-]

[dead]