Skip to content

Commit f765391

Browse files
authored
Merge branch 'main' into fix-vite-node-invalidate-source-map-cache
2 parents 78e8f22 + 03a7703 commit f765391

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

44 files changed

+520
-130
lines changed

docs/config/index.md

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1640,6 +1640,14 @@ Run the browser in a `headless` mode. If you are running Vitest in CI, it will b
16401640

16411641
Run every test in a separate iframe.
16421642

1643+
#### browser.testerHtmlPath
1644+
1645+
- **Type:** `string`
1646+
- **Default:** `@vitest/browser/tester.html`
1647+
- **Version:** Since Vitest 2.1.4
1648+
1649+
A path to the HTML entry point. Can be relative to the root of the project. This file will be processed with [`transformIndexHtml`](https://vite.dev/guide/api-plugin#transformindexhtml) hook.
1650+
16431651
#### browser.api
16441652

16451653
- **Type:** `number | { port?, strictPort?, host? }`

docs/guide/debugging.md

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -10,7 +10,7 @@ When debugging tests you might want to use `--test-timeout` CLI argument to prev
1010

1111
## VS Code
1212

13-
Quick way to debug tests in VS Code is via `JavaScript Debug Terminal`. Open a new `JavaScript Debug Terminal` and run `npm run test` or `vitest` directly. *this works with any code ran in Node, so will work with most JS testing frameworks*
13+
Quick way to debug tests in VS Code is via `JavaScript Debug Terminal`. Open a new `JavaScript Debug Terminal` and run `npm run test` or `vitest` directly. *this works with any code run in Node, so will work with most JS testing frameworks*
1414

1515
![image](https://user-images.githubusercontent.com/5594348/212169143-72bf39ce-f763-48f5-822a-0c8b2e6a8484.png)
1616

packages/browser/rollup.config.js

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -107,7 +107,7 @@ export default () =>
107107
input: './src/client/tester/state.ts',
108108
output: {
109109
file: 'dist/state.js',
110-
format: 'esm',
110+
format: 'iife',
111111
},
112112
plugins: [
113113
esbuild({

packages/browser/src/client/public/error-catcher.js

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -56,7 +56,9 @@ async function reportUnexpectedError(
5656
error,
5757
) {
5858
const processedError = serializeError(error)
59-
await client.rpc.onUnhandledError(processedError, type)
59+
await client.waitForConnection().then(() => {
60+
return client.rpc.onUnhandledError(processedError, type)
61+
}).catch(console.error)
6062
const state = __vitest_browser_runner__
6163

6264
if (state.type === 'orchestrator') {
Lines changed: 50 additions & 48 deletions
Original file line numberDiff line numberDiff line change
@@ -1,50 +1,52 @@
1-
const moduleCache = new Map();
2-
3-
function wrapModule(module) {
4-
if (typeof module === "function") {
5-
const promise = new Promise((resolve, reject) => {
6-
if (typeof __vitest_mocker__ === "undefined")
7-
return module().then(resolve, reject);
8-
__vitest_mocker__.prepare().finally(() => {
9-
module().then(resolve, reject);
1+
(() => {
2+
const moduleCache = new Map();
3+
4+
function wrapModule(module) {
5+
if (typeof module === "function") {
6+
const promise = new Promise((resolve, reject) => {
7+
if (typeof __vitest_mocker__ === "undefined")
8+
return module().then(resolve, reject);
9+
__vitest_mocker__.prepare().finally(() => {
10+
module().then(resolve, reject);
11+
});
1012
});
11-
});
12-
moduleCache.set(promise, { promise, evaluated: false });
13-
return promise.finally(() => moduleCache.delete(promise));
13+
moduleCache.set(promise, { promise, evaluated: false });
14+
return promise.finally(() => moduleCache.delete(promise));
15+
}
16+
return module;
1417
}
15-
return module;
16-
}
17-
18-
window.__vitest_browser_runner__ = {
19-
wrapModule,
20-
wrapDynamicImport: wrapModule,
21-
moduleCache,
22-
config: { __VITEST_CONFIG__ },
23-
viteConfig: { __VITEST_VITE_CONFIG__ },
24-
files: { __VITEST_FILES__ },
25-
type: { __VITEST_TYPE__ },
26-
contextId: { __VITEST_CONTEXT_ID__ },
27-
testerId: { __VITEST_TESTER_ID__ },
28-
provider: { __VITEST_PROVIDER__ },
29-
providedContext: { __VITEST_PROVIDED_CONTEXT__ },
30-
};
31-
32-
const config = __vitest_browser_runner__.config;
33-
34-
if (config.testNamePattern)
35-
config.testNamePattern = parseRegexp(config.testNamePattern);
36-
37-
function parseRegexp(input) {
38-
// Parse input
39-
const m = input.match(/(\/?)(.+)\1([a-z]*)/i);
40-
41-
// match nothing
42-
if (!m) return /$^/;
43-
44-
// Invalid flags
45-
if (m[3] && !/^(?!.*?(.).*?\1)[gmixXsuUAJ]+$/.test(m[3]))
46-
return RegExp(input);
47-
48-
// Create the regular expression
49-
return new RegExp(m[2], m[3]);
50-
}
18+
19+
window.__vitest_browser_runner__ = {
20+
wrapModule,
21+
wrapDynamicImport: wrapModule,
22+
moduleCache,
23+
config: { __VITEST_CONFIG__ },
24+
viteConfig: { __VITEST_VITE_CONFIG__ },
25+
files: { __VITEST_FILES__ },
26+
type: { __VITEST_TYPE__ },
27+
contextId: { __VITEST_CONTEXT_ID__ },
28+
testerId: { __VITEST_TESTER_ID__ },
29+
provider: { __VITEST_PROVIDER__ },
30+
providedContext: { __VITEST_PROVIDED_CONTEXT__ },
31+
};
32+
33+
const config = __vitest_browser_runner__.config;
34+
35+
if (config.testNamePattern)
36+
config.testNamePattern = parseRegexp(config.testNamePattern);
37+
38+
function parseRegexp(input) {
39+
// Parse input
40+
const m = input.match(/(\/?)(.+)\1([a-z]*)/i);
41+
42+
// match nothing
43+
if (!m) return /$^/;
44+
45+
// Invalid flags
46+
if (m[3] && !/^(?!.*?(.).*?\1)[gmixXsuUAJ]+$/.test(m[3]))
47+
return RegExp(input);
48+
49+
// Create the regular expression
50+
return new RegExp(m[2], m[3]);
51+
}
52+
})();

packages/browser/src/client/tester/tester.html

Lines changed: 1 addition & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,7 @@
44
<meta charset="UTF-8" />
55
<link rel="icon" href="{__VITEST_FAVICON__}" type="image/svg+xml">
66
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
7-
<title>{__VITEST_TITLE__}</title>
7+
<title>Vitest Browser Tester</title>
88
<style>
99
html {
1010
padding: 0;
@@ -16,13 +16,8 @@
1616
min-height: 100vh;
1717
}
1818
</style>
19-
{__VITEST_INJECTOR__}
20-
<script>{__VITEST_STATE__}</script>
21-
{__VITEST_INTERNAL_SCRIPTS__}
22-
{__VITEST_SCRIPTS__}
2319
</head>
2420
<body>
2521
<script type="module" src="./tester.ts"></script>
26-
{__VITEST_APPEND__}
2722
</body>
2823
</html>

packages/browser/src/client/vite.config.ts

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -42,13 +42,14 @@ export default defineConfig({
4242
)
4343

4444
const ui = resolve(root, 'ui/dist/client')
45+
const uiEntryPoint = resolve(ui, 'index.html')
4546
const browser = resolve(root, 'browser/dist/client/__vitest__/')
4647

4748
const timeout = setTimeout(
4849
() => console.log('[copy-ui-plugin] Waiting for UI to be built...'),
4950
1000,
5051
)
51-
await waitFor(() => fs.existsSync(ui))
52+
await waitFor(() => fs.existsSync(ui) && fs.existsSync(uiEntryPoint))
5253
clearTimeout(timeout)
5354

5455
const files = globSync(['**/*'], { cwd: ui, expandDirectories: false })

packages/browser/src/node/plugin.ts

Lines changed: 102 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,5 @@
11
import type { Stats } from 'node:fs'
2+
import type { HtmlTagDescriptor } from 'vite'
23
import type { WorkspaceProject } from 'vitest/node'
34
import type { BrowserServer } from './server'
45
import { lstatSync, readFileSync } from 'node:fs'
@@ -72,9 +73,11 @@ export default (browserServer: BrowserServer, base = '/'): Plugin[] => {
7273
return
7374
}
7475

75-
const html = await resolveTester(browserServer, url, res)
76-
res.write(html, 'utf-8')
77-
res.end()
76+
const html = await resolveTester(browserServer, url, res, next)
77+
if (html) {
78+
res.write(html, 'utf-8')
79+
res.end()
80+
}
7881
})
7982

8083
server.middlewares.use(
@@ -394,6 +397,102 @@ export default (browserServer: BrowserServer, base = '/'): Plugin[] => {
394397
}
395398
},
396399
},
400+
{
401+
name: 'vitest:browser:transform-tester-html',
402+
enforce: 'pre',
403+
async transformIndexHtml(html, ctx) {
404+
if (!ctx.path.startsWith(browserServer.prefixTesterUrl)) {
405+
return
406+
}
407+
408+
if (!browserServer.testerScripts) {
409+
const testerScripts = await browserServer.formatScripts(
410+
project.config.browser.testerScripts,
411+
)
412+
browserServer.testerScripts = testerScripts
413+
}
414+
const stateJs = typeof browserServer.stateJs === 'string'
415+
? browserServer.stateJs
416+
: await browserServer.stateJs
417+
418+
const testerScripts: HtmlTagDescriptor[] = []
419+
if (resolve(distRoot, 'client/tester/tester.html') !== browserServer.testerFilepath) {
420+
const manifestContent = browserServer.manifest instanceof Promise
421+
? await browserServer.manifest
422+
: browserServer.manifest
423+
const testerEntry = manifestContent['tester/tester.html']
424+
425+
testerScripts.push({
426+
tag: 'script',
427+
attrs: {
428+
type: 'module',
429+
crossorigin: '',
430+
src: `${browserServer.base}${testerEntry.file}`,
431+
},
432+
injectTo: 'head',
433+
})
434+
435+
for (const importName of testerEntry.imports || []) {
436+
const entryManifest = manifestContent[importName]
437+
if (entryManifest) {
438+
testerScripts.push(
439+
{
440+
tag: 'link',
441+
attrs: {
442+
href: `${browserServer.base}${entryManifest.file}`,
443+
rel: 'modulepreload',
444+
crossorigin: '',
445+
},
446+
injectTo: 'head',
447+
},
448+
)
449+
}
450+
}
451+
}
452+
453+
return [
454+
{
455+
tag: 'script',
456+
children: '{__VITEST_INJECTOR__}',
457+
injectTo: 'head-prepend' as const,
458+
},
459+
{
460+
tag: 'script',
461+
children: stateJs,
462+
injectTo: 'head-prepend',
463+
} as const,
464+
{
465+
tag: 'script',
466+
attrs: {
467+
type: 'module',
468+
src: browserServer.errorCatcherUrl,
469+
},
470+
injectTo: 'head' as const,
471+
},
472+
browserServer.locatorsUrl
473+
? {
474+
tag: 'script',
475+
attrs: {
476+
type: 'module',
477+
src: browserServer.locatorsUrl,
478+
},
479+
injectTo: 'head',
480+
} as const
481+
: null,
482+
...browserServer.testerScripts,
483+
...testerScripts,
484+
{
485+
tag: 'script',
486+
attrs: {
487+
'type': 'module',
488+
'data-vitest-append': '',
489+
},
490+
children: '{__VITEST_APPEND__}',
491+
injectTo: 'body',
492+
} as const,
493+
].filter(s => s != null)
494+
},
495+
},
397496
{
398497
name: 'vitest:browser:support-testing-library',
399498
config() {

packages/browser/src/node/pool.ts

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -101,8 +101,7 @@ export function createBrowserPool(ctx: Vitest): ProcessPool {
101101
url.searchParams.set('contextId', contextId)
102102
const page = provider
103103
.openPage(contextId, url.toString(), () => setBreakpoint(contextId, files[0]))
104-
.then(() => waitPromise)
105-
promises.push(page)
104+
promises.push(page, waitPromise)
106105
}
107106
})
108107

0 commit comments

Comments
 (0)