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
2 changes: 1 addition & 1 deletion docs/guide/learn/writing-tests.md
Original file line number Diff line number Diff line change
Expand Up @@ -176,7 +176,7 @@ test.for([
})
```

The placeholders `%i`, `%s`, and `%f` in the test name are replaced with the corresponding values from each row, so the output shows `add(1, 1) -> 2`, `add(1, 2) -> 3`, and so on.
In the example above, the %i placeholders are replaced with the integer values from each data row. Vitest also supports other placeholder types, such as %s for strings and %f for floating-point numbers. As a result, the test runner generates test names such as add(1, 1) -> 2, add(1, 2) -> 3, and add(2, 1) -> 3.

If your cases have more than two or three values, passing objects is more readable. Use `$property` in the name to interpolate fields:

Expand Down
4 changes: 2 additions & 2 deletions packages/ui/node/index.ts
Original file line number Diff line number Diff line change
@@ -1,13 +1,13 @@
import type { Vite, Vitest } from 'vitest/node'
import fs from 'node:fs'
import { fileURLToPath } from 'node:url'
import { join, resolve } from 'pathe'
import sirv from 'sirv'
import c from 'tinyrainbow'
import { isFileServingAllowed, isValidApiRequest } from 'vitest/node'
import { version } from '../package.json'
import { distClientRoot } from './paths'

export const distClientRoot: string = resolve(fileURLToPath(import.meta.url), '../client')
export { distClientRoot }

export default (ctx: Vitest): Vite.Plugin => {
if (ctx.version !== version) {
Expand Down
4 changes: 4 additions & 0 deletions packages/ui/node/paths.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
import { fileURLToPath } from 'node:url'
import { resolve } from 'pathe'

export const distClientRoot: string = resolve(fileURLToPath(import.meta.url), '../client')
60 changes: 20 additions & 40 deletions packages/ui/node/reporter.ts
Original file line number Diff line number Diff line change
@@ -1,23 +1,20 @@
import type { TestAttachment } from '@vitest/runner'
import type { SerializedError } from 'vitest'
import type { HTMLOptions, Reporter, RunnerTask, RunnerTestFile, TestModule, Vitest } from 'vitest/node'
import type { HTMLOptions, Reporter, ResolvedConfig, RunnerTask, RunnerTestFile, TestModule, Vitest } from 'vitest/node'
import type { HTMLReportMetadata } from '../client/composables/client/static'
import { existsSync, promises as fs, readFileSync } from 'node:fs'
import { fileURLToPath } from 'node:url'
import { promisify } from 'node:util'
import { gzip, constants as zlibConstants } from 'node:zlib'
import { stringify } from 'flatted'
import { dirname, relative, resolve } from 'pathe'
import { globSync } from 'tinyglobby'
import c from 'tinyrainbow'
import { getModuleGraph } from '../../vitest/src/utils/graph'
import { distClientRoot } from './paths'

interface PotentialConfig {
outputFile?: string | Partial<Record<string, string>>
}
const gzipAsync = promisify(gzip)

function getOutputFile(config: PotentialConfig | undefined) {
if (!config?.outputFile) {
function getOutputFile(config: ResolvedConfig) {
if (!config.outputFile) {
return
}

Expand All @@ -28,32 +25,24 @@ function getOutputFile(config: PotentialConfig | undefined) {
return config.outputFile.html
}

const distDir = resolve(fileURLToPath(import.meta.url), '../../dist')

export default class HTMLReporter implements Reporter {
start = 0
ctx!: Vitest
options: HTMLOptions

private reporterDir!: string
private htmlFilePath!: string

constructor(options: HTMLOptions) {
this.options = options
}

async onInit(ctx: Vitest): Promise<void> {
this.ctx = ctx
this.start = Date.now()
const htmlFile
= this.options.outputFile
|| getOutputFile(this.ctx.config)
|| 'html/index.html'
const htmlFilePath = resolve(this.ctx.config.root, htmlFile)
this.reporterDir = dirname(htmlFilePath)
this.htmlFilePath = htmlFilePath

await fs.mkdir(resolve(this.reporterDir, 'assets'), { recursive: true })
}

async onTestRunEnd(
Expand All @@ -69,29 +58,20 @@ export default class HTMLReporter implements Reporter {
await inlineAttachments(result.files)
}

const report = stringify(result)
const promiseGzip = promisify(gzip)
const data = await promiseGzip(report, {
// copy ui assets
await fs.cp(distClientRoot, this.reporterDir, { recursive: true })

// create index.html and metadata
const rawData = stringify(result)
const data = await gzipAsync(rawData, {
level: zlibConstants.Z_BEST_COMPRESSION,
})
const ui = resolve(distDir, 'client')
// copy ui
const files = globSync(['**/*'], { cwd: ui, expandDirectories: false })
await Promise.all(
files.map(async (f) => {
if (f === 'index.html') {
await handleIndexHtml({
srcDir: ui,
dstDir: this.reporterDir,
data,
singleFile: this.options.singleFile,
})
}
else {
await fs.copyFile(resolve(ui, f), resolve(this.reporterDir, f))
}
}),
)
await handleIndexHtml({
srcDir: distClientRoot,
dstDir: this.reporterDir,
data,
singleFile: this.options.singleFile,
})

// copy attachments
// TODO: unify attachmentsDir and html outputFile, so both live together without extra copy
Expand Down Expand Up @@ -220,12 +200,12 @@ async function handleIndexHtml(options: {

if (options.singleFile) {
html = await inlineHtmlAssets(indexHtmlFilePath, html)
const base64 = Buffer.from(options.data).toString('base64')
const base64 = options.data.toString('base64')
metadataCode = `Promise.resolve((${uint8ArrayFromBase64.toString()})("${base64}"))`
}
else {
const dataFile = `html.meta.json.gz`
await fs.writeFile(resolve(options.dstDir, dataFile), options.data, 'base64')
const dataFile = 'html.meta.json.gz'
await fs.writeFile(resolve(options.dstDir, dataFile), options.data)
metadataCode = `fetch(new URL("./${dataFile}", window.location.href)).then(async res => new Uint8Array(await res.arrayBuffer()))`
}

Expand Down
Loading