diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 6ef6d0538d0b..6d5cf0f849ab 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -116,6 +116,8 @@ jobs: - name: Test run: pnpm run test:ci + env: + VITEST_BLOB_LABEL_DOGFOOD: ${{ matrix.os }}-node-${{ matrix.node_version }} - name: Test Examples run: pnpm run test:examples @@ -127,6 +129,17 @@ jobs: path: test/ui/test-results/ retention-days: 30 + - uses: actions/upload-artifact@v7 + if: ${{ !cancelled() }} + with: + name: vitest-blob-${{ matrix.os }}-node-${{ matrix.node_version }} + path: | + README.md + test/core/.vitest-reports + test/cli/.vitest-reports + retention-days: 1 + include-hidden-files: true + test-cached: needs: changed name: 'Cache&Test: node-${{ matrix.node_version }}, ${{ matrix.os }}' @@ -248,3 +261,39 @@ jobs: name: playwright-report-rolldown path: rolldown/test/ui/test-results/ retention-days: 30 + + merge-reports: + needs: test + if: ${{ !cancelled() }} + runs-on: ubuntu-latest + name: Merge Reports + timeout-minutes: 10 + steps: + - uses: actions/checkout@v6 + + - uses: ./.github/actions/setup-and-cache + + - name: Install + run: pnpm i + + - name: Build + run: pnpm run build + + - uses: actions/download-artifact@v4 + with: + pattern: vitest-blob-* + merge-multiple: true + + - name: Merge reports + continue-on-error: true + run: pnpm --filter=./test/core --filter=./test/cli --no-bail --sequential test --merge-reports --reporter=html + + - uses: actions/upload-artifact@v7 + if: ${{ !cancelled() }} + with: + name: vitest-merge-reports + path: | + README.md + test/core/html + test/cli/html + retention-days: 7 diff --git a/docs/guide/cli.md b/docs/guide/cli.md index e1a16c45193b..64b9bc4782b8 100644 --- a/docs/guide/cli.md +++ b/docs/guide/cli.md @@ -225,7 +225,7 @@ You cannot use this option with `--watch` enabled (enabled in dev by default). ::: ::: tip -If `--reporter=blob` is used without an output file, the default path will include the current shard config to avoid collisions with other Vitest processes. +If `--reporter=blob` is used without an output file, the default path will include the current shard config and [label](/guide/reporters#labels) to avoid collisions with other Vitest processes. ::: ### merge-reports diff --git a/docs/guide/improving-performance.md b/docs/guide/improving-performance.md index efbbc804d3ac..85370a22b8a4 100644 --- a/docs/guide/improving-performance.md +++ b/docs/guide/improving-performance.md @@ -144,9 +144,10 @@ on: - main jobs: tests: - runs-on: ubuntu-latest + runs-on: ${{ matrix.os }} strategy: matrix: + os: [ubuntu-latest, macos-latest] shardIndex: [1, 2, 3, 4] shardTotal: [4] steps: @@ -163,12 +164,14 @@ jobs: - name: Run tests run: pnpm run test --reporter=blob --shard=${{ matrix.shardIndex }}/${{ matrix.shardTotal }} + env: + VITEST_BLOB_LABEL: ${{ matrix.os }} - name: Upload blob report to GitHub Actions Artifacts if: ${{ !cancelled() }} uses: actions/upload-artifact@v4 with: - name: blob-report-${{ matrix.shardIndex }} + name: blob-report-${{ matrix.os }}-${{ matrix.shardIndex }} path: .vitest-reports/* include-hidden-files: true retention-days: 1 @@ -177,7 +180,7 @@ jobs: if: ${{ !cancelled() }} uses: actions/upload-artifact@v4 with: - name: blob-attachments-${{ matrix.shardIndex }} + name: blob-attachments-${{ matrix.os }}-${{ matrix.shardIndex }} path: .vitest-attachments/** include-hidden-files: true retention-days: 1 diff --git a/docs/guide/reporters.md b/docs/guide/reporters.md index 95612f070208..f59854fdeb37 100644 --- a/docs/guide/reporters.md +++ b/docs/guide/reporters.md @@ -670,13 +670,18 @@ By default, stores all results in `.vitest-reports` folder, but can be overridde npx vitest --reporter=blob --outputFile=reports/blob-1.json ``` -We recommend using this reporter if you are running Vitest on different machines with the [`--shard`](/guide/cli#shard) flag. -All blob reports can be merged into any report by using `--merge-reports` command at the end of your CI pipeline: +We recommend using this reporter if you are running Vitest on different machines with the [`--shard`](/guide/cli#shard) flag or across multiple environments (e.g., linux/macos/windows). All blob reports can be merged into any report by using `--merge-reports` command at the end of your CI pipeline: ```bash npx vitest --merge-reports=reports --reporter=json --reporter=default ``` +When running the same tests across multiple environments, set the `label` option (or `VITEST_BLOB_LABEL` environment variable) to distinguish each environment's blob. Vitest reads labels at merge time and creates separate project entries automatically (e.g., `myproject [linux]`, `myproject [macos]`). + +```bash +VITEST_BLOB_LABEL=linux vitest run --reporter=blob +``` + Blob reporter output doesn't include file-based [attachments](/api/advanced/artifacts.html#testattachment). Make sure to merge [`attachmentsDir`](/config/attachmentsdir) separately alongside blob reports on CI when using this feature. diff --git a/packages/vitest/src/node/core.ts b/packages/vitest/src/node/core.ts index 60ce250c24bb..4ae72a5b5576 100644 --- a/packages/vitest/src/node/core.ts +++ b/packages/vitest/src/node/core.ts @@ -605,7 +605,7 @@ export class Vitest { throw new Error('Cannot merge reports when `--reporter=blob` is used. Remove blob reporter from the config first.') } - const { files, errors, coverages, executionTimes } = await readBlobs(this.version, directory || this.config.mergeReports, this.projects) + const { files, errors, coverages, executionTimes } = await readBlobs(this, directory || this.config.mergeReports) this.state.blobs = { files, errors, coverages, executionTimes } await this.report('onInit', this) diff --git a/packages/vitest/src/node/project.ts b/packages/vitest/src/node/project.ts index b6f687db692e..b67c5be939d7 100644 --- a/packages/vitest/src/node/project.ts +++ b/packages/vitest/src/node/project.ts @@ -727,7 +727,7 @@ export class TestProject { } /** @internal */ - static _cloneBrowserProject(parent: TestProject, config: ResolvedConfig): TestProject { + static _cloneProject(parent: TestProject, config: ResolvedConfig): TestProject { const clone = new TestProject(parent.vitest, undefined, parent.tmpDir) clone.runner = parent.runner clone._vite = parent._vite diff --git a/packages/vitest/src/node/projects/resolveProjects.ts b/packages/vitest/src/node/projects/resolveProjects.ts index bd69651a5510..103dee52ff1d 100644 --- a/packages/vitest/src/node/projects/resolveProjects.ts +++ b/packages/vitest/src/node/projects/resolveProjects.ts @@ -259,7 +259,7 @@ export async function resolveBrowserProjects( names.add(name) const clonedConfig = cloneConfig(project, config) clonedConfig.name = name - const clone = TestProject._cloneBrowserProject(project, clonedConfig) + const clone = TestProject._cloneProject(project, clonedConfig) resolvedProjects.push(clone) }) diff --git a/packages/vitest/src/node/reporters/blob.ts b/packages/vitest/src/node/reporters/blob.ts index 32dd65948bd7..bd4ebe60f60f 100644 --- a/packages/vitest/src/node/reporters/blob.ts +++ b/packages/vitest/src/node/reporters/blob.ts @@ -7,12 +7,19 @@ import type { Reporter } from '../types/reporter' import type { TestModule } from './reported-tasks' import { existsSync } from 'node:fs' import { mkdir, readdir, readFile, stat, writeFile } from 'node:fs/promises' +import { calculateSuiteHash, generateFileHash } from '@vitest/runner/utils' +import { deepClone } from '@vitest/utils/helpers' import { parse, stringify } from 'flatted' import { dirname, resolve } from 'pathe' import { getOutputFile } from '../../utils/config-helpers' export interface BlobOptions { outputFile?: string + /** + * Label for this environment's blob report (e.g., "linux", "node-22"). + * Can also be set via `VITEST_BLOB_LABEL` environment variable. + */ + label?: string } export class BlobReporter implements Reporter { @@ -46,13 +53,14 @@ export class BlobReporter implements Reporter { const errors = [...unhandledErrors] const coverage = this.coverage + const label = this.options.label ?? process.env.VITEST_BLOB_LABEL + let outputFile = this.options.outputFile ?? getOutputFile(this.ctx.config, 'blob') if (!outputFile) { const shard = this.ctx.config.shard - outputFile = shard - ? `.vitest-reports/blob-${shard.index}-${shard.count}.json` - : '.vitest-reports/blob.json' + const suffix = [label, shard && `${shard.index}-${shard.count}`].filter(Boolean).join('-') + outputFile = suffix ? `.vitest-reports/blob-${suffix}.json` : '.vitest-reports/blob.json' } const environmentModules: MergeReportEnvironmentModules = {} @@ -89,6 +97,7 @@ export class BlobReporter implements Reporter { coverage, executionTime, environmentModules, + label, ] satisfies MergeReport const reportFile = resolve(this.ctx.config.root, outputFile) @@ -110,9 +119,8 @@ export async function writeBlob(content: MergeReport, filename: string): Promise } export async function readBlobs( - currentVersion: string, + ctx: Vitest, blobsDirectory: string, - projectsArray: TestProject[], ): Promise { // using process.cwd() because --merge-reports can only be used in CLI const resolvedDir = resolve(process.cwd(), blobsDirectory) @@ -126,7 +134,7 @@ export async function readBlobs( ) } const content = await readFile(fullPath, 'utf-8') - const [version, files, errors, coverage, executionTime, environmentModules] = parse( + const [version, files, errors, coverage, executionTime, environmentModules, label] = parse( content, ) as MergeReport if (!version) { @@ -134,7 +142,7 @@ export async function readBlobs( `vitest.mergeReports() expects all paths in "${blobsDirectory}" to be files generated by the blob reporter, but "${filename}" is not a valid blob file`, ) } - return { version, files, errors, coverage, file: filename, executionTime, environmentModules } + return { version, label, files, errors, coverage, file: filename, executionTime, environmentModules } }) const blobs = await Promise.all(promises) @@ -151,13 +159,41 @@ export async function readBlobs( ) } - if (!versions.has(currentVersion)) { + if (!versions.has(ctx.version)) { throw new Error( - `the blobs in "${blobsDirectory}" were generated by a different version of Vitest. Expected v${currentVersion}, but received v${blobs[0].version}`, + `the blobs in "${blobsDirectory}" were generated by a different version of Vitest. Expected v${ctx.version}, but received v${blobs[0].version}`, + ) + } + + // Auto-discover labels and duplicate projects if needed + const labels = discoverMergeReportLabels(blobs) + if (labels) { + ctx.projects = resolveMergeReportProjects( + ctx.projects, + labels, ) } + // Rewrite blob data so they get attached to duplicated projects based on labels + for (const blob of blobs) { + const label = blob.label + if (!label) { + continue + } + for (const file of blob.files) { + file.projectName = suffixProjectName(file.projectName, label) + file.id = generateFileHash(file.name, file.projectName) + calculateSuiteHash(file) + } + const rewritten: MergeReportEnvironmentModules = {} + for (const [projectName, modules] of Object.entries(blob.environmentModules)) { + rewritten[suffixProjectName(projectName, label)] = modules + } + blob.environmentModules = rewritten + } + // Restore module graph + const projectsArray = ctx.projects const projects = Object.fromEntries( projectsArray.map(p => [p.name, p]), ) @@ -211,6 +247,58 @@ export async function readBlobs( } } +function suffixProjectName(originalName: string | undefined, label: string): string { + return originalName ? `${originalName} [${label}]` : label +} + +function resolveMergeReportProjects( + projects: TestProject[], + labels: string[], +): TestProject[] { + const names = new Set(projects.map(p => p.name)) + const clonedProjects: TestProject[] = [] + + for (const project of projects) { + for (const label of labels) { + const name = suffixProjectName(project.name || undefined, label) + + if (names.has(name)) { + throw new Error( + `Project name "${name}" is not unique. All projects should have unique names. Make sure your configuration is correct.`, + ) + } + + names.add(name) + const config = deepClone(project.config) + config.name = name + // TODO: importing `import "../project"` breaks some tests + clonedProjects.push((project.constructor as typeof TestProject)._cloneProject(project, config)) + } + } + + return clonedProjects +} + +function discoverMergeReportLabels(blobs: { file: string; label?: string }[]): string[] | undefined { + const labeled = blobs.filter(b => b.label) + + if (!labeled.length) { + return undefined + } + + // TODO: support mix of labeled and unlabeled blobs? + const unlabeled = blobs.filter(b => !b.label) + if (unlabeled.length) { + throw new Error( + `vitest.mergeReports() requires all blob files to have a label when any blob has one. ` + + `Missing label in: ${unlabeled.map(b => `"${b.file}"`).join(', ')}`, + ) + } + + const labels = new Set(labeled.map(b => b.label!)) + return [...labels] +} + export interface MergedBlobs { files: File[] errors: unknown[] @@ -225,6 +313,7 @@ type MergeReport = [ coverage: unknown, executionTime: number, environmentModules: MergeReportEnvironmentModules, + label?: string, ] interface MergeReportEnvironmentModules { diff --git a/test/cli/test/reporters/merge-reports.test.ts b/test/cli/test/reporters/merge-reports.test.ts index 2f445b5c20f9..745df54db036 100644 --- a/test/cli/test/reporters/merge-reports.test.ts +++ b/test/cli/test/reporters/merge-reports.test.ts @@ -1,10 +1,12 @@ +import type { RunVitestConfig } from '#test-utils' import type { File, Test } from '@vitest/runner/types' import type { TestUserConfig, Vitest } from 'vitest/node' import { rmSync } from 'node:fs' import { resolve } from 'node:path' -import { runVitest } from '#test-utils' +import { runVitest, useFS } from '#test-utils' import { playwright } from '@vitest/browser-playwright' import { createFileTask } from '@vitest/runner/utils' +import { globSync } from 'tinyglobby' import { beforeEach, expect, test } from 'vitest' import { version } from 'vitest/package.json' import { writeBlob } from 'vitest/src/node/reporters/blob.js' @@ -481,3 +483,522 @@ function createTest(name: string, file: File): Test { context: {} as any, } } + +test('merge report with labels', async () => { + const baseConfig: RunVitestConfig = { + root: './fixtures/reporters/merge-reports', + } + await runVitest({ + ...baseConfig, + reporters: [['blob', { label: 'linux' }]], + }) + + await runVitest({ + ...baseConfig, + reporters: [['blob', { label: 'macos' }]], + }) + + const result = await runVitest({ + ...baseConfig, + mergeReports: reportsDir, + }) + expect(result.errorTree({ project: true })).toMatchInlineSnapshot(` + { + "linux": { + "first.test.ts": { + "test 1-1": "passed", + "test 1-2": [ + "expected 1 to be 2 // Object.is equality", + ], + }, + "second.test.ts": { + "group": { + "test 2-2": "passed", + "test 2-3": "passed", + }, + "test 2-1": [ + "expected 1 to be 2 // Object.is equality", + ], + }, + }, + "macos": { + "first.test.ts": { + "test 1-1": "passed", + "test 1-2": [ + "expected 1 to be 2 // Object.is equality", + ], + }, + "second.test.ts": { + "group": { + "test 2-2": "passed", + "test 2-3": "passed", + }, + "test 2-1": [ + "expected 1 to be 2 // Object.is equality", + ], + }, + }, + } + `) +}) + +test('merge reports of different results with labels', async () => { + const root = resolve(process.cwd(), `vitest-test-${crypto.randomUUID()}`) + useFS(root, { + 'first.test.ts': ` +test("always good", () => {}) + +test("works on linux", () => { + expect(process.env.TEST_LABEL_ENV === 'linux').toBe(true) +}) + +test("works on macos", () => { + expect(process.env.TEST_LABEL_ENV === 'macos').toBe(true) +}) +`, + 'second.test.ts': ` +test("linux only", () => {}) +`, + 'third.test.ts': ` +test("macos only", () => {}) +`, + }) + process.env.TEST_LABEL_ENV = 'linux' + const result1 = await runVitest({ + root, + globals: true, + reporters: [['blob', { label: 'linux' }]], + }, ['first', 'second']) + expect(result1.stderr).toMatchInlineSnapshot(`""`) + expect(result1.errorTree({ project: true })).toMatchInlineSnapshot(` + { + "": { + "first.test.ts": { + "always good": "passed", + "works on linux": "passed", + "works on macos": [ + "expected false to be true // Object.is equality", + ], + }, + "second.test.ts": { + "linux only": "passed", + }, + }, + } + `) + process.env.TEST_LABEL_ENV = 'macos' + const result2 = await runVitest({ + root, + globals: true, + reporters: [['blob', { label: 'macos' }]], + }, ['first', 'third']) + expect(result2.stderr).toMatchInlineSnapshot(`""`) + expect(result2.errorTree({ project: true })).toMatchInlineSnapshot(` + { + "": { + "first.test.ts": { + "always good": "passed", + "works on linux": [ + "expected false to be true // Object.is equality", + ], + "works on macos": "passed", + }, + "third.test.ts": { + "macos only": "passed", + }, + }, + } + `) + const result = await runVitest({ + root, + mergeReports: resolve(root, '.vitest-reports'), + }) + expect(result.errorTree({ project: true })).toMatchInlineSnapshot(` + { + "linux": { + "first.test.ts": { + "always good": "passed", + "works on linux": "passed", + "works on macos": [ + "expected false to be true // Object.is equality", + ], + }, + "second.test.ts": { + "linux only": "passed", + }, + }, + "macos": { + "first.test.ts": { + "always good": "passed", + "works on linux": [ + "expected false to be true // Object.is equality", + ], + "works on macos": "passed", + }, + "third.test.ts": { + "macos only": "passed", + }, + }, + } + `) +}) + +test('merge report with labels and projects', async () => { + const baseConfig: RunVitestConfig = { + root: './fixtures/reporters/merge-reports', + projects: [ + { + extends: true, + test: { + name: 'first', + include: ['**/first.test.ts'], + }, + }, + { + extends: true, + test: { + name: 'second', + include: ['**/second.test.ts'], + }, + }, + ], + } + await runVitest({ + ...baseConfig, + reporters: [['blob', { label: 'linux' }]], + }) + + await runVitest({ + ...baseConfig, + reporters: [['blob', { label: 'macos' }]], + }) + + const result = await runVitest({ + ...baseConfig, + mergeReports: reportsDir, + }) + expect(globSync('*', { cwd: reportsDir }).sort()).toMatchInlineSnapshot(` + [ + "blob-linux.json", + "blob-macos.json", + ] + `) + expect(result.errorTree({ project: true })).toMatchInlineSnapshot(` + { + "first [linux]": { + "first.test.ts": { + "test 1-1": "passed", + "test 1-2": [ + "expected 1 to be 2 // Object.is equality", + ], + }, + }, + "first [macos]": { + "first.test.ts": { + "test 1-1": "passed", + "test 1-2": [ + "expected 1 to be 2 // Object.is equality", + ], + }, + }, + "second [linux]": { + "second.test.ts": { + "group": { + "test 2-2": "passed", + "test 2-3": "passed", + }, + "test 2-1": [ + "expected 1 to be 2 // Object.is equality", + ], + }, + }, + "second [macos]": { + "second.test.ts": { + "group": { + "test 2-2": "passed", + "test 2-3": "passed", + }, + "test 2-1": [ + "expected 1 to be 2 // Object.is equality", + ], + }, + }, + } + `) +}) + +test('merge report with labels and single browser', async () => { + const baseConfig: RunVitestConfig = { + root: './fixtures/reporters/merge-reports', + browser: { + enabled: true, + provider: playwright(), + instances: [{ browser: 'chromium' }], + headless: true, + }, + } + await runVitest({ + ...baseConfig, + reporters: [['blob', { label: 'linux' }]], + }) + + await runVitest({ + ...baseConfig, + reporters: [['blob', { label: 'macos' }]], + }) + + const result = await runVitest({ + ...baseConfig, + mergeReports: reportsDir, + }) + expect(result.errorTree({ project: true })).toMatchInlineSnapshot(` + { + "chromium [linux]": { + "first.test.ts": { + "test 1-1": "passed", + "test 1-2": [ + "expected 1 to be 2 // Object.is equality", + ], + }, + "second.test.ts": { + "group": { + "test 2-2": "passed", + "test 2-3": "passed", + }, + "test 2-1": [ + "expected 1 to be 2 // Object.is equality", + ], + }, + }, + "chromium [macos]": { + "first.test.ts": { + "test 1-1": "passed", + "test 1-2": [ + "expected 1 to be 2 // Object.is equality", + ], + }, + "second.test.ts": { + "group": { + "test 2-2": "passed", + "test 2-3": "passed", + }, + "test 2-1": [ + "expected 1 to be 2 // Object.is equality", + ], + }, + }, + } + `) +}) + +test('merge report with labels and multiple browsers', async () => { + const baseConfig: RunVitestConfig = { + root: './fixtures/reporters/merge-reports', + browser: { + enabled: true, + provider: playwright(), + instances: [ + { name: 'chrome1', browser: 'chromium' }, + { name: 'chrome2', browser: 'chromium' }, + ], + headless: true, + }, + } + await runVitest({ + ...baseConfig, + reporters: [['blob', { label: 'linux' }]], + }) + + await runVitest({ + ...baseConfig, + reporters: [['blob', { label: 'macos' }]], + }) + + const result = await runVitest({ + ...baseConfig, + mergeReports: reportsDir, + }) + expect(result.errorTree({ project: true })).toMatchInlineSnapshot(` + { + "chrome1 [linux]": { + "first.test.ts": { + "test 1-1": "passed", + "test 1-2": [ + "expected 1 to be 2 // Object.is equality", + ], + }, + "second.test.ts": { + "group": { + "test 2-2": "passed", + "test 2-3": "passed", + }, + "test 2-1": [ + "expected 1 to be 2 // Object.is equality", + ], + }, + }, + "chrome1 [macos]": { + "first.test.ts": { + "test 1-1": "passed", + "test 1-2": [ + "expected 1 to be 2 // Object.is equality", + ], + }, + "second.test.ts": { + "group": { + "test 2-2": "passed", + "test 2-3": "passed", + }, + "test 2-1": [ + "expected 1 to be 2 // Object.is equality", + ], + }, + }, + "chrome2 [linux]": { + "first.test.ts": { + "test 1-1": "passed", + "test 1-2": [ + "expected 1 to be 2 // Object.is equality", + ], + }, + "second.test.ts": { + "group": { + "test 2-2": "passed", + "test 2-3": "passed", + }, + "test 2-1": [ + "expected 1 to be 2 // Object.is equality", + ], + }, + }, + "chrome2 [macos]": { + "first.test.ts": { + "test 1-1": "passed", + "test 1-2": [ + "expected 1 to be 2 // Object.is equality", + ], + }, + "second.test.ts": { + "group": { + "test 2-2": "passed", + "test 2-3": "passed", + }, + "test 2-1": [ + "expected 1 to be 2 // Object.is equality", + ], + }, + }, + } + `) +}) + +test('merge report with labels and multiple browser projects', async () => { + const baseConfig: RunVitestConfig = { + root: './fixtures/reporters/merge-reports', + projects: [ + { + extends: true, + test: { + name: 'first', + include: ['**/first.test.ts'], + browser: { + enabled: true, + provider: playwright(), + instances: [ + { name: 'chrome1', browser: 'chromium' }, + { name: 'chrome2', browser: 'chromium' }, + ], + headless: true, + }, + }, + }, + { + extends: true, + test: { + name: 'second', + include: ['**/second.test.ts'], + browser: { + enabled: true, + provider: playwright(), + instances: [ + { browser: 'chromium' }, + ], + headless: true, + }, + }, + }, + ], + } + await runVitest({ + ...baseConfig, + reporters: [['blob', { label: 'linux' }]], + }) + + await runVitest({ + ...baseConfig, + reporters: [['blob', { label: 'macos' }]], + }) + + const result = await runVitest({ + ...baseConfig, + mergeReports: reportsDir, + }) + expect(result.errorTree({ project: true })).toMatchInlineSnapshot(` + { + "chrome1 [linux]": { + "first.test.ts": { + "test 1-1": "passed", + "test 1-2": [ + "expected 1 to be 2 // Object.is equality", + ], + }, + }, + "chrome1 [macos]": { + "first.test.ts": { + "test 1-1": "passed", + "test 1-2": [ + "expected 1 to be 2 // Object.is equality", + ], + }, + }, + "chrome2 [linux]": { + "first.test.ts": { + "test 1-1": "passed", + "test 1-2": [ + "expected 1 to be 2 // Object.is equality", + ], + }, + }, + "chrome2 [macos]": { + "first.test.ts": { + "test 1-1": "passed", + "test 1-2": [ + "expected 1 to be 2 // Object.is equality", + ], + }, + }, + "second (chromium) [linux]": { + "second.test.ts": { + "group": { + "test 2-2": "passed", + "test 2-3": "passed", + }, + "test 2-1": [ + "expected 1 to be 2 // Object.is equality", + ], + }, + }, + "second (chromium) [macos]": { + "second.test.ts": { + "group": { + "test 2-2": "passed", + "test 2-3": "passed", + }, + "test 2-1": [ + "expected 1 to be 2 // Object.is equality", + ], + }, + }, + } + `) +}) diff --git a/test/cli/test/workers-option.test.ts b/test/cli/test/workers-option.test.ts index 00372a6cd23c..304d433d6fb6 100644 --- a/test/cli/test/workers-option.test.ts +++ b/test/cli/test/workers-option.test.ts @@ -1,28 +1,5 @@ import * as testUtils from '#test-utils' -import { describe, expect, test, vi } from 'vitest' -import { getWorkersCountByPercentage } from 'vitest/src/utils/workers.js' - -vi.mock(import('node:os'), async importOriginal => ({ - ...(await importOriginal()), - default: { - ...(await importOriginal()).default, - availableParallelism: () => 10, - }, -})) - -describe('workers util', () => { - test('percent=50% should return 5', () => { - expect(getWorkersCountByPercentage('50%')).toBe(5) - }) - - test('percent=-10% should return 1', () => { - expect(getWorkersCountByPercentage('-10%')).toBe(1) - }) - - test('percent=110% should return 10', () => { - expect(getWorkersCountByPercentage('110%')).toBe(10) - }) -}) +import { expect, test } from 'vitest' test.each([ { pool: 'threads' }, diff --git a/test/cli/vitest.config.ts b/test/cli/vitest.config.ts index 52442d43a4b2..f312b9fb4a8b 100644 --- a/test/cli/vitest.config.ts +++ b/test/cli/vitest.config.ts @@ -4,7 +4,12 @@ export default defineConfig({ test: { include: ['test/**/**.{test,spec}.ts'], includeTaskLocation: true, - reporters: ['verbose'], + reporters: [ + 'verbose', + ...(process.env.VITEST_BLOB_LABEL_DOGFOOD + ? [['blob', { label: process.env.VITEST_BLOB_LABEL_DOGFOOD }]] as any + : []), + ], testTimeout: 60_000, isolate: false, fileParallelism: false, diff --git a/test/core/test/workers-option.test.ts b/test/core/test/workers-option.test.ts new file mode 100644 index 000000000000..0b95fb1c08d1 --- /dev/null +++ b/test/core/test/workers-option.test.ts @@ -0,0 +1,24 @@ +import { describe, expect, test, vi } from 'vitest' +import { getWorkersCountByPercentage } from 'vitest/src/utils/workers.js' + +vi.mock(import('node:os'), async importOriginal => ({ + ...(await importOriginal()), + default: { + ...(await importOriginal()).default, + availableParallelism: () => 10, + }, +})) + +describe('workers util', () => { + test('percent=50% should return 5', () => { + expect(getWorkersCountByPercentage('50%')).toBe(5) + }) + + test('percent=-10% should return 1', () => { + expect(getWorkersCountByPercentage('-10%')).toBe(1) + }) + + test('percent=110% should return 10', () => { + expect(getWorkersCountByPercentage('110%')).toBe(10) + }) +}) diff --git a/test/core/vite.config.ts b/test/core/vite.config.ts index ab7e3aad425a..2d1184bf2082 100644 --- a/test/core/vite.config.ts +++ b/test/core/vite.config.ts @@ -125,9 +125,14 @@ export default defineConfig({ }, }, includeTaskLocation: true, - reporters: process.env.GITHUB_ACTIONS - ? ['default', ['github-actions', { displayAnnotations: false }]] - : [['default', { summary: true }], 'hanging-process'], + reporters: [ + ...(process.env.GITHUB_ACTIONS + ? [['default'], ['github-actions', { displayAnnotations: false }] as any] + : [['default', { summary: true }], ['hanging-process']]), + ...(process.env.VITEST_BLOB_LABEL_DOGFOOD + ? [['blob', { label: process.env.VITEST_BLOB_LABEL_DOGFOOD }]] + : []), + ], testNamePattern: '^((?!does not include test that).)*$', coverage: { provider: 'istanbul',