fix: header subtitle width mismatch in skill-create-output; add 9 tests (Round 34)

- Fix subtitle padding 55→59 so line 94 matches 64-char border width
- Add 4 header width alignment tests (skill-create-output)
- Add 3 getExecCommand non-string args tests (package-manager)
- Add 2 detectFromPackageJson non-string type tests (package-manager)
This commit is contained in:
Affaan Mustafa
2026-02-13 03:58:16 -08:00
parent bb9df39d96
commit 554b5d6704
3 changed files with 127 additions and 1 deletions

View File

@@ -91,7 +91,7 @@ class SkillCreateOutput {
console.log('\n');
console.log(chalk.bold(chalk.magenta('╔════════════════════════════════════════════════════════════════╗')));
console.log(chalk.bold(chalk.magenta('║')) + chalk.bold(' 🔮 ECC Skill Creator ') + chalk.bold(chalk.magenta('║')));
console.log(chalk.bold(chalk.magenta('║')) + ` ${subtitle}${' '.repeat(Math.max(0, 55 - stripAnsi(subtitle).length))}` + chalk.bold(chalk.magenta('║')));
console.log(chalk.bold(chalk.magenta('║')) + ` ${subtitle}${' '.repeat(Math.max(0, 59 - stripAnsi(subtitle).length))}` + chalk.bold(chalk.magenta('║')));
console.log(chalk.bold(chalk.magenta('╚════════════════════════════════════════════════════════════════╝')));
console.log('');
}

View File

@@ -1093,6 +1093,77 @@ function runTests() {
}
})) passed++; else failed++;
// ── Round 34: getExecCommand non-string args & packageManager type ──
console.log('\nRound 34: getExecCommand non-string args:');
if (test('getExecCommand with args=0 produces command without extra args', () => {
const originalEnv = process.env.CLAUDE_PACKAGE_MANAGER;
try {
process.env.CLAUDE_PACKAGE_MANAGER = 'npm';
const cmd = pm.getExecCommand('prettier', 0);
// 0 is falsy, so ternary `args ? ' ' + args : ''` yields ''
assert.ok(!cmd.includes(' 0'), 'Should not append 0 as args');
assert.ok(cmd.includes('prettier'), 'Should include binary name');
} finally {
if (originalEnv !== undefined) process.env.CLAUDE_PACKAGE_MANAGER = originalEnv;
else delete process.env.CLAUDE_PACKAGE_MANAGER;
}
})) passed++; else failed++;
if (test('getExecCommand with args=false produces command without extra args', () => {
const originalEnv = process.env.CLAUDE_PACKAGE_MANAGER;
try {
process.env.CLAUDE_PACKAGE_MANAGER = 'npm';
const cmd = pm.getExecCommand('eslint', false);
assert.ok(!cmd.includes('false'), 'Should not append false as args');
assert.ok(cmd.includes('eslint'), 'Should include binary name');
} finally {
if (originalEnv !== undefined) process.env.CLAUDE_PACKAGE_MANAGER = originalEnv;
else delete process.env.CLAUDE_PACKAGE_MANAGER;
}
})) passed++; else failed++;
if (test('getExecCommand with args=null produces command without extra args', () => {
const originalEnv = process.env.CLAUDE_PACKAGE_MANAGER;
try {
process.env.CLAUDE_PACKAGE_MANAGER = 'npm';
const cmd = pm.getExecCommand('tsc', null);
assert.ok(!cmd.includes('null'), 'Should not append null as args');
assert.ok(cmd.includes('tsc'), 'Should include binary name');
} finally {
if (originalEnv !== undefined) process.env.CLAUDE_PACKAGE_MANAGER = originalEnv;
else delete process.env.CLAUDE_PACKAGE_MANAGER;
}
})) passed++; else failed++;
console.log('\nRound 34: detectFromPackageJson with non-string packageManager:');
if (test('detectFromPackageJson handles array packageManager field gracefully', () => {
const tmpDir = createTestDir();
try {
// Write a malformed package.json with array instead of string
fs.writeFileSync(path.join(tmpDir, 'package.json'),
JSON.stringify({ packageManager: ['pnpm@8', 'yarn@3'] }));
// Should not crash — try/catch in detectFromPackageJson catches TypeError
const result = pm.getPackageManager({ projectDir: tmpDir });
assert.ok(result.name, 'Should fallback to a valid package manager');
} finally {
fs.rmSync(tmpDir, { recursive: true, force: true });
}
})) passed++; else failed++;
if (test('detectFromPackageJson handles numeric packageManager field gracefully', () => {
const tmpDir = createTestDir();
try {
fs.writeFileSync(path.join(tmpDir, 'package.json'),
JSON.stringify({ packageManager: 42 }));
const result = pm.getPackageManager({ projectDir: tmpDir });
assert.ok(result.name, 'Should fallback to a valid package manager');
} finally {
fs.rmSync(tmpDir, { recursive: true, force: true });
}
})) passed++; else failed++;
// Summary
console.log('\n=== Test Results ===');
console.log(`Passed: ${passed}`);

View File

@@ -319,6 +319,61 @@ function runTests() {
assert.ok(combined.includes('Powered by'), 'Should include attribution text');
})) passed++; else failed++;
// ── Round 34: header width alignment ──
console.log('\nheader() width alignment (Round 34):');
if (test('header subtitle line matches border width', () => {
const output = new SkillCreateOutput('test-repo');
const logs = captureLog(() => output.header());
// Find the border and subtitle lines
const lines = logs.map(l => stripAnsi(l));
const borderLine = lines.find(l => l.includes('═══'));
const subtitleLine = lines.find(l => l.includes('Extracting patterns'));
assert.ok(borderLine, 'Should find border line');
assert.ok(subtitleLine, 'Should find subtitle line');
// Both lines should have the same visible width
assert.strictEqual(subtitleLine.length, borderLine.length,
`Subtitle width (${subtitleLine.length}) should match border width (${borderLine.length})`);
})) passed++; else failed++;
if (test('header all lines have consistent width for short repo name', () => {
const output = new SkillCreateOutput('abc');
const logs = captureLog(() => output.header());
const lines = logs.map(l => stripAnsi(l)).filter(l => l.includes('║') || l.includes('╔') || l.includes('╚'));
assert.ok(lines.length >= 4, 'Should have at least 4 box lines');
const widths = lines.map(l => l.length);
const first = widths[0];
widths.forEach((w, i) => {
assert.strictEqual(w, first,
`Line ${i} width (${w}) should match first line (${first})`);
});
})) passed++; else failed++;
if (test('header subtitle has correct content area width of 64 chars', () => {
const output = new SkillCreateOutput('myrepo');
const logs = captureLog(() => output.header());
const lines = logs.map(l => stripAnsi(l));
const subtitleLine = lines.find(l => l.includes('Extracting patterns'));
assert.ok(subtitleLine, 'Should find subtitle line');
// Content between ║ and ║ should be 64 chars (border is 66 total)
// Format: ║ + content(64) + ║ = 66
assert.strictEqual(subtitleLine.length, 66,
`Total subtitle line width should be 66, got ${subtitleLine.length}`);
})) passed++; else failed++;
if (test('header subtitle line does not truncate with medium-length repo name', () => {
const output = new SkillCreateOutput('my-medium-repo-name');
const logs = captureLog(() => output.header());
const combined = logs.join('\n');
assert.ok(combined.includes('my-medium-repo-name'), 'Should include full repo name');
const lines = logs.map(l => stripAnsi(l));
const subtitleLine = lines.find(l => l.includes('Extracting patterns'));
assert.ok(subtitleLine, 'Should have subtitle line');
// Should still be 66 chars even with a longer name
assert.strictEqual(subtitleLine.length, 66,
`Subtitle line should be 66 chars, got ${subtitleLine.length}`);
})) passed++; else failed++;
// Summary
console.log(`\nResults: Passed: ${passed}, Failed: ${failed}`);
process.exit(failed > 0 ? 1 : 0);