mirror of
https://github.com/affaan-m/everything-claude-code.git
synced 2026-05-18 23:03:06 +08:00
fix(installer): harden locale docs install
This commit is contained in:
172
tests/lib/locale-install.test.js
Normal file
172
tests/lib/locale-install.test.js
Normal file
@@ -0,0 +1,172 @@
|
||||
/**
|
||||
* Tests for --locale translated docs installs.
|
||||
*/
|
||||
|
||||
const assert = require('assert');
|
||||
const fs = require('fs');
|
||||
const os = require('os');
|
||||
const path = require('path');
|
||||
const { execFileSync } = require('child_process');
|
||||
|
||||
const {
|
||||
listInstallComponents,
|
||||
resolveInstallPlan,
|
||||
} = require('../../scripts/lib/install-manifests');
|
||||
|
||||
function normalizePlanPath(value) {
|
||||
return String(value || '').replace(/\\/g, '/');
|
||||
}
|
||||
|
||||
function runInstallApply(args, options = {}) {
|
||||
const scriptPath = path.join(__dirname, '..', '..', 'scripts', 'install-apply.js');
|
||||
return execFileSync('node', [scriptPath, ...args], {
|
||||
cwd: options.cwd || process.cwd(),
|
||||
env: { ...process.env, ...(options.env || {}) },
|
||||
encoding: 'utf8',
|
||||
maxBuffer: 16 * 1024 * 1024,
|
||||
stdio: ['pipe', 'pipe', 'pipe'],
|
||||
});
|
||||
}
|
||||
|
||||
function test(name, fn) {
|
||||
try {
|
||||
fn();
|
||||
console.log(` \u2713 ${name}`);
|
||||
return true;
|
||||
} catch (error) {
|
||||
console.log(` \u2717 ${name}`);
|
||||
console.log(` Error: ${error.message}`);
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
function runTests() {
|
||||
console.log('\n=== Testing --locale translated docs installs ===\n');
|
||||
|
||||
let passed = 0;
|
||||
let failed = 0;
|
||||
|
||||
if (test('component catalog includes locale entries', () => {
|
||||
const components = listInstallComponents({ family: 'locale' });
|
||||
assert.ok(components.some(component => component.id === 'locale:ja'));
|
||||
assert.ok(components.some(component => component.id === 'locale:zh-cn'));
|
||||
assert.ok(components.every(component => component.family === 'locale'));
|
||||
})) passed++; else failed++;
|
||||
|
||||
if (test('locale component resolves to the translated docs module', () => {
|
||||
const homeDir = fs.mkdtempSync(path.join(os.tmpdir(), 'locale-plan-'));
|
||||
try {
|
||||
const plan = resolveInstallPlan({
|
||||
includeComponentIds: ['locale:ja'],
|
||||
target: 'claude',
|
||||
homeDir,
|
||||
});
|
||||
|
||||
assert.deepStrictEqual(plan.selectedModuleIds, ['docs-ja-jp']);
|
||||
assert.ok(
|
||||
plan.operations.some(operation => (
|
||||
normalizePlanPath(operation.sourceRelativePath) === 'docs/ja-JP'
|
||||
&& normalizePlanPath(operation.destinationPath).endsWith('/.claude/docs/ja-JP')
|
||||
)),
|
||||
'Should map docs/ja-JP to ~/.claude/docs/ja-JP'
|
||||
);
|
||||
} finally {
|
||||
fs.rmSync(homeDir, { recursive: true, force: true });
|
||||
}
|
||||
})) passed++; else failed++;
|
||||
|
||||
if (test('end-to-end: --locale ja dry-run includes docs-ja-jp operations', () => {
|
||||
const homeDir = fs.mkdtempSync(path.join(os.tmpdir(), 'locale-dry-run-'));
|
||||
const projectDir = fs.mkdtempSync(path.join(os.tmpdir(), 'locale-dry-run-project-'));
|
||||
|
||||
try {
|
||||
const output = runInstallApply([
|
||||
'--locale', 'ja',
|
||||
'--dry-run',
|
||||
'--json',
|
||||
], {
|
||||
cwd: projectDir,
|
||||
env: { HOME: homeDir },
|
||||
});
|
||||
const json = JSON.parse(output);
|
||||
|
||||
assert.strictEqual(json.plan.mode, 'manifest');
|
||||
assert.deepStrictEqual(json.plan.includedComponentIds, ['locale:ja']);
|
||||
assert.deepStrictEqual(json.plan.selectedModuleIds, ['docs-ja-jp']);
|
||||
assert.ok(
|
||||
json.plan.operations.some(operation => (
|
||||
normalizePlanPath(operation.sourceRelativePath) === 'docs/ja-JP/README.md'
|
||||
&& normalizePlanPath(operation.destinationPath).endsWith('/.claude/docs/ja-JP/README.md')
|
||||
)),
|
||||
'Should copy translated README into ~/.claude/docs/ja-JP'
|
||||
);
|
||||
} finally {
|
||||
fs.rmSync(homeDir, { recursive: true, force: true });
|
||||
fs.rmSync(projectDir, { recursive: true, force: true });
|
||||
}
|
||||
})) passed++; else failed++;
|
||||
|
||||
if (test('end-to-end: legacy language plus --locale keeps legacy install and docs', () => {
|
||||
const homeDir = fs.mkdtempSync(path.join(os.tmpdir(), 'locale-legacy-dry-run-'));
|
||||
const projectDir = fs.mkdtempSync(path.join(os.tmpdir(), 'locale-legacy-dry-run-project-'));
|
||||
|
||||
try {
|
||||
const output = runInstallApply([
|
||||
'typescript',
|
||||
'--locale', 'ja',
|
||||
'--dry-run',
|
||||
'--json',
|
||||
], {
|
||||
cwd: projectDir,
|
||||
env: { HOME: homeDir },
|
||||
});
|
||||
const json = JSON.parse(output);
|
||||
|
||||
assert.strictEqual(json.plan.mode, 'legacy-compat');
|
||||
assert.deepStrictEqual(json.plan.legacyLanguages, ['typescript']);
|
||||
assert.ok(json.plan.includedComponentIds.includes('locale:ja'));
|
||||
assert.ok(json.plan.selectedModuleIds.includes('framework-language'));
|
||||
assert.ok(json.plan.selectedModuleIds.includes('docs-ja-jp'));
|
||||
} finally {
|
||||
fs.rmSync(homeDir, { recursive: true, force: true });
|
||||
fs.rmSync(projectDir, { recursive: true, force: true });
|
||||
}
|
||||
})) passed++; else failed++;
|
||||
|
||||
if (test('end-to-end: --locale ja installs translated docs side-by-side', () => {
|
||||
const homeDir = fs.mkdtempSync(path.join(os.tmpdir(), 'locale-install-'));
|
||||
const projectDir = fs.mkdtempSync(path.join(os.tmpdir(), 'locale-install-project-'));
|
||||
|
||||
try {
|
||||
runInstallApply([
|
||||
'--locale', 'ja',
|
||||
], {
|
||||
cwd: projectDir,
|
||||
env: { HOME: homeDir },
|
||||
});
|
||||
|
||||
const claudeRoot = path.join(homeDir, '.claude');
|
||||
assert.ok(
|
||||
fs.existsSync(path.join(claudeRoot, 'docs', 'ja-JP', 'README.md')),
|
||||
'Should install Japanese README under docs/ja-JP'
|
||||
);
|
||||
assert.ok(
|
||||
!fs.existsSync(path.join(claudeRoot, 'skills', 'ecc', 'configure-ecc', 'SKILL.md')),
|
||||
'Locale-only install should not install English skills'
|
||||
);
|
||||
|
||||
const statePath = path.join(claudeRoot, 'ecc', 'install-state.json');
|
||||
const state = JSON.parse(fs.readFileSync(statePath, 'utf8'));
|
||||
assert.deepStrictEqual(state.request.includeComponents, ['locale:ja']);
|
||||
assert.deepStrictEqual(state.resolution.selectedModules, ['docs-ja-jp']);
|
||||
} finally {
|
||||
fs.rmSync(homeDir, { recursive: true, force: true });
|
||||
fs.rmSync(projectDir, { recursive: true, force: true });
|
||||
}
|
||||
})) passed++; else failed++;
|
||||
|
||||
console.log(`\nResults: Passed: ${passed}, Failed: ${failed}`);
|
||||
process.exit(failed > 0 ? 1 : 0);
|
||||
}
|
||||
|
||||
runTests();
|
||||
Reference in New Issue
Block a user