RuleStack

Configs

Stacks

Compare

Diff

RuleStack

Configs

Stacks

Compare

Diff

Read API

RuleStack

Configs

Stacks

Compare

Diff

Read API

Diff/contentstack-cli-cursor-rules-testing ↔ contentstack-cli-cursor-rules-oclif-commands

Comparison

A · Cursor rules · contentstack/cliB · Cursor rules · contentstack/cli
What each file covers, counted
DimensionSharedOnly in AOnly in BOverlap
Sections235313%
Commands0100%
Section tags43057%

What each file covers

Sections

2 shared · 35 only in A · 31 only in B
  • − Testing Standards
  • − Framework Stack
  • − Primary Testing Tools
  • − Test Setup
  • − Test File Patterns
  • − Naming Conventions
  • − Directory Structure
  • − Mocha Configuration
  • − Standard Setup (.mocharc.json)
  • − TypeScript Compilation
  • − Test Structure
  • − Standard Test Pattern
  • − Async/Await Pattern
  • − Mocking Patterns
  • − Class Mocking
  • − Function Stubs
  • − Command Testing
  • − OCLIF Test Pattern
  • − Command Flag Testing
  • − Error Testing
  • − Error Types
  • − Test Data Management
  • − Mock Data Organization
  • − Test Helpers
  • − Coverage
  • − Coverage Goals
  • − Coverage Reporting
  • − Run tests with coverage
  • − Coverage reports generated in:
  • − - coverage/index.html (HTML report)
  • − - coverage/coverage-summary.json (JSON report)
  • − Critical Testing Rules
  • − Test Organization
  • − Async Test Patterns
  • − Isolation
  • + OCLIF Command Standards
  • + Command Structure
  • + Standard Command Pattern
  • + Base Classes
  • + Command Base Class
  • + Custom Base Classes
  • + OCLIF Configuration
  • + Package.json Setup
  • + Command Topics
  • + Command Naming
  • + Flag Management
  • + Flag Definition Patterns
  • + Flag Parsing
  • + Standard Error Pattern
  • + User-Friendly Messages
  • + Validation Patterns
  • + Early Validation
  • + Progress and Logging
  • + User Feedback
  • + Progress Indication
  • + Command Delegation
  • + Service Layer Separation
  • + Testing Commands
  • + OCLIF Test Support
  • + Log Integration
  • + Debug Logging
  • + Error Context
  • + Multi-Topic Commands
  • + Nested Command Structure
  • + Command Organization
  • + Clear Help Text
  •   Error Handling
  •   Best Practices

Commands

0 shared · 1 only in A · 0 only in B
  • − pnpm test:coverage

Section tags

4 shared · 3 only in A · 0 only in B
  • − types
  • − testing-strategy
  • − do-not
  •   setup
  •   test
  •   code-style
  •   architecture

Line diff

+270 added−241 removed83 unchanged23.5% identical
contentstack/cli · .cursor/rules/testing.mdc
@@ −1 @@
1---
2description: 'Testing patterns and TDD workflow'
3globs: ['**/test/**/*.ts', '**/test/**/*.js', '**/__tests__/**/*.ts', '**/*.spec.ts', '**/*.test.ts']
4alwaysApply: true
5---
6 
7# Testing Standards
8 
9## Framework Stack
10 
11### Primary Testing Tools
12- **Mocha** - Test runner (used across all packages)
13- **Chai** - Assertion library
14- **@oclif/test** - Command testing support (for plugin packages)
 
15 
16### Test Setup
17- TypeScript compilation via ts-node/register
18- Source map support for stack traces
19- Global test timeout: 30 seconds (configurable per package)
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
20 
21## Test File Patterns
22 
23### Naming Conventions
24- **Primary**: `*.test.ts` (standard pattern across all packages)
25- **Location**: `test/unit/**/*.test.ts` (most packages)
 
26 
27### Directory Structure
 
 
 
 
28```
29packages/*/
30├── test/
31│ └── unit/
32│ ├── commands/ # Command-specific tests
33│ ├── services/ # Service/business logic tests
34│ └── utils/ # Utility function tests
35└── src/ # Source code
36 ├── commands/ # CLI commands
37 ├── services/ # Business logic
38 └── utils/ # Utilities
39```
40 
41## Mocha Configuration
 
 
 
 
 
 
42 
43### Standard Setup (.mocharc.json)
44```json
45{
46 "require": [
47 "test/helpers/init.js",
48 "ts-node/register",
49 "source-map-support/register"
50 ],
51 "recursive": true,
52 "timeout": 30000,
53 "spec": "test/**/*.test.ts"
54}
55```
56 
57### TypeScript Compilation
 
 
58```json
59// package.json scripts
60{
61 "test": "mocha \"test/unit/**/*.test.ts\"",
62 "test:coverage": "nyc mocha \"test/unit/**/*.test.ts\""
 
 
 
63}
64```
65 
66## Test Structure
 
 
 
67 
68### Standard Test Pattern
 
 
 
 
 
 
 
69```typescript
70// ✅ GOOD - Comprehensive test structure
71describe('ConfigService', () => {
72 let service: ConfigService;
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
73 
74 beforeEach(() => {
75 service = new ConfigService();
76 });
 
 
 
 
 
 
 
 
 
 
 
 
77 
78 describe('loadConfig()', () => {
79 it('should load configuration successfully', async () => {
80 // Arrange
81 const expectedConfig = { region: 'us' };
82
83 // Act
84 const result = await service.loadConfig();
85
86 // Assert
87 expect(result).to.deep.equal(expectedConfig);
88 });
89 
90 it('should handle missing configuration', async () => {
91 // Arrange & Act & Assert
92 await expect(service.loadConfig()).to.be.rejectedWith('Config not found');
93 });
94 });
95});
 
 
96```
97 
98### Async/Await Pattern
99```typescript
100// ✅ GOOD - Use async/await in tests
101it('should process data asynchronously', async () => {
102 const result = await service.processAsync();
103 expect(result).to.exist;
104});
105 
106// ✅ GOOD - Explicit Promise handling
107it('should return a promise', () => {
108 return service.asyncMethod().then(result => {
109 expect(result).to.be.true;
110 });
111});
 
 
112```
113 
114## Mocking Patterns
115 
116### Class Mocking
117```typescript
118// ✅ GOOD - Mock class dependencies
119class MockConfigService {
120 async loadConfig() {
121 return { region: 'us' };
 
 
 
122 }
 
 
 
 
 
 
 
123}
 
124 
125it('should use mocked service', async () => {
126 const mockService = new MockConfigService();
127 const result = await mockService.loadConfig();
128 expect(result.region).to.equal('us');
129});
 
 
 
 
 
 
 
 
 
 
130```
131 
132### Function Stubs
133```typescript
134// ✅ GOOD - Stub module functions if needed
135beforeEach(() => {
136 // Stub file system operations
137 // Stub network calls
138});
 
 
 
 
139 
140afterEach(() => {
141 // Restore original implementations
142});
 
 
 
 
 
 
 
 
 
 
 
 
 
 
143```
144 
145## Command Testing
146 
147### OCLIF Test Pattern
148```typescript
149// ✅ GOOD - Test commands with @oclif/test
150import { test } from '@oclif/test';
151 
152describe('cm:config:region', () => {
153 test
154 .stdout()
155 .command(['cm:config:region', '--help'])
156 .it('shows help message', ctx => {
157 expect(ctx.stdout).to.contain('Display region');
158 });
159 
160 test
161 .stdout()
162 .command(['cm:config:region'])
163 .it('shows current region', ctx => {
164 expect(ctx.stdout).to.contain('us');
165 });
166});
167```
168 
169### Command Flag Testing
 
 
170```typescript
171// ✅ GOOD - Test command flags and arguments
172describe('cm:config:set', () => {
173 test
174 .command(['cm:config:set', '--help'])
175 .it('shows usage information');
176 
177 test
178 .command(['cm:config:set', '--region', 'eu'])
179 .it('sets region to eu');
 
180});
181```
182 
183## Error Testing
184 
185### Error Handling
186```typescript
187// ✅ GOOD - Test error scenarios
188it('should throw ValidationError on invalid input', async () => {
189 const invalidInput = '';
190 await expect(service.validate(invalidInput))
191 .to.be.rejectedWith('Invalid input');
192});
193 
194it('should handle network errors gracefully', async () => {
195 // Mock network failure
196 const result = await service.fetchWithRetry();
197 expect(result).to.be.null;
198});
199```
200 
201### Error Types
202```typescript
203// ✅ GOOD - Test specific error types
204it('should throw appropriate error', async () => {
205 try {
206 await service.failingOperation();
207 } catch (error) {
208 expect(error).to.be.instanceof(ValidationError);
209 expect(error.code).to.equal('INVALID_CONFIG');
210 }
211});
 
212```
213 
214## Test Data Management
215 
216### Mock Data Organization
217```typescript
218// ✅ GOOD - Organize test data
219const mockData = {
220 validConfig: {
221 region: 'us',
222 timeout: 30000,
223 },
224 invalidConfig: {
225 region: '',
226 },
227 users: [
228 { email: 'user1@example.com', name: 'User 1' },
229 { email: 'user2@example.com', name: 'User 2' },
230 ],
231};
232```
233 
234### Test Helpers
235```typescript
236// ✅ GOOD - Create reusable test utilities
237export function createMockConfig(overrides?: Partial<Config>): Config {
238 return {
239 region: 'us',
240 timeout: 30000,
241 ...overrides,
242 };
243}
244 
245export function createMockService(
246 config: Config = createMockConfig()
247): ConfigService {
248 return new ConfigService(config);
 
249}
250```
251 
252## Coverage
253 
254### Coverage Goals
255- **Team aspiration**: 80% minimum coverage
256- **Current enforcement**: Applied consistently across packages
257- **Focus areas**: Critical business logic and error paths
258 
259### Coverage Reporting
260```bash
261# Run tests with coverage
262pnpm test:coverage
263 
264# Coverage reports generated in:
265# - coverage/index.html (HTML report)
266# - coverage/coverage-summary.json (JSON report)
267```
268 
269## Critical Testing Rules
270 
271- **No real external calls** - Mock all dependencies
272- **Test both success and failure paths** - Cover error scenarios completely
273- **One assertion per test** - Focus each test on single behavior
274- **Use descriptive test names** - Test name should explain what's tested
275- **Arrange-Act-Assert** - Follow AAA pattern consistently
276- **Test command validation** - Verify flag validation and error messages
277- **Clean up after tests** - Restore any mocked state
278 
279## Best Practices
280 
281### Test Organization
282```typescript
283// ✅ GOOD - Organize related tests
284describe('AuthCommand', () => {
285 describe('login', () => {
286 it('should authenticate user');
287 it('should save token');
288 });
289
290 describe('logout', () => {
291 it('should clear token');
292 it('should reset config');
293 });
294});
295```
296 
297### Async Test Patterns
298```typescript
299// ✅ GOOD - Handle async operations properly
300it('should complete async operation', async () => {
301 const promise = service.asyncMethod();
302 expect(promise).to.be.instanceof(Promise);
303
304 const result = await promise;
305 expect(result).to.equal('success');
306});
307```
308 
309### Isolation
310```typescript
311// ✅ GOOD - Ensure test isolation
312describe('ConfigService', () => {
313 let service: ConfigService;
314
315 beforeEach(() => {
316 service = new ConfigService();
317 });
 
 
 
 
 
318
319 afterEach(() => {
320 // Clean up resources
321 });
322});
323```
 
 
 
 
 
 
324 
contentstack/cli · .cursor/rules/oclif-commands.mdc
@@ +1 @@
1---
2description: 'OCLIF command development patterns and CLI best practices'
3globs: ['**/commands/**/*.ts', '**/base-command.ts']
4alwaysApply: false
5---
6 
7# OCLIF Command Standards
8 
9## Command Structure
10 
11### Standard Command Pattern
12```typescript
13// ✅ GOOD - Standard command structure
14import { Command } from '@contentstack/cli-command';
15import { cliux, flags, FlagInput, handleAndLogError } from '@contentstack/cli-utilities';
16 
17export default class ConfigSetCommand extends Command {
18 static description = 'Set CLI configuration values';
19
20 static flags: FlagInput = {
21 region: flags.string({
22 char: 'r',
23 description: 'Set region (us/eu)',
24 }),
25 alias: flags.string({
26 char: 'a',
27 description: 'Configuration alias',
28 }),
29 };
30
31 static examples = [
32 'csdx config:set --region eu',
33 'csdx config:set --region us --alias default',
34 ];
35
36 async run(): Promise<void> {
37 try {
38 const { flags: configFlags } = await this.parse(ConfigSetCommand);
39 // Command logic here
40 } catch (error) {
41 handleAndLogError(error, { module: 'config-set' });
42 }
43 }
44}
45```
46 
47## Base Classes
48 
49### Command Base Class
50```typescript
51// ✅ GOOD - Extend Command from @contentstack/cli-command
52import { Command } from '@contentstack/cli-command';
53 
54export default class MyCommand extends Command {
55 async run(): Promise<void> {
56 // Command implementation
57 }
58}
59```
 
 
 
 
 
 
 
 
 
 
 
60 
61### Custom Base Classes
62```typescript
63// ✅ GOOD - Create custom base classes for shared functionality
64export abstract class BaseCommand<T extends typeof Command> extends Command {
65 protected contextDetails = {
66 command: this.id || 'unknown',
67 };
68 
69 async init(): Promise<void> {
70 await super.init();
71 log.debug('Command initialized', this.contextDetails);
72 }
 
 
 
 
 
 
 
73}
74```
75 
76## OCLIF Configuration
77 
78### Package.json Setup
79```json
 
80{
81 "oclif": {
82 "commands": "./lib/commands",
83 "bin": "csdx",
84 "topicSeparator": ":"
85 }
86}
87```
88 
89### Command Topics
90- All commands use `cm` topic: `cm:config:set`, `cm:auth:login`
91- Built commands live in `lib/commands` (compiled from `src/commands`)
92- Commands use nested directories: `src/commands/config/set.ts` → `cm:config:set`
93 
94### Command Naming
95- **Topic hierarchy**: `config/remove/proxy.ts` → `cm:config:remove:proxy`
96- **Descriptive names**: Use verb-noun pattern (`set`, `remove`, `show`)
97- **Grouping**: Related commands share parent topics
98 
99## Flag Management
100 
101### Flag Definition Patterns
102```typescript
103// ✅ GOOD - Define flags clearly
104static flags: FlagInput = {
105 'stack-api-key': flags.string({
106 char: 'k',
107 description: 'Stack API key',
108 required: false,
109 }),
110 region: flags.string({
111 char: 'r',
112 description: 'Set region',
113 options: ['us', 'eu'],
114 }),
115 verbose: flags.boolean({
116 char: 'v',
117 description: 'Show verbose output',
118 default: false,
119 }),
120};
121```
122 
123### Flag Parsing
124```typescript
125// ✅ GOOD - Parse and validate flags
126async run(): Promise<void> {
127 const { flags: parsedFlags } = await this.parse(MyCommand);
128
129 // Validate flag combinations
130 if (!parsedFlags['stack-api-key'] && !parsedFlags.alias) {
131 this.error('Either --stack-api-key or --alias is required');
132 }
133
134 // Use parsed flags
135 const region = parsedFlags.region || 'us';
136}
137```
138 
139## Error Handling
 
 
 
 
 
 
 
 
 
 
140 
141### Standard Error Pattern
142```typescript
143// ✅ GOOD - Use handleAndLogError from utilities
144try {
145 await this.executeCommand();
146} catch (error) {
147 handleAndLogError(error, { module: 'my-command' });
148}
149```
150 
151### User-Friendly Messages
152```typescript
153// ✅ GOOD - Clear user feedback
154import { cliux } from '@contentstack/cli-utilities';
 
 
 
155 
156// Success message
157cliux.success('Configuration updated successfully', { color: 'green' });
158 
159// Error message
160cliux.error('Invalid region specified', { color: 'red' });
161 
162// Info message
163cliux.print('Setting region to eu', { color: 'blue' });
164```
165 
166## Validation Patterns
167 
168### Early Validation
169```typescript
170// ✅ GOOD - Validate flags early
171async run(): Promise<void> {
172 const { flags } = await this.parse(MyCommand);
173
174 // Validate required flags
175 if (!flags.region) {
176 this.error('--region is required');
177 }
178
179 // Validate flag values
180 if (!['us', 'eu'].includes(flags.region)) {
181 this.error('Region must be "us" or "eu"');
182 }
183
184 // Proceed with validated input
185}
186```
187 
188## Progress and Logging
189 
190### User Feedback
191```typescript
192// ✅ GOOD - Provide user feedback
193import { log, cliux } from '@contentstack/cli-utilities';
194 
195// Regular logging
196this.log('Starting configuration update...');
197 
198// Debug logging
199log.debug('Detailed operation information', { context: 'data' });
200 
201// Status messages
202cliux.print('Processing...', { color: 'blue' });
203```
204 
205### Progress Indication
206```typescript
207// ✅ GOOD - Show progress for long operations
208cliux.print('Processing items...', { color: 'blue' });
209let count = 0;
210for (const item of items) {
211 await this.processItem(item);
212 count++;
213 cliux.print(`Processed ${count}/${items.length} items`, { color: 'blue' });
214}
215```
216 
217## Command Delegation
218 
219### Service Layer Separation
220```typescript
221// ✅ GOOD - Commands orchestrate, services implement
222async run(): Promise<void> {
223 try {
224 const { flags } = await this.parse(MyCommand);
225 const config = this.buildConfig(flags);
226 const service = new ConfigService(config);
227
228 await service.execute();
229 cliux.success('Operation completed successfully');
230 } catch (error) {
231 this.handleError(error);
232 }
233}
234```
235 
236## Testing Commands
237 
238### OCLIF Test Support
239```typescript
240// ✅ GOOD - Use @oclif/test for command testing
241import { test } from '@oclif/test';
242 
243describe('cm:config:set', () => {
244 test
245 .stdout()
246 .command(['cm:config:set', '--help'])
247 .it('shows help', ctx => {
248 expect(ctx.stdout).to.contain('Set CLI configuration');
249 });
250 
251 test
252 .stdout()
253 .command(['cm:config:set', '--region', 'eu'])
254 .it('sets region to eu', ctx => {
255 expect(ctx.stdout).to.contain('success');
256 });
257});
258```
259 
260## Log Integration
261 
262### Debug Logging
263```typescript
264// ✅ GOOD - Use structured debug logging
265import { log } from '@contentstack/cli-utilities';
 
 
 
266 
267log.debug('Command started', {
268 command: this.id,
269 flags: this.flags,
270 timestamp: new Date().toISOString(),
271});
 
272 
273log.debug('Processing complete', {
274 itemsProcessed: count,
275 module: 'my-command',
 
 
 
 
 
 
276});
 
 
 
 
 
 
277```
278 
279### Error Context
280```typescript
281// ✅ GOOD - Include context in error handling
282try {
283 await operation();
284} catch (error) {
285 handleAndLogError(error, {
286 module: 'config-set',
287 command: 'cm:config:set',
288 flags: { region: 'eu' },
289 });
290}
291```
292 
293## Multi-Topic Commands
294 
295### Nested Command Structure
296```typescript
297// File: src/commands/config/show.ts
298export default class ShowConfigCommand extends Command {
299 static description = 'Show current configuration';
300 static examples = ['csdx config:show'];
301 async run(): Promise<void> { }
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
302}
303 
304// File: src/commands/config/set.ts
305export default class SetConfigCommand extends Command {
306 static description = 'Set configuration values';
307 static examples = ['csdx config:set --region eu'];
308 async run(): Promise<void> { }
309}
 
310 
311// Generated commands:
312// - cm:config:show
313// - cm:config:set
 
 
 
 
 
 
 
 
 
 
 
 
314```
315 
 
 
 
 
 
 
 
 
 
 
316## Best Practices
317 
318### Command Organization
319```typescript
320// ✅ GOOD - Well-organized command
321export default class MyCommand extends Command {
322 static description = 'Clear, concise description';
 
 
 
323
324 static flags: FlagInput = {
325 // Define all flags
326 };
 
 
 
 
 
 
 
 
 
 
327
328 static examples = [
329 'csdx my:command',
330 'csdx my:command --flag value',
331 ];
 
 
 
 
 
 
332
333 async run(): Promise<void> {
334 try {
335 const { flags } = await this.parse(MyCommand);
336 await this.execute(flags);
337 } catch (error) {
338 handleAndLogError(error, { module: 'my-command' });
339 }
340 }
341
342 private async execute(flags: Flags<typeof MyCommand>): Promise<void> {
343 // Implementation
344 }
345}
346```
347 
348### Clear Help Text
349- Write description as action-oriented statement
350- Provide multiple examples for common use cases
351- Document each flag with clear description
352- Show output format or examples of results
353 
@@ −1 +1 @@
11 ---
2−description: 'Testing patterns and TDD workflow'
3−globs: ['**/test/**/*.ts', '**/test/**/*.js', '**/__tests__/**/*.ts', '**/*.spec.ts', '**/*.test.ts']
4−alwaysApply: true
2+description: 'OCLIF command development patterns and CLI best practices'
3+globs: ['**/commands/**/*.ts', '**/base-command.ts']
4+alwaysApply: false
55 ---
66  
7−# Testing Standards
7+# OCLIF Command Standards
88  
9−## Framework Stack
9+## Command Structure
1010  
11−### Primary Testing Tools
12−- **Mocha** - Test runner (used across all packages)
13−- **Chai** - Assertion library
14−- **@oclif/test** - Command testing support (for plugin packages)
11+### Standard Command Pattern
12+```typescript
13+// ✅ GOOD - Standard command structure
14+import { Command } from '@contentstack/cli-command';
15+import { cliux, flags, FlagInput, handleAndLogError } from '@contentstack/cli-utilities';
1516  
16−### Test Setup
17−- TypeScript compilation via ts-node/register
18−- Source map support for stack traces
19−- Global test timeout: 30 seconds (configurable per package)
17+export default class ConfigSetCommand extends Command {
18+ static description = 'Set CLI configuration values';
19+
20+ static flags: FlagInput = {
21+ region: flags.string({
22+ char: 'r',
23+ description: 'Set region (us/eu)',
24+ }),
25+ alias: flags.string({
26+ char: 'a',
27+ description: 'Configuration alias',
28+ }),
29+ };
30+
31+ static examples = [
32+ 'csdx config:set --region eu',
33+ 'csdx config:set --region us --alias default',
34+ ];
35+
36+ async run(): Promise<void> {
37+ try {
38+ const { flags: configFlags } = await this.parse(ConfigSetCommand);
39+ // Command logic here
40+ } catch (error) {
41+ handleAndLogError(error, { module: 'config-set' });
42+ }
43+ }
44+}
45+```
2046  
21−## Test File Patterns
47+## Base Classes
2248  
23−### Naming Conventions
24−- **Primary**: `*.test.ts` (standard pattern across all packages)
25−- **Location**: `test/unit/**/*.test.ts` (most packages)
49+### Command Base Class
50+```typescript
51+// ✅ GOOD - Extend Command from @contentstack/cli-command
52+import { Command } from '@contentstack/cli-command';
2653  
27−### Directory Structure
54+export default class MyCommand extends Command {
55+ async run(): Promise<void> {
56+ // Command implementation
57+ }
58+}
2859 ```
29−packages/*/
30−├── test/
31−│ └── unit/
32−│ ├── commands/ # Command-specific tests
33−│ ├── services/ # Service/business logic tests
34−│ └── utils/ # Utility function tests
35−└── src/ # Source code
36− ├── commands/ # CLI commands
37− ├── services/ # Business logic
38− └── utils/ # Utilities
39−```
4060  
41−## Mocha Configuration
61+### Custom Base Classes
62+```typescript
63+// ✅ GOOD - Create custom base classes for shared functionality
64+export abstract class BaseCommand<T extends typeof Command> extends Command {
65+ protected contextDetails = {
66+ command: this.id || 'unknown',
67+ };
4268  
43−### Standard Setup (.mocharc.json)
44−```json
45−{
46− "require": [
47− "test/helpers/init.js",
48− "ts-node/register",
49− "source-map-support/register"
50− ],
51− "recursive": true,
52− "timeout": 30000,
53− "spec": "test/**/*.test.ts"
69+ async init(): Promise<void> {
70+ await super.init();
71+ log.debug('Command initialized', this.contextDetails);
72+ }
5473 }
5574 ```
5675  
57−### TypeScript Compilation
76+## OCLIF Configuration
77+ 
78+### Package.json Setup
5879 ```json
59−// package.json scripts
6080 {
61− "test": "mocha \"test/unit/**/*.test.ts\"",
62− "test:coverage": "nyc mocha \"test/unit/**/*.test.ts\""
81+ "oclif": {
82+ "commands": "./lib/commands",
83+ "bin": "csdx",
84+ "topicSeparator": ":"
85+ }
6386 }
6487 ```
6588  
66−## Test Structure
89+### Command Topics
90+- All commands use `cm` topic: `cm:config:set`, `cm:auth:login`
91+- Built commands live in `lib/commands` (compiled from `src/commands`)
92+- Commands use nested directories: `src/commands/config/set.ts` → `cm:config:set`
6793  
68−### Standard Test Pattern
94+### Command Naming
95+- **Topic hierarchy**: `config/remove/proxy.ts` → `cm:config:remove:proxy`
96+- **Descriptive names**: Use verb-noun pattern (`set`, `remove`, `show`)
97+- **Grouping**: Related commands share parent topics
98+ 
99+## Flag Management
100+ 
101+### Flag Definition Patterns
69102 ```typescript
70−// ✅ GOOD - Comprehensive test structure
71−describe('ConfigService', () => {
72− let service: ConfigService;
103+// ✅ GOOD - Define flags clearly
104+static flags: FlagInput = {
105+ 'stack-api-key': flags.string({
106+ char: 'k',
107+ description: 'Stack API key',
108+ required: false,
109+ }),
110+ region: flags.string({
111+ char: 'r',
112+ description: 'Set region',
113+ options: ['us', 'eu'],
114+ }),
115+ verbose: flags.boolean({
116+ char: 'v',
117+ description: 'Show verbose output',
118+ default: false,
119+ }),
120+};
121+```
73122  
74− beforeEach(() => {
75− service = new ConfigService();
76− });
123+### Flag Parsing
124+```typescript
125+// ✅ GOOD - Parse and validate flags
126+async run(): Promise<void> {
127+ const { flags: parsedFlags } = await this.parse(MyCommand);
128+
129+ // Validate flag combinations
130+ if (!parsedFlags['stack-api-key'] && !parsedFlags.alias) {
131+ this.error('Either --stack-api-key or --alias is required');
132+ }
133+
134+ // Use parsed flags
135+ const region = parsedFlags.region || 'us';
136+}
137+```
77138  
78− describe('loadConfig()', () => {
79− it('should load configuration successfully', async () => {
80− // Arrange
81− const expectedConfig = { region: 'us' };
82−
83− // Act
84− const result = await service.loadConfig();
85−
86− // Assert
87− expect(result).to.deep.equal(expectedConfig);
88− });
139+## Error Handling
89140  
90− it('should handle missing configuration', async () => {
91− // Arrange & Act & Assert
92− await expect(service.loadConfig()).to.be.rejectedWith('Config not found');
93− });
94− });
95−});
141+### Standard Error Pattern
142+```typescript
143+// ✅ GOOD - Use handleAndLogError from utilities
144+try {
145+ await this.executeCommand();
146+} catch (error) {
147+ handleAndLogError(error, { module: 'my-command' });
148+}
96149 ```
97150  
98−### Async/Await Pattern
151+### User-Friendly Messages
99152 ```typescript
100−// ✅ GOOD - Use async/await in tests
101−it('should process data asynchronously', async () => {
102− const result = await service.processAsync();
103− expect(result).to.exist;
104−});
153+// ✅ GOOD - Clear user feedback
154+import { cliux } from '@contentstack/cli-utilities';
105155  
106−// ✅ GOOD - Explicit Promise handling
107−it('should return a promise', () => {
108− return service.asyncMethod().then(result => {
109− expect(result).to.be.true;
110− });
111−});
156+// Success message
157+cliux.success('Configuration updated successfully', { color: 'green' });
158+ 
159+// Error message
160+cliux.error('Invalid region specified', { color: 'red' });
161+ 
162+// Info message
163+cliux.print('Setting region to eu', { color: 'blue' });
112164 ```
113165  
114−## Mocking Patterns
166+## Validation Patterns
115167  
116−### Class Mocking
168+### Early Validation
117169 ```typescript
118−// ✅ GOOD - Mock class dependencies
119−class MockConfigService {
120− async loadConfig() {
121− return { region: 'us' };
170+// ✅ GOOD - Validate flags early
171+async run(): Promise<void> {
172+ const { flags } = await this.parse(MyCommand);
173+
174+ // Validate required flags
175+ if (!flags.region) {
176+ this.error('--region is required');
122177 }
178+
179+ // Validate flag values
180+ if (!['us', 'eu'].includes(flags.region)) {
181+ this.error('Region must be "us" or "eu"');
182+ }
183+
184+ // Proceed with validated input
123185 }
186+```
124187  
125−it('should use mocked service', async () => {
126− const mockService = new MockConfigService();
127− const result = await mockService.loadConfig();
128− expect(result.region).to.equal('us');
129−});
188+## Progress and Logging
189+ 
190+### User Feedback
191+```typescript
192+// ✅ GOOD - Provide user feedback
193+import { log, cliux } from '@contentstack/cli-utilities';
194+ 
195+// Regular logging
196+this.log('Starting configuration update...');
197+ 
198+// Debug logging
199+log.debug('Detailed operation information', { context: 'data' });
200+ 
201+// Status messages
202+cliux.print('Processing...', { color: 'blue' });
130203 ```
131204  
132−### Function Stubs
205+### Progress Indication
133206 ```typescript
134−// ✅ GOOD - Stub module functions if needed
135−beforeEach(() => {
136− // Stub file system operations
137− // Stub network calls
138−});
207+// ✅ GOOD - Show progress for long operations
208+cliux.print('Processing items...', { color: 'blue' });
209+let count = 0;
210+for (const item of items) {
211+ await this.processItem(item);
212+ count++;
213+ cliux.print(`Processed ${count}/${items.length} items`, { color: 'blue' });
214+}
215+```
139216  
140−afterEach(() => {
141− // Restore original implementations
142−});
217+## Command Delegation
218+ 
219+### Service Layer Separation
220+```typescript
221+// ✅ GOOD - Commands orchestrate, services implement
222+async run(): Promise<void> {
223+ try {
224+ const { flags } = await this.parse(MyCommand);
225+ const config = this.buildConfig(flags);
226+ const service = new ConfigService(config);
227+
228+ await service.execute();
229+ cliux.success('Operation completed successfully');
230+ } catch (error) {
231+ this.handleError(error);
232+ }
233+}
143234 ```
144235  
145−## Command Testing
236+## Testing Commands
146237  
147−### OCLIF Test Pattern
238+### OCLIF Test Support
148239 ```typescript
149−// ✅ GOOD - Test commands with @oclif/test
240+// ✅ GOOD - Use @oclif/test for command testing
150241 import { test } from '@oclif/test';
151242  
152−describe('cm:config:region', () => {
243+describe('cm:config:set', () => {
153244 test
154245 .stdout()
155− .command(['cm:config:region', '--help'])
156− .it('shows help message', ctx => {
157− expect(ctx.stdout).to.contain('Display region');
246+ .command(['cm:config:set', '--help'])
247+ .it('shows help', ctx => {
248+ expect(ctx.stdout).to.contain('Set CLI configuration');
158249 });
159250  
160251 test
161252 .stdout()
162− .command(['cm:config:region'])
163− .it('shows current region', ctx => {
164− expect(ctx.stdout).to.contain('us');
253+ .command(['cm:config:set', '--region', 'eu'])
254+ .it('sets region to eu', ctx => {
255+ expect(ctx.stdout).to.contain('success');
165256 });
166257 });
167258 ```
168259  
169−### Command Flag Testing
260+## Log Integration
261+ 
262+### Debug Logging
170263 ```typescript
171−// ✅ GOOD - Test command flags and arguments
172−describe('cm:config:set', () => {
173− test
174− .command(['cm:config:set', '--help'])
175− .it('shows usage information');
264+// ✅ GOOD - Use structured debug logging
265+import { log } from '@contentstack/cli-utilities';
176266  
177− test
178− .command(['cm:config:set', '--region', 'eu'])
179− .it('sets region to eu');
267+log.debug('Command started', {
268+ command: this.id,
269+ flags: this.flags,
270+ timestamp: new Date().toISOString(),
180271 });
181−```
182272  
183−## Error Testing
184− 
185−### Error Handling
186−```typescript
187−// ✅ GOOD - Test error scenarios
188−it('should throw ValidationError on invalid input', async () => {
189− const invalidInput = '';
190− await expect(service.validate(invalidInput))
191− .to.be.rejectedWith('Invalid input');
273+log.debug('Processing complete', {
274+ itemsProcessed: count,
275+ module: 'my-command',
192276 });
193− 
194−it('should handle network errors gracefully', async () => {
195− // Mock network failure
196− const result = await service.fetchWithRetry();
197− expect(result).to.be.null;
198−});
199277 ```
200278  
201−### Error Types
279+### Error Context
202280 ```typescript
203−// ✅ GOOD - Test specific error types
204−it('should throw appropriate error', async () => {
205− try {
206− await service.failingOperation();
207− } catch (error) {
208− expect(error).to.be.instanceof(ValidationError);
209− expect(error.code).to.equal('INVALID_CONFIG');
210− }
211−});
281+// ✅ GOOD - Include context in error handling
282+try {
283+ await operation();
284+} catch (error) {
285+ handleAndLogError(error, {
286+ module: 'config-set',
287+ command: 'cm:config:set',
288+ flags: { region: 'eu' },
289+ });
290+}
212291 ```
213292  
214−## Test Data Management
293+## Multi-Topic Commands
215294  
216−### Mock Data Organization
295+### Nested Command Structure
217296 ```typescript
218−// ✅ GOOD - Organize test data
219−const mockData = {
220− validConfig: {
221− region: 'us',
222− timeout: 30000,
223− },
224− invalidConfig: {
225− region: '',
226− },
227− users: [
228− { email: 'user1@example.com', name: 'User 1' },
229− { email: 'user2@example.com', name: 'User 2' },
230− ],
231−};
232−```
233− 
234−### Test Helpers
235−```typescript
236−// ✅ GOOD - Create reusable test utilities
237−export function createMockConfig(overrides?: Partial<Config>): Config {
238− return {
239− region: 'us',
240− timeout: 30000,
241− ...overrides,
242− };
297+// File: src/commands/config/show.ts
298+export default class ShowConfigCommand extends Command {
299+ static description = 'Show current configuration';
300+ static examples = ['csdx config:show'];
301+ async run(): Promise<void> { }
243302 }
244303  
245−export function createMockService(
246− config: Config = createMockConfig()
247−): ConfigService {
248− return new ConfigService(config);
304+// File: src/commands/config/set.ts
305+export default class SetConfigCommand extends Command {
306+ static description = 'Set configuration values';
307+ static examples = ['csdx config:set --region eu'];
308+ async run(): Promise<void> { }
249309 }
250−```
251310  
252−## Coverage
253− 
254−### Coverage Goals
255−- **Team aspiration**: 80% minimum coverage
256−- **Current enforcement**: Applied consistently across packages
257−- **Focus areas**: Critical business logic and error paths
258− 
259−### Coverage Reporting
260−```bash
261−# Run tests with coverage
262−pnpm test:coverage
263− 
264−# Coverage reports generated in:
265−# - coverage/index.html (HTML report)
266−# - coverage/coverage-summary.json (JSON report)
311+// Generated commands:
312+// - cm:config:show
313+// - cm:config:set
267314 ```
268315  
269−## Critical Testing Rules
270− 
271−- **No real external calls** - Mock all dependencies
272−- **Test both success and failure paths** - Cover error scenarios completely
273−- **One assertion per test** - Focus each test on single behavior
274−- **Use descriptive test names** - Test name should explain what's tested
275−- **Arrange-Act-Assert** - Follow AAA pattern consistently
276−- **Test command validation** - Verify flag validation and error messages
277−- **Clean up after tests** - Restore any mocked state
278− 
279316 ## Best Practices
280317  
281−### Test Organization
318+### Command Organization
282319 ```typescript
283−// ✅ GOOD - Organize related tests
284−describe('AuthCommand', () => {
285− describe('login', () => {
286− it('should authenticate user');
287− it('should save token');
288− });
320+// ✅ GOOD - Well-organized command
321+export default class MyCommand extends Command {
322+ static description = 'Clear, concise description';
289323
290− describe('logout', () => {
291− it('should clear token');
292− it('should reset config');
293− });
294−});
295−```
296− 
297−### Async Test Patterns
298−```typescript
299−// ✅ GOOD - Handle async operations properly
300−it('should complete async operation', async () => {
301− const promise = service.asyncMethod();
302− expect(promise).to.be.instanceof(Promise);
324+ static flags: FlagInput = {
325+ // Define all flags
326+ };
303327
304− const result = await promise;
305− expect(result).to.equal('success');
306−});
307−```
308− 
309−### Isolation
310−```typescript
311−// ✅ GOOD - Ensure test isolation
312−describe('ConfigService', () => {
313− let service: ConfigService;
328+ static examples = [
329+ 'csdx my:command',
330+ 'csdx my:command --flag value',
331+ ];
314332
315− beforeEach(() => {
316− service = new ConfigService();
317− });
333+ async run(): Promise<void> {
334+ try {
335+ const { flags } = await this.parse(MyCommand);
336+ await this.execute(flags);
337+ } catch (error) {
338+ handleAndLogError(error, { module: 'my-command' });
339+ }
340+ }
318341
319− afterEach(() => {
320− // Clean up resources
321− });
322−});
342+ private async execute(flags: Flags<typeof MyCommand>): Promise<void> {
343+ // Implementation
344+ }
345+}
323346 ```
347+ 
348+### Clear Help Text
349+- Write description as action-oriented statement
350+- Provide multiple examples for common use cases
351+- Document each flag with clear description
352+- Show output format or examples of results
324353  
RuleStack

Built by

Kynth Studio

Directory

Configs
Stacks
Compare formats
Diff two configs
Best AGENTS.md examples

Formats

AGENTS.md
CLAUDE.md
Cursor rules
Copilot instructions

Reference

Read API
Corpus health
Privacy Policy
Terms

RuleStack

RuleStack

Built by

Kynth Studio

Directory

Configs
Stacks
Compare formats
Diff two configs
Best AGENTS.md examples

Formats

AGENTS.md
CLAUDE.md
Cursor rules
Copilot instructions

Reference

Read API
Corpus health
Privacy Policy
Terms

RuleStack

RuleStack

Built by

Kynth Studio

Directory

Configs
Stacks
Compare formats
Diff two configs
Best AGENTS.md examples

Formats

AGENTS.md
CLAUDE.md
Cursor rules
Copilot instructions

Reference

Read API
Corpus health
Privacy Policy
Terms

RuleStack