mirror of
https://github.com/Matysh/houseplan-card
synced 2026-09-29 03:09:36 +00:00
Owner's Windows run after #496 (2338 pass, 2 fail): both remaining failures are tests building the script path as `new URL(...).pathname`, which is `/C:/Users/...` on Windows and makes Node look for `C:\C:\Users\...`. check-inputs and classify-changes CLI tests now use fileURLToPath; the portability test forbids `import.meta.url).pathname` in test/**. Issue: #496 User-Visible: no
63 lines
4.0 KiB
JavaScript
63 lines
4.0 KiB
JavaScript
import test from 'node:test';
|
||
import assert from 'node:assert/strict';
|
||
import { readFileSync, readdirSync } from 'node:fs';
|
||
import { fileURLToPath, pathToFileURL } from 'node:url';
|
||
import { isMainModule, portableCommand } from '../scripts/spawn-portable.mjs';
|
||
|
||
// #496: на машине владельца (Windows) три инфраструктурных теста падали при
|
||
// зелёном Linux CI. Причины — не логика, а переносимость: разбор argv[1] через
|
||
// `file://`, запуск команд через оболочку, CRLF из глобального git config.
|
||
// Здесь закреплены правила, чтобы они не вернулись с очередным скриптом.
|
||
|
||
const SCRIPTS = fileURLToPath(new URL('../scripts/', import.meta.url));
|
||
const scriptSources = () => readdirSync(SCRIPTS)
|
||
.filter((name) => name.endsWith('.mjs'))
|
||
.map((name) => ({ name, text: readFileSync(new URL(name, `file://${SCRIPTS}`), 'utf8') }));
|
||
|
||
test('скрипты не собирают file-URL конкатенацией с argv (#496)', () => {
|
||
const offenders = scriptSources()
|
||
.filter(({ text }) => /new URL\(`file:\/\/\$\{process\.argv/.test(text))
|
||
.map(({ name }) => name);
|
||
assert.deepEqual(offenders, [], 'на Windows это даёт file:///C:/C:/… и CLI молчит; использовать isMainModule');
|
||
});
|
||
|
||
test('скрипты не включают оболочку по платформе — только portableCommand (#496)', () => {
|
||
const offenders = scriptSources()
|
||
.filter(({ name, text }) => name !== 'spawn-portable.mjs' && /shell:\s*process\.platform\s*===\s*'win32'/.test(text))
|
||
.map(({ name }) => name);
|
||
assert.deepEqual(offenders, [], 'оболочка нужна только npm.cmd; node/git через shell теряют кавычки');
|
||
});
|
||
|
||
test('portableCommand: оболочка только для npm/npx/.cmd на Windows (#496)', () => {
|
||
assert.deepEqual(portableCommand('npm', 'win32'), { cmd: 'npm.cmd', shell: true });
|
||
assert.deepEqual(portableCommand('npx', 'win32'), { cmd: 'npx.cmd', shell: true });
|
||
assert.deepEqual(portableCommand('tool.CMD', 'win32'), { cmd: 'tool.CMD', shell: true });
|
||
assert.deepEqual(portableCommand(process.execPath, 'win32'), { cmd: process.execPath, shell: false });
|
||
assert.deepEqual(portableCommand('git', 'win32'), { cmd: 'git', shell: false });
|
||
assert.deepEqual(portableCommand('npm', 'linux'), { cmd: 'npm', shell: false });
|
||
assert.deepEqual(portableCommand('npm', 'darwin'), { cmd: 'npm', shell: false });
|
||
});
|
||
|
||
test('isMainModule сравнивает через pathToFileURL и терпит мусор в argv (#496)', () => {
|
||
const here = fileURLToPath(import.meta.url);
|
||
assert.equal(isMainModule(import.meta.url, here), true);
|
||
assert.equal(isMainModule(pathToFileURL(here).href, here), true);
|
||
assert.equal(isMainModule(import.meta.url, `${here}.other`), false);
|
||
assert.equal(isMainModule(import.meta.url, null), false);
|
||
assert.equal(isMainModule(import.meta.url, ''), false);
|
||
});
|
||
|
||
test('тесты с временным git-репозиторием изолируют переводы строк от глобального конфига (#496)', () => {
|
||
const text = readFileSync(new URL('./rebase-on-dev.test.mjs', import.meta.url), 'utf8');
|
||
assert.match(text, /GIT_CONFIG_KEY_0: 'core\.autocrlf', GIT_CONFIG_VALUE_0: 'false'/);
|
||
});
|
||
|
||
test('тесты не запускают скрипты по URL.pathname — на Windows это /C:/… → C:\\C:\\… (#496)', () => {
|
||
const TESTS = fileURLToPath(new URL('./', import.meta.url));
|
||
const offenders = readdirSync(TESTS)
|
||
.filter((name) => name.endsWith('.test.mjs'))
|
||
.filter((name) => /import\.meta\.url\)\.pathname/.test(readFileSync(new URL(name, `file://${TESTS}`), 'utf8')))
|
||
.filter((name) => name !== 'windows-portability.test.mjs');
|
||
assert.deepEqual(offenders, [], 'путь для execSync/spawn — только через fileURLToPath');
|
||
});
|