-
Notifications
You must be signed in to change notification settings - Fork 12
web-test-runner integration with vite 3.0 #22
Description
Hi, I found this repo through a link on vitest and on google.
I was looking for the latest vite support (currently 3.x), but quickly realized the code was for the old version.
After hitting myself against the wall for some time, I develop an integration that works with the latest version.
In the spirit of OSS, rather than creating another npm package, I would love to help the maintainer in this repo with the package update if there is the willingness to do so.
For the record, if anyone wants to do the integration in the meantime, here is the code:
// vite-web-test-runner-plugin.js
import { createServer } from 'vite';
import { join, relative } from 'node:path';
import koaConnect from 'koa-connect';
import minimatch from 'minimatch';
/** @typedef { import('@web/test-runner').TestRunnerPlugin } RunnerPlugin */
/**
* @return { RunnerPlugin }
*/
export default function viteWebTestRunnerPlugin({ testMatch, testRoot = process.cwd(), viteConfigFile } = {}) {
let viteServer;
let viteRoot;
let relativeRoot;
return {
name: 'vite-wtr-plugin',
async serverStart({ app, fileWatcher }) {
viteServer = await createServer({
clearScreen: true,
server: { middlewareMode: true, hmr: false },
appType: 'custom',
configFile: viteConfigFile || join(testRoot, 'vite.config.ts')
});
viteRoot = viteServer.config.root;
// This path represents the diff beween the test root and the vite root
// viteRoot should always be a relative path from the root (ex. testRoot: /root/test vs viteRoot: /root/test/src/module)
relativeRoot = `/${relative(testRoot, viteRoot)}`;
// Allow vite to take over most requests
app.use(koaConnect(viteServer.middlewares));
// Vite is taking over the handling of URLs, hence we need to forward the watching to the runner
viteServer.watcher.on('change', (...args) => fileWatcher.emit('change', ...args));
},
async transformImport({ source }) {
const [absSource, ] = source.split('?'); // Remove the queryString otherwise vite will fail resolving
const relativeSource = absSource.at(0) === '/' ? absSource.substring(1) : absSource;
for (const match of testMatch) {
if (minimatch(relativeSource, match)) {
const newPath = absSource.replace(relativeRoot, '');
return newPath;
}
}
},
async serverStop() {
return viteServer.close();
},
}
}Example usage:
// web-test-runner-config.js
import { jasmineTestRunnerConfig } from 'web-test-runner-jasmine';
import viteWebTestRunnerPlugin from './scripts/testing/vite-web-test-runner-plugin.mjs';
const testMatch = ['src/**/*.test.ts'];
export default {
...jasmineTestRunnerConfig(),
files: testMatch,
nodeResolve: true,
plugins: [
viteWebTestRunnerPlugin({ testMatch })
],
};Also, if you want to use commands in WTR you have to tell vite to ignore that endpoint
//vite.config.ts
const webTestRunnerIgnore = (): Plugin => {
return {
name: 'web-dev-server',
resolveId: (id): { external: boolean; id: string } | void => {
// Vite should not transform the WebSocket route to allow WTR commands to function correctly
if (id === '/__web-dev-server__web-socket.js') {
return { external: true, id };
}
},
};
};
export default defineConfig({
plugins: [webTestRunnerIgnore()]
});My 2cents: If you are using vite and a web-component framework like lit, using web-test-runner is a superior testing approach rather than using any synthetic DOM implementation like JSDOM or HappyDOM.