mirror of
https://github.com/tiennm99/ccs.git
synced 2026-07-16 10:16:49 +00:00
245 lines
7.7 KiB
TypeScript
245 lines
7.7 KiB
TypeScript
import { afterEach, describe, expect, it } from 'bun:test';
|
|
import { mkdtempSync, mkdirSync, realpathSync, rmSync, symlinkSync, writeFileSync } from 'fs';
|
|
import { tmpdir } from 'os';
|
|
import { join } from 'path';
|
|
import {
|
|
buildPackageManagerEnv,
|
|
detectCurrentInstall,
|
|
formatManualUpdateCommand,
|
|
readInstalledPackageVersion,
|
|
} from '../../../src/utils/package-manager-detector';
|
|
|
|
const tempDirs: string[] = [];
|
|
|
|
function makeTempDir(prefix: string): string {
|
|
const dir = mkdtempSync(join(tmpdir(), prefix));
|
|
tempDirs.push(dir);
|
|
return dir;
|
|
}
|
|
|
|
function writePackage(root: string, version: string): void {
|
|
mkdirSync(root, { recursive: true });
|
|
writeFileSync(
|
|
join(root, 'package.json'),
|
|
JSON.stringify({ name: '@kaitranntt/ccs', version }, null, 2)
|
|
);
|
|
}
|
|
|
|
afterEach(() => {
|
|
while (tempDirs.length > 0) {
|
|
const dir = tempDirs.pop();
|
|
if (dir) {
|
|
rmSync(dir, { recursive: true, force: true });
|
|
}
|
|
}
|
|
});
|
|
|
|
describe('package-manager-detector', () => {
|
|
it('detects npm installs from the current binary path and keeps the custom prefix', () => {
|
|
const tempRoot = makeTempDir('ccs-install-detector-npm-');
|
|
const packageRoot = join(tempRoot, 'prefix', 'lib', 'node_modules', '@kaitranntt', 'ccs');
|
|
const scriptPath = join(packageRoot, 'dist', 'ccs.js');
|
|
|
|
writePackage(packageRoot, '7.67.0-dev.5');
|
|
|
|
const install = detectCurrentInstall(scriptPath);
|
|
|
|
expect(install.manager).toBe('npm');
|
|
expect(install.prefix).toBe(join(tempRoot, 'prefix'));
|
|
expect(install.packageRoot).toBe(packageRoot);
|
|
expect(readInstalledPackageVersion(install)).toBe('7.67.0-dev.5');
|
|
});
|
|
|
|
it('detects bun installs from the resolved package path', () => {
|
|
const tempRoot = makeTempDir('ccs-install-detector-bun-');
|
|
const packageRoot = join(
|
|
tempRoot,
|
|
'.bun',
|
|
'install',
|
|
'global',
|
|
'node_modules',
|
|
'@kaitranntt',
|
|
'ccs'
|
|
);
|
|
const scriptPath = join(packageRoot, 'dist', 'ccs.js');
|
|
|
|
writePackage(packageRoot, '7.67.0-dev.9');
|
|
|
|
const install = detectCurrentInstall(scriptPath);
|
|
|
|
expect(install.manager).toBe('bun');
|
|
expect(install.prefix).toBe(join(tempRoot, '.bun'));
|
|
expect(readInstalledPackageVersion(install)).toBe('7.67.0-dev.9');
|
|
});
|
|
|
|
it.if(process.platform !== 'win32')(
|
|
'detects bun installs from a POSIX symlinked ~/.bun/bin/ccs entrypoint',
|
|
() => {
|
|
const tempRoot = makeTempDir('ccs-install-detector-bun-symlink-');
|
|
const packageRoot = join(
|
|
tempRoot,
|
|
'.bun',
|
|
'install',
|
|
'global',
|
|
'node_modules',
|
|
'@kaitranntt',
|
|
'ccs'
|
|
);
|
|
const scriptPath = join(packageRoot, 'dist', 'ccs.js');
|
|
const symlinkPath = join(tempRoot, 'home', '.bun', 'bin', 'ccs');
|
|
|
|
writePackage(packageRoot, '7.67.0-dev.9');
|
|
mkdirSync(join(packageRoot, 'dist'), { recursive: true });
|
|
writeFileSync(scriptPath, '#!/usr/bin/env node\n');
|
|
mkdirSync(join(tempRoot, 'home', '.bun', 'bin'), { recursive: true });
|
|
symlinkSync(scriptPath, symlinkPath);
|
|
|
|
const install = detectCurrentInstall(symlinkPath);
|
|
const resolvedTempRoot = realpathSync(tempRoot);
|
|
const resolvedScriptPath = realpathSync(scriptPath);
|
|
|
|
expect(install.manager).toBe('bun');
|
|
expect(install.prefix).toBe(join(resolvedTempRoot, '.bun'));
|
|
expect(install.resolvedScriptPath).toBe(resolvedScriptPath);
|
|
expect(readInstalledPackageVersion(install)).toBe('7.67.0-dev.9');
|
|
}
|
|
);
|
|
|
|
it('detects custom bun install roots that still use install/global/node_modules', () => {
|
|
const tempRoot = makeTempDir('ccs-install-detector-custom-bun-');
|
|
const packageRoot = join(
|
|
tempRoot,
|
|
'custom-bun-root',
|
|
'install',
|
|
'global',
|
|
'node_modules',
|
|
'@kaitranntt',
|
|
'ccs'
|
|
);
|
|
|
|
writePackage(packageRoot, '7.67.0-dev.9');
|
|
|
|
const install = detectCurrentInstall(join(packageRoot, 'dist', 'ccs.js'));
|
|
|
|
expect(install.manager).toBe('bun');
|
|
expect(install.prefix).toBe(join(tempRoot, 'custom-bun-root'));
|
|
});
|
|
|
|
it('detects custom yarn global layouts', () => {
|
|
const tempRoot = makeTempDir('ccs-install-detector-custom-yarn-');
|
|
const packageRoot = join(
|
|
tempRoot,
|
|
'custom-yarn-root',
|
|
'global',
|
|
'node_modules',
|
|
'@kaitranntt',
|
|
'ccs'
|
|
);
|
|
|
|
writePackage(packageRoot, '7.67.0-dev.9');
|
|
|
|
const install = detectCurrentInstall(join(packageRoot, 'dist', 'ccs.js'));
|
|
|
|
expect(install.manager).toBe('yarn');
|
|
expect(install.prefix).toBe(join(tempRoot, 'custom-yarn-root'));
|
|
});
|
|
|
|
it('detects custom pnpm global layouts that include a store version segment', () => {
|
|
const tempRoot = makeTempDir('ccs-install-detector-custom-pnpm-');
|
|
const packageRoot = join(
|
|
tempRoot,
|
|
'custom-pnpm-root',
|
|
'global',
|
|
'5',
|
|
'.pnpm',
|
|
'@kaitranntt+ccs@7.67.0-dev.9',
|
|
'node_modules',
|
|
'@kaitranntt',
|
|
'ccs'
|
|
);
|
|
|
|
writePackage(packageRoot, '7.67.0-dev.9');
|
|
|
|
const install = detectCurrentInstall(join(packageRoot, 'dist', 'ccs.js'));
|
|
|
|
expect(install.manager).toBe('pnpm');
|
|
expect(install.prefix).toBe(join(tempRoot, 'custom-pnpm-root'));
|
|
});
|
|
|
|
it('detects pnpm global layouts without a visible .pnpm segment in the script path', () => {
|
|
const tempRoot = makeTempDir('ccs-install-detector-pnpm-global-flat-');
|
|
const packageRoot = join(
|
|
tempRoot,
|
|
'custom-pnpm-root',
|
|
'global',
|
|
'5',
|
|
'node_modules',
|
|
'@kaitranntt',
|
|
'ccs'
|
|
);
|
|
|
|
writePackage(packageRoot, '7.67.0-dev.9');
|
|
|
|
const install = detectCurrentInstall(join(packageRoot, 'dist', 'ccs.js'));
|
|
|
|
expect(install.manager).toBe('pnpm');
|
|
expect(install.prefix).toBe(join(tempRoot, 'custom-pnpm-root'));
|
|
});
|
|
|
|
it('detects Windows npm globals without a lib directory', () => {
|
|
const install = detectCurrentInstall(
|
|
'C:/Program Files/node-prefix/node_modules/@kaitranntt/ccs/dist/ccs.js'
|
|
);
|
|
|
|
expect(install.manager).toBe('npm');
|
|
expect(install.prefix).toBe('C:/Program Files/node-prefix');
|
|
});
|
|
|
|
it('formats manual npm update commands with the current prefix', () => {
|
|
const install = {
|
|
manager: 'npm' as const,
|
|
scriptPath: '/tmp/prefix/bin/ccs',
|
|
resolvedScriptPath: '/tmp/prefix/lib/node_modules/@kaitranntt/ccs/dist/ccs.js',
|
|
packageRoot: '/tmp/prefix/lib/node_modules/@kaitranntt/ccs',
|
|
prefix: '/tmp/prefix',
|
|
detectionSource: 'path' as const,
|
|
};
|
|
|
|
expect(formatManualUpdateCommand('dev', install)).toBe(
|
|
'NPM_CONFIG_PREFIX=/tmp/prefix npm install -g @kaitranntt/ccs@dev'
|
|
);
|
|
});
|
|
|
|
it('formats Windows-safe manual npm update commands for prefixes with spaces', () => {
|
|
const install = {
|
|
manager: 'npm' as const,
|
|
scriptPath: 'C:/Tools/CCS/ccs.cmd',
|
|
resolvedScriptPath: 'C:/Program Files/CCS/lib/node_modules/@kaitranntt/ccs/dist/ccs.js',
|
|
packageRoot: 'C:/Program Files/CCS/lib/node_modules/@kaitranntt/ccs',
|
|
prefix: 'C:/Program Files/CCS',
|
|
detectionSource: 'path' as const,
|
|
};
|
|
|
|
expect(formatManualUpdateCommand('dev', install, 'win32')).toBe(
|
|
`powershell -NoProfile -Command "$env:NPM_CONFIG_PREFIX='C:/Program Files/CCS'; npm install -g @kaitranntt/ccs@dev"`
|
|
);
|
|
});
|
|
|
|
it('builds manager-specific env overrides for the current install', () => {
|
|
const install = {
|
|
manager: 'npm' as const,
|
|
scriptPath: '/tmp/prefix/bin/ccs',
|
|
resolvedScriptPath: '/tmp/prefix/lib/node_modules/@kaitranntt/ccs/dist/ccs.js',
|
|
packageRoot: '/tmp/prefix/lib/node_modules/@kaitranntt/ccs',
|
|
prefix: '/tmp/prefix',
|
|
detectionSource: 'path' as const,
|
|
};
|
|
|
|
const env = buildPackageManagerEnv(install, { PATH: '/usr/bin' });
|
|
|
|
expect(env.PATH).toBe('/usr/bin');
|
|
expect(env.npm_config_prefix).toBe('/tmp/prefix');
|
|
expect(env.NPM_CONFIG_PREFIX).toBe('/tmp/prefix');
|
|
});
|
|
});
|