From 629990580106648a7cd853ab47d88c642c6142c8 Mon Sep 17 00:00:00 2001 From: Vladyslav Tezyk Date: Wed, 12 Aug 2026 11:21:22 +0200 Subject: [PATCH] test(locale): cover uk-UA aliases, module lookup, and a clean install - locale-install.test.js: verify locale:uk-ua resolves to docs-uk-ua, the uk alias dry-run resolves the same plan, and a real (non-dry-run) --locale uk-UA install lands files under docs/uk-UA - install-manifests.test.js: assert every SUPPORTED_LOCALES alias resolves to a real component whose modules exist on disk, guarding against orphaned locale: entries like the one this PR fixes --- tests/lib/install-manifests.test.js | 24 ++++++++ tests/lib/locale-install.test.js | 86 +++++++++++++++++++++++++++++ 2 files changed, 110 insertions(+) diff --git a/tests/lib/install-manifests.test.js b/tests/lib/install-manifests.test.js index 481f0d092..0bfc2a946 100644 --- a/tests/lib/install-manifests.test.js +++ b/tests/lib/install-manifests.test.js @@ -14,9 +14,11 @@ const { listLegacyCompatibilityLanguages, listInstallModules, listInstallProfiles, + listSupportedLocales, resolveInstallPlan, resolveLegacyCompatibilitySelection, validateInstallModuleIds, + LOCALE_ALIAS_TO_COMPONENT_ID, } = require('../../scripts/lib/install-manifests'); function test(name, fn) { @@ -106,6 +108,28 @@ function runTests() { 'Should include skill:mle-workflow'); })) passed++; else failed++; + if (test('every locale alias resolves to a real component with a real module', () => { + const manifests = loadInstallManifests(); + + for (const locale of listSupportedLocales()) { + const componentId = LOCALE_ALIAS_TO_COMPONENT_ID[locale]; + assert.ok(componentId, `Locale ${locale} should have an alias mapping`); + + const component = getInstallComponent(componentId); + assert.strictEqual(component.family, 'locale', `${componentId} should be in the locale family`); + assert.ok(component.moduleIds.length > 0, `${componentId} should reference at least one module`); + + for (const moduleId of component.moduleIds) { + const module = manifests.modulesById.get(moduleId); + assert.ok(module, `${componentId} module ${moduleId} should exist in install-modules.json`); + assert.ok( + module.paths.every(modulePath => fs.existsSync(path.join(manifests.repoRoot, modulePath))), + `${moduleId} paths should exist on disk` + ); + } + } + })) passed++; else failed++; + if (test('gets install component details and validates component IDs', () => { const component = getInstallComponent(' lang:typescript '); diff --git a/tests/lib/locale-install.test.js b/tests/lib/locale-install.test.js index 0df64f4e1..ceb3b489b 100644 --- a/tests/lib/locale-install.test.js +++ b/tests/lib/locale-install.test.js @@ -51,9 +51,32 @@ function runTests() { assert.ok(components.some(component => component.id === 'locale:ja')); assert.ok(components.some(component => component.id === 'locale:zh-cn')); assert.ok(components.some(component => component.id === 'locale:de-de')); + assert.ok(components.some(component => component.id === 'locale:uk-ua')); assert.ok(components.every(component => component.family === 'locale')); })) passed++; else failed++; + if (test('locale:uk-ua resolves to the Ukrainian translated docs module', () => { + const homeDir = fs.mkdtempSync(path.join(os.tmpdir(), 'locale-plan-uk-')); + try { + const plan = resolveInstallPlan({ + includeComponentIds: ['locale:uk-ua'], + target: 'claude', + homeDir, + }); + + assert.deepStrictEqual(plan.selectedModuleIds, ['docs-uk-ua']); + assert.ok( + plan.operations.some(operation => ( + normalizePlanPath(operation.sourceRelativePath) === 'docs/uk-UA' + && normalizePlanPath(operation.destinationPath).endsWith('/.claude/docs/uk-UA') + )), + 'Should map docs/uk-UA to ~/.claude/docs/uk-UA' + ); + } finally { + fs.rmSync(homeDir, { recursive: true, force: true }); + } + })) passed++; else failed++; + if (test('locale component resolves to the translated docs module', () => { const homeDir = fs.mkdtempSync(path.join(os.tmpdir(), 'locale-plan-')); try { @@ -160,6 +183,37 @@ function runTests() { } })) passed++; else failed++; + if (test('end-to-end: --locale uk dry-run includes docs-uk-ua operations', () => { + const homeDir = fs.mkdtempSync(path.join(os.tmpdir(), 'locale-dry-run-uk-')); + const projectDir = fs.mkdtempSync(path.join(os.tmpdir(), 'locale-dry-run-uk-project-')); + + try { + const output = runInstallApply([ + '--locale', 'uk', + '--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:uk-ua']); + assert.deepStrictEqual(json.plan.selectedModuleIds, ['docs-uk-ua']); + assert.ok( + json.plan.operations.some(operation => ( + normalizePlanPath(operation.sourceRelativePath) === 'docs/uk-UA/README.md' + && normalizePlanPath(operation.destinationPath).endsWith('/.claude/docs/uk-UA/README.md') + )), + 'Should copy translated README into ~/.claude/docs/uk-UA' + ); + } 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-')); @@ -219,6 +273,38 @@ function runTests() { } })) passed++; else failed++; + if (test('end-to-end: --locale uk-UA installs translated docs cleanly', () => { + const homeDir = fs.mkdtempSync(path.join(os.tmpdir(), 'locale-install-uk-')); + const projectDir = fs.mkdtempSync(path.join(os.tmpdir(), 'locale-install-uk-project-')); + + try { + runInstallApply([ + '--locale', 'uk-UA', + ], { + cwd: projectDir, + env: { HOME: homeDir }, + }); + + const claudeRoot = path.join(homeDir, '.claude'); + assert.ok( + fs.existsSync(path.join(claudeRoot, 'docs', 'uk-UA', 'README.md')), + 'Should install Ukrainian README under docs/uk-UA' + ); + assert.ok( + !fs.existsSync(path.join(claudeRoot, 'skills', '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:uk-ua']); + assert.deepStrictEqual(state.resolution.selectedModules, ['docs-uk-ua']); + } 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); }