vite-plugin-testem 1.0.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/LICENSE +21 -0
- package/README.md +70 -0
- package/index.js +100 -0
- package/package.json +55 -0
package/LICENSE
ADDED
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
MIT License
|
|
2
|
+
|
|
3
|
+
Copyright (c) 2026 Gaurav Munjal
|
|
4
|
+
|
|
5
|
+
Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
6
|
+
of this software and associated documentation files (the "Software"), to deal
|
|
7
|
+
in the Software without restriction, including without limitation the rights
|
|
8
|
+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
9
|
+
copies of the Software, and to permit persons to whom the Software is
|
|
10
|
+
furnished to do so, subject to the following conditions:
|
|
11
|
+
|
|
12
|
+
The above copyright notice and this permission notice shall be included in all
|
|
13
|
+
copies or substantial portions of the Software.
|
|
14
|
+
|
|
15
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
16
|
+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
17
|
+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
18
|
+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
19
|
+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
20
|
+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
|
21
|
+
SOFTWARE.
|
package/README.md
ADDED
|
@@ -0,0 +1,70 @@
|
|
|
1
|
+
# vite-plugin-testem
|
|
2
|
+
|
|
3
|
+
[Vite](https://vite.dev/) plugin and [Testem](https://github.com/testem/testem) middleware helper for browser unit tests.
|
|
4
|
+
|
|
5
|
+
## Install
|
|
6
|
+
|
|
7
|
+
```bash
|
|
8
|
+
npm install vite-plugin-testem --save-dev
|
|
9
|
+
```
|
|
10
|
+
|
|
11
|
+
You must also install a compatible Vite version (peer dependency: `^7.0.0 || ^8.0.0`).
|
|
12
|
+
|
|
13
|
+
To run browser tests with Testem, install Testem in your project (optional peer dependency: `^3.20.0`):
|
|
14
|
+
|
|
15
|
+
```bash
|
|
16
|
+
npm install testem@^3.20.0 --save-dev
|
|
17
|
+
```
|
|
18
|
+
|
|
19
|
+
## `vitePluginTestem(options)`
|
|
20
|
+
|
|
21
|
+
Vite plugin that injects the Testem client script (`/testem.js`) into `index.html`. For TAP-style runners it can inject the usual `Testem.handleConsoleMessage` bridge.
|
|
22
|
+
|
|
23
|
+
**Options**
|
|
24
|
+
|
|
25
|
+
- `framework`: `'tap'` (default), `'mocha'`, or `'none'`
|
|
26
|
+
- `injectTapBridge`: override whether the TAP console bridge is injected (defaults to on when `framework === 'tap'`)
|
|
27
|
+
|
|
28
|
+
## `createTestemViteMiddleware(inlineConfig)`
|
|
29
|
+
|
|
30
|
+
Returns a Promise of `{ middleware, close }`. Use `middleware` in Testem’s `middleware` array so Vite runs in [middleware mode](https://vite.dev/guide/ssr.html#setting-up-the-dev-server) ahead of Testem’s own routes. The helper skips `/testem.js`, `/testem/*`, and `/socket.io` so Testem still serves its client and Socket.IO on the same origin.
|
|
31
|
+
|
|
32
|
+
Pass Vite `InlineConfig` fields as needed (for example `root: __dirname`). Set `configFile: false` if you do not want Vite to load `vite.config.js`.
|
|
33
|
+
|
|
34
|
+
## Recommended: `on_exit` and `close()`
|
|
35
|
+
|
|
36
|
+
Vite’s dev server registers file watchers and keeps resources open. If you only register the middleware and exit Testem, those handles can prevent the process from exiting cleanly or leave watcher noise in the background.
|
|
37
|
+
|
|
38
|
+
Call the `close()` function returned with the middleware from Testem’s **`on_exit`** hook. That shuts down the Vite server the same way as stopping the CLI dev server.
|
|
39
|
+
|
|
40
|
+
Example `testem.js`:
|
|
41
|
+
|
|
42
|
+
```javascript
|
|
43
|
+
const { createTestemViteMiddleware } = require('vite-plugin-testem');
|
|
44
|
+
|
|
45
|
+
let viteClose;
|
|
46
|
+
|
|
47
|
+
module.exports = async function testemConfig() {
|
|
48
|
+
const { middleware, close } = await createTestemViteMiddleware({
|
|
49
|
+
root: __dirname,
|
|
50
|
+
});
|
|
51
|
+
viteClose = close;
|
|
52
|
+
|
|
53
|
+
return {
|
|
54
|
+
middleware: [middleware],
|
|
55
|
+
test_page: 'index.html',
|
|
56
|
+
on_exit(config, data, callback) {
|
|
57
|
+
if (!viteClose) {
|
|
58
|
+
return callback(null);
|
|
59
|
+
}
|
|
60
|
+
viteClose()
|
|
61
|
+
.then(() => callback(null))
|
|
62
|
+
.catch(callback);
|
|
63
|
+
},
|
|
64
|
+
};
|
|
65
|
+
};
|
|
66
|
+
```
|
|
67
|
+
|
|
68
|
+
## License
|
|
69
|
+
|
|
70
|
+
MIT
|
package/index.js
ADDED
|
@@ -0,0 +1,100 @@
|
|
|
1
|
+
'use strict';
|
|
2
|
+
|
|
3
|
+
const path = require('path');
|
|
4
|
+
const vite = require('vite');
|
|
5
|
+
|
|
6
|
+
/**
|
|
7
|
+
* Vite plugin for projects tested with [Testem](https://github.com/testem/testem).
|
|
8
|
+
*
|
|
9
|
+
* Injects the Testem browser client (`/testem.js`) into `index.html`. For `framework: 'tap'`,
|
|
10
|
+
* also injects the usual `Testem.handleConsoleMessage` bridge so tape / TAP output reaches Testem.
|
|
11
|
+
* For Mocha, QUnit, etc., omit the TAP bridge (use `framework: 'mocha'` or `injectTapBridge: false`).
|
|
12
|
+
*
|
|
13
|
+
* @param {{ framework?: 'tap' | 'mocha' | 'none', injectTapBridge?: boolean }} [options]
|
|
14
|
+
* @returns {import('vite').Plugin}
|
|
15
|
+
*/
|
|
16
|
+
function vitePluginTestem(options = {}) {
|
|
17
|
+
const framework = options.framework || 'tap';
|
|
18
|
+
const injectTapBridge =
|
|
19
|
+
options.injectTapBridge !== undefined
|
|
20
|
+
? options.injectTapBridge
|
|
21
|
+
: framework === 'tap';
|
|
22
|
+
|
|
23
|
+
return {
|
|
24
|
+
name: 'testem',
|
|
25
|
+
enforce: 'pre',
|
|
26
|
+
transformIndexHtml(html) {
|
|
27
|
+
if (/\/testem\.js/.test(html)) {
|
|
28
|
+
return html;
|
|
29
|
+
}
|
|
30
|
+
let snippet = '<script src="/testem.js"></script>';
|
|
31
|
+
if (injectTapBridge) {
|
|
32
|
+
snippet += `
|
|
33
|
+
<script>
|
|
34
|
+
Testem.handleConsoleMessage = function (msg) {
|
|
35
|
+
Testem.emit('tap', msg);
|
|
36
|
+
return false;
|
|
37
|
+
};
|
|
38
|
+
</script>`;
|
|
39
|
+
}
|
|
40
|
+
if (/<head[^>]*>/i.test(html)) {
|
|
41
|
+
return html.replace(/<head[^>]*>/i, (m) => `${m}\n${snippet}\n`);
|
|
42
|
+
}
|
|
43
|
+
return `${snippet}\n${html}`;
|
|
44
|
+
},
|
|
45
|
+
};
|
|
46
|
+
}
|
|
47
|
+
|
|
48
|
+
/**
|
|
49
|
+
* Creates Express middleware (for Testem `middleware:`) that forwards requests to Vite in middleware mode.
|
|
50
|
+
* Skips `/testem.js`, `/testem/*`, and `/socket.io` so Testem’s own routes run later in the stack.
|
|
51
|
+
*
|
|
52
|
+
* @param {import('vite').InlineConfig} [inlineConfig] merged after defaults; set `configFile: false` to skip loading `vite.config.js`
|
|
53
|
+
* @returns {Promise<{ middleware: (app: import('express').Application) => void, close: () => Promise<void> }>}
|
|
54
|
+
*/
|
|
55
|
+
async function createTestemViteMiddleware(inlineConfig = {}) {
|
|
56
|
+
const cwd = inlineConfig.root || inlineConfig.cwd || process.cwd();
|
|
57
|
+
const configFile =
|
|
58
|
+
inlineConfig.configFile !== undefined
|
|
59
|
+
? inlineConfig.configFile
|
|
60
|
+
: path.join(cwd, 'vite.config.js');
|
|
61
|
+
|
|
62
|
+
const base = vite.mergeConfig(
|
|
63
|
+
{
|
|
64
|
+
configFile,
|
|
65
|
+
root: cwd,
|
|
66
|
+
server: {
|
|
67
|
+
middlewareMode: true,
|
|
68
|
+
hmr: false,
|
|
69
|
+
appType: 'custom',
|
|
70
|
+
},
|
|
71
|
+
},
|
|
72
|
+
{ ...inlineConfig, cwd: undefined },
|
|
73
|
+
);
|
|
74
|
+
|
|
75
|
+
const server = await vite.createServer(base);
|
|
76
|
+
|
|
77
|
+
function middleware(app) {
|
|
78
|
+
app.use((req, res, next) => {
|
|
79
|
+
const pathname = req.url.split('?')[0];
|
|
80
|
+
if (
|
|
81
|
+
pathname === '/testem.js' ||
|
|
82
|
+
pathname.startsWith('/testem/') ||
|
|
83
|
+
pathname.startsWith('/socket.io')
|
|
84
|
+
) {
|
|
85
|
+
return next();
|
|
86
|
+
}
|
|
87
|
+
server.middlewares(req, res, next);
|
|
88
|
+
});
|
|
89
|
+
}
|
|
90
|
+
|
|
91
|
+
return {
|
|
92
|
+
middleware,
|
|
93
|
+
close: () => server.close(),
|
|
94
|
+
};
|
|
95
|
+
}
|
|
96
|
+
|
|
97
|
+
module.exports = {
|
|
98
|
+
vitePluginTestem,
|
|
99
|
+
createTestemViteMiddleware,
|
|
100
|
+
};
|
package/package.json
ADDED
|
@@ -0,0 +1,55 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "vite-plugin-testem",
|
|
3
|
+
"version": "1.0.0",
|
|
4
|
+
"description": "Vite plugin and Testem middleware helper for running browser tests with Testem",
|
|
5
|
+
"keywords": [
|
|
6
|
+
"vite",
|
|
7
|
+
"plugin",
|
|
8
|
+
"vite-plugin",
|
|
9
|
+
"testem",
|
|
10
|
+
"testing"
|
|
11
|
+
],
|
|
12
|
+
"author": "Gaurav Munjal <Gaurav0@aol.com>",
|
|
13
|
+
"license": "MIT",
|
|
14
|
+
"repository": {
|
|
15
|
+
"type": "git",
|
|
16
|
+
"url": "git+https://github.com/Gaurav0/vite-plugin-testem.git"
|
|
17
|
+
},
|
|
18
|
+
"bugs": {
|
|
19
|
+
"url": "https://github.com/Gaurav0/vite-plugin-testem/issues"
|
|
20
|
+
},
|
|
21
|
+
"engines": {
|
|
22
|
+
"node": "^20.19.0 || ^22.12.0 || >=24.0.0"
|
|
23
|
+
},
|
|
24
|
+
"main": "./index.js",
|
|
25
|
+
"exports": {
|
|
26
|
+
".": {
|
|
27
|
+
"require": "./index.js",
|
|
28
|
+
"default": "./index.js"
|
|
29
|
+
}
|
|
30
|
+
},
|
|
31
|
+
"files": [
|
|
32
|
+
"index.js",
|
|
33
|
+
"README.md",
|
|
34
|
+
"LICENSE"
|
|
35
|
+
],
|
|
36
|
+
"peerDependencies": {
|
|
37
|
+
"vite": "^7.0.0 || ^8.0.0",
|
|
38
|
+
"testem": "^3.20.0"
|
|
39
|
+
},
|
|
40
|
+
"peerDependenciesMeta": {
|
|
41
|
+
"testem": {
|
|
42
|
+
"optional": true
|
|
43
|
+
}
|
|
44
|
+
},
|
|
45
|
+
"scripts": {
|
|
46
|
+
"lint": "eslint .",
|
|
47
|
+
"test": "node scripts/smoke-test.js"
|
|
48
|
+
},
|
|
49
|
+
"devDependencies": {
|
|
50
|
+
"@eslint/js": "^10.0.0",
|
|
51
|
+
"eslint": "^10.2.0",
|
|
52
|
+
"globals": "^16.0.0",
|
|
53
|
+
"vite": "^8.0.0"
|
|
54
|
+
}
|
|
55
|
+
}
|