[READ-ONLY] Mirror of https://github.com/vitest-dev/vitest. Next generation testing framework powered by Vite. vitest.dev
test testing-tools vite
12

Configure Feed

Select the types of activity you want to include in your feed.

fix(browser): correctly run in-source tests in the browser (#6440)

authored by

Vladimir and committed by
GitHub
(Sep 2, 2024, 3:46 PM +0200) c853126e 7188709c

+70 -13
+2 -1
test/browser/tsconfig.json
··· 9 9 "types": [ 10 10 "vite/client", 11 11 "@vitest/browser/providers/playwright", 12 - "vitest-browser-react" 12 + "vitest-browser-react", 13 + "vitest/import-meta" 13 14 ], 14 15 "esModuleInterop": true 15 16 }
+1
test/browser/vitest.config.mts
··· 28 28 }, 29 29 test: { 30 30 include: ['test/**.test.{ts,js,tsx}'], 31 + includeSource: ['src/*.ts'], 31 32 // having a snapshot environment doesn't affect browser tests 32 33 snapshotEnvironment: './custom-snapshot-env.ts', 33 34 browser: {
+2 -2
test/browser/vitest.config.unit.mts
··· 8 8 singleFork: true, 9 9 }, 10 10 }, 11 - hookTimeout: process.env.CI ? 120_000 : 10_000, 12 - testTimeout: process.env.CI ? 120_000 : 10_000, 11 + hookTimeout: process.env.CI ? 120_000 : 20_000, 12 + testTimeout: process.env.CI ? 120_000 : 20_000, 13 13 }, 14 14 })
+9 -2
test/browser/specs/runner.test.ts
··· 23 23 console.error(stderr) 24 24 }) 25 25 26 - expect(browserResultJson.testResults).toHaveLength(18) 27 - expect(passedTests).toHaveLength(16) 26 + expect(browserResultJson.testResults).toHaveLength(19) 27 + expect(passedTests).toHaveLength(17) 28 28 expect(failedTests).toHaveLength(2) 29 29 30 30 expect(stderr).not.toContain('has been externalized for browser compatibility') 31 31 expect(stderr).not.toContain('Unhandled Error') 32 + }) 33 + 34 + test('runs in-source tests', () => { 35 + expect(stdout).toContain('src/actions.ts') 36 + const actionsTest = passedTests.find(t => t.name.includes('/actions.ts')) 37 + expect(actionsTest).toBeDefined() 38 + expect(actionsTest.assertionResults).toHaveLength(1) 32 39 }) 33 40 34 41 test('correctly prints error', () => {
+8
test/browser/src/actions.ts
··· 1 1 export function plus(a: number, b: number) { 2 2 return a + b 3 3 } 4 + 5 + if (import.meta.vitest) { 6 + const { test, expect } = import.meta.vitest 7 + 8 + test('in-source plus works correctly', () => { 9 + expect(plus(1, 2)).toBe(3) 10 + }) 11 + }
+22
packages/browser/src/node/plugin.ts
··· 10 10 import { toArray } from '@vitest/utils' 11 11 import { defaultBrowserPort } from 'vitest/config' 12 12 import { dynamicImportPlugin } from '@vitest/mocker/node' 13 + import MagicString from 'magic-string' 13 14 import BrowserContext from './plugins/pluginContext' 14 15 import type { BrowserServer } from './server' 15 16 import { resolveOrchestrator } from './serverOrchestrator' ··· 349 350 } 350 351 }, 351 352 }, 353 + { 354 + name: 'vitest:browser:in-source-tests', 355 + transform(code, id) { 356 + if (!project.isTestFile(id) || !code.includes('import.meta.vitest')) { 357 + return 358 + } 359 + const s = new MagicString(code, { filename: cleanUrl(id) }) 360 + s.prepend( 361 + `import.meta.vitest = __vitest_index__;\n`, 362 + ) 363 + return { 364 + code: s.toString(), 365 + map: s.generateMap({ hires: true }), 366 + } 367 + }, 368 + }, 352 369 // TODO: remove this when @testing-library/vue supports ESM 353 370 { 354 371 name: 'vitest:browser:support-testing-library', ··· 444 461 } 445 462 446 463 return [resolve(root, subdir), `/${basename(root)}/${subdir}/`] 464 + } 465 + 466 + const postfixRE = /[?#].*$/ 467 + function cleanUrl(url: string): string { 468 + return url.replace(postfixRE, '') 447 469 }
+18 -3
packages/browser/src/client/tester/tester.ts
··· 140 140 debug('prepare time', state.durations.prepare, 'ms') 141 141 142 142 try { 143 - await setupCommonEnv(config) 144 - await startCoverageInsideWorker(config.coverage, executor) 143 + await Promise.all([ 144 + setupCommonEnv(config), 145 + startCoverageInsideWorker(config.coverage, executor), 146 + (async () => { 147 + const VitestIndex = await import('vitest') 148 + Object.defineProperty(window, '__vitest_index__', { 149 + value: VitestIndex, 150 + enumerable: false, 151 + }) 152 + })(), 153 + ]) 145 154 146 155 for (const file of files) { 147 156 state.filepath = file ··· 168 177 }, 'Cleanup Error') 169 178 } 170 179 state.environmentTeardownRun = true 171 - await stopCoverageInsideWorker(config.coverage, executor) 180 + await stopCoverageInsideWorker(config.coverage, executor).catch((error) => { 181 + client.rpc.onUnhandledError({ 182 + name: error.name, 183 + message: error.message, 184 + stack: String(error.stack), 185 + }, 'Coverage Error').catch(() => {}) 186 + }) 172 187 173 188 debug('finished running tests') 174 189 done(files)
+1 -1
packages/ui/client/composables/explorer/collector.ts
··· 304 304 file.prepareDuration = f.prepareDuration 305 305 file.environmentLoad = f.environmentLoad 306 306 file.collectDuration = f.collectDuration 307 - file.duration = f.result?.duration 307 + file.duration = f.result?.duration != null ? Math.round(f.result?.duration) : undefined 308 308 file.state = f.result?.state 309 309 } 310 310 time += Math.max(0, f.collectDuration || 0)
+7 -4
packages/ui/client/composables/explorer/utils.ts
··· 69 69 tasks: [], 70 70 typecheck: !!file.meta && 'typecheck' in file.meta, 71 71 indent: 0, 72 - duration: file.result?.duration, 72 + duration: file.result?.duration != null ? Math.round(file.result?.duration) : undefined, 73 73 filepath: file.filepath, 74 74 projectName: file.projectName || '', 75 75 projectNameColor: getProjectNameColor(file.projectName), ··· 132 132 ) { 133 133 const node = explorerTree.nodes.get(parentId) as ParentTreeNode | undefined 134 134 let taskNode: UITaskTreeNode | undefined 135 + const duration = task.result?.duration != null 136 + ? Math.round(task.result?.duration) 137 + : undefined 135 138 if (node) { 136 139 taskNode = explorerTree.nodes.get(task.id) 137 140 if (taskNode) { ··· 141 144 } 142 145 143 146 taskNode.mode = task.mode 144 - taskNode.duration = task.result?.duration 147 + taskNode.duration = duration 145 148 taskNode.state = task.result?.state 146 149 } 147 150 else { ··· 156 159 expandable: false, 157 160 expanded: false, 158 161 indent: node.indent + 1, 159 - duration: task.result?.duration, 162 + duration, 160 163 state: task.result?.state, 161 164 } as TestTreeNode | CustomTestTreeNode 162 165 } ··· 174 177 children: new Set(), 175 178 tasks: [], 176 179 indent: node.indent + 1, 177 - duration: task.result?.duration, 180 + duration, 178 181 state: task.result?.state, 179 182 } as SuiteTreeNode 180 183 }