CLI tool
lorenzofox3/zora avatar
lorenzofox3/zora

zora: a test library that runs anywhere JavaScript does

Lightest, yet Fastest Javascript test runner for nodejs and browsers

537 stars92 forksJavaScriptMIT

At a glance

What is it?
zora is split into four small packages: a testing library, an assertion library behind it, a set of reporters, and a command line runner for Node. The design bet is that a test program is just a JavaScript program, so it does not need a special runner in Node, in Deno or in a browser, and the project measures itself against other frameworks with a benchmark it calls a pseudo benchmark.
Who is it for?
zora suits somebody who wants tests to be ordinary JavaScript programs that run in more than one environment, and who is happy to assemble the runner and the reporting from small pieces rather than accept a monolith's defaults.
Can I use it commercially?
Yes. MIT is a permissive licence: you can use, modify and sell software built on it, as long as you keep its copyright and licence notices.
Is it still maintained?
Yes. The repository last received commits 103 days ago.
What is it written in?
Mainly JavaScript, according to GitHub's language statistics.

Answers come from the project's GitHub data, last synced on October 22, 2026, and from our analysis. They are not legal advice.

Editorial analysis

Four packages, one idea

zora describes itself as the lightest, yet fastest JavaScript test runner for Node.js and browsers, and the repository is organised as a set of small projects rather than one.

The four packages are listed in the README. The zora package is the testing library. zora-assert is the assertion library behind zora, and it is marked as unpublished, which means it exists in the repository but is not distributed on its own. zora-reporters is a set of reporters which can be used as a command line tool. And pta is a test runner, used with a command line interface, for a Node.js environment.

The layering is the design. The library is the core, the assertions are an implementation detail of it, the reporters are the output side, and the runner is one way of invoking the library from a shell. A project that only wants to run tests in a browser needs the library and nothing else, and a project that wants a terminal reporter needs the reporters package as well.

The repository also ships two things that are not packages: a pseudo benchmark under perfs/ which shows the testing experience with various testing frameworks, and a list of recipes under examples/ to get started in different environments, with directories for a browser project built with Vite, Node with CommonJS, Node with ES modules and Node with TypeScript.

The licence is MIT, the primary language is JavaScript, the default branch is master, and the last push to the repository was on 2026-07-12. The releases are [email protected], [email protected] and [email protected], all published on the same day, which is what a coordinated monorepo release looks like.

A test program is just a program

The first design principle is the one that explains the rest of the project.

It runs with any JavaScript environment: Node.js, Deno, or the browser. The reasoning follows directly, and it is worth stating in the README's own terms: you do not need any specific test runner to run your testing program, it is just a regular JavaScript program.

That is a bigger deal than it sounds. A conventional test runner is a program that finds your test files, loads them, intercepts the registration calls, and runs the callbacks, and the reason it exists is that the language has no module system that works everywhere, or no way to discover files. A library designed so that the test file is an ordinary program removes that dependency. Your test file imports the library, calls the test function, and when the program ends the tests have run.

The practical consequences are visible in the repository. The examples directory has a browser project built with Vite, and separate Node projects for CommonJS, ES modules and TypeScript, and the same tests run in all of them. There is no bundler-specific integration layer, because there is nothing to integrate.

The topic tags support the same reading: deno, nodejs, typescript, tdd, tap and mocha all appear, which is a mix of runtimes, of testing styles and of the tools this kind of library is often compared against or used with.

The limitation of the approach is equally visible, and it is worth holding on to: if the test file is a program, then something has to run the program. In Node that is pta, the runner package, or the node command. In a browser it is your bundler's dev server or whatever page you load. The flexibility is real, and so is the fact that the runner is now your problem to choose.

Small codebase, UNIX philosophy, minimum overhead

The second principle is about size, and the README gives the reasoning in a way that is unusually direct.

It is fast and simple: a small codebase achieving the best performances to deliver the best developer experience. The README links to packagephobia for the size of the package and to the perfs directory for the performance comparison.

The third principle is the one that decides the shape of the repository. It follows the UNIX philosophy: a set of focused, composable small software to deliver the best flexibility with the minimum overhead, rather than a huge monolith hard to tweak, with a large set of options.

That sentence explains four packages, an unpublished assertion library and a separate runner. A monolith would have all of that in one package with a configuration object and a set of flags, and the cost of that arrangement is that every option is available everywhere and the code has to keep all of them working. The composable arrangement means the browser user does not load the Node runner, and the library does not carry the code to discover test files.

The measurement claims are stated in the same hedged style throughout, with the phrasing that one of the lightest, if not the lightest, and one of the fastest JavaScript testing libraries, if not the fastest. That is a project measuring itself against its own competitors and being careful about the claim, and the perfs directory is called a pseudo benchmark in the README rather than a benchmark, which is a good sign about how the results should be read.

It is also worth noticing that the four packages are versioned separately, zora at 6.0.4, the reporters at 3.0.1 and the runner at 1.4.0. Separate version lines are the practical consequence of separate packages: the reporters can change their output format without a major version of the library.

The workspace configuration

The root package.json shows how the packages are put together, and it is a modern npm workspace setup with the scripts that matter.

json
    "build": "npm run build --workspaces --if-present",
    "clean:install": "npm run clean && npm run install:fresh && npm run build",
    "test": "npm t --workspaces --if-present",

The workspaces are the four directories, assert, reporters, zora and pta. The engine requirements are node at 22.18.0 or newer and npm at 7 or newer, which is a recent floor for Node and worth noticing if your CI image is old.

The scripts follow a pattern worth copying. build runs the build script in every workspace that has one. test does the same for the test script. clean removes node_modules, dist and package-lock.json from each of the four directories, and install:fresh installs at the root and then in each workspace, and clean:install chains the three together. That last one is the reset button for a monorepo, and having it as a single command is what keeps a workspace setup usable.

The build tooling is Rollup, with the commonjs and node-resolve plugins, and rollup-plugin-dts for generating type declarations, and TypeScript 5.3.3 for the types. Prettier 3.1.1 handles formatting, configured with singleQuote true, and the format script targets the source and test directories of every workspace.

The dev dependencies are all build-time tools. There is no test framework in the root dev dependencies, which is the point: the library is the test framework, and it tests itself with its own facilities.

Recipes for four environments, and a benchmark

Two directories in the repository are documentation in executable form.

The examples directory holds a list of recipes to get started with different environments, and the four subdirectories say exactly which ones: browser-vanilla-vite for the browser, node-cjs for Node with CommonJS, node-es for Node with ES modules, and node-ts for Node with TypeScript. There is a readme in the examples directory as well.

That set of four is the practical specification of the claim that the library runs anywhere. CommonJS and ES modules are the two module systems, TypeScript is the compile step, and the browser case is the one where the runner cannot help you at all, because in a browser there is no command line and no file discovery, so your test program runs in the page.

The perfs directory is the other one. The README calls it a pseudo benchmark which shows the testing experience with various testing frameworks, and the word pseudo is doing honest work: it is a comparison the project made itself, with its own harness and its own choices of what to measure, so it tells you what the author believes about the relative speed rather than giving you a neutral measurement.

That does not make it useless. For a library whose central claim is that it is fast, having the comparison in the repository at all is better than not, and reading it tells you which frameworks the author considers the comparison set. It should just not be quoted as a neutral result, and the project itself does not quote it that way.

Where zora is the wrong choice

There are clear cases where a minimal composable library is the wrong answer, and they come from what it deliberately leaves out.

The first is the runner. Because the test file is an ordinary program, somebody has to run it, and in Node that is the pta package. What pta gives you is a command line interface, and the README describes it as a test runner for a Node.js environment rather than as a full harness. So the features a large test suite expects from a runner, file discovery patterns, watch mode, running only the tests that changed, a flag to filter by name, are either in pta or are yours to write.

The second is the assertion library being unpublished. zora-assert exists in the monorepo and is the assertion library behind zora, but it cannot be installed on its own, so you cannot pin it separately, and you cannot use its assertions without pulling in zora. For most projects that is irrelevant. For a project that wants to reuse the assertions in a different framework, it is a wall.

The third is the ecosystem. The topics list mentions tap, mocha and tdd, which places zora in the same world as the established runners, but those runners come with mocking, timers, coverage instrumentation, snapshot testing and reporters for every CI system. Assembling those from small pieces is exactly the flexibility the project wants, and it is also a set of decisions you now have to make and maintain.

The alternative approach is a batteries included runner that already integrates with your CI, your watcher and your coverage tooling. The difference in approach is that zora gives you a library with almost no opinions and a small set of composable companions, while a full runner gives you conventions for free. For a small project with one environment, zora's model is lighter and quicker to understand. For a large codebase with a hundred test files and a coverage requirement, the conventions are worth more than the lightness.

The last practical note is the engine requirement. Node 22.18.0 or newer is the stated floor, and while a project that only runs in a browser would not hit that, any Node CI image older than that needs updating before the tests will run at all.

Editorial conclusion

zora suits somebody who wants tests to be ordinary JavaScript programs that run in more than one environment, and who is happy to assemble the runner and the reporting from small pieces rather than accept a monolith's defaults. It does not suit a team that wants a batteries included runner with watch mode, mocking, parallelism and coverage reporting in one install, and it does not suit somebody who needs the performance comparison to be neutral, since the project's own benchmark is described as a pseudo benchmark. Check three things before you adopt it: that your Node version is 22.18.0 or newer, since that is the stated engine requirement, which of the four packages you actually need, since the assertion library is unpublished and cannot be consumed on its own, and whether your environment is covered by the examples, which run the same tests under CommonJS, ES modules, TypeScript and a browser bundle. The last push to the repository was on 2026-07-12 and the newest releases are [email protected], [email protected] and [email protected].

Frequently asked questions

What is zora?

It is a JavaScript testing library for Node.js, Deno and the browser, described as one of the lightest yet fastest. The repository is split into four packages: the zora library, the unpublished zora-assert assertions behind it, the zora-reporters output packages, and pta, a runner with a command line interface for Node.

Why does zora not need a test runner?

Because a test program is just a regular JavaScript program. The README states the principle as running with any JavaScript environment, so you do not need any specific test runner, and the same tests run under Node with CommonJS, Node with ES modules, TypeScript and the browser.

How is the zora repository organised?

As npm workspaces for the four packages, assert, reporters, zora and pta, with the engine requirements of node 22.18.0 or newer and npm 7 or newer. The build and test scripts run across the workspaces, and the packages are versioned separately, with zora at 6.0.4, the reporters at 3.0.1 and pta at 1.4.0.

What does zora include for examples and comparisons?

The repository includes a pseudo benchmark under perfs/ that shows the testing experience with various testing frameworks, and a list of recipes under examples/ covering a browser project built with Vite, Node with CommonJS, Node with ES modules and Node with TypeScript.

Can I install zora-assert on its own?

No. The README lists zora-assert as the assertion library behind zora and marks it as unpublished, so it exists in the monorepo but is not distributed separately. It comes with zora rather than as a standalone dependency.

Official sources

  1. Issues
  2. License: MIT
  3. lorenzofox3/zora on GitHub
  4. README
  5. Releases
Add this badge to your README

If you maintain this project, the badge below links readers to this analysis and shows its maintenance status from the daily GitHub snapshot. Paste the markdown into your README; add ?metric=license or ?metric=stars to the image URL for a different field.

Add this badge to your README

markdown
[![Hysen Labs](https://hysenlabs.com/badge/lorenzofox3-zora.svg)](https://hysenlabs.com/projects/lorenzofox3-zora)

Was this useful?