// Проверяемо на Linux: стенд запускает инструменты так, что под Windows не нужен // .cmd-обёрточный файл (spawn без shell падает на них с ENOENT). import { existsSync, readFileSync } from 'node:fs'; import path from 'node:path'; import { describe, expect, it } from 'vitest'; import { baseEnv, nodeTool, nodeWithTsx, repoRoot } from '../../../scripts/test/node-commands.mjs'; const forbidden = /\.cmd\b|[\\/]\.bin[\\/]|^npx$|^npm$/i; describe('[HARNESS-WIN] запуск инструментов без .cmd-обёрток', () => { it.each(['tsx', 'vitest', 'prettier'] as const)('%s: process.execPath + JS-файл', (tool) => { const command = nodeTool(tool, ['--version']); expect(command.command).toBe(process.execPath); const entry = command.args[0]!; expect(entry).not.toMatch(forbidden); expect(entry).toMatch(/\.(mjs|cjs|js)$/); expect(path.isAbsolute(entry)).toBe(true); expect(existsSync(entry)).toBe(true); }); it('сервер: один процесс node с загрузчиком tsx', () => { const command = nodeWithTsx(['src/server.ts']); expect(command.command).toBe(process.execPath); expect(command.args[0]).toBe('--import'); expect(command.args[1]).toMatch(/^file:\/\/.*\.mjs$/); expect(command.args.join(' ')).not.toMatch(forbidden); expect(command.args.at(-1)).toBe('src/server.ts'); }); it('под win32 дочерний процесс получает SystemRoot/TEMP, а секреты не наследуются', () => { const env = baseEnv('win32', { PATH: 'C:\\Windows', SystemRoot: 'C:\\Windows', TEMP: 'C:\\Temp', DATABASE_URL: 'secret-must-not-leak', }); expect(env).toMatchObject({ PATH: 'C:\\Windows', SystemRoot: 'C:\\Windows', TEMP: 'C:\\Temp' }); expect(env).not.toHaveProperty('DATABASE_URL'); expect(baseEnv('linux', { PATH: '/bin', SystemRoot: 'x' })).toEqual({ PATH: '/bin' }); }); it.each([ 'scripts/test/run-e2e.mjs', 'scripts/test/n13-race.mjs', 'tests/e2e/harness/global-setup.ts', ])('%s не вызывает npx и node_modules/.bin', (file) => { const source = readFileSync(path.join(repoRoot, file), 'utf8'); expect(source).not.toMatch(/spawn(Sync)?\(\s*['"`]npx/); expect(source).not.toMatch(/node_modules\/\.bin/); }); });