@keplog/cli 0.2.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/LICENSE +21 -0
- package/README.md +495 -0
- package/bin/keplog +2 -0
- package/dist/commands/delete.d.ts +3 -0
- package/dist/commands/delete.d.ts.map +1 -0
- package/dist/commands/delete.js +158 -0
- package/dist/commands/delete.js.map +1 -0
- package/dist/commands/init.d.ts +3 -0
- package/dist/commands/init.d.ts.map +1 -0
- package/dist/commands/init.js +131 -0
- package/dist/commands/init.js.map +1 -0
- package/dist/commands/issues.d.ts +3 -0
- package/dist/commands/issues.d.ts.map +1 -0
- package/dist/commands/issues.js +543 -0
- package/dist/commands/issues.js.map +1 -0
- package/dist/commands/list.d.ts +3 -0
- package/dist/commands/list.d.ts.map +1 -0
- package/dist/commands/list.js +104 -0
- package/dist/commands/list.js.map +1 -0
- package/dist/commands/releases.d.ts +3 -0
- package/dist/commands/releases.d.ts.map +1 -0
- package/dist/commands/releases.js +100 -0
- package/dist/commands/releases.js.map +1 -0
- package/dist/commands/upload.d.ts +3 -0
- package/dist/commands/upload.d.ts.map +1 -0
- package/dist/commands/upload.js +76 -0
- package/dist/commands/upload.js.map +1 -0
- package/dist/index.d.ts +3 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +28 -0
- package/dist/index.js.map +1 -0
- package/dist/lib/config.d.ts +57 -0
- package/dist/lib/config.d.ts.map +1 -0
- package/dist/lib/config.js +155 -0
- package/dist/lib/config.js.map +1 -0
- package/dist/lib/uploader.d.ts +11 -0
- package/dist/lib/uploader.d.ts.map +1 -0
- package/dist/lib/uploader.js +171 -0
- package/dist/lib/uploader.js.map +1 -0
- package/jest.config.js +16 -0
- package/package.json +58 -0
- package/src/commands/delete.ts +186 -0
- package/src/commands/init.ts +137 -0
- package/src/commands/issues.ts +695 -0
- package/src/commands/list.ts +124 -0
- package/src/commands/releases.ts +122 -0
- package/src/commands/upload.ts +76 -0
- package/src/index.ts +31 -0
- package/src/lib/config.ts +138 -0
- package/src/lib/uploader.ts +168 -0
- package/tests/README.md +380 -0
- package/tests/config.test.ts +397 -0
- package/tests/uploader.test.ts +524 -0
- package/tsconfig.json +20 -0
package/tests/README.md
ADDED
|
@@ -0,0 +1,380 @@
|
|
|
1
|
+
# Keplog CLI Test Suite
|
|
2
|
+
|
|
3
|
+
Comprehensive unit tests for the official Keplog CLI.
|
|
4
|
+
|
|
5
|
+
## Test Overview
|
|
6
|
+
|
|
7
|
+
### Test Coverage
|
|
8
|
+
|
|
9
|
+
- **Total Tests**: 53 passing
|
|
10
|
+
- **Test Suites**: 2 (config.test.ts, uploader.test.ts)
|
|
11
|
+
- **Core Library Coverage**: 96%+
|
|
12
|
+
- `lib/config.ts`: 97.43% coverage
|
|
13
|
+
- `lib/uploader.ts`: 95.5% coverage
|
|
14
|
+
|
|
15
|
+
### Test Files
|
|
16
|
+
|
|
17
|
+
#### `config.test.ts` (31 tests)
|
|
18
|
+
|
|
19
|
+
Tests for the `ConfigManager` class that handles CLI configuration.
|
|
20
|
+
|
|
21
|
+
**Coverage Areas:**
|
|
22
|
+
- ✅ Local config file operations (.keplog.json)
|
|
23
|
+
- ✅ Global config file operations (~/.keplogrc)
|
|
24
|
+
- ✅ Config file discovery (walks up directory tree)
|
|
25
|
+
- ✅ Priority system (local > global > environment variables)
|
|
26
|
+
- ✅ Environment variable fallbacks
|
|
27
|
+
- ✅ Default values
|
|
28
|
+
- ✅ Error handling (malformed JSON, missing files)
|
|
29
|
+
- ✅ Edge cases (empty strings, partial configs)
|
|
30
|
+
|
|
31
|
+
**Key Test Scenarios:**
|
|
32
|
+
```typescript
|
|
33
|
+
// Config priority
|
|
34
|
+
ConfigManager.getConfig() // local > global > env vars
|
|
35
|
+
|
|
36
|
+
// Directory tree walking
|
|
37
|
+
project/
|
|
38
|
+
├── deep/
|
|
39
|
+
│ └── nested/
|
|
40
|
+
│ └── current-dir/ <- Finds .keplog.json from root
|
|
41
|
+
└── .keplog.json
|
|
42
|
+
|
|
43
|
+
// Environment variable fallback
|
|
44
|
+
KEPLOG_PROJECT_ID=env-project // Used when file config is empty
|
|
45
|
+
KEPLOG_API_KEY=env-key
|
|
46
|
+
```
|
|
47
|
+
|
|
48
|
+
#### `uploader.test.ts` (22 tests)
|
|
49
|
+
|
|
50
|
+
Tests for the `uploadSourceMaps` function that uploads source maps to Keplog API.
|
|
51
|
+
|
|
52
|
+
**Coverage Areas:**
|
|
53
|
+
- ✅ File discovery with glob patterns
|
|
54
|
+
- ✅ Nested directory traversal
|
|
55
|
+
- ✅ Multiple file patterns
|
|
56
|
+
- ✅ Duplicate file removal
|
|
57
|
+
- ✅ .map file filtering
|
|
58
|
+
- ✅ HTTP API communication
|
|
59
|
+
- ✅ Request headers and authentication
|
|
60
|
+
- ✅ Form data creation
|
|
61
|
+
- ✅ Error handling (401, 404, network errors, timeouts)
|
|
62
|
+
- ✅ Connection errors (ECONNREFUSED, ENOTFOUND)
|
|
63
|
+
- ✅ Verbose mode output
|
|
64
|
+
- ✅ Edge cases (large file sets, custom API URLs)
|
|
65
|
+
|
|
66
|
+
**Key Test Scenarios:**
|
|
67
|
+
```typescript
|
|
68
|
+
// Glob pattern matching
|
|
69
|
+
uploadSourceMaps({
|
|
70
|
+
filePatterns: [
|
|
71
|
+
'dist/**/*.map', // Nested directories
|
|
72
|
+
'build/*.map', // Single directory
|
|
73
|
+
],
|
|
74
|
+
// ... other options
|
|
75
|
+
});
|
|
76
|
+
|
|
77
|
+
// Error handling
|
|
78
|
+
- 401 Unauthorized (invalid API key)
|
|
79
|
+
- 404 Not Found (project doesn't exist)
|
|
80
|
+
- Network errors
|
|
81
|
+
- Timeout errors
|
|
82
|
+
- Connection refused
|
|
83
|
+
- DNS resolution failures
|
|
84
|
+
```
|
|
85
|
+
|
|
86
|
+
## Running Tests
|
|
87
|
+
|
|
88
|
+
### Run All Tests
|
|
89
|
+
```bash
|
|
90
|
+
npm test
|
|
91
|
+
```
|
|
92
|
+
|
|
93
|
+
### Watch Mode (Re-run on Changes)
|
|
94
|
+
```bash
|
|
95
|
+
npm run test:watch
|
|
96
|
+
```
|
|
97
|
+
|
|
98
|
+
### Coverage Report
|
|
99
|
+
```bash
|
|
100
|
+
npm run test:coverage
|
|
101
|
+
```
|
|
102
|
+
|
|
103
|
+
### Verbose Output
|
|
104
|
+
```bash
|
|
105
|
+
npm run test:verbose
|
|
106
|
+
```
|
|
107
|
+
|
|
108
|
+
## Test Structure
|
|
109
|
+
|
|
110
|
+
### ConfigManager Tests
|
|
111
|
+
|
|
112
|
+
```
|
|
113
|
+
ConfigManager
|
|
114
|
+
├── writeLocalConfig
|
|
115
|
+
│ ├── should write config to local .keplog.json file
|
|
116
|
+
│ ├── should format config file with proper indentation
|
|
117
|
+
│ └── should overwrite existing config
|
|
118
|
+
├── writeGlobalConfig
|
|
119
|
+
│ └── should write config to global ~/.keplogrc file
|
|
120
|
+
├── readConfig
|
|
121
|
+
│ ├── should read local config when it exists
|
|
122
|
+
│ ├── should read global config when local does not exist
|
|
123
|
+
│ ├── should prefer local config over global config
|
|
124
|
+
│ ├── should return empty object when no config exists
|
|
125
|
+
│ ├── should handle malformed JSON gracefully
|
|
126
|
+
│ └── should walk up directory tree to find local config
|
|
127
|
+
├── getConfig
|
|
128
|
+
│ ├── should merge file config with environment variables
|
|
129
|
+
│ ├── should prioritize file config over environment variables
|
|
130
|
+
│ ├── should use environment variables when file config is empty
|
|
131
|
+
│ ├── should use default API URL when not specified
|
|
132
|
+
│ ├── should override default API URL with environment variable
|
|
133
|
+
│ └── should override environment API URL with file config
|
|
134
|
+
├── hasLocalConfig / hasGlobalConfig
|
|
135
|
+
│ ├── should return true when config exists
|
|
136
|
+
│ └── should return false when config does not exist
|
|
137
|
+
├── getLocalConfigPath
|
|
138
|
+
│ ├── should return config path when it exists
|
|
139
|
+
│ ├── should return null when config does not exist
|
|
140
|
+
│ └── should return parent directory config path
|
|
141
|
+
├── deleteLocalConfig / deleteGlobalConfig
|
|
142
|
+
│ ├── should delete config file
|
|
143
|
+
│ └── should not throw when config does not exist
|
|
144
|
+
└── edge cases
|
|
145
|
+
├── should handle partial config objects
|
|
146
|
+
├── should handle config with only optional fields
|
|
147
|
+
└── should handle empty string values
|
|
148
|
+
```
|
|
149
|
+
|
|
150
|
+
### Uploader Tests
|
|
151
|
+
|
|
152
|
+
```
|
|
153
|
+
uploadSourceMaps
|
|
154
|
+
├── file discovery
|
|
155
|
+
│ ├── should find source map files matching pattern
|
|
156
|
+
│ ├── should find nested source map files with glob pattern
|
|
157
|
+
│ ├── should handle multiple file patterns
|
|
158
|
+
│ ├── should remove duplicate files from multiple patterns
|
|
159
|
+
│ ├── should exit with error when no files found
|
|
160
|
+
│ └── should filter out non-.map files
|
|
161
|
+
├── API communication
|
|
162
|
+
│ ├── should send correct API request
|
|
163
|
+
│ ├── should include release in form data
|
|
164
|
+
│ ├── should handle successful upload
|
|
165
|
+
│ └── should exit with error when upload has errors
|
|
166
|
+
├── error handling
|
|
167
|
+
│ ├── should handle 401 authentication error
|
|
168
|
+
│ ├── should handle 404 project not found
|
|
169
|
+
│ ├── should handle network errors
|
|
170
|
+
│ ├── should handle timeout errors
|
|
171
|
+
│ ├── should handle server connection errors
|
|
172
|
+
│ └── should handle DNS resolution errors
|
|
173
|
+
├── verbose mode
|
|
174
|
+
│ ├── should display detailed information in verbose mode
|
|
175
|
+
│ └── should not display extra information when verbose is false
|
|
176
|
+
└── edge cases
|
|
177
|
+
├── should handle empty release string
|
|
178
|
+
├── should handle very large number of files
|
|
179
|
+
└── should handle custom API URL
|
|
180
|
+
```
|
|
181
|
+
|
|
182
|
+
## Testing Approach
|
|
183
|
+
|
|
184
|
+
### Unit Testing Strategy
|
|
185
|
+
|
|
186
|
+
1. **Isolation**: Each test runs in a temporary directory with clean state
|
|
187
|
+
2. **Mocking**: External dependencies (axios, process.exit) are mocked
|
|
188
|
+
3. **Coverage**: Aim for >95% code coverage on core modules
|
|
189
|
+
4. **Edge Cases**: Test boundary conditions and error paths
|
|
190
|
+
5. **Real Scenarios**: Test actual use cases developers will encounter
|
|
191
|
+
|
|
192
|
+
### Test Setup/Teardown
|
|
193
|
+
|
|
194
|
+
```typescript
|
|
195
|
+
beforeEach(() => {
|
|
196
|
+
// Create temporary test directory
|
|
197
|
+
testDir = fs.mkdtempSync(path.join(os.tmpdir(), 'keplog-test-'));
|
|
198
|
+
|
|
199
|
+
// Save original state
|
|
200
|
+
originalCwd = process.cwd();
|
|
201
|
+
originalEnv = { ...process.env };
|
|
202
|
+
|
|
203
|
+
// Clean environment
|
|
204
|
+
process.chdir(testDir);
|
|
205
|
+
delete process.env.KEPLOG_PROJECT_ID;
|
|
206
|
+
delete process.env.KEPLOG_API_KEY;
|
|
207
|
+
});
|
|
208
|
+
|
|
209
|
+
afterEach(() => {
|
|
210
|
+
// Restore original state
|
|
211
|
+
process.chdir(originalCwd);
|
|
212
|
+
process.env = originalEnv;
|
|
213
|
+
|
|
214
|
+
// Clean up test files
|
|
215
|
+
fs.rmSync(testDir, { recursive: true, force: true });
|
|
216
|
+
});
|
|
217
|
+
```
|
|
218
|
+
|
|
219
|
+
### Mocking Strategy
|
|
220
|
+
|
|
221
|
+
#### Axios Mocking
|
|
222
|
+
```typescript
|
|
223
|
+
import MockAdapter from 'axios-mock-adapter';
|
|
224
|
+
|
|
225
|
+
const mock = new MockAdapter(axios);
|
|
226
|
+
|
|
227
|
+
// Mock successful response
|
|
228
|
+
mock.onPost('/api/endpoint').reply(200, { data: 'response' });
|
|
229
|
+
|
|
230
|
+
// Mock error
|
|
231
|
+
mock.onPost('/api/endpoint').reply(404, { error: 'Not found' });
|
|
232
|
+
|
|
233
|
+
// Mock network error
|
|
234
|
+
mock.onPost('/api/endpoint').networkError();
|
|
235
|
+
```
|
|
236
|
+
|
|
237
|
+
#### Process Exit Mocking
|
|
238
|
+
```typescript
|
|
239
|
+
process.exit = jest.fn() as any;
|
|
240
|
+
|
|
241
|
+
// Test that exit was called
|
|
242
|
+
expect(process.exit).toHaveBeenCalledWith(1);
|
|
243
|
+
```
|
|
244
|
+
|
|
245
|
+
#### Console Output Suppression
|
|
246
|
+
```typescript
|
|
247
|
+
jest.spyOn(console, 'log').mockImplementation();
|
|
248
|
+
jest.spyOn(console, 'error').mockImplementation();
|
|
249
|
+
```
|
|
250
|
+
|
|
251
|
+
## Future Test Additions
|
|
252
|
+
|
|
253
|
+
### Planned Enhancements
|
|
254
|
+
|
|
255
|
+
1. **Integration Tests**
|
|
256
|
+
- End-to-end CLI command testing
|
|
257
|
+
- Test actual command execution
|
|
258
|
+
- Verify command-line argument parsing
|
|
259
|
+
|
|
260
|
+
2. **Command Tests**
|
|
261
|
+
- `keplog init` - Interactive configuration setup
|
|
262
|
+
- `keplog upload` - Source map upload workflow
|
|
263
|
+
- `keplog list` - List releases
|
|
264
|
+
- `keplog delete` - Delete releases
|
|
265
|
+
- `keplog releases` - Manage releases
|
|
266
|
+
|
|
267
|
+
3. **Error Recovery Tests**
|
|
268
|
+
- Partial upload failures
|
|
269
|
+
- Network interruption recovery
|
|
270
|
+
- Invalid configuration recovery
|
|
271
|
+
|
|
272
|
+
4. **Performance Tests**
|
|
273
|
+
- Large file upload performance
|
|
274
|
+
- Many files (1000+) handling
|
|
275
|
+
- Memory usage profiling
|
|
276
|
+
|
|
277
|
+
## Continuous Integration
|
|
278
|
+
|
|
279
|
+
### Running Tests in CI
|
|
280
|
+
|
|
281
|
+
```yaml
|
|
282
|
+
# GitHub Actions example
|
|
283
|
+
- name: Run tests
|
|
284
|
+
run: npm test
|
|
285
|
+
|
|
286
|
+
- name: Generate coverage report
|
|
287
|
+
run: npm run test:coverage
|
|
288
|
+
|
|
289
|
+
- name: Upload coverage to Codecov
|
|
290
|
+
uses: codecov/codecov-action@v3
|
|
291
|
+
```
|
|
292
|
+
|
|
293
|
+
### Test Quality Gates
|
|
294
|
+
|
|
295
|
+
- **Minimum Coverage**: 90% for core library modules
|
|
296
|
+
- **All Tests Must Pass**: No failing tests allowed in CI
|
|
297
|
+
- **No console warnings**: Tests should run cleanly
|
|
298
|
+
|
|
299
|
+
## Troubleshooting
|
|
300
|
+
|
|
301
|
+
### Common Issues
|
|
302
|
+
|
|
303
|
+
**Issue**: Tests fail with "Cannot find module"
|
|
304
|
+
```bash
|
|
305
|
+
# Solution: Rebuild TypeScript
|
|
306
|
+
npm run build
|
|
307
|
+
```
|
|
308
|
+
|
|
309
|
+
**Issue**: Permission errors on ~/.keplogrc
|
|
310
|
+
```bash
|
|
311
|
+
# Solution: Clean up global config before tests
|
|
312
|
+
rm ~/.keplogrc
|
|
313
|
+
```
|
|
314
|
+
|
|
315
|
+
**Issue**: Tests timeout
|
|
316
|
+
```bash
|
|
317
|
+
# Solution: Increase Jest timeout in jest.config.js
|
|
318
|
+
testTimeout: 30000 // 30 seconds
|
|
319
|
+
```
|
|
320
|
+
|
|
321
|
+
**Issue**: Path differences on macOS (/var vs /private/var)
|
|
322
|
+
```typescript
|
|
323
|
+
// Solution: Use fs.realpathSync() for path comparisons
|
|
324
|
+
const expectedPath = fs.realpathSync(path.join(testDir, '.keplog.json'));
|
|
325
|
+
```
|
|
326
|
+
|
|
327
|
+
## Contributing Tests
|
|
328
|
+
|
|
329
|
+
### Adding New Tests
|
|
330
|
+
|
|
331
|
+
1. Create test file in `tests/` directory
|
|
332
|
+
2. Import module under test
|
|
333
|
+
3. Write describe/it blocks
|
|
334
|
+
4. Ensure proper setup/teardown
|
|
335
|
+
5. Run tests: `npm test`
|
|
336
|
+
6. Check coverage: `npm run test:coverage`
|
|
337
|
+
|
|
338
|
+
### Test Naming Conventions
|
|
339
|
+
|
|
340
|
+
```typescript
|
|
341
|
+
describe('ClassName or functionName', () => {
|
|
342
|
+
describe('methodName or scenario', () => {
|
|
343
|
+
it('should do something specific', () => {
|
|
344
|
+
// Test implementation
|
|
345
|
+
});
|
|
346
|
+
});
|
|
347
|
+
});
|
|
348
|
+
```
|
|
349
|
+
|
|
350
|
+
### Test Best Practices
|
|
351
|
+
|
|
352
|
+
✅ **DO**:
|
|
353
|
+
- Write descriptive test names
|
|
354
|
+
- Test one thing per test
|
|
355
|
+
- Use beforeEach/afterEach for setup/cleanup
|
|
356
|
+
- Mock external dependencies
|
|
357
|
+
- Test edge cases and error paths
|
|
358
|
+
- Keep tests fast (<100ms per test)
|
|
359
|
+
|
|
360
|
+
❌ **DON'T**:
|
|
361
|
+
- Test implementation details
|
|
362
|
+
- Share state between tests
|
|
363
|
+
- Use real network requests
|
|
364
|
+
- Hardcode file paths
|
|
365
|
+
- Skip cleanup
|
|
366
|
+
|
|
367
|
+
## Test Metrics
|
|
368
|
+
|
|
369
|
+
Current Status (as of latest run):
|
|
370
|
+
- ✅ 53 tests passing
|
|
371
|
+
- ✅ 0 tests failing
|
|
372
|
+
- ✅ 96% average coverage on core modules
|
|
373
|
+
- ⏱️ ~1s total test execution time
|
|
374
|
+
|
|
375
|
+
---
|
|
376
|
+
|
|
377
|
+
**Test Suite Maintained By**: Keplog Team
|
|
378
|
+
**Last Updated**: December 2024
|
|
379
|
+
**Jest Version**: 30.2.0
|
|
380
|
+
**TypeScript Version**: 5.3.3
|