[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): process artifact attachments when generating HTML reporter (#9472)

authored by

Raul Macarie and committed by
GitHub
(Jan 19, 2026, 11:10 AM +0100) 96eb9282 9027af33

+97 -5
+3
pnpm-lock.yaml
··· 1540 1540 '@testing-library/dom': 1541 1541 specifier: ^10.4.1 1542 1542 version: 10.4.1 1543 + '@vitest/browser-playwright': 1544 + specifier: workspace:* 1545 + version: link:../../packages/browser-playwright 1543 1546 happy-dom: 1544 1547 specifier: latest 1545 1548 version: 20.1.0
+1
test/ui/package.json
··· 10 10 }, 11 11 "devDependencies": { 12 12 "@testing-library/dom": "^10.4.1", 13 + "@vitest/browser-playwright": "workspace:*", 13 14 "happy-dom": "latest", 14 15 "vitest": "workspace:*" 15 16 }
+28 -2
test/ui/vitest.config.ts
··· 1 + import { resolve } from 'node:path' 2 + import { playwright } from '@vitest/browser-playwright' 1 3 import { defineConfig } from 'vitest/config' 2 4 3 5 export default defineConfig({ 4 6 test: { 5 - dir: './fixtures', 6 - environment: 'happy-dom', 7 7 coverage: { 8 8 reportOnFailure: true, 9 9 }, 10 + projects: [{ 11 + extends: true, 12 + test: { 13 + name: 'fixtures', 14 + dir: './fixtures', 15 + environment: 'happy-dom', 16 + }, 17 + }, { 18 + extends: true, 19 + test: { 20 + name: 'browser', 21 + dir: './fixtures-browser', 22 + browser: { 23 + enabled: true, 24 + headless: true, 25 + provider: playwright(), 26 + instances: [{ browser: 'chromium' }], 27 + screenshotFailures: false, 28 + expect: { 29 + toMatchScreenshot: { 30 + resolveScreenshotPath: ({ root, testFileDirectory, arg, ext }) => resolve(root, testFileDirectory, `${arg}${ext}`), 31 + }, 32 + }, 33 + }, 34 + }, 35 + }], 10 36 }, 11 37 })
+8
packages/ui/node/reporter.ts
··· 90 90 promises.push(this.processAttachment(attachment)) 91 91 } 92 92 }) 93 + task.artifacts.forEach((artifact) => { 94 + const attachments = artifact.attachments 95 + if (attachments) { 96 + attachments.forEach((attachment) => { 97 + promises.push(this.processAttachment(attachment)) 98 + }) 99 + } 100 + }) 93 101 } 94 102 else { 95 103 task.tasks.forEach(processAttachments)
+16
test/ui/fixtures-browser/visual-regression.test.ts
··· 1 + import { test } from 'vitest' 2 + import { server } from 'vitest/browser' 3 + 4 + test('visual regression test', async ({ expect, onTestFinished }) => { 5 + const screenshotName = 'visual-regression-screenshot.png' 6 + 7 + onTestFinished(async () => { 8 + if (server.config.snapshotOptions.updateSnapshot !== 'none') { 9 + await server.commands.removeFile(`fixtures-browser/${screenshotName}`) 10 + } 11 + }) 12 + 13 + await expect(expect(document.body).toMatchScreenshot(screenshotName)).rejects.toThrowError( 14 + 'No existing reference screenshot found', 15 + ) 16 + })
+20 -1
test/ui/test/html-report.spec.ts
··· 66 66 await page.goto(pageUrl) 67 67 68 68 // dashboard 69 - await expect(page.locator('[aria-labelledby=tests]')).toContainText('13 Pass 1 Fail 14 Total') 69 + await expect(page.locator('[aria-labelledby=tests]')).toContainText('14 Pass 1 Fail 15 Total') 70 70 71 71 // unhandled errors 72 72 await expect(page.getByTestId('unhandled-errors')).toContainText( ··· 189 189 190 190 await expect(annotations.last().getByRole('link')).toHaveAttribute('href', /data\/\w+/) 191 191 await expect(annotations.nth(3).getByRole('link')).toHaveAttribute('href', /data\/\w+/) 192 + }) 193 + 194 + test('visual regression in the report tab', async ({ page }) => { 195 + await page.goto(pageUrl) 196 + 197 + await test.step('attachments get processed', async () => { 198 + const item = page.getByLabel('visual regression test') 199 + await item.click({ force: true }) 200 + await page.getByTestId('btn-report').click({ force: true }) 201 + 202 + const artifact = page.getByRole('note') 203 + await expect(artifact).toHaveCount(1) 204 + 205 + await expect(artifact.getByRole('heading')).toContainText('Visual Regression') 206 + await expect(artifact).toContainText('fixtures-browser/visual-regression.test.ts:13:3') 207 + await expect(artifact.getByRole('tablist')).toHaveText('Reference') 208 + await expect(artifact.getByRole('tabpanel').getByRole('link')).toHaveAttribute('href', /data\/\w+\.png/) 209 + await expect(artifact.getByRole('tabpanel').getByRole('img')).toHaveAttribute('src', /data\/\w+\.png/) 210 + }) 192 211 }) 193 212 })
+21 -2
test/ui/test/ui.spec.ts
··· 70 70 await page.goto(pageUrl) 71 71 72 72 // dashboard 73 - await expect(page.locator('[aria-labelledby=tests]')).toContainText('13 Pass 1 Fail 14 Total') 73 + await expect(page.locator('[aria-labelledby=tests]')).toContainText('14 Pass 1 Fail 15 Total') 74 74 75 75 // unhandled errors 76 76 await expect(page.getByTestId('unhandled-errors')).toContainText( ··· 212 212 213 213 // match all files when no filter 214 214 await page.getByPlaceholder('Search...').fill('') 215 - await page.getByText('PASS (5)').click() 215 + await page.getByText('PASS (6)').click() 216 216 await expect(page.getByTestId('details-panel').getByText('fixtures/sample.test.ts', { exact: true })).toBeVisible() 217 217 218 218 // match nothing ··· 288 288 await expect(page.getByLabel(/pass/i)).not.toBeChecked() 289 289 await expect(page.getByLabel(/fail/i)).not.toBeChecked() 290 290 await expect(page.getByLabel(/skip/i)).not.toBeChecked() 291 + }) 292 + 293 + test('visual regression in the report tab', async ({ page }) => { 294 + await page.goto(pageUrl) 295 + 296 + await test.step('attachments get processed', async () => { 297 + const item = page.getByLabel('visual regression test') 298 + await item.click({ force: true }) 299 + await page.getByTestId('btn-report').click({ force: true }) 300 + 301 + const artifact = page.getByRole('note') 302 + await expect(artifact).toHaveCount(1) 303 + 304 + await expect(artifact.getByRole('heading')).toContainText('Visual Regression') 305 + await expect(artifact).toContainText('fixtures-browser/visual-regression.test.ts:13:3') 306 + await expect(artifact.getByRole('tablist')).toHaveText('Reference') 307 + await expect(artifact.getByRole('tabpanel').getByRole('link')).toHaveAttribute('href', /__vitest_attachment__\?path=.*?\.png/) 308 + await expect(artifact.getByRole('tabpanel').getByRole('img')).toHaveAttribute('src', /__vitest_attachment__\?path=.*?\.png/) 309 + }) 291 310 }) 292 311 }) 293 312