scaffold-scripts
Version:
Simple CLI tool for managing and running your own scripts. Add any script, run it anywhere.
218 lines (176 loc) • 8.73 kB
text/typescript
/**
* Basic smoke tests for Scaffold Scripts CLI
* Each test is properly isolated with clean database state
*/
import { execSync } from 'child_process';
import { join } from 'path';
import { setupTest, cleanupTest, execCLI, CLI_PATH } from './test-isolation';
describe('Scaffold Scripts CLI - Smoke Tests', () => {
beforeAll(() => {
// Build the project
try {
execSync('npm run build', { cwd: join(__dirname, '..'), stdio: 'pipe' });
} catch (error) {
console.warn('Build failed, tests may not work correctly');
}
});
beforeEach(() => {
setupTest();
});
afterEach(() => {
cleanupTest();
});
it('should show help without crashing', () => {
const result = execCLI('--help', { encoding: 'utf8' });
expect(result).toContain('scaffold');
});
it('should show version without crashing', () => {
const result = execCLI('--version', { encoding: 'utf8' });
expect(result).toMatch(/\d+\.\d+\.\d+/);
});
it('should support -v for version', () => {
const result = execCLI('-v', { encoding: 'utf8' });
expect(result).toMatch(/\d+\.\d+\.\d+/);
// Test that -v and --version produce same output
const longResult = execCLI('--version', { encoding: 'utf8' });
expect(result).toBe(longResult);
});
it('should handle list command without crashing', () => {
expect(() => {
execCLI('list', { stdio: 'pipe' });
}).not.toThrow();
});
it('should verify scripts alias is configured', () => {
// Test that our package.json has the right aliases
const packageJson = require('../package.json');
expect(packageJson.bin.scripts).toBe('./bin/scaffold.js');
expect(packageJson.bin.scaffold).toBe('./bin/scaffold.js');
// sc alias should not exist (conflicts with Windows Service Control)
expect(packageJson.bin.sc).toBeUndefined();
});
it('should support ALL command aliases correctly', () => {
// Test every single alias to ensure they work exactly like their full commands
let result;
// Test 'a' alias for 'add' command
result = execCLI('a', { stdio: 'pipe' });
expect(result).toContain('Suggestion: Use:');
expect(result).not.toContain('unknown option');
expect(result).not.toContain('unknown command');
// Test 'add' full command produces same error
const addResult = execCLI('add', { stdio: 'pipe' });
expect(addResult).toContain('Suggestion: Use:');
// Both should produce similar error messages
expect(addResult).toContain('name');
// Test 'u' alias for 'update' command
result = execCLI('u', { stdio: 'pipe' });
expect(result).toContain('Suggestion: Use:');
expect(result).not.toContain('unknown option');
expect(result).not.toContain('unknown command');
// Test 'update' full command produces same error
const updateResult = execCLI('update', { stdio: 'pipe' });
expect(updateResult).toContain('Suggestion: Use:');
// Test 'r' alias for 'remove' command
result = execCLI('r', { stdio: 'pipe' });
expect(result).toContain('Suggestion: Use:');
expect(result).not.toContain('unknown option');
expect(result).not.toContain('unknown command');
// Test 'remove' full command produces same error
const removeResult = execCLI('remove', { stdio: 'pipe' });
expect(removeResult).toContain('Suggestion: Use:');
// Test 'l' alias for 'list' command - should work without error
expect(() => {
execCLI('l', { stdio: 'pipe' });
}).not.toThrow();
// Test 'list' full command - should work without error
expect(() => {
execCLI('list', { stdio: 'pipe' });
}).not.toThrow();
// Verify 'l' and 'list' produce same output (in clean state, both should show "No scripts available")
const lResult = execCLI('l', { encoding: 'utf8', stdio: 'pipe' });
const listResult = execCLI('list', { encoding: 'utf8', stdio: 'pipe' });
expect(lResult).toBe(listResult);
expect(lResult).toContain('No scripts available');
// Test 's' alias for 'view' command - should show error for missing arguments
result = execCLI('s', { stdio: 'pipe' });
expect(result).toContain('Suggestion: Use:');
expect(result).not.toContain('unknown option');
expect(result).not.toContain('unknown command');
// Test 'view' full command produces same error
const viewResult = execCLI('view', { stdio: 'pipe' });
expect(viewResult).toContain('Suggestion: Use:');
});
it('should reject old-style flag syntax', () => {
// Test that -a, -u, -r, -l are rejected as unknown options
// Note: -v is now valid for version, so it's excluded from this test
const oldFlags = ['-a', '-u', '-r', '-l'];
for (const flag of oldFlags) {
const result = execCLI(`${flag} test-name test-file`, { stdio: 'pipe' });
expect(result).toContain('Suggestion: Use --help to see available options');
// The error output no longer shows the specific flag, but shows helpful suggestions
expect(result).toContain('Suggestion: Use --help to see available options');
}
});
it('should perform full workflow with aliases', () => {
// Test complete add -> list -> remove workflow using aliases
const { writeFileSync, rmSync, mkdtempSync } = require('fs');
const { tmpdir } = require('os');
const { join } = require('path');
const tempDir = mkdtempSync(join(tmpdir(), 'scaffold-test-'));
const scriptFile = join(tempDir, 'test-script.sh');
writeFileSync(scriptFile, '#!/bin/bash\necho "test script"');
try {
// Test adding with alias 'a'
const addResult = execCLI(`a test-workflow "${scriptFile}"`, { encoding: 'utf8' });
expect(addResult).toContain('Added script "test-workflow"');
// Test listing with alias 'l' shows our script
const listResult = execCLI('l', { encoding: 'utf8' });
expect(listResult).toContain('test-workflow');
// Test removing with alias 'r'
const removeResult = execCLI('r test-workflow', { encoding: 'utf8' });
expect(removeResult).toContain('Removed script "test-workflow"');
// Test listing again should not show our script
const listAfterRemove = execCLI('l', { encoding: 'utf8' });
expect(listAfterRemove).not.toContain('test-workflow');
} finally {
rmSync(tempDir, { recursive: true, force: true });
}
});
it('should perform same workflow with full commands', () => {
// Test same workflow using full command names for comparison
const { writeFileSync, rmSync, mkdtempSync } = require('fs');
const { tmpdir } = require('os');
const { join } = require('path');
const tempDir = mkdtempSync(join(tmpdir(), 'scaffold-test-'));
const scriptFile = join(tempDir, 'test-script2.sh');
writeFileSync(scriptFile, '#!/bin/bash\necho "test script 2"');
try {
// Test adding with full command
const addResult = execCLI(`add test-full-workflow "${scriptFile}"`, { encoding: 'utf8' });
expect(addResult).toContain('Added script "test-full-workflow"');
// Test listing with full command
const listResult = execCLI('list', { encoding: 'utf8' });
expect(listResult).toContain('test-full-workflow');
// Test removing with full command
const removeResult = execCLI('remove test-full-workflow', { encoding: 'utf8' });
expect(removeResult).toContain('Removed script "test-full-workflow"');
// Test listing again should not show our script
const listAfterRemove = execCLI('list', { encoding: 'utf8' });
expect(listAfterRemove).not.toContain('test-full-workflow');
} finally {
rmSync(tempDir, { recursive: true, force: true });
}
});
it('should reject binary files', () => {
// Test file type validation works
const { writeFileSync, rmSync, mkdtempSync } = require('fs');
const { tmpdir } = require('os');
const { join } = require('path');
const tempDir = mkdtempSync(join(tmpdir(), 'scaffold-test-'));
const binaryFile = join(tempDir, 'test-binary.exe');
writeFileSync(binaryFile, 'text content'); // Text content but binary extension
const result = execCLI(`add test-binary "${binaryFile}"`, { encoding: 'utf8' });
expect(result).toContain('Binary file type not supported');
expect(result).toContain('.exe');
rmSync(tempDir, { recursive: true, force: true });
});
});