Testing Lit components created with TypeScript and Vite using Web Test Runner

By Markus Johansson
2024-04-23

With only about a month left until the initial release of Umbraco 14 aka Bellissima and the new Backoffice, I'm working hard to migrate/update my email-package Newsletter Studio. This package makes it possible create and design emails to send as campaigns or use as transactional emails.

The new Backoffice

The new Umbraco backoffice is based on Web Components and implemented using Lit and TypeScript. These technologies were all new to me when I started the migration, and it took quite som learning to get up to speed, but it has ben (and still is) a fun journey.

My package is quite complicated so I figured I needed a way to run different kinds of tests (unit tests, end 2 end tests). As always, I looked at the Umbraco source code to find some inspiration. I must say that it has been very interesting and I've learned a lot from looking at how the great minds at Umbraco HQ have done things.

Web Test Runner

When it comes to testing they've chosen to use Web Test Runner which is a modern test runner that will execute tests in a real browser. Many other test runner will execute in a Node-environment and "mock" the browser DOM (which is not an easy thing to do), Web Test Runner will execute all the unit tests in a real browser which saves us a lot of hassle.

Now I've setup my project to be ready for the new import map feature in modern browser. This feature basically allow us to write JavaScript code imports like:"import {Thing} from 'lib';" and then tell the browser which file/URL to load when it sees "lib".

When using TypeScript and Vite it's quite easy to set this up using TypeScript paths, Matt Brailsford wrote a a great article about this that I highly recommend reading.

Now, when I added Web Test Runner to my project I started by trying to use the same dependencies as Bellissima but I had a really hard time to get my imports to work in the browser that executed the tests. The @web/test-runner uses @web/dev-server to serve code to the browser during the test runs. Since we're using TypeScript the recommended approach seems to be to use @web/dev-server-esbuild and since we want import maps we would also need @web/dev-server-import-maps.

Not that easy

Setting this up basically makes us have two different build-pipelines, one with Vite and another one for the Web Test Runner. I spent a fair amount of time trying to get this to work but kept getting an error in the test run browser: "Error: Failed to fetch dynamically imported module". I think I looked at all web sites on the internet 🤥 but I could not find a solution. Obviously it works since the Bellissima project uses this approach, but since I was frustrated I started to look for alternatives.

Another approach

Luckily this brought my attention to the plugin @remcovaes/web-test-runner-vite-plugin. This plugin will reuse all the configuration from the Vite setup (including the Paths from tsconfig.json which had to be duplicated in the Web Test Runner configuration) and after installing it, my tests was working in 2 minutes. After spending many hours debugging I could not believe it was working, I was actually thinking: "No, this can't be right, it cant be this easy" 😆. But it was. The code in my web-test-runner.config.mjs file went from 50 lines to 15 lines and the experience was really nice.

Now I have a nice setup to be able to unit test my web components and TypeScript code. I've shared a working example of the setup in this github repository if anyone else is struggling with the same problems.






More blog posts



15 januari 2021

Umbraco and MiniProfiler