Hacker News new | past | comments | ask | show | jobs | submit login
Should you use Jest as a testing library? (2022) (backend.cafe)
98 points by fagnerbrack on July 1, 2023 | hide | past | favorite | 64 comments



`instanceof Array` is a famous JavaScript footgun you should not use anyway. The same happens when sharing objects with an `iframe` (aka "cross-realm objects"). This is why `Array.isArray` exists.

That said, Jest used to be so good when it was first released, and got gradually slower and more complex. Same with Yarn.

I hope React won't face the same fate. I loved integrating the recent suspense and async rendering features. It made my app feel so much better by removing loading flickers with no architectural changes.


In a way React has already had the same fate. It really astounds me that react-dom is >100KB big while the API-compatible Preact is something like 7KB.

There are edge cases where you can't just drop it in directly as a replacement but you can very, very many times. Really makes me wonder what React is doing with that extra 93KB of JS, it's not actually even that fast compared to other frontend frameworks.


I wrote a jQuery (30kb) alternative called Umbrella JS (2.6kb) and based on my experience and if I had to guess, probably most of the rest of React's size is in compatibility stuff. Like making sure events work uniformly across browsers, I remember that making everything work with SVGs was also a big milestone, normalizing events (e.g. we have synthetic events which are basically React's events on top of the normal DOM events), etc. An astute/old fashion dev will realize that React's onChange actually behaves like `addEventListener('input')` and not really like `addEventListener('change')`, since the latter only triggers on blur and not on each keystroke.

I strongly believe React team is shooting themselves on the foot by not making Error Boundaries into Hooks. If they did, someone could create a Preact 2.0 so to speak that is like React but purely functional (no classes). But since we don't have that, and error handling IS an important part of React, any react alternative would have to implement classes fully as well, which might retract many from even trying to create a React alternative (I don't think myself smart enough to do a React alternative properly, but I'd certainly tried if they did this).


There's actually a recent PR up for a `<Catch>` component:

- https://github.com/facebook/react/pull/26854


I wonder if error boundary components/functionality are an anti-pattern. They invite the developer to create components which expect to fail. Even basic hide/show logic is better than expecting devs to orchestrate unified error handling across the app.


What's wrong with components that expect to fail? Don't you need some way to notify users of predictable problems?


OK, hold up, I’ve been hearing this line forever and I’m here to hold it to account:

> the API-compatible Preact is something like 7KB

Something is up here. Either Preact is not in fact API-compatible (in which case people should stop saying this), or the React devs are dummies who have never thought of Preact’s architecture or looked at its open source code (I rank this unlikely) or there’s somehow some other catch that no one talks about.

Which is it? Why doesn’t React just use Preact’s architecture if it’s so lightweight? What is Preact actually giving up?


There are definitely differences here and there. One I can remember from a year or so ago is that Preact deprecated support for string refs while React still supports them (though the docs point out they intend to deprecate IIRC).

Honestly to my mind the biggest thing is that bundle size just isn’t a priority for the React team. A sibling comment pointed out that React does a lot to correctly handle SVGs. Good to have, obviously, but what percentage of React users are making interactive SVGs? Probably not a whole lot. If they wanted to the React folks could break that out into a react-svg module or something and save some KB. But they don’t want to.

To my mind React these days is the enterprise software of the frontend. It’s big, it’s bulky, but it does absolutely everything with a minimum of fuss. They have a one size fits all approach and they’re not willing to deviate from it.


> what percentage of React users are making interactive SVGs

Every single app I worked on for the past 5 years did. `mui` icons are SVG for example, and it's common practice to embed SVG as components to avoid the HTTP requests overhead and allow for theming through props.


Most people who embed svgs aren’t looking to make them interactive though. I think I’ve attached event handlers to internal elements in an svg maybe once in my entire career.


Things like the sparkline charts on npmjs (e.g. https://www.npmjs.com/package/npm ) are interactive SVGs. I think they're pretty common for data visualizations of all kinds


That’s a great example of what I’m talking about: it would be the perfect place to bring in a react-svg module. Vast majority of sites don’t use sparkline so the SVG stuff is unused.


Sure, but data visualisations make up a tiny percentage of websites.


That’s not what I’m talking about though: those aren’t interactive. You could dangerouslySetInnerHTML with them (arguably you should, it’s a waste of VDOM otherwise) and they’d be just fine.


From memory, Preact doesn't use synthetic events system like React and its runtime is much smaller. It can't be used generically like React can in mobile (React Native) or similar though because of this


Preact takes the King Bumi approach to API compatibility - by sometimes doing nothing.

The syntax may be compatible, but the semantics are not. For example, it doesn’t support react's concurrency features; transitions are just empty wrappers.


It's fully api compatible pre-fiber. in fact it has more apis in some regards.


Hi Did have success on littlefs on stm32 ? On arduino ? Please, contact me tcpipchip@hotmail.com PS: sorry if I post here


I did have some success with it. I used their generic config way to hook up fro block writing/erasing and implemented those parts in the os i was writing. However one thing I was not a fan of is that its IO is synchronous, so you have to use some sort of coroutines/multitasking unless you're ok with blocking


It’s often cheaper to couple things tightly. Abstractions and interfaces have costs. However, they also have benefits. Perhaps React and Preact is one such example.

React is a tiny fully agnostic library that does components, props, hooks and all that jazz. You can use it anywhere, from DOM to CLI. To tie it to DOM, a separate library exists—named, unimaginatively, ReactDOM—and that’s where the 100KB heft comes in.

Preact is the opposite: smaller, but coupled to DOM. The architecture probably doesn’t facilitate cool stuff like render components to embedded LCD[0], and even to do SSR you would have to add extra libraries.

[0] https://github.com/doodlewind/react-ssd1306/blob/master/docs...


It's somewhere in between.

React as a lib and architecture _is_ platform-agnostic. The core logic is defined in the `react-reconciler` package. It contains all the implementation of rendering components, diffing trees, managing state, and running effects, as well as all the "Suspense" implementation.

However, the way `react-reconciler` works is that it's built _into_ each platform-specific renderer implementation. So, the size of `react-dom` is actually the size of `react-reconciler` + all the DOM-specific behavior.

A quick check of https://bundlejs.com/?q=react-reconciler suggests it's about 100K minified. https://bundlejs.com/?q=react-dom is 138K, so that tells me that the DOM-specific logic is 38K.


Seeing Preact mentioned, just wanted to give a shoutout to one of the authors, Marvin, an ex colleague. Absolutely amazing dev and person.


Think the biggest slow down is from it running all the test suites in isolation in separate contexts (think that's the right word). I got frustrated with how slow our frontend tests were one day like 4 years ago and wrote a hacky jest runtime that reused the context unless it detected jest.mock or jest.spy or timer stuff in the file it was on. It speed it up by 2x with cache cleared. It was still pretty slow though...

There was also an existing issue opened requesting this to be built in by a lot of people and facebook said lol no.


npm took up most of yarn's significant changes to the point where I switched back years ago.

I think the Jest situation is a little different as it was the incumbent not the challenger.

React is similar in the it's become an incumbent, though probably with less marketshare. Ironically I believe the lack of a virtual DOM is a big selling point for Svelte (sp?) which my frontend developers are really excited about.


I mostly use npm, but does npm have anything like yarn's workspaces or ability to patch dependencies with project-specific changes?

Those are the "killer features" for yarn IMO, and why I think a lot of projects using it would have friction moving to npm



Vitest[0] is a drop in replacement to Jest that we've had exceptional success with. Faster test runs, more reliable, default TS and ESM support, etc.

[0] https://vitest.dev/


Vitest may not be a good drop in replacement either. It uses Workers for multi-threading via Tinypool. For us, we use the AWS SDK and the binaries in it would cause Vitest to crash. After wasting a lot of time, we had to retreat back to Jest.

I really like Vitest, and it's a great fit for lots of projects. I'm a bit sad it wasn't for ours.


Just curious, were you using v2 or v3 of the AWS SDK? I was going to try Vitest after reading these comments, but maybe it's not feasible right now.


Big fan of vitest, I like typescript and esm support out of the box and without adding dependencies like types/jest or ts-jest. I've filed bugs and pull requests and the maintainers have been responsive


It is most definitely not drop in. I looked into this yesterday funnily enough and you can expect to have to make many syntax changes to your test files.


It's an _almost_ drop in replacement - when I tried migrating our tests recently (because of memory leak issues / slowness resulting from Jest + a Node upgrade) I found I had to manually finagle a lot of our mocks to get them working.


Does vitest have this same issue or make a trade off to avoid it like jest-light-runner


That seems tied to Vite though?


It's actually not! You can use vitest in a node environment as well just fine.


Clickbait, hard skip. Jest is the best testing framework I have ever worked with, every other testing framework should learn from it (seriously). Iterating on tests in watch mode is a joy.


If you love iterating on tests in watch mode, Vitest will feel even better: https://maxrozen.com/beginners-guide-to-react-testing/react-...


I’d love to hear more about your reasoning because it’s not the experience I’ve had, but I’ve heard it before and would like to understand it more.

I personally found Jest to do a lot of magic that, as an only occasional contributor to JS codebases, made it somewhat impenetrable.

As a comparison, many testing libraries look a lot like Python’s unittest if you squint, a design originated in the Java ecosystem I think. I find I can move between testing many languages and be immediately productive with test and know how things work, which is a huge productivity bonus.

Alternatively, I’ve found pytest’s dependency injection makes writing tests really nice and easy, the whole lifecycle management is very good. I’d even consider coordinating integration tests with it if I was just running precompiled binaries etc.


The specific workflow for Jest I really enjoy:

- Opening an editor split with a terminal

- Running Jest in watch mode

- Using a pattern to pick specific test(s) at a time

- Editing tests and code to either fix bugs or add features, and watching the test quickly re-run every save

Specifically the watch interface of Jest, which seems pretty simple, is great. It's a joyful way to work on code. Any test runner that doesn't support this workflow is a nightmare. And I don't get why many test runners don't support this workflow, it seems pretty easy to implement.


I’d love to see how you use it. My encounters with jest have been painful, and it seemed unnecessarily cruel to run browser tests in node, where you couldn’t just easily put a debugger statement in there and use the inspector to see what was going on.


You can debug Jest tests in Chrome use node's included inspector.

Ironically it's vitest that doesn't support this (IIRC, haven't checked in a minute)


Missed the edit window, but looks like I'm outdated: vitest does support node's debugger

https://vitest.dev/guide/debugging.html


oh thanks for that tip!


Not being sarcastic, but what qualifies your opinion? i.e., which other testing frameworks and/or language environments have you used?


Have you tried vitest?


A bit a click bait title, are we really advising to throw out Jest because of a single hang up?


Despite the title this thread has brought up numerous other pain points with jest that make it less than ideal. At the cost of ensuring tests don’t bleed into each other due to the virtualization that occurs running large suites of tests in jest is extremely slow.

We still use jest but it’s one of the slowest parts of our pipelines.


If you're looking for a minimalist framework that can be learned in 10 minutes or so, I recommend "ospec". For me it was a delight compared with Jest.

https://github.com/MithrilJS/ospec


Nice project! I will have a look at it.

I recently tried `bun:test` [1], which aims to become a drop-in replacement for Jest. It is quite good, but there is no way to do test coverage at the moment [2]. I am not sure that it will be fixed soon, as to my knowledge there is no test coverage instrumentation on JSC.

I replaced AVA with a minimal testing lib called Oletus [3]. It was also a delight compared to AVA. I am currently one of the maintainers of Oletus.

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

[2] https://github.com/oven-sh/bun/issues/3158

[3] https://github.com/bearror/oletus


bun test will get test coverage. I recently learned about a JSC api that lets you see which functions have been called or not called. There’s a “control flow profiler”. Just need to wire it up.


I like that ospec does away with the `it(...)` convention in favor of “bullets”

“It” always caused weird grammatical problems with test descriptions. You can’t always describe tests that way. Some authors would try and some would ignore “it”.


Wow that's so refreshingly simple. Do you have any recommended / official tutorials or cookbooks for this, for web projects?


As far the library itself goes, the README is all you need to know. That's what's great.

It does assume familiarity with testing in general (ie, how to design for unit testing, how to write clear tests, etc), but you'll need that to use any testing library effectively, and that skill is orthogonal to the library itself.

If you're looking for resources on that, I recommend: https://github.com/testdouble/contributing-tests/wiki/London...


So this is like the iframe Array isn't the same as the parent window's Array issue? I guess both Array types are same in semantics, but have different prototypes for isolation so code in one context can't dick with code in another context in a language where dicking with other code trivially used to be very commonplace. Good ol Prototype.js used to love extending every DOMElement prototype it could.

Do you need to use an instanceof in the example code? I feel like it's already covered that in the first assertion, unless there's some horrifying way that another type could be implicitly coerced into an array looking shape.

    expect(values.bar).toEqual(['a', 'b'])


It's well-known to use `Array.isArray` instead [0].

[0] https://developer.mozilla.org/en-US/docs/Web/JavaScript/Refe...


> This means that the instanceof operator will not work as expected, and it will generate false negatives!

But this isn’t a silent failure, so it’s obviously detectable and therefore (if you know why) avoidable. It’s also so rare that you’d need to read a blog article to even know it was possible.

So I’ll keep using jest, because my tests all pass. When I hit one that doesn’t (and I can’t figure out why) I keep this in mind, but otherwise “not recommended” is overkill.


Except when you test that something is *not* an instance of something else and the test wrongly passes. Then you'll be scratching your head trying to fix a bug already in production.


I've never written such a test assertion in my life. I'll be fine with Jest


That's no the issue, the issue is if the code you can't access or control uses `instanceof`. If the only problem was you needed to avoid `instanceof` in tests, this wouldn't matter at all.


One of the reasons I always preferred running tests in real browsers with Karma.


Same! Is there a modern equivalent?

I still use Karma, but the GitHub says it's deprecated!


I much prefer Mocha to Jest together with some other things. I guess you get used to what you know.


The main reason I’ve ended up migrating Jest projects to mocha is for backend integration tests using the db. Jest is clearly built for the frontend first. It needs workarounds to run sequentially. That’s important for setting up and tearing down a certain specific backend app state for a test. startup scripts (db teardown and migrations maybe) are tough to configure with typescript, or even at all. generally typescript is tough to configure at all with Jest. Nested tests do not always work predictably with setup and teardown. The mocking and spies aren’t as good as Sinon or nock. expect doesn’t allow a fallback error message like plain assert (just a pattern, no lock in to jest there). running jest with a debugger requires annoying re-configuration per specific test in Jetbrains because Jest has its own VM, doesn’t pick up subtle config, and jest doesn’t often run your code in the same way as plain nodejs due to the vm.


Oh is this just the multi global issue you have on the web?




Guidelines | FAQ | Lists | API | Security | Legal | Apply to YC | Contact

Search: