diff --git a/packages/vite-node/package.json b/packages/vite-node/package.json index 25e3dc0f0cce..f0f31f22ef74 100644 --- a/packages/vite-node/package.json +++ b/packages/vite-node/package.json @@ -45,7 +45,8 @@ "types": "./dist/source-map.d.ts", "require": "./dist/source-map.cjs", "import": "./dist/source-map.mjs" - } + }, + "./*": "./*" }, "main": "./dist/index.mjs", "module": "./dist/index.mjs", diff --git a/packages/vite-node/src/hmr/emitter.ts b/packages/vite-node/src/hmr/emitter.ts index 1faa87fdedfb..304cfa014ef8 100644 --- a/packages/vite-node/src/hmr/emitter.ts +++ b/packages/vite-node/src/hmr/emitter.ts @@ -37,6 +37,12 @@ export function viteNodeHmrPlugin(): Plugin { _send(payload) emitter.emit('message', payload) } + if (process.env.VITE_NODE_WATCHER_DEBUG) { + server.watcher.on('ready', () => { + // eslint-disable-next-line no-console + console.log('[vie-node] watcher is ready') + }) + } }, } } diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml index 48cf26e137bf..03eaff59afa4 100644 --- a/pnpm-lock.yaml +++ b/pnpm-lock.yaml @@ -1850,6 +1850,9 @@ importers: vite: specifier: ^4.3.9 version: 4.3.9(@types/node@18.16.19) + vite-node: + specifier: workspace:* + version: link:../../packages/vite-node vitest: specifier: workspace:* version: link:../../packages/vitest diff --git a/test/test-utils/index.ts b/test/test-utils/index.ts index 99ab08ece2e9..171a245cd644 100644 --- a/test/test-utils/index.ts +++ b/test/test-utils/index.ts @@ -1,5 +1,6 @@ import { Console } from 'node:console' import { Writable } from 'node:stream' +import fs from 'node:fs' import { type UserConfig, type VitestRunMode, afterEach } from 'vitest' import type { Vitest } from 'vitest/node' import { startVitest } from 'vitest/node' @@ -86,7 +87,7 @@ function captureLogs() { } } -export async function runVitestCli(_options?: Options | string, ...args: string[]) { +export async function runCli(command: string, _options?: Options | string, ...args: string[]) { let options = _options if (typeof _options === 'string') { @@ -94,7 +95,7 @@ export async function runVitestCli(_options?: Options | string, ...args: string[ options = undefined } - const subprocess = execa('vitest', args, options as Options) + const subprocess = execa(command, args, options as Options) let setDone: (value?: unknown) => void const isDone = new Promise(resolve => (setDone = resolve)) @@ -115,7 +116,7 @@ export async function runVitestCli(_options?: Options | string, ...args: string[ return resolve() const timeout = setTimeout(() => { - reject(new Error(`Timeout when waiting for output "${expected}".\nReceived:\n${this.stdout}. \nStderr:\n${this.stderr}`)) + reject(new Error(`Timeout when waiting for output "${expected}".\nReceived:\n${this.stdout} \nStderr:\n${this.stderr}`)) }, process.env.CI ? 20_000 : 4_000) const listener = () => { @@ -136,7 +137,7 @@ export async function runVitestCli(_options?: Options | string, ...args: string[ return resolve() const timeout = setTimeout(() => { - reject(new Error(`Timeout when waiting for error "${expected}".\nReceived:\n${this.stderr}`)) + reject(new Error(`Timeout when waiting for error "${expected}".\nReceived:\n${this.stderr}\nStdout:\n${this.stdout}`)) }, process.env.CI ? 20_000 : 4_000) const listener = () => { @@ -177,6 +178,14 @@ export async function runVitestCli(_options?: Options | string, ...args: string[ await vitest.isDone }) + if (command !== 'vitest') { + if (!args.includes('--watch')) + await vitest.isDone + else + await vitest.waitForStdout('[vie-node] watcher is ready') + return vitest + } + if (args.includes('--watch')) { // Wait for initial test run to complete await vitest.waitForStdout('Waiting for file changes') vitest.resetOutput() @@ -187,3 +196,26 @@ export async function runVitestCli(_options?: Options | string, ...args: string[ return vitest } + +export async function runVitestCli(_options?: Options | string, ...args: string[]) { + return runCli('vitest', _options, ...args) +} + +export async function runViteNodeCli(_options?: Options | string, ...args: string[]) { + process.env.VITE_NODE_WATCHER_DEBUG = 'true' + return runCli('vite-node', _options, ...args) +} + +const originalFiles = new Map() +afterEach(() => { + originalFiles.forEach((content, file) => { + fs.writeFileSync(file, content, 'utf-8') + }) +}) + +export function editFile(file: string, callback: (content: string) => string) { + const content = fs.readFileSync(file, 'utf-8') + if (!originalFiles.has(file)) + originalFiles.set(file, content) + fs.writeFileSync(file, callback(content), 'utf-8') +} diff --git a/test/test-utils/package.json b/test/test-utils/package.json index a9b39f620758..8005128685c5 100644 --- a/test/test-utils/package.json +++ b/test/test-utils/package.json @@ -8,6 +8,7 @@ "execa": "^7.1.1", "strip-ansi": "^7.0.1", "vite": "latest", + "vite-node": "workspace:*", "vitest": "workspace:*" } } diff --git a/test/vite-node/src/watched.js b/test/vite-node/src/watched.js new file mode 100644 index 000000000000..54046b60bfa1 --- /dev/null +++ b/test/vite-node/src/watched.js @@ -0,0 +1,2 @@ +// eslint-disable-next-line no-console +console.log('test 1') diff --git a/test/vite-node/test/circular.test.ts b/test/vite-node/test/circular.test.ts index 297c7dd93cda..e17152ff00bf 100644 --- a/test/vite-node/test/circular.test.ts +++ b/test/vite-node/test/circular.test.ts @@ -1,17 +1,15 @@ import { expect, test } from 'vitest' -import { execa } from 'execa' import { resolve } from 'pathe' - -const cliPath = resolve(__dirname, '../../../packages/vite-node/src/cli.ts') +import { runViteNodeCli } from '../../test-utils' test('circular 1', async () => { const entryPath = resolve(__dirname, '../src/circular1/index.ts') - const result = await execa('npx', ['esno', cliPath, entryPath], { reject: true }) - expect(result.stdout).toMatchInlineSnapshot('"A Bindex index"') + const cli = await runViteNodeCli(entryPath) + expect(cli.stdout).toContain('A Bindex index') }, 60_000) test('circular 2', async () => { const entryPath = resolve(__dirname, '../src/circular2/index.ts') - const result = await execa('npx', ['esno', cliPath, entryPath], { reject: true }) - expect(result.stdout).toMatchInlineSnapshot('"ac b"') + const cli = await runViteNodeCli(entryPath) + expect(cli.stdout).toContain('ac b') }, 60_000) diff --git a/test/vite-node/test/cli.test.ts b/test/vite-node/test/cli.test.ts index 600a316cf971..08625c318794 100644 --- a/test/vite-node/test/cli.test.ts +++ b/test/vite-node/test/cli.test.ts @@ -1,38 +1,48 @@ -import { execa } from 'execa' import { resolve } from 'pathe' +import pkg from 'vite-node/package.json' import { expect, it } from 'vitest' +import { editFile, runViteNodeCli } from '../../test-utils' -const cliPath = resolve(__dirname, '../../../packages/vite-node/src/cli.ts') const entryPath = resolve(__dirname, '../src/cli-parse-args.js') +const version = (pkg as any).version + const parseResult = (s: string) => JSON.parse(s.replaceAll('\'', '"')) it('basic', async () => { - const result = await execa('npx', ['esno', cliPath, entryPath], { reject: true }) - expect(result.stdout).include('node') - expect(parseResult(result.stdout)).length(2) -}, 60_000) + const cli = await runViteNodeCli(entryPath) + expect(cli.stdout).toContain('node') + expect(parseResult(cli.stdout)).toHaveLength(2) +}) it('--help', async () => { - const r1 = await execa('npx', ['esno', cliPath, '--help', entryPath], { reject: true }) - expect(r1.stdout).include('help') - const r2 = await execa('npx', ['esno', cliPath, '-h', entryPath], { reject: true }) - expect(r2.stdout).include('help') -}, 60_000) + const cli1 = await runViteNodeCli('--help', entryPath) + expect(cli1.stdout).toContain('Usage:') + const cli2 = await runViteNodeCli('-h', entryPath) + expect(cli2.stdout).toContain('Usage:') +}) it('--version', async () => { - const r1 = await execa('npx', ['esno', cliPath, '--version', entryPath], { reject: true }) - expect(r1.stdout).include('vite-node/') - const r2 = await execa('npx', ['esno', cliPath, '-v', entryPath], { reject: true }) - expect(r2.stdout).include('vite-node/') -}, 60_000) + const cli1 = await runViteNodeCli('--version', entryPath) + expect(cli1.stdout).toContain(`vite-node/${version}`) + const cli2 = await runViteNodeCli('-v', entryPath) + expect(cli2.stdout).toContain(`vite-node/${version}`) +}) it('script args', async () => { - const r1 = await execa('npx', ['esno', cliPath, entryPath, '--version', '--help'], { reject: true }) - expect(parseResult(r1.stdout)).include('--version').include('--help') -}, 60_000) + const cli1 = await runViteNodeCli(entryPath, '--version', '--help') + expect(parseResult(cli1.stdout)).include('--version').include('--help') +}) it('script args in -- after', async () => { - const r1 = await execa('npx', ['esno', cliPath, entryPath, '--', '--version', '--help'], { reject: true }) - expect(parseResult(r1.stdout)).include('--version').include('--help') -}, 60_000) + const cli1 = await runViteNodeCli(entryPath, '--', '--version', '--help') + expect(parseResult(cli1.stdout)).include('--version').include('--help') +}) + +it('correctly runs --watch', async () => { + const entryPath = resolve(__dirname, '../src/watched.js') + const cli = await runViteNodeCli('--watch', entryPath) + await cli.waitForStdout('test 1') + editFile(entryPath, c => c.replace('test 1', 'test 2')) + await cli.waitForStdout('test 2') +}) diff --git a/test/vite-node/test/self-export.test.ts b/test/vite-node/test/self-export.test.ts index 53cfc47dfff4..e4b7cc51dd62 100644 --- a/test/vite-node/test/self-export.test.ts +++ b/test/vite-node/test/self-export.test.ts @@ -1,7 +1,7 @@ import { expect, it } from 'vitest' -import { execa } from 'execa' import { resolve } from 'pathe' import ansiEscapes, { HelloWorld } from '../src/self-export' +import { runViteNodeCli } from '../../test-utils' it('should export self', () => { expect(ansiEscapes.HelloWorld).eq(HelloWorld) @@ -9,16 +9,14 @@ it('should export self', () => { expect(HelloWorld).eq(1) }) -const cliPath = resolve(__dirname, '../../../packages/vite-node/src/cli.ts') - it('example 1', async () => { const entryPath = resolve(__dirname, '../src/self-export-example1.ts') - const result = await execa('npx', ['esno', cliPath, entryPath], { reject: true }) - expect(result.stdout).includes('Function') + const cli = await runViteNodeCli(entryPath) + await cli.waitForStdout('Function') }, 60_000) it('example 2', async () => { const entryPath = resolve(__dirname, '../src/self-export-example2.ts') - const result = await execa('npx', ['esno', cliPath, entryPath], { reject: true }) - expect(result.stdout).includes('HelloWorld: 1').includes('default') + const cli = await runViteNodeCli(entryPath) + await cli.waitForStdout('HelloWorld: 1') }, 60_000)