Cursor rule
.cursor/rules/testing.mdcTesting patterns and TDD workflow
Cursor rules
Quality
89/100
Scores the file, not the repository.Length
891 words
37 headings · 17 code blocksRepository
14
— · pushed 0 days agoLast changed
3 days ago
First indexed 3 days ago.1234567# Testing Standards89## Framework Stack1011### Primary Testing Tools12- **Mocha** - Test runner (used across all packages)13- **Chai** - Assertion library14- **@oclif/test** - Command testing support (for plugin packages)1516### Test Setup17- TypeScript compilation via ts-node/register18- Source map support for stack traces19- Global test timeout: 30 seconds (configurable per package)2021## Test File Patterns2223### Naming Conventions24- **Primary**: `*.test.ts` (standard pattern across all packages)25- **Location**: `test/unit/**/*.test.ts` (most packages)2627### Directory Structure28```29packages/*/30├── test/31│ └── unit/32│ ├── commands/ # Command-specific tests33│ ├── services/ # Service/business logic tests34│ └── utils/ # Utility function tests35└── src/ # Source code36 ├── commands/ # CLI commands37 ├── services/ # Business logic38 └── utils/ # Utilities39```4041## Mocha Configuration4243### Standard Setup (.mocharc.json)44```json45{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```5657### TypeScript Compilation58```json59// package.json scripts60{61 "test": "mocha \"test/unit/**/*.test.ts\"",62 "test:coverage": "nyc mocha \"test/unit/**/*.test.ts\""63}64```6566## Test Structure6768### Standard Test Pattern69```typescript70// ✅ GOOD - Comprehensive test structure71describe('ConfigService', () => {72 let service: ConfigService;7374 beforeEach(() => {75 service = new ConfigService();76 });7778 describe('loadConfig()', () => {79 it('should load configuration successfully', async () => {80 // Arrange81 const expectedConfig = { region: 'us' };8283 // Act84 const result = await service.loadConfig();8586 // Assert87 expect(result).to.deep.equal(expectedConfig);88 });8990 it('should handle missing configuration', async () => {91 // Arrange & Act & Assert92 await expect(service.loadConfig()).to.be.rejectedWith('Config not found');93 });94 });95});96```9798### Async/Await Pattern99```typescript100// ✅ GOOD - Use async/await in tests101it('should process data asynchronously', async () => {102 const result = await service.processAsync();103 expect(result).to.exist;104});105106// ✅ GOOD - Explicit Promise handling107it('should return a promise', () => {108 return service.asyncMethod().then(result => {109 expect(result).to.be.true;110 });111});112```113114## Mocking Patterns115116### Class Mocking117```typescript118// ✅ GOOD - Mock class dependencies119class MockConfigService {120 async loadConfig() {121 return { region: 'us' };122 }123}124125it('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```131132### Function Stubs133```typescript134// ✅ GOOD - Stub module functions if needed135beforeEach(() => {136 // Stub file system operations137 // Stub network calls138});139140afterEach(() => {141 // Restore original implementations142});143```144145## Command Testing146147### OCLIF Test Pattern148```typescript149// ✅ GOOD - Test commands with @oclif/test150import { test } from '@oclif/test';151152describe('cm:config:region', () => {153 test154 .stdout()155 .command(['cm:config:region', '--help'])156 .it('shows help message', ctx => {157 expect(ctx.stdout).to.contain('Display region');158 });159160 test161 .stdout()162 .command(['cm:config:region'])163 .it('shows current region', ctx => {164 expect(ctx.stdout).to.contain('us');165 });166});167```168169### Command Flag Testing170```typescript171// ✅ GOOD - Test command flags and arguments172describe('cm:config:set', () => {173 test174 .command(['cm:config:set', '--help'])175 .it('shows usage information');176177 test178 .command(['cm:config:set', '--region', 'eu'])179 .it('sets region to eu');180});181```182183## Error Testing184185### Error Handling186```typescript187// ✅ GOOD - Test error scenarios188it('should throw ValidationError on invalid input', async () => {189 const invalidInput = '';190 await expect(service.validate(invalidInput))191 .to.be.rejectedWith('Invalid input');192});193194it('should handle network errors gracefully', async () => {195 // Mock network failure196 const result = await service.fetchWithRetry();197 expect(result).to.be.null;198});199```200201### Error Types202```typescript203// ✅ GOOD - Test specific error types204it('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```213214## Test Data Management215216### Mock Data Organization217```typescript218// ✅ GOOD - Organize test data219const 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```233234### Test Helpers235```typescript236// ✅ GOOD - Create reusable test utilities237export function createMockConfig(overrides?: Partial<Config>): Config {238 return {239 region: 'us',240 timeout: 30000,241 ...overrides,242 };243}244245export function createMockService(246 config: Config = createMockConfig()247): ConfigService {248 return new ConfigService(config);249}250```251252## Coverage253254### Coverage Goals255- **Team aspiration**: 80% minimum coverage256- **Current enforcement**: Applied consistently across packages257- **Focus areas**: Critical business logic and error paths258259### Coverage Reporting260```bash261# Run tests with coverage262pnpm test:coverage263264# Coverage reports generated in:265# - coverage/index.html (HTML report)266# - coverage/coverage-summary.json (JSON report)267```268269## Critical Testing Rules270271- **No real external calls** - Mock all dependencies272- **Test both success and failure paths** - Cover error scenarios completely273- **One assertion per test** - Focus each test on single behavior274- **Use descriptive test names** - Test name should explain what's tested275- **Arrange-Act-Assert** - Follow AAA pattern consistently276- **Test command validation** - Verify flag validation and error messages277- **Clean up after tests** - Restore any mocked state278279## Best Practices280281### Test Organization282```typescript283// ✅ GOOD - Organize related tests284describe('AuthCommand', () => {285 describe('login', () => {286 it('should authenticate user');287 it('should save token');288 });289290 describe('logout', () => {291 it('should clear token');292 it('should reset config');293 });294});295```296297### Async Test Patterns298```typescript299// ✅ GOOD - Handle async operations properly300it('should complete async operation', async () => {301 const promise = service.asyncMethod();302 expect(promise).to.be.instanceof(Promise);303304 const result = await promise;305 expect(result).to.equal('success');306});307```308309### Isolation310```typescript311// ✅ GOOD - Ensure test isolation312describe('ConfigService', () => {313 let service: ConfigService;314315 beforeEach(() => {316 service = new ConfigService();317 });318319 afterEach(() => {320 // Clean up resources321 });322});323```324
Also in contentstack/cli
Diff this repo’s formatsOne repository carrying more than one format is the comparison this product exists for: does anyone actually write different content in each file, or is one a copy of the other?
| Repository | Format | Stack | Covers | Score | Changed |
|---|---|---|---|---|---|
| contentstack/cli.cursor/rules/contentstack-core.mdc · 14 | Cursor rules | buildteststylearch+3 | 69/100 | 3 days ago | |
| contentstack/cli.cursor/rules/oclif-commands.mdc · 14 | Cursor rules | setupteststylearch | 74/100 | 3 days ago | |
| contentstack/cli.cursor/rules/typescript.mdc · 14 | Cursor rules | stylearchtypessecurity+1 | 70/100 | 3 days ago |
Similar configs
Same format, overlapping stack, ranked by quality.
| Repository | Format | Stack | Covers | Score | Changed |
|---|---|---|---|---|---|
| hiromaily/go-crypto-wallet.cursor/rules/typescript.mdc · 126 | Cursor rules | setupbuildtestlint-format+6 | 100/100 | 3 days ago | |
| TechSquidTV/Hermes.cursor/rules/10-hermes-api.mdc · 45 | Cursor rules | testlint-formatstylearch+5 | 100/100 | 3 days ago | |
| markstev/mark-starter.cursor/rules/frontend.mdc · 0 | Cursor rules | setuptestlint-formatstyle+6 | 99/100 | 3 days ago | |
| Allymahmoud/case-intake-platform.cursor/rules/frontend.mdc · 0 | Cursor rules | setuptestlint-formatstyle+7 | 99/100 | 3 days ago | |
| dodgecfr/combatfilms-webapp.cursor/rules/frontend.mdc · 0 | Cursor rules | setuptestlint-formatstyle+7 | 99/100 | 3 days ago | |
| deifos/clipmira-subtitles.cursor/rules/frontend.mdc · 1 | Cursor rules | setuptestlint-formatstyle+7 | 99/100 | 3 days ago | |
| TechSquidTV/Hermes.cursor/rules/20-hermes-api-tests.mdc · 45 | Cursor rules | teststyletesting-strategysecurity+3 | 97/100 | 3 days ago | |
| langflow-ai/langflow.cursor/rules/docs_development.mdc · 153k | Cursor rules | setupbuildtestlint-format+7 | 97/100 | 3 days ago |
