Riot Component Unit Test with Vitest (Node env)

Steeve - Mar 21 - - Dev Community

This article covers testing Riot Input components using Vitest and Riot/SSR in a Node environment.

A second method exists: Vitest into a JsDom environment (or HappyDom); read this article to learn more

Before going forward, ensure you have a base Riot+Vite project and have created at least one component. If not, you can read my previous article on creating an Input Component.

These articles form a series focusing on RiotJS paired with BeerCSS, designed to guide you through creating components and mastering best practices for building production-ready applications. I assume you have a foundational understanding of Riot; however, feel free to refer to the documentation if needed: https://riot.js.org/documentation/

Riot + Vitest + Riot-SSR: Next Generation Testing Framework

Vite is used as a development server to provide real-time rendering of my Riot application. Using Vitest for testing offers many advantages:

  • A test runner that uses the same configuration as Vite (vite.config.js).
  • It provides a compatible Jest API (one of the most used test runners)
  • Performances: it uses Worker threads to run as much as possible in parallel.
  • Easy setup and configuration (almost none).

Add Vitest to your Riot project:

npm install -D vitest
Enter fullscreen mode Exit fullscreen mode

To execute the test, add the following section to your package.json:

{
  "scripts": {
    "test": "vitest"
  }
}
Enter fullscreen mode Exit fullscreen mode

And that's it for Vitest! If you need a specific configuration, add test property in your Vite config vite.config.js. Configuration documentation: https://vitest.dev/config/

Write a first Test with Riot-SSR

Our tests will use Riot SSR (Riot Server-Side Rendering) because it is a module that renders riot components on the server.

First, add Riot-SSR to your project:

npm i -D @riotjs/ssr
Enter fullscreen mode Exit fullscreen mode

The module takes a component and renders it as HTML; we must assert if we don't get the expected result.

As the HTML rendering is only a String, so we can't test Component events, such as value changes, button clicks, key types, etc. A Browser Dom environment, such as JsDom, is required to test Riot Component reactivity.

Here is the minimum test we can create with Vitest and Riot-SSR:

import { assert, describe, it } from 'vitest'
import render from '@riotjs/ssr'

import cInput from '../components/c-input.riot'

describe('Component c-input', () => {
    it('should render the input without props', () => {
        const html = render('c-input', cInput, {})

        assert.strictEqual(html, '<c-input><div class="field border"><input value="" type="text"></div></c-input>')
    })
});

Enter fullscreen mode Exit fullscreen mode

Code Breakdown:

  1. Modules and the component are loaded.
  2. Vitest provides common utilities for testing, similar to Mocha and Jest:
    • describe() is used to define a group of tests
    • it() for defining a test
    • assert() for validating tests
  3. The render() function takes 3 arguments:
    • First: The component name built as String
    • Second: The component module
    • Third: Optional props are properties passed to the components.
  4. Validate the result of the rendered HTML as String with the assert.strictEqual(result, expected).

Now start the test through the NPM command:

npm run test
Enter fullscreen mode Exit fullscreen mode

We get the following result:

 DEV  v1.4.0 /riot-beercss

 ✓ tests/c-input.test.js (1)
   ✓ Component c-input (1)
     ✓ should load a basic input without props

 Test Files  1 passed (1)
      Tests  1 passed (1)
   Start at  13:41:34
   Duration  242ms (transform 108ms, setup 0ms, collect 128ms, tests 6ms, environment 0ms, prepare 35ms)
Enter fullscreen mode Exit fullscreen mode

✅ The test succeeds; everything is good. Vitest is listening to changes, and it will print the result when a new test is created.

Advanced Tests

The goal now is to try all input states by passing props to the components, render it with Riot-SSR, and it should render the expected result.

Let's try testing a default value for the input:

    it('should render the input with a default value', () => {
        const _htmlExpected = '<c-input><div class="field border"><input value="Firstname" type="text"></div></c-input>';
        const _html = render('c-input', cInput, { value: "Firstname"})

        assert.strictEqual(_html, _htmlExpected)
    })
Enter fullscreen mode Exit fullscreen mode

Code Details:

  1. First the expected HTML result is stored into a constant
  2. The Component is built with a props value: "Firstname"
  3. The result is validated with the assert expression. In this case, everything is fine.

Now we can replicate this testing method for all props and multiple props combined: Let's create a rounded small input with a "Password" type, label, and an error.

it('should render multiple props: label, type, error and round', () => {
    const _htmlExpected = '<c-input><div class="field border round invalid label"><input value="" type="password"><label>Password</label><span class="error">The password is too show, minimum 20 characters.</span></div></c-input>';
    const _html = render('c-input', cInput, { label: "Password", type: "password", error: "The password is too show, minimum 20 characters.", round: true})

    assert.strictEqual(_html, _htmlExpected)
})
Enter fullscreen mode Exit fullscreen mode

Code Breakdown:

  • Multiple props are passed to the render() function
  • A constant is created with the expected HTML result based on the component's logic.

The test pass ✅

Find all input tests the following GitHub repository:
https://github.com/steevepay/riot-beercss/blob/main/tests/c-input.node.test.js

Conclusion

Combining Riot-SSR with Vitest is a good method for quickly testing the rendering of Riot Components, but it does not provide a Browser for testing HTML events.

I covered another testing method in a JsDom environment, to compare the two solutions:

  • For extensive but verbose Riot testing: use a JsDom environment
  • For fast, no-brain but limited Riot testing: use a Node Server Environment with Riot-SSR

Feel free to comment if you have questions or need help about RiotJS.

Have a great day! Cheers 🍻

. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .