VOOZH about

URL: https://blog.logrocket.com/how-to-use-uvu/

โ‡ฑ How to use uvu: A fast and lightweight test runner - LogRocket Blog


2021-02-02
1289
Kasra Khosravi
33744
๐Ÿ‘ Image

See how LogRocket's Galileo AI surfaces the most severe issues for you

No signup required

Check it out

uvu (short for ultimate velocity, unleashed) is considered to be one of the fastest and most lightweight test runners for Node.js and browsers. Its main features include individually executing test files, supporting asynchronous testing, supporting native ES modules, compatibility with browsers, outstanding lightweight size, familiar API, and remarkable performance. This blog post will cover the usage of uvu, its comparison with two other popular test runner libraries called Jest and AVA, and why and when to use it for testing.

๐Ÿ‘ How to use uvu: A fast and lightweight test-runner

๐Ÿš€ Sign up for The Replay newsletter

The Replay is a weekly newsletter for dev and engineering leaders.

Delivered once a week, it's your curated guide to the most important conversations around frontend dev, emerging AI tools, and the state of modern software.

Why use uvu?

First of all, uvu supports asynchronous testing which is one of the common advantages that some testing libraries support. It assists in determining that the code which is being tested has completed the test process before it moves towards the next test. The prime objective of an asynchronous (async) function is just to clarify the syntax that is mandatory to consume promise based APIโ€™s. In asynchronous testing, a method will be used like callback or promise which will determine the completion of a test process.

Another main feature is browser compatibility. At first, it was an issue that uvu was not compatible with the browsers but this was resolved by performing a little modification with the process file. You can find the discussion regarding the issue resolution here. So even if you are having any kind of issues with the browser compatibility you can check this link for a better understanding and sort out your problem.

Using uvu

Using uvu is simple and works like this:

// tests/demo.js
// Source: https://github.com/lukeed/uvu

import { test } from 'uvu';
import * as assert from 'uvu/assert';

test('Math.sqrt()', () => {
 assert.is(Math.sqrt(4), 2);
 assert.is(Math.sqrt(144), 12);
 assert.is(Math.sqrt(2), Math.SQRT2);
});

test('JSON', () => {
 const input = {
 foo: 'hello',
 bar: 'world'
 };
 const output = JSON.stringify(input);
 assert.snapshot(output, `{"foo":"hello","bar":"world"}`);
 assert.equal(JSON.parse(output), input, 'matches original');
});

test.run();

Now what you need to do is just to execute this test file:

# via `uvu` cli, for all `/tests/**` files
$ uvu -r esm tests

# via `node` directly, for file isolation
$ node -r esm tests/demo.js

The point to be noted about the above command lines is that โ€“r esm is only specified for legacy Node.js modules since the Ecmascript (ES) modules are deposited to Node.js versions >12.x. By default, .js and .cjs files are treated as Common.js, and .mjs file extensions are only the ones that would be served as Ecmascript Modules (ESM).

The above example can be considered as the simplest method through which Node.js will load ES modules and grant them to import any module when required. Also, you can load modules in some other ways as well that are shown below.

There are also other ways through which Node.js will load ES modules. These methods include type, module and esm package procedures. Here are the complete guides of these methods:

Main uvu module

The main uvu module will assist regarding the tests or test suits(series of individual tests that are related to a certain functionality in the code) that are required for all the uvu tests. The users have the option available here whether to choose uvu.test or uvu.suite. Through uvu.suite one can grasp numerous additional perks like testing multiple files at once while one should choose uvu.test if thinking about testing a single file only (technically uvu.test is an unnamed test suite).

uvu.suite(name: string, context?:T)

You can have as many suites as you want in the same file but itโ€™s necessary to call suites run for each suite to be added to uvuโ€™s queue. This just returns a suite along with creating a new suite. The name here corresponds to the name of the suite and is of type string. This will combine all console output together and will suffix the name of any test that fails. The context of the suite has an empty object as default value and is of any type. This will be passed to every test-block and hook inside the suite.

uvu.test (name: string, callback: function)

If there is a requirement of testing only one file you can import this uvu.test. The name here obviously denotes the name of the test and is of type string and the callback here is consisted of the test code and is of type promise<any> or function<any>. The callback may be asynchronous and return values that are even though abandoned.

Methods

Creating

Each and every suite can be called and like this suite(name, callback).

Running

In order to run a suite, one should add the suite to uvu test queue and use suite.run().

Skipping

Skipping a suite can assist in missing an entire test block as suite.skip(name, callback).

Additional methods

For organizing an environment or establishing fixtures an ideal case would be to request the given callback before the beginning of the suit in the following way suite.before(callback).


Over 200k developers use LogRocket to create better digital experiences

๐Ÿ‘ Image
Learn more โ†’

Also for finishing an environment or fixture an ideal case would be to request the callback after the completion of the suite in the following way suite.after(callback).

Here is a sample code of the above description:

import { suite } from 'uvu';
import * as assert from 'uvu/assert';
import * as dates from '../src/dates';

const Now = suite('Date.now()');

let _Date;
Now.before(() => {
 let count = 0;
 _Date = global.Date;
 global.Date = { now: () => 100 + count++ };
});

Now.after(() => {
 global.Date = _Date;
});

// this is not run (skip)
Now.skip('should be a function', () => {
 assert.type(Date.now, 'function');
});

// this is not run (only)
Now('should return a number', () => {
 assert.type(Date.now(), 'number');
});

// this is run (only)
Now.only('should progress with time', () => {
 assert.is(Date.now(), 100);
 assert.is(Date.now(), 101);
 assert.is(Date.now(), 102);
});

Now.run();

Why uvu is better than Jest and AVA

First, letโ€™s take a look at a comparison of test runnersโ€™ times. Below are the results of the sample test (achieved by testing the sample code which is present here) ran by few test runners with two timings. The first value is the total execution time of the whole process and the other value is the self-reported performance time only if it is known:

~> "ava" took 594ms ( ??? )
~> "jest" took 962ms (356 ms)
~> "mocha" took 209ms (4 ms)
~> "tape" took 122ms ( ??? )
~> "uvu" took 72ms (1.3ms)

Itโ€™s obvious from the above result that uvu is the fastest option among its competitors.

Now let us talk a bit about the features comparison as well:

  • AVA and uvu both provide asynchronous testing while Jest doesnโ€™t
  • Jest and uvu allows you to integrate into other apps quite easily while AVA, being a minimalistic testing library, doesnโ€™t provide such integration as the other two do
  • AVA containing just a simple API requires installing an additional library for mocking support while Jest and uvu have a wide range of API not requiring the user to include additional libraries to have numerous features support

Conclusion

There has always been apprehension regarding the performance of test runners, but the features that uvu has provided have proved to be one of the finest ones. Itโ€™s just like an all-in-one library for anyone worried about browser compatibility, high-speed testing, supporting native ES modules, asynchronous testing, and individually executing test files from a single library. So whenever you are anxious about all these things you just need to switch to one solution and thatโ€™s uvu.

Get set up with LogRocket's modern error tracking in minutes:

  1. Visit https://logrocket.com/signup/ to get an app ID
  2. Install LogRocket via npm or script tag. LogRocket.init() must be called client-side, not server-side

    $ npm i --save logrocket 
    
    // Code:
    
    import LogRocket from 'logrocket'; 
    LogRocket.init('app/id');
     
    // Add to your HTML:
    
    <script src="https://cdn.lr-ingest.com/LogRocket.min.js"></script>
    <script>window.LogRocket && window.LogRocket.init('app/id');</script>
     
  3. (Optional) Install plugins for deeper integrations with your stack:
    • Redux middleware
    • NgRx middleware
    • Vuex plugin
Get started now
๐Ÿ‘ Image
๐Ÿ‘ Image
๐Ÿ‘ Image

Stop guessing about your digital experience with LogRocket

Get started for free

Recent posts:

How to build a virtual engineering team with Gemini CLI subagents

Learn how to use Gemini CLI subagents to delegate frontend, backend, testing, and docs tasks to specialized agents with guardrails and clear ownership.

๐Ÿ‘ Image
Emmanuel John
Jun 18, 2026 โ‹… 10 min read

Debug Next.js apps with AI agents and next-browser

Learn how next-browser gives AI agents runtime context for debugging Next.js apps, including React props, hydration, PPR, forms, and performance.

๐Ÿ‘ Image
Emmanuel John
Jun 17, 2026 โ‹… 9 min read

Stop hardcoding LLM SDKs: Dynamic LLM routing with OpenRouter and Next.js

Build dynamic LLM routing in Next.js with OpenRouter, TanStack AI, task classification, model fallbacks, and cost-aware routing.

๐Ÿ‘ Image
Chizaram Ken
Jun 16, 2026 โ‹… 13 min read

What is TSRX?: What JSX would look like if it were designed today

TSRX adds first-class control flow, conditional hooks, and scoped styles to React via a TypeScript compiler extension โ€” no new framework required.

๐Ÿ‘ Image
Ikeh Akinyemi
Jun 12, 2026 โ‹… 6 min read
View all posts

Hey there, want to help make our blog better?

Join LogRocketโ€™s Content Advisory Board. Youโ€™ll help inform the type of content we create and get access to exclusive meetups, social accreditation, and swag.

Sign up now