diff --git a/packages/vitest/src/node/cli-api.ts b/packages/vitest/src/node/cli-api.ts index d68d0306a9ad..c48490577946 100644 --- a/packages/vitest/src/node/cli-api.ts +++ b/packages/vitest/src/node/cli-api.ts @@ -87,8 +87,9 @@ export async function startVitest( return ctx } + let stdinCleanup if (process.stdin.isTTY) - registerConsoleShortcuts(ctx) + stdinCleanup = registerConsoleShortcuts(ctx) ctx.onServerRestart((reason) => { ctx.report('onServerRestart', reason) @@ -115,6 +116,7 @@ export async function startVitest( if (ctx.shouldKeepServer()) return ctx + stdinCleanup?.() await ctx.close() return ctx } diff --git a/packages/vitest/src/node/stdin.ts b/packages/vitest/src/node/stdin.ts index 460d42235ad6..f4b3b82dc8ef 100644 --- a/packages/vitest/src/node/stdin.ts +++ b/packages/vitest/src/node/stdin.ts @@ -140,4 +140,8 @@ export function registerConsoleShortcuts(ctx: Vitest) { } on() + + return function cleanup() { + off() + } } diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml index 1beae6acb30d..9d8e5112d725 100644 --- a/pnpm-lock.yaml +++ b/pnpm-lock.yaml @@ -1809,6 +1809,15 @@ importers: specifier: workspace:* version: link:../../packages/vitest + test/run: + devDependencies: + vite: + specifier: ^4.3.9 + version: 4.3.9(@types/node@18.16.18) + vitest: + specifier: workspace:* + version: link:../../packages/vitest + test/run-once: devDependencies: vitest: diff --git a/test/coverage-test/testing.mjs b/test/coverage-test/testing.mjs index 0678463cbc4b..e3855a6fd733 100644 --- a/test/coverage-test/testing.mjs +++ b/test/coverage-test/testing.mjs @@ -64,6 +64,7 @@ for (const threads of threadsConfig) { exit() } else if (process.exitCode) { + process.exitCode = null console.warn(`Browser tests failed, retrying ${1 + retry}/${retries.length - 1}...`) } else { diff --git a/test/run/fixtures/example.test.ts b/test/run/fixtures/example.test.ts new file mode 100644 index 000000000000..4fd8bd10912c --- /dev/null +++ b/test/run/fixtures/example.test.ts @@ -0,0 +1,7 @@ +import { expect, test } from 'vitest' + +import { getHelloWorld } from './example' + +test('getHello', async () => { + expect(getHelloWorld()).toBe('Hello world') +}) diff --git a/test/run/fixtures/example.ts b/test/run/fixtures/example.ts new file mode 100644 index 000000000000..1c18cd94437c --- /dev/null +++ b/test/run/fixtures/example.ts @@ -0,0 +1,3 @@ +export function getHelloWorld() { + return 'Hello world' +} diff --git a/test/run/fixtures/math.test.ts b/test/run/fixtures/math.test.ts new file mode 100644 index 000000000000..e1994a02ed3d --- /dev/null +++ b/test/run/fixtures/math.test.ts @@ -0,0 +1,7 @@ +import { expect, test } from 'vitest' + +import { sum } from './math' + +test('sum', () => { + expect(sum(1, 2)).toBe(3) +}) diff --git a/test/run/fixtures/math.ts b/test/run/fixtures/math.ts new file mode 100644 index 000000000000..5d8550bb9d4d --- /dev/null +++ b/test/run/fixtures/math.ts @@ -0,0 +1,3 @@ +export function sum(a: number, b: number) { + return a + b +} diff --git a/test/run/fixtures/vitest.config.ts b/test/run/fixtures/vitest.config.ts new file mode 100644 index 000000000000..b23df45d410e --- /dev/null +++ b/test/run/fixtures/vitest.config.ts @@ -0,0 +1,13 @@ +import { defineConfig } from 'vitest/config' + +// Patch stdin on the process so that we can fake it to seem like a real interactive terminal and pass the TTY checks +process.stdin.isTTY = true +process.stdin.setRawMode = () => process.stdin + +export default defineConfig({ + test: { + watch: false, + reporters: 'verbose', + teardownTimeout: 5_000, + }, +}) diff --git a/test/run/package.json b/test/run/package.json new file mode 100644 index 000000000000..5bc48ffdaa9d --- /dev/null +++ b/test/run/package.json @@ -0,0 +1,11 @@ +{ + "name": "@vitest/test-run", + "private": true, + "scripts": { + "test": "vitest" + }, + "devDependencies": { + "vite": "latest", + "vitest": "workspace:*" + } +} diff --git a/test/run/test/tty.test.ts b/test/run/test/tty.test.ts new file mode 100644 index 000000000000..2e283b154070 --- /dev/null +++ b/test/run/test/tty.test.ts @@ -0,0 +1,15 @@ +import { expect, test } from 'vitest' +import { runVitestCli } from '../../test-utils' + +test('run mode does not get stuck when TTY', async () => { + const vitest = await runVitestCli('--root', 'fixtures') + await vitest.isDone + + expect(vitest.stdout).toContain('✓ example.test.ts') + expect(vitest.stdout).toContain('✓ math.test.ts') + expect(vitest.stdout).toContain('2 passed') + + // Regression #3642 + expect(vitest.stderr).not.toContain('close timed out') + expect(vitest.stderr).toBe('') +}) diff --git a/test/run/vitest.config.ts b/test/run/vitest.config.ts new file mode 100644 index 000000000000..8ac03af33561 --- /dev/null +++ b/test/run/vitest.config.ts @@ -0,0 +1,12 @@ +import { defineConfig } from 'vitest/config' + +export default defineConfig({ + test: { + reporters: 'verbose', + include: ['test/**/*.test.*'], + chaiConfig: { + truncateThreshold: 0, + }, + testTimeout: process.env.CI ? 30_000 : 10_000, + }, +})