Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
6 changes: 4 additions & 2 deletions docs/config/attachmentsdir.md
Original file line number Diff line number Diff line change
Expand Up @@ -3,9 +3,11 @@ title: attachmentsDir | Config
outline: deep
---

# attachmentsDir
# attachmentsDir <CRoot />

- **Type:** `string`
- **Default:** `'.vitest/attachments'`

Directory path for storing attachments created by [`context.annotate`](/guide/test-context#annotate) relative to the project root.
Directory path for storing file attachments created by [`context.annotate`](/guide/test-context#annotate).

This option is resolved relative to the root Vitest config. When using [`projects`](/guide/projects), all projects share the same `attachmentsDir`; it cannot be configured per project.
1 change: 1 addition & 0 deletions docs/guide/projects.md
Original file line number Diff line number Diff line change
Expand Up @@ -289,6 +289,7 @@ Some of the configuration options are not allowed in a project config. Most nota
- `coverage`: coverage is done for the whole process
- `reporters`: only root-level reporters can be supported
- `resolveSnapshotPath`: only root-level resolver is respected
- `attachmentsDir`: attachments are stored in one root-level directory shared by all projects
- all other options that don't affect test runners

All configuration options that are not supported inside a project configuration are marked with a <CRoot /> icon next to their name. They can only be defined once in the root config file.
Expand Down
1 change: 1 addition & 0 deletions eslint.config.js
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,7 @@ export default antfu(
'**/assets/**',
'**/*.d.ts',
'**/*.timestamp-*',
'**/test-results',
'test/unit/src/self',
'test/unit/test/mocking/already-hoisted.test.ts',
'test/cache/cache/.vitest-base/results.json',
Expand Down
1 change: 1 addition & 0 deletions packages/ui/.gitignore
Original file line number Diff line number Diff line change
@@ -1 +1,2 @@
__screenshots__
html/
17 changes: 16 additions & 1 deletion packages/ui/CONTRIBUTING.md
Original file line number Diff line number Diff line change
Expand Up @@ -38,7 +38,7 @@ Use this setup for developing Browser Mode UI features with Vite HMR. It serves
Start a browser-mode Vitest server:

```bash
pnpm -C packages/ui test:ui --browser.headless --ui --open=false
pnpm -C packages/ui test:ui --ui --open=false
```

Start the UI dev server in browser preview mode:
Expand All @@ -54,3 +54,18 @@ The UI dev server fetches browser runner state from the browser runner server on
```bash
BROWSER_DEV_PORT=63316 BROWSER_DEV=true pnpm -C packages/ui dev:client
```

## HTML report

Use this setup for developing static HTML report UI with Vite HMR.

```bash
HTML_REPORT_DIR=<path-to-html-report-dir> pnpm -C packages/ui dev:client
```

For example,

```bash
pnpm -C packages/ui test:ui --reporter=html --run
HTML_REPORT_DIR="$PWD/packages/ui/html" pnpm -C packages/ui dev:client
```
7 changes: 4 additions & 3 deletions packages/ui/client/test.ts
Original file line number Diff line number Diff line change
@@ -1,15 +1,16 @@
import type { ComponentRenderOptions, RenderResult } from 'vitest-browser-vue'
import { vTooltip } from 'floating-vue'
import { vi } from 'vitest'
import {
render as _render,
} from 'vitest-browser-vue'

export { page } from 'vitest/browser'

export function render<C>(
export const render = vi.defineHelper(<C>(
component: C,
options?: ComponentRenderOptions<C, any>,
): PromiseLike<RenderResult<any>> {
): PromiseLike<RenderResult<any>> => {
return _render(component, {
...options,
global: {
Expand All @@ -18,4 +19,4 @@ export function render<C>(
},
},
})
}
})
48 changes: 34 additions & 14 deletions packages/ui/vite.config.ts
Original file line number Diff line number Diff line change
@@ -1,15 +1,12 @@
import type { Plugin } from 'vite'
import fs from 'node:fs'
import path from 'node:path'
import Vue from '@vitejs/plugin-vue'
import { resolve } from 'pathe'
import { presetAttributify, presetIcons, presetWind3, transformerDirectives } from 'unocss'
import Unocss from 'unocss/vite'
import { defineConfig } from 'vite'

// for debug:
// open a static file serve to share the report json
// and ui using the link to load the report json data
// const debugLink = 'http://127.0.0.1:4173/__vitest__'

export default defineConfig({
base: './',
resolve: {
Expand Down Expand Up @@ -41,15 +38,9 @@ export default defineConfig({
],
safelist: 'absolute origin-top mt-[8px]'.split(' '),
}),
devUiScriptPlugin(),
// uncomment to see the HTML reporter preview
// {
// name: 'debug-html-report',
// apply: 'serve',
// transformIndexHtml(html) {
// return html.replace('<!-- !LOAD_METADATA! -->', `<script>window.METADATA_PATH="${debugLink}/html.meta.json.gz"</script>`)
// },
// },
process.env.HTML_REPORT_DIR
? devHtmlReportPlugin({ htmlDir: process.env.HTML_REPORT_DIR })
: devUiScriptPlugin(),
{
// workaround `crossorigin` issues on some browsers
// https://github.com/vitejs/vite/issues/6648
Expand Down Expand Up @@ -119,3 +110,32 @@ function devUiScriptPlugin(): Plugin {
},
}
}

function devHtmlReportPlugin({ htmlDir }: { htmlDir: string }): Plugin {
const REPORT_FILE = 'html.meta.json.gz'
return {
name: 'dev-html-report',
apply(_config, env) {
return !!htmlDir && env.command === 'serve' && env.mode !== 'test'
},
async transformIndexHtml() {
return [
{
tag: 'script',
children: `window.METADATA_PATH="${REPORT_FILE}"`,
},
]
},
configureServer(server) {
server.middlewares.use(async (req, res, next) => {
const url = new URL(req.url || '', `http://localhost`)
if (url.pathname === `/${REPORT_FILE}`) {
const data = fs.readFileSync(path.join(htmlDir, REPORT_FILE))
res.end(data)
return
}
next()
})
},
}
}
1 change: 1 addition & 0 deletions packages/ui/vitest.config.ts
Original file line number Diff line number Diff line change
Expand Up @@ -29,6 +29,7 @@ const testConfig = defineConfig({
browser: {
enabled: true,
traceView: true,
headless: true,
provider:
providerName === 'preview'
? preview()
Expand Down
2 changes: 2 additions & 0 deletions packages/vitest/src/node/project.ts
Original file line number Diff line number Diff line change
Expand Up @@ -550,7 +550,9 @@ export class TestProject {
this.vitest,
{
...options,
// root-only configs
coverage: this.vitest.config.coverage,
attachmentsDir: this.vitest.config.attachmentsDir,
},
server.config,
)
Expand Down
51 changes: 51 additions & 0 deletions test/e2e/test/annotations.test.ts
Original file line number Diff line number Diff line change
@@ -1,5 +1,7 @@
import type { TestArtifact } from '@vitest/runner'
import type { TestAnnotation } from 'vitest'
import { readdirSync } from 'node:fs'
import path from 'node:path'
import { playwright } from '@vitest/browser-playwright'
import { describe, expect, test } from 'vitest'
import { runInlineTests } from '../../test-utils'
Expand Down Expand Up @@ -665,3 +667,52 @@ describe('reporters', () => {
})
})
})

test('attachmentsDir is root only', async () => {
const result = await runInlineTests(
{
'packages/client/basic.test.ts': `
import { test } from 'vitest'
test("hello", ({ annotate }) => {
annotate("hello annotation", { path: "./hello.txt" })
})
`,
'packages/client/hello.txt': `HELLO`,
'packages/server/basic.test.ts': `
import { test } from 'vitest'
test("world", ({ annotate }) => {
annotate("world annotation", { path: "./world.txt" })
})
`,
'packages/server/world.txt': `WORLD`,
},
{
projects: ['./packages/*'],
},
)
expect(result.stderr).toMatchInlineSnapshot(`""`)
expect(result.errorTree({ project: true })).toMatchInlineSnapshot(`
{
"client": {
"basic.test.ts": {
"hello": "passed",
},
},
"server": {
"basic.test.ts": {
"world": "passed",
},
},
}
`)
const files = readdirSync(path.join(result.root, '.vitest/attachments'))
const contents = files.sort().map(file =>
result.fs.readFile(path.join('.vitest/attachments', file)),
)
expect(contents).toMatchInlineSnapshot(`
[
"HELLO",
"WORLD",
]
`)
})
10 changes: 7 additions & 3 deletions test/e2e/test/reporters/junit.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -163,13 +163,17 @@ test.each([true, false])('addFileAttribute %s', async (t) => {
})

test('many errors without warning', async () => {
const { stderr } = await runVitestCli(
const result = await runVitestCli(
'run',
'--reporter=junit',
'--root',
resolve(import.meta.dirname, '../fixtures/reporters/many-errors'),
resolve(import.meta.dirname, '../../fixtures/reporters/many-errors'),
)
expect(stderr).not.toContain('MaxListenersExceededWarning')
expect(stabilizeReport(result.stdout).split('\n')[1]).toMatchInlineSnapshot(
`"<testsuites name="vitest tests" tests="20" failures="20" errors="0" time="...">"`,
)
expect(result.stderr).not.toContain('MaxListenersExceededWarning')
expect(result.exitCode).not.toBe(0)
})

test('CLI reporter option preserves config file options', async () => {
Expand Down
7 changes: 4 additions & 3 deletions test/ui/README.md
Original file line number Diff line number Diff line change
@@ -1,10 +1,11 @@
# test/ui

```sh
# run e2e
# run e2e on playwright
pnpm test
pnpm test --ui

# run fixture projects
pnpm test-fixtures --ui
pnpm test-fixtures --root fixtures-trace
pnpm test-fixtures --root fixtures/main --ui
pnpm test-fixtures --root fixtures/trace
```
16 changes: 0 additions & 16 deletions test/ui/fixtures-browser/visual-regression.test.ts

This file was deleted.

10 changes: 10 additions & 0 deletions test/ui/fixtures/main/browser/visual-regression.test.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
import { test } from 'vitest'
import { server } from 'vitest/browser'

test('visual regression test', async ({ expect }) => {
// reset screenshots to ensure consistent assertion results with new screenshot
await (server.commands as any).rm(`__screenshots__`)
await expect(expect(document.body).toMatchScreenshot()).rejects.toThrow(
'No existing reference screenshot found',
)
})
Original file line number Diff line number Diff line change
Expand Up @@ -11,13 +11,13 @@ test('annotated typed test', async ({ annotate }) => {

test('annotated file test', async ({ annotate }) => {
await annotate('file annotation', {
path: './fixtures/example.txt'
path: './example.txt'
})
})

test('annotated image test', async ({ annotate }) => {
await annotate('image annotation', {
path: './fixtures/cute-puppy.jpg'
path: './cute-puppy.jpg'
})
})

Expand Down
File renamed without changes.
File renamed without changes.
49 changes: 49 additions & 0 deletions test/ui/fixtures/main/vitest.config.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,49 @@
import path, { resolve } from "node:path";
import { playwright } from "@vitest/browser-playwright";
import { defineConfig } from "vitest/config";
import type { BrowserCommand } from "vitest/node";
import fs from "node:fs"

const rmCommand: BrowserCommand<[filepath: string]> = async (ctx, filePath) => {
const resolved = resolve(ctx.project.config.root, filePath)
fs.rmSync(resolved, { recursive: true, force: true })
}

export default defineConfig({
test: {
coverage: {
reportOnFailure: true,
},
tags: [{ name: "db" }, { name: "flaky" }],
projects: [
{
extends: true,
test: {
name: "node",
root: path.join(import.meta.dirname, "node"),
// TODO: https://github.com/vitest-dev/vitest/issues/10326
attachmentsDir: path.join(import.meta.dirname, ".vitest/attachments"),
environment: "happy-dom",
},
},
{
extends: true,
test: {
name: "browser",
root: path.join(import.meta.dirname, "browser"),
attachmentsDir: path.join(import.meta.dirname, ".vitest/attachments"),
browser: {
enabled: true,
headless: true,
provider: playwright(),
instances: [{ browser: "chromium" }],
screenshotFailures: false,
commands: {
rm: rmCommand,
}
},
},
},
],
},
});
4 changes: 1 addition & 3 deletions test/ui/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -3,9 +3,7 @@
"type": "module",
"private": true,
"scripts": {
"test": "GITHUB_ACTIONS=false playwright test",
"test-e2e": "GITHUB_ACTIONS=false playwright test",
"test-e2e-ui": "GITHUB_ACTIONS=false playwright test --ui",
"test": "playwright test",
"test-fixtures": "vitest"
},
"devDependencies": {
Expand Down
Loading
Loading