DEV Community

Jordan Jaramillo
Jordan Jaramillo

Posted on

Node 18 is now available!!! 😎

In this little post we will be testing a new feature of nodeJS 18.
Node.js 18 will be promoted to Long Term Support (LTS) in October 2022.

For the Node.js 18 release, I'll highlight some of the new features.

Exciting new features include:

  • Experimental Fetch
  • Test Runner
  • ECMAScript modules improvements
  • Improved support for AbortController and AbortSignal
  • Updated Platform Support

Among other features.

Today we are going to be doing some examples with testing where we will also be testing fetch, Array.findLast and Array.findLastIndex in a superficial way.

You can get all the code from this repository

Getting started

So let's create our package.json with the command:

npm init -y
Enter fullscreen mode Exit fullscreen mode

Remember that you must install version 18 of node from the official page

Now we are going to create a file which will be the index.js where we are going to start writing our tests.

To start let's see what we have to import:

import test from "node:test";
import assert from "node:assert";
Enter fullscreen mode Exit fullscreen mode

We see that we have 2 apis that come have to be prefixed to node: or it won't work for you.

Once importing this we can now write our first test.

Test a string:

test("Testing a string", () => {
   assert.match("Welcome Node 18", /Node 18/);
});
Enter fullscreen mode Exit fullscreen mode

This test will give us the following output :

ok 1 - Testing a string
  ---
  duration_ms: 0.000385918
  ...
Enter fullscreen mode Exit fullscreen mode

First what we will do is use the tests method which receives the description as the first parameter and a callback as the second parameter which will have the logic of our test or we can even execute subtest as indicated in the official documentation

To assert a string we have to pass the string we want to test as the first parameter and as the second parameter we send the regular expression as we saw in the previous code.

We can also send a third parameter which is optional but will serve as a custom error message. Let's see the example:

test("Testing a string fails", () => {
   assert.match("Hello", /world/, 'This string does not contain "world"');
});
Enter fullscreen mode Exit fullscreen mode

This test will give us the following output :

❯node index.test.js 
not ok 1 - Testing a string fails
  duration_ms: 0.000888784
  failureType: 'testCodeFailure'
  error: 'This string not contains "world"'
  code: ERR_ASSERTION
  stack: |-
    TestContext.<anonymous> (file:///Users/jordandev/Desktop/node18/index.test.js:5:10)
    Test.runInAsyncScope (node:async_hooks:202:9)
    Test.run (node:internal/test_runner/test:333:20)
    Test.start (node:internal/test_runner/test:287:17)
    Test.test (node:internal/test_runner/harness:126:18)
    file:///Users/jordandev/Desktop/node18/index.test.js:4:1
    ModuleJob.run (node:internal/modules/esm/module_job:198:25)
    async Promise.all (index 0)
    async ESMLoader.import (node:internal/modules/esm/loader:409:24)
    async loadESM (node:internal/process/esm_loader:85:5)
  ...
  tests 1
  pass 0
  fail 1
  skipped 0
  todo 0
  duration_ms 0.062970366

Enter fullscreen mode Exit fullscreen mode

As you can see in the error our custom error appears.

equal and notEqual

Now we will see the equal and notEqual methods which will allow us to test 2 values to know if they are equal and not equal:

test("Testing that a number is equal", () => {
   let current = 99;
   let expected = 99;
   assert.equal(actual, expected);
});

test("Testing that a number is not equal", () => {
   let current = 22;
   let expected = 393;
   assert.notEqual(actual, expected, `${actual} is not equal to ${expected}`);
});
Enter fullscreen mode Exit fullscreen mode

As you can see, the 2 receive the current value as the first parameter and the expected value as the second parameter.

Remember to run the test with

node index.js
Enter fullscreen mode Exit fullscreen mode

deepStrictEqual

We are going to test an object, for this we are going to use the deepStrictEqual method that will help us to deeply test the properties of our object:

test("Testing objects", () => {
   assert.deepStrictEqual(
     { name: "jordan" },
     { name: "jordan" },
     "Objects are not equal"
   );
});
Enter fullscreen mode Exit fullscreen mode

Testing asynchronous functionality

To test an asynchronous function we only have to use the asynchronous callback and in this way we can use await to be able to resolve promises:

test("Testing asynchronous functionality", async() => {
   const number = await Promise.resolve(90);
   assert.equal(number, 90, "The number is not equal to 90");
});
Enter fullscreen mode Exit fullscreen mode

Array.findLast and Array.findLastIndex

Now we are going to try the Array.findLast method, what we will do is create an array of numbers from 1 to 10 and we will look for the last multiple of 3 and as a result we should obtain 9

test("Array.findLast", () => {
     constant numbers = [1, 2, 3, 4, 5, 6, 7, 8, 9, 10];
     const lastmultipleofthree = numbers.findlast((n) => n % 3 === 0);
     assert.equal(lastMultipleOfThree, 9);
});
Enter fullscreen mode Exit fullscreen mode

The findLast method is similar in syntax to a filter but it will return the last element found.

Now we will see the operation of the Array.findLastIndex method, we will have an array with repeated numbers and we will look for the last index of the element that is equal to 3, in this case it should be 9 according to the array that we will pass to it.

test("Array.findLastIndex", () => {
   const numbers = [1, 3, 2, 4, 4, 3, 4, 1, 9, 3];
   const lastIndexOfThree = numbers.findLastIndex((n) => n === 3);
   assert.equal(lastIndexOfThree, 9);
});
Enter fullscreen mode Exit fullscreen mode

This works similar to findIndex but returns the last found index of an element based on the condition.

Fetch

Now we are going to try one of my favorite features which is fetch.

Let's make a call to the jsonplaceholder api endpoint https://jsonplaceholder.typicode.com/users/1

test("Fetch", async() => {
   const reponse = await fetch("https://jsonplaceholder.typicode.com/users/1");
   const json = await response.json();
   assert.equal(json.name, "Leanne Graham");
});
Enter fullscreen mode Exit fullscreen mode

As we can see we have the fetch functionality just as we would from the browser.

I have personally loved this and can't wait for it to be stable.

Subtests

Finally we are going to do a subtest so that you have an example of how to do it:

test("top level test", async (t) => {
   await t.test("subtest 1", (t) => {
     assert.strictEqual(1, 1);
   });

   await t.test("subtest 2", (t) => {
     assert.strictEqual(2, 2);
   });
});
Enter fullscreen mode Exit fullscreen mode

This example is offered by the official nodejs documentation. As you can see, it is very easy to chain tests through the parameter that the callback gives you.

So having this clear, you can try out the new node. Personally, I really liked that they incorporate the test and node api.

We cannot fail to mention the new methods for Arrays that will surely be super useful.

If you want to know more about this update you can see it from the official blog here

Top comments (1)

Collapse
 
bfunc profile image
Pavel Litkin • Edited

Regarding test runner, unfortunately:

  1. out of the box it looks only for js, mjs, cjs files, so it will miss .ts specs when scanning folders.
  2. TypeScript definitions for "node:test" module are missing in @types/node.
  3. Watch mode is missing.

Currently we can write native tests in typescript and run them with ts-node, when we want to run bulk we can run those test with tape library ("node:test" will work) and watch mode can be done with nodemon.