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.
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 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:
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.
Each and every suite can be called and like this suite(name, callback)
.
In order to run a suite, one should add the suite to uvu test queue and use suite.run()
.
Skipping a suite can assist in missing an entire test block as suite.skip(name, callback)
.
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)
.
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();
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:
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.
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>
Would you be interested in joining LogRocket's developer community?
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 nowLearn how to implement one-way and two-way data binding in Vue.js, using v-model and advanced techniques like defineModel for better apps.
Compare Prisma and Drizzle ORMs to learn their differences, strengths, and weaknesses for data access and migrations.
It’s easy for devs to default to JavaScript to fix every problem. Let’s use the RoLP to find simpler alternatives with HTML and CSS.
Learn how to manage memory leaks in Rust, avoid unsafe behavior, and use tools like weak references to ensure efficient programs.