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
To execute the test, add the following section to your package.json
:
{
"scripts": {
"test": "vitest"
}
}
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
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>')
})
});
Code Breakdown:
- Modules and the component are loaded.
- 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
- 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.
- 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
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)
✅ 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)
})
Code Details:
- First the expected HTML result is stored into a constant
- The Component is built with a props
value: "Firstname"
- 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)
})
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 🍻