[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(ui): fix module graph in browser mode with --ui (#10386)

authored by

Hiroshi Ogawa and committed by
GitHub
(May 19, 2026, 11:40 AM +0200) 3003c432 6d772c80

+57 -16
+1 -1
test/ui/playwright.config.ts
··· 6 6 { 7 7 name: 'chromium', 8 8 // increase viewport height so virtual scroller renders all explorer items 9 - use: { ...devices['Desktop Chrome'], viewport: { width: 1280, height: 900 } }, 9 + use: { ...devices['Desktop Chrome'], viewport: { width: 800, height: 1300 } }, 10 10 }, 11 11 ], 12 12 use: {
-1
packages/ui/node/reporter.ts
··· 201 201 ctx, 202 202 projectName, 203 203 testModule.moduleId, 204 - project.config.browser.enabled, 205 204 ) 206 205 })()) 207 206 }
+44 -5
test/ui/test/ui.spec.ts
··· 53 53 await testFilter(page, { mode: 'ui' }) 54 54 }) 55 55 56 + test('filter reveals initially invisible explorer item', async ({ page }) => { 57 + await page.setViewportSize({ width: 1000, height: 500 }) 58 + await page.goto(pageUrl) 59 + await testFilterInitiallyInvisibleItem(page) 60 + }) 61 + 56 62 test('tags filter', async ({ page }) => { 57 63 await page.goto(pageUrl) 58 64 await testTagsFilter(page) ··· 86 92 test('can execute', async ({ page }) => { 87 93 await page.goto(pageUrl) 88 94 await testExecute(page, { mode: 'ui' }) 95 + }) 96 + 97 + test('module graph', async ({ page }) => { 98 + await page.goto(pageUrl) 99 + await testModuleGraph(page) 89 100 }) 90 101 }) 91 102 ··· 175 186 await page.goto(pageUrl) 176 187 await testExecute(page, { mode: 'static' }) 177 188 }) 189 + 190 + test('module graph', async ({ page }) => { 191 + await page.goto(pageUrl) 192 + await testModuleGraph(page) 193 + }) 178 194 }) 195 + 196 + const TEST_COUNTS = { 197 + pass: 18, 198 + fail: 3, 199 + files: { 200 + pass: 7, 201 + }, 202 + } 179 203 180 204 async function testBasic(page: Page, pageUrl: string) { 181 205 const pageErrors: unknown[] = [] ··· 184 208 await page.goto(pageUrl) 185 209 186 210 // dashboard 187 - await assertTestCounts(page, { pass: 17, fail: 3 }) 211 + await assertTestCounts(page, { pass: TEST_COUNTS.pass, fail: TEST_COUNTS.fail }) 188 212 189 213 // unhandled errors 190 214 await expect(page.getByTestId('unhandled-errors')).toContainText( ··· 208 232 await expect(page.getByTestId('console')).toContainText('log test') 209 233 210 234 expect(pageErrors).toEqual([]) 235 + } 236 + 237 + async function testModuleGraph(page: Page) { 238 + await openExplorerFileItem(page, 'sample.test.ts') 239 + await page.getByTestId('btn-graph').click() 240 + await expect(page.locator('[data-testid=graph] text')).toBeVisible() 241 + await expect(page.locator('[data-testid=graph] text')).toHaveText('sample.test.ts') 242 + 243 + await openExplorerFileItem(page, 'sample-browser.test.ts') 244 + await page.getByTestId('btn-graph').click() 245 + await expect(page.locator('[data-testid=graph] text')).toBeVisible() 246 + await expect(page.locator('[data-testid=graph] text')).toHaveText('sample-browser.test.ts') 211 247 } 212 248 213 249 async function testCoverage(page: Page) { ··· 414 450 async function testFilter(page: Page, options: { mode: 'ui' | 'static' }) { 415 451 // match all files when no filter 416 452 await page.getByPlaceholder('Search...').fill('') 417 - await page.getByText('PASS (6)').click() 453 + await page.getByText(`PASS (${TEST_COUNTS.files.pass})`).click() 418 454 await expect(page.getByTestId('results-panel').getByText('sample.test.ts', { exact: true })).toBeVisible() 419 455 420 456 // match nothing ··· 464 500 await testItem.getByLabel('Run current test').click() 465 501 await expect(page.getByText('The test has passed without any errors')).toBeVisible() 466 502 } 503 + } 504 + 505 + async function testFilterInitiallyInvisibleItem(page: Page) { 506 + await expect(getExplorerItem(page, 'sample.test.ts')).not.toBeVisible() 507 + await page.getByPlaceholder('Search...').fill('sample.test.ts') 508 + await expect(getExplorerItem(page, 'sample.test.ts')).toBeVisible() 467 509 } 468 510 469 511 async function testCrossOriginAccess(page: Page, pageUrl: string) { ··· 527 569 await item.hover() 528 570 await expect(item.getByTestId('btn-run-test')).toBeEnabled() 529 571 530 - await page.getByPlaceholder('Search...').fill('snapshot') 531 572 const snapshotItem = getExplorerItem(page, 'snapshot.test.ts') 532 573 await snapshotItem.hover() 533 574 await expect(snapshotItem.getByTestId('btn-fix-snapshot')).toBeVisible() ··· 539 580 await item.hover() 540 581 await expect(item.getByTestId('btn-run-test')).toBeDisabled() 541 582 542 - await page.getByPlaceholder('Search...').fill('snapshot') 543 583 const snapshotItem = getExplorerItem(page, 'snapshot.test.ts') 544 584 await snapshotItem.hover() 545 585 await expect(snapshotItem.getByTestId('btn-fix-snapshot')).not.toBeVisible() ··· 551 591 await item.hover() 552 592 await expect(item.getByTestId('btn-run-test')).not.toBeVisible() 553 593 554 - await page.getByPlaceholder('Search...').fill('snapshot') 555 594 const snapshotItem = getExplorerItem(page, 'snapshot.test.ts') 556 595 await snapshotItem.hover() 557 596 await expect(snapshotItem.getByTestId('btn-fix-snapshot')).not.toBeVisible()
-1
packages/ui/client/components/FileDetails.vue
··· 113 113 let moduleGraph = await client.rpc.getModuleGraph( 114 114 gd.projectName, 115 115 gd.filepath, 116 - !!browserState, 117 116 ) 118 117 // remove node_modules from the graph when enabled 119 118 if (hideNodeModules.value) {
+2 -2
packages/ui/client/components/ModuleTransformResultView.vue
··· 6 6 import { Tooltip as VueTooltip } from 'floating-vue' 7 7 import { join, relative } from 'pathe' 8 8 import { computed } from 'vue' 9 - import { browserState, client, config } from '~/composables/client' 9 + import { client, config } from '~/composables/client' 10 10 import { currentModule } from '~/composables/navigation' 11 11 import { formatPreciseTime, formatTime, getDurationClass, getImportDurationType } from '~/utils/task' 12 12 import Badge from './Badge.vue' ··· 31 31 return undefined 32 32 } 33 33 if (props.type === 'inline') { 34 - return client.rpc.getTransformResult(props.projectName, props.id, currentModule.value.id, !!browserState) 34 + return client.rpc.getTransformResult(props.projectName, props.id, currentModule.value.id) 35 35 } 36 36 if (props.type === 'external') { 37 37 return client.rpc.getExternalResult(props.id, currentModule.value.id)
+4 -3
packages/vitest/src/api/setup.ts
··· 122 122 123 123 return result 124 124 }, 125 - async getTransformResult(projectName: string, moduleId, testFileTaskId, browser = false) { 125 + async getTransformResult(projectName: string, moduleId, testFileTaskId) { 126 126 const project = ctx.getProjectByName(projectName) 127 127 const testModule = ctx.state.getReportedEntityById(testFileTaskId) as TestModule | undefined 128 128 if (!testModule || !isFileServingAllowed(project.vite.config, moduleId)) { 129 129 return 130 130 } 131 131 132 + const browser = !!project.config.browser.enabled 132 133 const environment = getTestFileEnvironment(project, testModule.moduleId, browser) 133 134 134 135 const moduleNode = environment?.moduleGraph.getModuleById(moduleId) ··· 155 156 catch {} 156 157 return result 157 158 }, 158 - async getModuleGraph(project, id, browser): Promise<ModuleGraphData> { 159 - return getModuleGraph(ctx, project, id, browser) 159 + async getModuleGraph(project, id): Promise<ModuleGraphData> { 160 + return getModuleGraph(ctx, project, id) 160 161 }, 161 162 async updateSnapshot(file?: File) { 162 163 // silently ignore exec/write attempts if not allowed
-2
packages/vitest/src/api/types.ts
··· 47 47 getModuleGraph: ( 48 48 projectName: string, 49 49 id: string, 50 - browser?: boolean, 51 50 ) => Promise<ModuleGraphData> 52 51 getTransformResult: ( 53 52 projectName: string, 54 53 id: string, 55 54 testFileId: string, 56 - browser?: boolean, 57 55 ) => Promise<TransformResultWithSource | undefined> 58 56 getExternalResult: ( 59 57 id: string,
+1 -1
packages/vitest/src/utils/graph.ts
··· 7 7 ctx: Vitest, 8 8 projectName: string, 9 9 testFilePath: string, 10 - browser = false, 11 10 ): Promise<ModuleGraphData> { 12 11 const graph: Record<string, string[]> = {} 13 12 const externalized = new Set<string>() 14 13 const inlined = new Set<string>() 15 14 16 15 const project = ctx.getProjectByName(projectName) 16 + const browser = project.config.browser.enabled 17 17 18 18 const environment = project.config.experimental.viteModuleRunner === false 19 19 ? project.vite.environments.__vitest__
+5
test/ui/fixtures/main/browser/sample-browser.test.ts
··· 1 + import { expect, test } from 'vitest' 2 + 3 + test('window', () => { 4 + expect(typeof window).toBe('object') 5 + })