Initial commit

This commit is contained in:
Zhongwei Li
2025-11-30 09:04:14 +08:00
commit 70c36b5eff
248 changed files with 47482 additions and 0 deletions

View File

@@ -0,0 +1,145 @@
# Jest Basic CLI Testing Example
This example demonstrates basic CLI testing patterns using Jest for Node.js/TypeScript projects.
## Setup
```bash
npm install --save-dev jest @types/jest ts-jest @types/node
```
## Test Structure
```typescript
import { execSync } from 'child_process';
import path from 'path';
describe('CLI Tool Tests', () => {
const CLI_PATH = path.join(__dirname, '../bin/mycli');
function runCLI(args: string) {
try {
const stdout = execSync(`${CLI_PATH} ${args}`, {
encoding: 'utf8',
stdio: 'pipe',
});
return { stdout, stderr: '', code: 0 };
} catch (error: any) {
return {
stdout: error.stdout || '',
stderr: error.stderr || '',
code: error.status || 1,
};
}
}
test('should display version', () => {
const { stdout, code } = runCLI('--version');
expect(code).toBe(0);
expect(stdout).toContain('1.0.0');
});
test('should display help', () => {
const { stdout, code } = runCLI('--help');
expect(code).toBe(0);
expect(stdout).toContain('Usage:');
});
test('should handle unknown command', () => {
const { stderr, code } = runCLI('unknown-command');
expect(code).toBe(1);
expect(stderr).toContain('unknown command');
});
});
```
## Running Tests
```bash
# Run all tests
npm test
# Run with coverage
npm run test:coverage
# Run in watch mode
npm run test:watch
```
## Key Patterns
### 1. Command Execution Helper
Create a reusable `runCLI()` function that:
- Executes CLI commands using `execSync`
- Captures stdout, stderr, and exit codes
- Handles both success and failure cases
### 2. Exit Code Testing
Always test exit codes:
- `0` for success
- Non-zero for errors
- Specific codes for different error types
### 3. Output Validation
Test output content using Jest matchers:
- `.toContain()` for substring matching
- `.toMatch()` for regex patterns
- `.toBe()` for exact matches
### 4. Error Handling
Test error scenarios:
- Unknown commands
- Invalid options
- Missing required arguments
- Invalid argument types
## Example Test Cases
```typescript
describe('deploy command', () => {
test('should deploy with valid arguments', () => {
const { stdout, code } = runCLI('deploy production --force');
expect(code).toBe(0);
expect(stdout).toContain('Deploying to production');
});
test('should fail without required arguments', () => {
const { stderr, code } = runCLI('deploy');
expect(code).toBe(1);
expect(stderr).toContain('missing required argument');
});
test('should validate environment names', () => {
const { stderr, code } = runCLI('deploy invalid-env');
expect(code).toBe(1);
expect(stderr).toContain('invalid environment');
});
});
```
## Best Practices
1. **Isolate Tests**: Each test should be independent
2. **Use Descriptive Names**: Test names should describe what they validate
3. **Test Both Success and Failure**: Cover happy path and error cases
4. **Mock External Dependencies**: Don't make real API calls or file system changes
5. **Use Type Safety**: Leverage TypeScript for better test reliability
6. **Keep Tests Fast**: Fast tests encourage frequent running
## Common Pitfalls
- ❌ Not testing exit codes
- ❌ Only testing success cases
- ❌ Hardcoding paths instead of using `path.join()`
- ❌ Not handling async operations properly
- ❌ Testing implementation details instead of behavior
## Resources
- [Jest Documentation](https://jestjs.io/docs/getting-started)
- [Testing CLI Applications](https://jestjs.io/docs/cli)
- [TypeScript with Jest](https://jestjs.io/docs/getting-started#using-typescript)