@skillsmith/mcp-server 0.1.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/dist/.tsbuildinfo +1 -0
- package/dist/src/__tests__/get-skill.test.d.ts +6 -0
- package/dist/src/__tests__/get-skill.test.d.ts.map +1 -0
- package/dist/src/__tests__/get-skill.test.js +88 -0
- package/dist/src/__tests__/get-skill.test.js.map +1 -0
- package/dist/src/__tests__/middleware/errorFormatter.test.d.ts +7 -0
- package/dist/src/__tests__/middleware/errorFormatter.test.d.ts.map +1 -0
- package/dist/src/__tests__/middleware/errorFormatter.test.js +304 -0
- package/dist/src/__tests__/middleware/errorFormatter.test.js.map +1 -0
- package/dist/src/__tests__/middleware/license.test.d.ts +7 -0
- package/dist/src/__tests__/middleware/license.test.d.ts.map +1 -0
- package/dist/src/__tests__/middleware/license.test.js +500 -0
- package/dist/src/__tests__/middleware/license.test.js.map +1 -0
- package/dist/src/__tests__/search.test.d.ts +6 -0
- package/dist/src/__tests__/search.test.d.ts.map +1 -0
- package/dist/src/__tests__/search.test.js +86 -0
- package/dist/src/__tests__/search.test.js.map +1 -0
- package/dist/src/__tests__/test-utils.d.ts +19 -0
- package/dist/src/__tests__/test-utils.d.ts.map +1 -0
- package/dist/src/__tests__/test-utils.js +87 -0
- package/dist/src/__tests__/test-utils.js.map +1 -0
- package/dist/src/context/index.d.ts +19 -0
- package/dist/src/context/index.d.ts.map +1 -0
- package/dist/src/context/index.js +25 -0
- package/dist/src/context/index.js.map +1 -0
- package/dist/src/context/project-detector.d.ts +145 -0
- package/dist/src/context/project-detector.d.ts.map +1 -0
- package/dist/src/context/project-detector.js +321 -0
- package/dist/src/context/project-detector.js.map +1 -0
- package/dist/src/context.d.ts +100 -0
- package/dist/src/context.d.ts.map +1 -0
- package/dist/src/context.js +157 -0
- package/dist/src/context.js.map +1 -0
- package/dist/src/core-shim.d.ts +7 -0
- package/dist/src/core-shim.d.ts.map +1 -0
- package/dist/src/core-shim.js +9 -0
- package/dist/src/core-shim.js.map +1 -0
- package/dist/src/health/healthCheck.d.ts +88 -0
- package/dist/src/health/healthCheck.d.ts.map +1 -0
- package/dist/src/health/healthCheck.js +117 -0
- package/dist/src/health/healthCheck.js.map +1 -0
- package/dist/src/health/index.d.ts +21 -0
- package/dist/src/health/index.d.ts.map +1 -0
- package/dist/src/health/index.js +21 -0
- package/dist/src/health/index.js.map +1 -0
- package/dist/src/health/readinessCheck.d.ts +139 -0
- package/dist/src/health/readinessCheck.d.ts.map +1 -0
- package/dist/src/health/readinessCheck.js +266 -0
- package/dist/src/health/readinessCheck.js.map +1 -0
- package/dist/src/index.d.ts +8 -0
- package/dist/src/index.d.ts.map +1 -0
- package/dist/src/index.js +178 -0
- package/dist/src/index.js.map +1 -0
- package/dist/src/index.test.d.ts +2 -0
- package/dist/src/index.test.d.ts.map +1 -0
- package/dist/src/index.test.js +43 -0
- package/dist/src/index.test.js.map +1 -0
- package/dist/src/logger.d.ts +26 -0
- package/dist/src/logger.d.ts.map +1 -0
- package/dist/src/logger.js +179 -0
- package/dist/src/logger.js.map +1 -0
- package/dist/src/middleware/__tests__/csp.test.d.ts +2 -0
- package/dist/src/middleware/__tests__/csp.test.d.ts.map +1 -0
- package/dist/src/middleware/__tests__/csp.test.js +389 -0
- package/dist/src/middleware/__tests__/csp.test.js.map +1 -0
- package/dist/src/middleware/csp.d.ts +87 -0
- package/dist/src/middleware/csp.d.ts.map +1 -0
- package/dist/src/middleware/csp.js +273 -0
- package/dist/src/middleware/csp.js.map +1 -0
- package/dist/src/middleware/degradation.d.ts +99 -0
- package/dist/src/middleware/degradation.d.ts.map +1 -0
- package/dist/src/middleware/degradation.js +315 -0
- package/dist/src/middleware/degradation.js.map +1 -0
- package/dist/src/middleware/errorFormatter.d.ts +119 -0
- package/dist/src/middleware/errorFormatter.d.ts.map +1 -0
- package/dist/src/middleware/errorFormatter.js +294 -0
- package/dist/src/middleware/errorFormatter.js.map +1 -0
- package/dist/src/middleware/index.d.ts +10 -0
- package/dist/src/middleware/index.d.ts.map +1 -0
- package/dist/src/middleware/index.js +14 -0
- package/dist/src/middleware/index.js.map +1 -0
- package/dist/src/middleware/license.d.ts +161 -0
- package/dist/src/middleware/license.d.ts.map +1 -0
- package/dist/src/middleware/license.js +281 -0
- package/dist/src/middleware/license.js.map +1 -0
- package/dist/src/middleware/toolFeatureMapping.d.ts +36 -0
- package/dist/src/middleware/toolFeatureMapping.d.ts.map +1 -0
- package/dist/src/middleware/toolFeatureMapping.js +90 -0
- package/dist/src/middleware/toolFeatureMapping.js.map +1 -0
- package/dist/src/onboarding/first-run.d.ts +64 -0
- package/dist/src/onboarding/first-run.d.ts.map +1 -0
- package/dist/src/onboarding/first-run.js +77 -0
- package/dist/src/onboarding/first-run.js.map +1 -0
- package/dist/src/onboarding/index.d.ts +7 -0
- package/dist/src/onboarding/index.d.ts.map +1 -0
- package/dist/src/onboarding/index.js +7 -0
- package/dist/src/onboarding/index.js.map +1 -0
- package/dist/src/suggestions/index.d.ts +21 -0
- package/dist/src/suggestions/index.d.ts.map +1 -0
- package/dist/src/suggestions/index.js +20 -0
- package/dist/src/suggestions/index.js.map +1 -0
- package/dist/src/suggestions/suggestion-engine.d.ts +185 -0
- package/dist/src/suggestions/suggestion-engine.d.ts.map +1 -0
- package/dist/src/suggestions/suggestion-engine.js +352 -0
- package/dist/src/suggestions/suggestion-engine.js.map +1 -0
- package/dist/src/suggestions/types.d.ts +88 -0
- package/dist/src/suggestions/types.d.ts.map +1 -0
- package/dist/src/suggestions/types.js +21 -0
- package/dist/src/suggestions/types.js.map +1 -0
- package/dist/src/tools/analyze.d.ts +151 -0
- package/dist/src/tools/analyze.d.ts.map +1 -0
- package/dist/src/tools/analyze.js +205 -0
- package/dist/src/tools/analyze.js.map +1 -0
- package/dist/src/tools/compare.d.ts +149 -0
- package/dist/src/tools/compare.d.ts.map +1 -0
- package/dist/src/tools/compare.js +464 -0
- package/dist/src/tools/compare.js.map +1 -0
- package/dist/src/tools/get-skill.d.ts +116 -0
- package/dist/src/tools/get-skill.d.ts.map +1 -0
- package/dist/src/tools/get-skill.js +224 -0
- package/dist/src/tools/get-skill.js.map +1 -0
- package/dist/src/tools/index.d.ts +20 -0
- package/dist/src/tools/index.d.ts.map +1 -0
- package/dist/src/tools/index.js +20 -0
- package/dist/src/tools/index.js.map +1 -0
- package/dist/src/tools/install.d.ts +122 -0
- package/dist/src/tools/install.d.ts.map +1 -0
- package/dist/src/tools/install.js +314 -0
- package/dist/src/tools/install.js.map +1 -0
- package/dist/src/tools/recommend.d.ts +171 -0
- package/dist/src/tools/recommend.d.ts.map +1 -0
- package/dist/src/tools/recommend.js +325 -0
- package/dist/src/tools/recommend.js.map +1 -0
- package/dist/src/tools/search.d.ts +121 -0
- package/dist/src/tools/search.d.ts.map +1 -0
- package/dist/src/tools/search.js +249 -0
- package/dist/src/tools/search.js.map +1 -0
- package/dist/src/tools/suggest.d.ts +181 -0
- package/dist/src/tools/suggest.d.ts.map +1 -0
- package/dist/src/tools/suggest.js +342 -0
- package/dist/src/tools/suggest.js.map +1 -0
- package/dist/src/tools/uninstall.d.ts +123 -0
- package/dist/src/tools/uninstall.d.ts.map +1 -0
- package/dist/src/tools/uninstall.js +250 -0
- package/dist/src/tools/uninstall.js.map +1 -0
- package/dist/src/tools/validate.d.ts +122 -0
- package/dist/src/tools/validate.d.ts.map +1 -0
- package/dist/src/tools/validate.js +497 -0
- package/dist/src/tools/validate.js.map +1 -0
- package/dist/src/utils/installed-skills.d.ts +101 -0
- package/dist/src/utils/installed-skills.d.ts.map +1 -0
- package/dist/src/utils/installed-skills.js +220 -0
- package/dist/src/utils/installed-skills.js.map +1 -0
- package/dist/src/utils/validation.d.ts +76 -0
- package/dist/src/utils/validation.d.ts.map +1 -0
- package/dist/src/utils/validation.js +153 -0
- package/dist/src/utils/validation.js.map +1 -0
- package/dist/src/webhooks/index.d.ts +8 -0
- package/dist/src/webhooks/index.d.ts.map +1 -0
- package/dist/src/webhooks/index.js +9 -0
- package/dist/src/webhooks/index.js.map +1 -0
- package/dist/src/webhooks/webhook-endpoint.d.ts +149 -0
- package/dist/src/webhooks/webhook-endpoint.d.ts.map +1 -0
- package/dist/src/webhooks/webhook-endpoint.js +339 -0
- package/dist/src/webhooks/webhook-endpoint.js.map +1 -0
- package/dist/tests/compare.test.d.ts +6 -0
- package/dist/tests/compare.test.d.ts.map +1 -0
- package/dist/tests/compare.test.js +225 -0
- package/dist/tests/compare.test.js.map +1 -0
- package/dist/tests/context/project-detector.test.d.ts +6 -0
- package/dist/tests/context/project-detector.test.d.ts.map +1 -0
- package/dist/tests/context/project-detector.test.js +719 -0
- package/dist/tests/context/project-detector.test.js.map +1 -0
- package/dist/tests/e2e/compare.e2e.test.d.ts +10 -0
- package/dist/tests/e2e/compare.e2e.test.d.ts.map +1 -0
- package/dist/tests/e2e/compare.e2e.test.js +286 -0
- package/dist/tests/e2e/compare.e2e.test.js.map +1 -0
- package/dist/tests/e2e/install-flow.e2e.test.d.ts +10 -0
- package/dist/tests/e2e/install-flow.e2e.test.d.ts.map +1 -0
- package/dist/tests/e2e/install-flow.e2e.test.js +209 -0
- package/dist/tests/e2e/install-flow.e2e.test.js.map +1 -0
- package/dist/tests/e2e/recommend.e2e.test.d.ts +12 -0
- package/dist/tests/e2e/recommend.e2e.test.d.ts.map +1 -0
- package/dist/tests/e2e/recommend.e2e.test.js +347 -0
- package/dist/tests/e2e/recommend.e2e.test.js.map +1 -0
- package/dist/tests/e2e/skill-flow.e2e.test.d.ts +10 -0
- package/dist/tests/e2e/skill-flow.e2e.test.d.ts.map +1 -0
- package/dist/tests/e2e/skill-flow.e2e.test.js +280 -0
- package/dist/tests/e2e/skill-flow.e2e.test.js.map +1 -0
- package/dist/tests/e2e/suggest.e2e.test.d.ts +13 -0
- package/dist/tests/e2e/suggest.e2e.test.d.ts.map +1 -0
- package/dist/tests/e2e/suggest.e2e.test.js +347 -0
- package/dist/tests/e2e/suggest.e2e.test.js.map +1 -0
- package/dist/tests/e2e/utils/baseline-collector.d.ts +107 -0
- package/dist/tests/e2e/utils/baseline-collector.d.ts.map +1 -0
- package/dist/tests/e2e/utils/baseline-collector.js +211 -0
- package/dist/tests/e2e/utils/baseline-collector.js.map +1 -0
- package/dist/tests/e2e/utils/hardcoded-detector.d.ts +46 -0
- package/dist/tests/e2e/utils/hardcoded-detector.d.ts.map +1 -0
- package/dist/tests/e2e/utils/hardcoded-detector.js +255 -0
- package/dist/tests/e2e/utils/hardcoded-detector.js.map +1 -0
- package/dist/tests/e2e/utils/index.d.ts +7 -0
- package/dist/tests/e2e/utils/index.d.ts.map +1 -0
- package/dist/tests/e2e/utils/index.js +7 -0
- package/dist/tests/e2e/utils/index.js.map +1 -0
- package/dist/tests/e2e/utils/linear-reporter.d.ts +60 -0
- package/dist/tests/e2e/utils/linear-reporter.d.ts.map +1 -0
- package/dist/tests/e2e/utils/linear-reporter.js +232 -0
- package/dist/tests/e2e/utils/linear-reporter.js.map +1 -0
- package/dist/tests/health.test.d.ts +9 -0
- package/dist/tests/health.test.d.ts.map +1 -0
- package/dist/tests/health.test.js +308 -0
- package/dist/tests/health.test.js.map +1 -0
- package/dist/tests/integration/analyze.integration.test.d.ts +2 -0
- package/dist/tests/integration/analyze.integration.test.d.ts.map +1 -0
- package/dist/tests/integration/analyze.integration.test.js +244 -0
- package/dist/tests/integration/analyze.integration.test.js.map +1 -0
- package/dist/tests/integration/compare.integration.test.d.ts +2 -0
- package/dist/tests/integration/compare.integration.test.d.ts.map +1 -0
- package/dist/tests/integration/compare.integration.test.js +120 -0
- package/dist/tests/integration/compare.integration.test.js.map +1 -0
- package/dist/tests/integration/fixtures/test-skills.d.ts +62 -0
- package/dist/tests/integration/fixtures/test-skills.d.ts.map +1 -0
- package/dist/tests/integration/fixtures/test-skills.js +644 -0
- package/dist/tests/integration/fixtures/test-skills.js.map +1 -0
- package/dist/tests/integration/get-skill.integration.test.d.ts +6 -0
- package/dist/tests/integration/get-skill.integration.test.d.ts.map +1 -0
- package/dist/tests/integration/get-skill.integration.test.js +203 -0
- package/dist/tests/integration/get-skill.integration.test.js.map +1 -0
- package/dist/tests/integration/github-api.integration.test.d.ts +14 -0
- package/dist/tests/integration/github-api.integration.test.d.ts.map +1 -0
- package/dist/tests/integration/github-api.integration.test.js +190 -0
- package/dist/tests/integration/github-api.integration.test.js.map +1 -0
- package/dist/tests/integration/install.integration.test.d.ts +6 -0
- package/dist/tests/integration/install.integration.test.d.ts.map +1 -0
- package/dist/tests/integration/install.integration.test.js +282 -0
- package/dist/tests/integration/install.integration.test.js.map +1 -0
- package/dist/tests/integration/recommend.integration.test.d.ts +2 -0
- package/dist/tests/integration/recommend.integration.test.d.ts.map +1 -0
- package/dist/tests/integration/recommend.integration.test.js +215 -0
- package/dist/tests/integration/recommend.integration.test.js.map +1 -0
- package/dist/tests/integration/search.integration.test.d.ts +6 -0
- package/dist/tests/integration/search.integration.test.d.ts.map +1 -0
- package/dist/tests/integration/search.integration.test.js +229 -0
- package/dist/tests/integration/search.integration.test.js.map +1 -0
- package/dist/tests/integration/setup.d.ts +71 -0
- package/dist/tests/integration/setup.d.ts.map +1 -0
- package/dist/tests/integration/setup.js +124 -0
- package/dist/tests/integration/setup.js.map +1 -0
- package/dist/tests/integration/uninstall.integration.test.d.ts +6 -0
- package/dist/tests/integration/uninstall.integration.test.d.ts.map +1 -0
- package/dist/tests/integration/uninstall.integration.test.js +296 -0
- package/dist/tests/integration/uninstall.integration.test.js.map +1 -0
- package/dist/tests/integration/validate.integration.test.d.ts +2 -0
- package/dist/tests/integration/validate.integration.test.d.ts.map +1 -0
- package/dist/tests/integration/validate.integration.test.js +181 -0
- package/dist/tests/integration/validate.integration.test.js.map +1 -0
- package/dist/tests/onboarding/first-run.test.d.ts +7 -0
- package/dist/tests/onboarding/first-run.test.d.ts.map +1 -0
- package/dist/tests/onboarding/first-run.test.js +258 -0
- package/dist/tests/onboarding/first-run.test.js.map +1 -0
- package/dist/tests/performance/search-performance.test.d.ts +10 -0
- package/dist/tests/performance/search-performance.test.d.ts.map +1 -0
- package/dist/tests/performance/search-performance.test.js +218 -0
- package/dist/tests/performance/search-performance.test.js.map +1 -0
- package/dist/tests/recommend.test.d.ts +6 -0
- package/dist/tests/recommend.test.d.ts.map +1 -0
- package/dist/tests/recommend.test.js +208 -0
- package/dist/tests/recommend.test.js.map +1 -0
- package/dist/tests/suggestions/suggestion-engine.test.d.ts +6 -0
- package/dist/tests/suggestions/suggestion-engine.test.d.ts.map +1 -0
- package/dist/tests/suggestions/suggestion-engine.test.js +448 -0
- package/dist/tests/suggestions/suggestion-engine.test.js.map +1 -0
- package/dist/tests/test-utils.d.ts +74 -0
- package/dist/tests/test-utils.d.ts.map +1 -0
- package/dist/tests/test-utils.js +98 -0
- package/dist/tests/test-utils.js.map +1 -0
- package/dist/tests/tools.test.d.ts +5 -0
- package/dist/tests/tools.test.d.ts.map +1 -0
- package/dist/tests/tools.test.js +138 -0
- package/dist/tests/tools.test.js.map +1 -0
- package/dist/tests/unit/installed-skills.test.d.ts +6 -0
- package/dist/tests/unit/installed-skills.test.d.ts.map +1 -0
- package/dist/tests/unit/installed-skills.test.js +285 -0
- package/dist/tests/unit/installed-skills.test.js.map +1 -0
- package/dist/tests/unit/logger.test.d.ts +6 -0
- package/dist/tests/unit/logger.test.d.ts.map +1 -0
- package/dist/tests/unit/logger.test.js +281 -0
- package/dist/tests/unit/logger.test.js.map +1 -0
- package/dist/tests/validate.test.d.ts +5 -0
- package/dist/tests/validate.test.d.ts.map +1 -0
- package/dist/tests/validate.test.js +303 -0
- package/dist/tests/validate.test.js.map +1 -0
- package/dist/tests/webhooks/proxy-trust.security.test.d.ts +8 -0
- package/dist/tests/webhooks/proxy-trust.security.test.d.ts.map +1 -0
- package/dist/tests/webhooks/proxy-trust.security.test.js +145 -0
- package/dist/tests/webhooks/proxy-trust.security.test.js.map +1 -0
- package/dist/tests/webhooks/rate-limiter.security.test.d.ts +8 -0
- package/dist/tests/webhooks/rate-limiter.security.test.d.ts.map +1 -0
- package/dist/tests/webhooks/rate-limiter.security.test.js +122 -0
- package/dist/tests/webhooks/rate-limiter.security.test.js.map +1 -0
- package/dist/vitest.config.d.ts +6 -0
- package/dist/vitest.config.d.ts.map +1 -0
- package/dist/vitest.config.js +13 -0
- package/dist/vitest.config.js.map +1 -0
- package/package.json +63 -0
|
@@ -0,0 +1,448 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Unit tests for SMI-913: Contextual skill suggestions after first success
|
|
3
|
+
* Tests the SuggestionEngine class comprehensively
|
|
4
|
+
*/
|
|
5
|
+
import { describe, it, expect, beforeEach, afterEach, beforeAll, afterAll } from 'vitest';
|
|
6
|
+
import * as fs from 'node:fs';
|
|
7
|
+
import * as path from 'node:path';
|
|
8
|
+
import * as os from 'node:os';
|
|
9
|
+
import { SuggestionEngine } from '../../src/suggestions/suggestion-engine.js';
|
|
10
|
+
// Create test directory path
|
|
11
|
+
const TEST_BASE_DIR = path.join(os.tmpdir(), 'skillsmith-suggestion-test');
|
|
12
|
+
let testDir;
|
|
13
|
+
/**
|
|
14
|
+
* Helper to create a mock ProjectContext
|
|
15
|
+
*/
|
|
16
|
+
function createMockContext(overrides = {}) {
|
|
17
|
+
return {
|
|
18
|
+
hasDocker: false,
|
|
19
|
+
hasLinear: false,
|
|
20
|
+
hasGitHub: false,
|
|
21
|
+
testFramework: null,
|
|
22
|
+
apiFramework: null,
|
|
23
|
+
hasNativeModules: false,
|
|
24
|
+
language: null,
|
|
25
|
+
...overrides,
|
|
26
|
+
};
|
|
27
|
+
}
|
|
28
|
+
/**
|
|
29
|
+
* Helper to create a mock state file
|
|
30
|
+
*/
|
|
31
|
+
function writeMockState(stateDir, state) {
|
|
32
|
+
const fullState = {
|
|
33
|
+
lastSuggestionTime: 0,
|
|
34
|
+
suggestionsToday: 0,
|
|
35
|
+
optedOut: false,
|
|
36
|
+
dismissedSkills: [],
|
|
37
|
+
...state,
|
|
38
|
+
};
|
|
39
|
+
if (!fs.existsSync(stateDir)) {
|
|
40
|
+
fs.mkdirSync(stateDir, { recursive: true });
|
|
41
|
+
}
|
|
42
|
+
fs.writeFileSync(path.join(stateDir, 'suggestions-state.json'), JSON.stringify(fullState, null, 2));
|
|
43
|
+
}
|
|
44
|
+
/**
|
|
45
|
+
* Clean up test directory
|
|
46
|
+
*/
|
|
47
|
+
function cleanupTestDir() {
|
|
48
|
+
if (testDir && fs.existsSync(testDir)) {
|
|
49
|
+
fs.rmSync(testDir, { recursive: true, force: true });
|
|
50
|
+
}
|
|
51
|
+
}
|
|
52
|
+
/**
|
|
53
|
+
* Create a SuggestionEngine with test state directory
|
|
54
|
+
*/
|
|
55
|
+
function createTestEngine(config = {}) {
|
|
56
|
+
return new SuggestionEngine({ ...config, stateDir: testDir });
|
|
57
|
+
}
|
|
58
|
+
describe('SuggestionEngine', () => {
|
|
59
|
+
beforeAll(() => {
|
|
60
|
+
// Ensure base test directory exists
|
|
61
|
+
if (!fs.existsSync(TEST_BASE_DIR)) {
|
|
62
|
+
fs.mkdirSync(TEST_BASE_DIR, { recursive: true });
|
|
63
|
+
}
|
|
64
|
+
});
|
|
65
|
+
afterAll(() => {
|
|
66
|
+
// Clean up base test directory
|
|
67
|
+
if (fs.existsSync(TEST_BASE_DIR)) {
|
|
68
|
+
fs.rmSync(TEST_BASE_DIR, { recursive: true, force: true });
|
|
69
|
+
}
|
|
70
|
+
});
|
|
71
|
+
beforeEach(() => {
|
|
72
|
+
// Create unique directory for each test
|
|
73
|
+
testDir = path.join(TEST_BASE_DIR, `test-${Date.now()}-${Math.random().toString(36).slice(2)}`);
|
|
74
|
+
fs.mkdirSync(testDir, { recursive: true });
|
|
75
|
+
});
|
|
76
|
+
afterEach(() => {
|
|
77
|
+
cleanupTestDir();
|
|
78
|
+
});
|
|
79
|
+
describe('constructor', () => {
|
|
80
|
+
it('should initialize with default config', () => {
|
|
81
|
+
const engine = createTestEngine();
|
|
82
|
+
const state = engine.getState();
|
|
83
|
+
expect(state.optedOut).toBe(false);
|
|
84
|
+
expect(state.suggestionsToday).toBe(0);
|
|
85
|
+
expect(state.dismissedSkills).toEqual([]);
|
|
86
|
+
});
|
|
87
|
+
it('should accept custom config', () => {
|
|
88
|
+
const engine = createTestEngine({
|
|
89
|
+
cooldownMs: 10 * 60 * 1000,
|
|
90
|
+
maxSuggestionsPerDay: 5,
|
|
91
|
+
});
|
|
92
|
+
// Engine should still work with custom config
|
|
93
|
+
expect(engine.canSuggest()).toBe(true);
|
|
94
|
+
});
|
|
95
|
+
it('should load existing state from disk', () => {
|
|
96
|
+
// Set lastSuggestionTime to today so the daily count doesn't reset
|
|
97
|
+
writeMockState(testDir, {
|
|
98
|
+
lastSuggestionTime: Date.now(),
|
|
99
|
+
suggestionsToday: 2,
|
|
100
|
+
dismissedSkills: ['community/docker'],
|
|
101
|
+
});
|
|
102
|
+
const engine = createTestEngine();
|
|
103
|
+
const state = engine.getState();
|
|
104
|
+
expect(state.suggestionsToday).toBe(2);
|
|
105
|
+
expect(state.dismissedSkills).toContain('community/docker');
|
|
106
|
+
});
|
|
107
|
+
it('should reset daily count on new day', () => {
|
|
108
|
+
// Write state from yesterday
|
|
109
|
+
const yesterday = Date.now() - 24 * 60 * 60 * 1000;
|
|
110
|
+
writeMockState(testDir, {
|
|
111
|
+
lastSuggestionTime: yesterday,
|
|
112
|
+
suggestionsToday: 3,
|
|
113
|
+
});
|
|
114
|
+
const engine = createTestEngine();
|
|
115
|
+
const state = engine.getState();
|
|
116
|
+
expect(state.suggestionsToday).toBe(0);
|
|
117
|
+
});
|
|
118
|
+
it('should handle corrupted state file gracefully', () => {
|
|
119
|
+
if (!fs.existsSync(testDir)) {
|
|
120
|
+
fs.mkdirSync(testDir, { recursive: true });
|
|
121
|
+
}
|
|
122
|
+
fs.writeFileSync(path.join(testDir, 'suggestions-state.json'), '{ invalid json }');
|
|
123
|
+
const engine = createTestEngine();
|
|
124
|
+
const state = engine.getState();
|
|
125
|
+
expect(state.optedOut).toBe(false);
|
|
126
|
+
expect(state.suggestionsToday).toBe(0);
|
|
127
|
+
});
|
|
128
|
+
});
|
|
129
|
+
describe('canSuggest', () => {
|
|
130
|
+
it('should return true by default', () => {
|
|
131
|
+
const engine = createTestEngine();
|
|
132
|
+
expect(engine.canSuggest()).toBe(true);
|
|
133
|
+
});
|
|
134
|
+
it('should return false when opted out', () => {
|
|
135
|
+
const engine = createTestEngine();
|
|
136
|
+
engine.optOut();
|
|
137
|
+
expect(engine.canSuggest()).toBe(false);
|
|
138
|
+
});
|
|
139
|
+
it('should return false when daily limit reached', () => {
|
|
140
|
+
const engine = createTestEngine({ maxSuggestionsPerDay: 3 });
|
|
141
|
+
// Simulate showing 3 suggestions
|
|
142
|
+
engine.recordSuggestionShown();
|
|
143
|
+
engine.recordSuggestionShown();
|
|
144
|
+
engine.recordSuggestionShown();
|
|
145
|
+
expect(engine.canSuggest()).toBe(false);
|
|
146
|
+
});
|
|
147
|
+
it('should return false during cooldown period', () => {
|
|
148
|
+
const engine = createTestEngine({ cooldownMs: 5 * 60 * 1000 });
|
|
149
|
+
engine.recordSuggestionShown();
|
|
150
|
+
// Should be in cooldown immediately after showing
|
|
151
|
+
expect(engine.canSuggest()).toBe(false);
|
|
152
|
+
});
|
|
153
|
+
it('should return true after cooldown expires', async () => {
|
|
154
|
+
// Use 100ms cooldown for testing
|
|
155
|
+
const engine = createTestEngine({ cooldownMs: 100 });
|
|
156
|
+
engine.recordSuggestionShown();
|
|
157
|
+
// Wait for cooldown
|
|
158
|
+
await new Promise((resolve) => setTimeout(resolve, 150));
|
|
159
|
+
expect(engine.canSuggest()).toBe(true);
|
|
160
|
+
});
|
|
161
|
+
});
|
|
162
|
+
describe('getSuggestions', () => {
|
|
163
|
+
it('should return empty array when opted out', () => {
|
|
164
|
+
const engine = createTestEngine();
|
|
165
|
+
engine.optOut();
|
|
166
|
+
const context = createMockContext({ hasDocker: true, hasNativeModules: true });
|
|
167
|
+
const suggestions = engine.getSuggestions(context);
|
|
168
|
+
expect(suggestions).toEqual([]);
|
|
169
|
+
});
|
|
170
|
+
it('should return empty array when rate limited', () => {
|
|
171
|
+
const engine = createTestEngine({ maxSuggestionsPerDay: 1 });
|
|
172
|
+
engine.recordSuggestionShown();
|
|
173
|
+
const context = createMockContext({ hasDocker: true, hasNativeModules: true });
|
|
174
|
+
const suggestions = engine.getSuggestions(context);
|
|
175
|
+
expect(suggestions).toEqual([]);
|
|
176
|
+
});
|
|
177
|
+
it('should suggest docker for native modules + docker projects', () => {
|
|
178
|
+
const engine = createTestEngine();
|
|
179
|
+
const context = createMockContext({ hasDocker: true, hasNativeModules: true });
|
|
180
|
+
const suggestions = engine.getSuggestions(context);
|
|
181
|
+
expect(suggestions).toHaveLength(1);
|
|
182
|
+
expect(suggestions[0].skillId).toBe('community/docker');
|
|
183
|
+
expect(suggestions[0].skillName).toBe('docker');
|
|
184
|
+
expect(suggestions[0].reason).toContain('native modules');
|
|
185
|
+
});
|
|
186
|
+
it('should suggest linear for Linear-integrated projects', () => {
|
|
187
|
+
const engine = createTestEngine();
|
|
188
|
+
const context = createMockContext({ hasLinear: true });
|
|
189
|
+
const suggestions = engine.getSuggestions(context);
|
|
190
|
+
expect(suggestions).toHaveLength(1);
|
|
191
|
+
expect(suggestions[0].skillId).toBe('user/linear');
|
|
192
|
+
expect(suggestions[0].skillName).toBe('linear');
|
|
193
|
+
});
|
|
194
|
+
it('should suggest review-pr for GitHub projects', () => {
|
|
195
|
+
const engine = createTestEngine();
|
|
196
|
+
const context = createMockContext({ hasGitHub: true });
|
|
197
|
+
const suggestions = engine.getSuggestions(context);
|
|
198
|
+
expect(suggestions).toHaveLength(1);
|
|
199
|
+
expect(suggestions[0].skillId).toBe('anthropic/review-pr');
|
|
200
|
+
expect(suggestions[0].skillName).toBe('review-pr');
|
|
201
|
+
});
|
|
202
|
+
it('should suggest jest-helper for Jest projects', () => {
|
|
203
|
+
const engine = createTestEngine();
|
|
204
|
+
const context = createMockContext({ testFramework: 'jest' });
|
|
205
|
+
const suggestions = engine.getSuggestions(context);
|
|
206
|
+
expect(suggestions).toHaveLength(1);
|
|
207
|
+
expect(suggestions[0].skillId).toBe('community/jest-helper');
|
|
208
|
+
expect(suggestions[0].skillName).toBe('jest-helper');
|
|
209
|
+
});
|
|
210
|
+
it('should suggest vitest-helper for Vitest projects', () => {
|
|
211
|
+
const engine = createTestEngine();
|
|
212
|
+
const context = createMockContext({ testFramework: 'vitest' });
|
|
213
|
+
const suggestions = engine.getSuggestions(context);
|
|
214
|
+
expect(suggestions).toHaveLength(1);
|
|
215
|
+
expect(suggestions[0].skillId).toBe('community/vitest-helper');
|
|
216
|
+
expect(suggestions[0].skillName).toBe('vitest-helper');
|
|
217
|
+
});
|
|
218
|
+
it('should suggest api-docs for Express projects', () => {
|
|
219
|
+
const engine = createTestEngine();
|
|
220
|
+
const context = createMockContext({ apiFramework: 'express' });
|
|
221
|
+
const suggestions = engine.getSuggestions(context);
|
|
222
|
+
expect(suggestions).toHaveLength(1);
|
|
223
|
+
expect(suggestions[0].skillId).toBe('community/api-docs');
|
|
224
|
+
expect(suggestions[0].skillName).toBe('api-docs');
|
|
225
|
+
});
|
|
226
|
+
it('should suggest api-docs for Next.js projects', () => {
|
|
227
|
+
const engine = createTestEngine();
|
|
228
|
+
const context = createMockContext({ apiFramework: 'nextjs' });
|
|
229
|
+
const suggestions = engine.getSuggestions(context);
|
|
230
|
+
expect(suggestions).toHaveLength(1);
|
|
231
|
+
expect(suggestions[0].skillId).toBe('community/api-docs');
|
|
232
|
+
expect(suggestions[0].skillName).toBe('api-docs');
|
|
233
|
+
});
|
|
234
|
+
it('should not suggest FastAPI for api-docs (only express/nextjs)', () => {
|
|
235
|
+
const engine = createTestEngine();
|
|
236
|
+
const context = createMockContext({ apiFramework: 'fastapi' });
|
|
237
|
+
const suggestions = engine.getSuggestions(context);
|
|
238
|
+
expect(suggestions).toHaveLength(0);
|
|
239
|
+
});
|
|
240
|
+
it('should filter out installed skills', () => {
|
|
241
|
+
const engine = createTestEngine();
|
|
242
|
+
const context = createMockContext({ hasLinear: true });
|
|
243
|
+
const suggestions = engine.getSuggestions(context, ['user/linear']);
|
|
244
|
+
expect(suggestions).toHaveLength(0);
|
|
245
|
+
});
|
|
246
|
+
it('should filter out installed skills by partial name match', () => {
|
|
247
|
+
const engine = createTestEngine();
|
|
248
|
+
const context = createMockContext({ hasLinear: true });
|
|
249
|
+
// Match by skill name within the installed skill ID
|
|
250
|
+
const suggestions = engine.getSuggestions(context, ['some-prefix/linear']);
|
|
251
|
+
expect(suggestions).toHaveLength(0);
|
|
252
|
+
});
|
|
253
|
+
it('should filter out dismissed skills', () => {
|
|
254
|
+
const engine = createTestEngine();
|
|
255
|
+
engine.dismissSkill('user/linear');
|
|
256
|
+
const context = createMockContext({ hasLinear: true });
|
|
257
|
+
const suggestions = engine.getSuggestions(context);
|
|
258
|
+
expect(suggestions).toHaveLength(0);
|
|
259
|
+
});
|
|
260
|
+
it('should return highest priority suggestion when multiple match', () => {
|
|
261
|
+
const engine = createTestEngine();
|
|
262
|
+
// Docker + native modules (priority 1) + GitHub (priority 2)
|
|
263
|
+
const context = createMockContext({
|
|
264
|
+
hasDocker: true,
|
|
265
|
+
hasNativeModules: true,
|
|
266
|
+
hasGitHub: true,
|
|
267
|
+
});
|
|
268
|
+
const suggestions = engine.getSuggestions(context);
|
|
269
|
+
expect(suggestions).toHaveLength(1);
|
|
270
|
+
expect(suggestions[0].skillName).toBe('docker');
|
|
271
|
+
expect(suggestions[0].priority).toBe(1);
|
|
272
|
+
});
|
|
273
|
+
it('should include context matches in suggestion', () => {
|
|
274
|
+
const engine = createTestEngine();
|
|
275
|
+
const context = createMockContext({
|
|
276
|
+
hasDocker: true,
|
|
277
|
+
hasNativeModules: true,
|
|
278
|
+
hasGitHub: true,
|
|
279
|
+
testFramework: 'jest',
|
|
280
|
+
});
|
|
281
|
+
const suggestions = engine.getSuggestions(context);
|
|
282
|
+
expect(suggestions[0].contextMatch).toContain('hasDocker');
|
|
283
|
+
expect(suggestions[0].contextMatch).toContain('hasNativeModules');
|
|
284
|
+
expect(suggestions[0].contextMatch).toContain('hasGitHub');
|
|
285
|
+
expect(suggestions[0].contextMatch).toContain('testFramework:jest');
|
|
286
|
+
});
|
|
287
|
+
it('should return empty array for empty context', () => {
|
|
288
|
+
const engine = createTestEngine();
|
|
289
|
+
const context = createMockContext();
|
|
290
|
+
const suggestions = engine.getSuggestions(context);
|
|
291
|
+
expect(suggestions).toEqual([]);
|
|
292
|
+
});
|
|
293
|
+
});
|
|
294
|
+
describe('recordSuggestionShown', () => {
|
|
295
|
+
it('should increment suggestionsToday', () => {
|
|
296
|
+
const engine = createTestEngine();
|
|
297
|
+
engine.recordSuggestionShown();
|
|
298
|
+
expect(engine.getState().suggestionsToday).toBe(1);
|
|
299
|
+
engine.recordSuggestionShown();
|
|
300
|
+
expect(engine.getState().suggestionsToday).toBe(2);
|
|
301
|
+
});
|
|
302
|
+
it('should update lastSuggestionTime', () => {
|
|
303
|
+
const engine = createTestEngine();
|
|
304
|
+
const before = Date.now();
|
|
305
|
+
engine.recordSuggestionShown();
|
|
306
|
+
const state = engine.getState();
|
|
307
|
+
expect(state.lastSuggestionTime).toBeGreaterThanOrEqual(before);
|
|
308
|
+
expect(state.lastSuggestionTime).toBeLessThanOrEqual(Date.now());
|
|
309
|
+
});
|
|
310
|
+
it('should persist state to disk', () => {
|
|
311
|
+
const engine = createTestEngine();
|
|
312
|
+
engine.recordSuggestionShown();
|
|
313
|
+
// Create new engine to load from disk
|
|
314
|
+
const engine2 = createTestEngine();
|
|
315
|
+
expect(engine2.getState().suggestionsToday).toBe(1);
|
|
316
|
+
});
|
|
317
|
+
});
|
|
318
|
+
describe('dismissSkill', () => {
|
|
319
|
+
it('should add skill to dismissed list', () => {
|
|
320
|
+
const engine = createTestEngine();
|
|
321
|
+
engine.dismissSkill('community/docker');
|
|
322
|
+
expect(engine.getState().dismissedSkills).toContain('community/docker');
|
|
323
|
+
});
|
|
324
|
+
it('should not duplicate dismissed skills', () => {
|
|
325
|
+
const engine = createTestEngine();
|
|
326
|
+
engine.dismissSkill('community/docker');
|
|
327
|
+
engine.dismissSkill('community/docker');
|
|
328
|
+
expect(engine.getState().dismissedSkills.filter((s) => s === 'community/docker')).toHaveLength(1);
|
|
329
|
+
});
|
|
330
|
+
it('should persist dismissed skills to disk', () => {
|
|
331
|
+
const engine = createTestEngine();
|
|
332
|
+
engine.dismissSkill('user/linear');
|
|
333
|
+
const engine2 = createTestEngine();
|
|
334
|
+
expect(engine2.getState().dismissedSkills).toContain('user/linear');
|
|
335
|
+
});
|
|
336
|
+
});
|
|
337
|
+
describe('optOut/optIn', () => {
|
|
338
|
+
it('should set optedOut to true', () => {
|
|
339
|
+
const engine = createTestEngine();
|
|
340
|
+
engine.optOut();
|
|
341
|
+
expect(engine.getState().optedOut).toBe(true);
|
|
342
|
+
});
|
|
343
|
+
it('should persist opt-out to disk', () => {
|
|
344
|
+
const engine = createTestEngine();
|
|
345
|
+
engine.optOut();
|
|
346
|
+
const engine2 = createTestEngine();
|
|
347
|
+
expect(engine2.getState().optedOut).toBe(true);
|
|
348
|
+
});
|
|
349
|
+
it('should re-enable suggestions with optIn', () => {
|
|
350
|
+
const engine = createTestEngine();
|
|
351
|
+
engine.optOut();
|
|
352
|
+
expect(engine.canSuggest()).toBe(false);
|
|
353
|
+
engine.optIn();
|
|
354
|
+
expect(engine.getState().optedOut).toBe(false);
|
|
355
|
+
expect(engine.canSuggest()).toBe(true);
|
|
356
|
+
});
|
|
357
|
+
it('should persist opt-in to disk', () => {
|
|
358
|
+
const engine = createTestEngine();
|
|
359
|
+
engine.optOut();
|
|
360
|
+
engine.optIn();
|
|
361
|
+
const engine2 = createTestEngine();
|
|
362
|
+
expect(engine2.getState().optedOut).toBe(false);
|
|
363
|
+
});
|
|
364
|
+
});
|
|
365
|
+
describe('resetState', () => {
|
|
366
|
+
it('should reset all state to defaults', () => {
|
|
367
|
+
const engine = createTestEngine();
|
|
368
|
+
engine.recordSuggestionShown();
|
|
369
|
+
engine.dismissSkill('community/docker');
|
|
370
|
+
engine.optOut();
|
|
371
|
+
engine.resetState();
|
|
372
|
+
const state = engine.getState();
|
|
373
|
+
expect(state.suggestionsToday).toBe(0);
|
|
374
|
+
expect(state.dismissedSkills).toEqual([]);
|
|
375
|
+
expect(state.optedOut).toBe(false);
|
|
376
|
+
expect(state.lastSuggestionTime).toBe(0);
|
|
377
|
+
});
|
|
378
|
+
it('should persist reset state to disk', () => {
|
|
379
|
+
const engine = createTestEngine();
|
|
380
|
+
engine.optOut();
|
|
381
|
+
engine.dismissSkill('user/linear');
|
|
382
|
+
engine.resetState();
|
|
383
|
+
const engine2 = createTestEngine();
|
|
384
|
+
expect(engine2.getState().optedOut).toBe(false);
|
|
385
|
+
expect(engine2.getState().dismissedSkills).toEqual([]);
|
|
386
|
+
});
|
|
387
|
+
});
|
|
388
|
+
describe('getState', () => {
|
|
389
|
+
it('should return a copy of the state', () => {
|
|
390
|
+
const engine = createTestEngine();
|
|
391
|
+
const state = engine.getState();
|
|
392
|
+
// Modifying the returned state should not affect the engine
|
|
393
|
+
state.optedOut = true;
|
|
394
|
+
state.dismissedSkills.push('modified');
|
|
395
|
+
expect(engine.getState().optedOut).toBe(false);
|
|
396
|
+
expect(engine.getState().dismissedSkills).not.toContain('modified');
|
|
397
|
+
});
|
|
398
|
+
});
|
|
399
|
+
describe('daily reset behavior', () => {
|
|
400
|
+
it('should maintain count on same day', () => {
|
|
401
|
+
const engine = createTestEngine();
|
|
402
|
+
engine.recordSuggestionShown();
|
|
403
|
+
engine.recordSuggestionShown();
|
|
404
|
+
// Load fresh engine on same day
|
|
405
|
+
const engine2 = createTestEngine();
|
|
406
|
+
expect(engine2.getState().suggestionsToday).toBe(2);
|
|
407
|
+
});
|
|
408
|
+
it('should not reset count when loading multiple times on same day', () => {
|
|
409
|
+
const engine1 = createTestEngine();
|
|
410
|
+
engine1.recordSuggestionShown();
|
|
411
|
+
const engine2 = createTestEngine();
|
|
412
|
+
engine2.recordSuggestionShown();
|
|
413
|
+
const engine3 = createTestEngine();
|
|
414
|
+
expect(engine3.getState().suggestionsToday).toBe(2);
|
|
415
|
+
});
|
|
416
|
+
});
|
|
417
|
+
describe('edge cases', () => {
|
|
418
|
+
it('should handle missing state directory', () => {
|
|
419
|
+
// Remove the test directory
|
|
420
|
+
fs.rmSync(testDir, { recursive: true, force: true });
|
|
421
|
+
// Directory should be created on first save
|
|
422
|
+
const engine = createTestEngine();
|
|
423
|
+
engine.recordSuggestionShown();
|
|
424
|
+
expect(fs.existsSync(testDir)).toBe(true);
|
|
425
|
+
});
|
|
426
|
+
it('should handle concurrent modifications gracefully', () => {
|
|
427
|
+
const engine1 = createTestEngine();
|
|
428
|
+
const engine2 = createTestEngine();
|
|
429
|
+
engine1.dismissSkill('skill1');
|
|
430
|
+
engine2.dismissSkill('skill2');
|
|
431
|
+
// Last write wins - this is acceptable behavior
|
|
432
|
+
const engine3 = createTestEngine();
|
|
433
|
+
// Should have skill2 (last write)
|
|
434
|
+
expect(engine3.getState().dismissedSkills).toContain('skill2');
|
|
435
|
+
});
|
|
436
|
+
it('should work with zero cooldown', () => {
|
|
437
|
+
const engine = createTestEngine({ cooldownMs: 0 });
|
|
438
|
+
engine.recordSuggestionShown();
|
|
439
|
+
// Should be able to suggest again immediately with zero cooldown
|
|
440
|
+
expect(engine.canSuggest()).toBe(true);
|
|
441
|
+
});
|
|
442
|
+
it('should work with zero max suggestions per day', () => {
|
|
443
|
+
const engine = createTestEngine({ maxSuggestionsPerDay: 0 });
|
|
444
|
+
expect(engine.canSuggest()).toBe(false);
|
|
445
|
+
});
|
|
446
|
+
});
|
|
447
|
+
});
|
|
448
|
+
//# sourceMappingURL=suggestion-engine.test.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"suggestion-engine.test.js","sourceRoot":"","sources":["../../../tests/suggestions/suggestion-engine.test.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,74 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* SMI-992: Shared Test Utilities for Date/Time Mocking
|
|
3
|
+
*
|
|
4
|
+
* Provides consistent date mocking utilities to eliminate flaky tests
|
|
5
|
+
* caused by timing dependencies on Date.now() and new Date() calls.
|
|
6
|
+
*/
|
|
7
|
+
/**
|
|
8
|
+
* Fixed timestamp for deterministic testing - January 15, 2024 at 10:00 UTC
|
|
9
|
+
*/
|
|
10
|
+
export declare const FIXED_TIMESTAMP = 1705312800000;
|
|
11
|
+
/**
|
|
12
|
+
* Fixed date object for deterministic testing
|
|
13
|
+
*/
|
|
14
|
+
export declare const FIXED_DATE: Date;
|
|
15
|
+
/**
|
|
16
|
+
* Fixed ISO string for deterministic testing
|
|
17
|
+
*/
|
|
18
|
+
export declare const FIXED_DATE_ISO: string;
|
|
19
|
+
/**
|
|
20
|
+
* One day in milliseconds
|
|
21
|
+
*/
|
|
22
|
+
export declare const ONE_DAY_MS: number;
|
|
23
|
+
/**
|
|
24
|
+
* One year in milliseconds (365 days)
|
|
25
|
+
*/
|
|
26
|
+
export declare const ONE_YEAR_MS: number;
|
|
27
|
+
/**
|
|
28
|
+
* Creates a date relative to FIXED_DATE
|
|
29
|
+
* @param daysOffset - Number of days to add (negative for past dates)
|
|
30
|
+
* @returns Date object
|
|
31
|
+
*/
|
|
32
|
+
export declare function createRelativeDate(daysOffset: number): Date;
|
|
33
|
+
/**
|
|
34
|
+
* Creates an ISO date string relative to FIXED_DATE
|
|
35
|
+
* @param daysOffset - Number of days to add (negative for past dates)
|
|
36
|
+
* @returns ISO date string
|
|
37
|
+
*/
|
|
38
|
+
export declare function createRelativeDateISO(daysOffset: number): string;
|
|
39
|
+
/**
|
|
40
|
+
* Sets up fake timers with FIXED_DATE for the current test suite.
|
|
41
|
+
* Call in beforeEach() and pair with cleanupFakeTimers() in afterEach().
|
|
42
|
+
*/
|
|
43
|
+
export declare function setupFakeTimers(): void;
|
|
44
|
+
/**
|
|
45
|
+
* Cleans up fake timers after tests.
|
|
46
|
+
* Call in afterEach() when paired with setupFakeTimers().
|
|
47
|
+
*/
|
|
48
|
+
export declare function cleanupFakeTimers(): void;
|
|
49
|
+
/**
|
|
50
|
+
* Helper to advance fake timers by a specified amount
|
|
51
|
+
* @param ms - Milliseconds to advance
|
|
52
|
+
*/
|
|
53
|
+
export declare function advanceTime(ms: number): void;
|
|
54
|
+
/**
|
|
55
|
+
* Helper to advance fake timers by a number of days
|
|
56
|
+
* @param days - Days to advance
|
|
57
|
+
*/
|
|
58
|
+
export declare function advanceTimeByDays(days: number): void;
|
|
59
|
+
/**
|
|
60
|
+
* Creates a unique test directory path with deterministic naming
|
|
61
|
+
* @param prefix - Prefix for the directory name
|
|
62
|
+
* @param counter - A counter to ensure uniqueness within the test
|
|
63
|
+
*/
|
|
64
|
+
export declare function createTestDirPath(prefix: string, counter: number): string;
|
|
65
|
+
/**
|
|
66
|
+
* Decorator to set up and tear down fake timers for a describe block.
|
|
67
|
+
* Usage:
|
|
68
|
+
* withFakeTimers(() => {
|
|
69
|
+
* beforeEach(() => { ... })
|
|
70
|
+
* it('test', () => { ... })
|
|
71
|
+
* })
|
|
72
|
+
*/
|
|
73
|
+
export declare function withFakeTimers(fn: () => void): void;
|
|
74
|
+
//# sourceMappingURL=test-utils.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"test-utils.d.ts","sourceRoot":"","sources":["../../tests/test-utils.ts"],"names":[],"mappings":"AAAA;;;;;GAKG;AAIH;;GAEG;AACH,eAAO,MAAM,eAAe,gBAAgB,CAAA;AAE5C;;GAEG;AACH,eAAO,MAAM,UAAU,MAA4B,CAAA;AAEnD;;GAEG;AACH,eAAO,MAAM,cAAc,QAA2B,CAAA;AAEtD;;GAEG;AACH,eAAO,MAAM,UAAU,QAAsB,CAAA;AAE7C;;GAEG;AACH,eAAO,MAAM,WAAW,QAAmB,CAAA;AAE3C;;;;GAIG;AACH,wBAAgB,kBAAkB,CAAC,UAAU,EAAE,MAAM,GAAG,IAAI,CAE3D;AAED;;;;GAIG;AACH,wBAAgB,qBAAqB,CAAC,UAAU,EAAE,MAAM,GAAG,MAAM,CAEhE;AAED;;;GAGG;AACH,wBAAgB,eAAe,IAAI,IAAI,CAGtC;AAED;;;GAGG;AACH,wBAAgB,iBAAiB,IAAI,IAAI,CAExC;AAED;;;GAGG;AACH,wBAAgB,WAAW,CAAC,EAAE,EAAE,MAAM,GAAG,IAAI,CAE5C;AAED;;;GAGG;AACH,wBAAgB,iBAAiB,CAAC,IAAI,EAAE,MAAM,GAAG,IAAI,CAEpD;AAED;;;;GAIG;AACH,wBAAgB,iBAAiB,CAAC,MAAM,EAAE,MAAM,EAAE,OAAO,EAAE,MAAM,GAAG,MAAM,CAEzE;AAED;;;;;;;GAOG;AACH,wBAAgB,cAAc,CAAC,EAAE,EAAE,MAAM,IAAI,GAAG,IAAI,CAUnD"}
|
|
@@ -0,0 +1,98 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* SMI-992: Shared Test Utilities for Date/Time Mocking
|
|
3
|
+
*
|
|
4
|
+
* Provides consistent date mocking utilities to eliminate flaky tests
|
|
5
|
+
* caused by timing dependencies on Date.now() and new Date() calls.
|
|
6
|
+
*/
|
|
7
|
+
import { vi, beforeEach, afterEach } from 'vitest';
|
|
8
|
+
/**
|
|
9
|
+
* Fixed timestamp for deterministic testing - January 15, 2024 at 10:00 UTC
|
|
10
|
+
*/
|
|
11
|
+
export const FIXED_TIMESTAMP = 1705312800000;
|
|
12
|
+
/**
|
|
13
|
+
* Fixed date object for deterministic testing
|
|
14
|
+
*/
|
|
15
|
+
export const FIXED_DATE = new Date(FIXED_TIMESTAMP);
|
|
16
|
+
/**
|
|
17
|
+
* Fixed ISO string for deterministic testing
|
|
18
|
+
*/
|
|
19
|
+
export const FIXED_DATE_ISO = FIXED_DATE.toISOString();
|
|
20
|
+
/**
|
|
21
|
+
* One day in milliseconds
|
|
22
|
+
*/
|
|
23
|
+
export const ONE_DAY_MS = 24 * 60 * 60 * 1000;
|
|
24
|
+
/**
|
|
25
|
+
* One year in milliseconds (365 days)
|
|
26
|
+
*/
|
|
27
|
+
export const ONE_YEAR_MS = 365 * ONE_DAY_MS;
|
|
28
|
+
/**
|
|
29
|
+
* Creates a date relative to FIXED_DATE
|
|
30
|
+
* @param daysOffset - Number of days to add (negative for past dates)
|
|
31
|
+
* @returns Date object
|
|
32
|
+
*/
|
|
33
|
+
export function createRelativeDate(daysOffset) {
|
|
34
|
+
return new Date(FIXED_TIMESTAMP + daysOffset * ONE_DAY_MS);
|
|
35
|
+
}
|
|
36
|
+
/**
|
|
37
|
+
* Creates an ISO date string relative to FIXED_DATE
|
|
38
|
+
* @param daysOffset - Number of days to add (negative for past dates)
|
|
39
|
+
* @returns ISO date string
|
|
40
|
+
*/
|
|
41
|
+
export function createRelativeDateISO(daysOffset) {
|
|
42
|
+
return createRelativeDate(daysOffset).toISOString();
|
|
43
|
+
}
|
|
44
|
+
/**
|
|
45
|
+
* Sets up fake timers with FIXED_DATE for the current test suite.
|
|
46
|
+
* Call in beforeEach() and pair with cleanupFakeTimers() in afterEach().
|
|
47
|
+
*/
|
|
48
|
+
export function setupFakeTimers() {
|
|
49
|
+
vi.useFakeTimers();
|
|
50
|
+
vi.setSystemTime(FIXED_DATE);
|
|
51
|
+
}
|
|
52
|
+
/**
|
|
53
|
+
* Cleans up fake timers after tests.
|
|
54
|
+
* Call in afterEach() when paired with setupFakeTimers().
|
|
55
|
+
*/
|
|
56
|
+
export function cleanupFakeTimers() {
|
|
57
|
+
vi.useRealTimers();
|
|
58
|
+
}
|
|
59
|
+
/**
|
|
60
|
+
* Helper to advance fake timers by a specified amount
|
|
61
|
+
* @param ms - Milliseconds to advance
|
|
62
|
+
*/
|
|
63
|
+
export function advanceTime(ms) {
|
|
64
|
+
vi.advanceTimersByTime(ms);
|
|
65
|
+
}
|
|
66
|
+
/**
|
|
67
|
+
* Helper to advance fake timers by a number of days
|
|
68
|
+
* @param days - Days to advance
|
|
69
|
+
*/
|
|
70
|
+
export function advanceTimeByDays(days) {
|
|
71
|
+
vi.advanceTimersByTime(days * ONE_DAY_MS);
|
|
72
|
+
}
|
|
73
|
+
/**
|
|
74
|
+
* Creates a unique test directory path with deterministic naming
|
|
75
|
+
* @param prefix - Prefix for the directory name
|
|
76
|
+
* @param counter - A counter to ensure uniqueness within the test
|
|
77
|
+
*/
|
|
78
|
+
export function createTestDirPath(prefix, counter) {
|
|
79
|
+
return `${prefix}-${FIXED_TIMESTAMP}-${counter.toString(36)}`;
|
|
80
|
+
}
|
|
81
|
+
/**
|
|
82
|
+
* Decorator to set up and tear down fake timers for a describe block.
|
|
83
|
+
* Usage:
|
|
84
|
+
* withFakeTimers(() => {
|
|
85
|
+
* beforeEach(() => { ... })
|
|
86
|
+
* it('test', () => { ... })
|
|
87
|
+
* })
|
|
88
|
+
*/
|
|
89
|
+
export function withFakeTimers(fn) {
|
|
90
|
+
beforeEach(() => {
|
|
91
|
+
setupFakeTimers();
|
|
92
|
+
});
|
|
93
|
+
afterEach(() => {
|
|
94
|
+
cleanupFakeTimers();
|
|
95
|
+
});
|
|
96
|
+
fn();
|
|
97
|
+
}
|
|
98
|
+
//# sourceMappingURL=test-utils.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"test-utils.js","sourceRoot":"","sources":["../../tests/test-utils.ts"],"names":[],"mappings":"AAAA;;;;;GAKG;AAEH,OAAO,EAAE,EAAE,EAAE,UAAU,EAAE,SAAS,EAAE,MAAM,QAAQ,CAAA;AAElD;;GAEG;AACH,MAAM,CAAC,MAAM,eAAe,GAAG,aAAa,CAAA;AAE5C;;GAEG;AACH,MAAM,CAAC,MAAM,UAAU,GAAG,IAAI,IAAI,CAAC,eAAe,CAAC,CAAA;AAEnD;;GAEG;AACH,MAAM,CAAC,MAAM,cAAc,GAAG,UAAU,CAAC,WAAW,EAAE,CAAA;AAEtD;;GAEG;AACH,MAAM,CAAC,MAAM,UAAU,GAAG,EAAE,GAAG,EAAE,GAAG,EAAE,GAAG,IAAI,CAAA;AAE7C;;GAEG;AACH,MAAM,CAAC,MAAM,WAAW,GAAG,GAAG,GAAG,UAAU,CAAA;AAE3C;;;;GAIG;AACH,MAAM,UAAU,kBAAkB,CAAC,UAAkB;IACnD,OAAO,IAAI,IAAI,CAAC,eAAe,GAAG,UAAU,GAAG,UAAU,CAAC,CAAA;AAC5D,CAAC;AAED;;;;GAIG;AACH,MAAM,UAAU,qBAAqB,CAAC,UAAkB;IACtD,OAAO,kBAAkB,CAAC,UAAU,CAAC,CAAC,WAAW,EAAE,CAAA;AACrD,CAAC;AAED;;;GAGG;AACH,MAAM,UAAU,eAAe;IAC7B,EAAE,CAAC,aAAa,EAAE,CAAA;IAClB,EAAE,CAAC,aAAa,CAAC,UAAU,CAAC,CAAA;AAC9B,CAAC;AAED;;;GAGG;AACH,MAAM,UAAU,iBAAiB;IAC/B,EAAE,CAAC,aAAa,EAAE,CAAA;AACpB,CAAC;AAED;;;GAGG;AACH,MAAM,UAAU,WAAW,CAAC,EAAU;IACpC,EAAE,CAAC,mBAAmB,CAAC,EAAE,CAAC,CAAA;AAC5B,CAAC;AAED;;;GAGG;AACH,MAAM,UAAU,iBAAiB,CAAC,IAAY;IAC5C,EAAE,CAAC,mBAAmB,CAAC,IAAI,GAAG,UAAU,CAAC,CAAA;AAC3C,CAAC;AAED;;;;GAIG;AACH,MAAM,UAAU,iBAAiB,CAAC,MAAc,EAAE,OAAe;IAC/D,OAAO,GAAG,MAAM,IAAI,eAAe,IAAI,OAAO,CAAC,QAAQ,CAAC,EAAE,CAAC,EAAE,CAAA;AAC/D,CAAC;AAED;;;;;;;GAOG;AACH,MAAM,UAAU,cAAc,CAAC,EAAc;IAC3C,UAAU,CAAC,GAAG,EAAE;QACd,eAAe,EAAE,CAAA;IACnB,CAAC,CAAC,CAAA;IAEF,SAAS,CAAC,GAAG,EAAE;QACb,iBAAiB,EAAE,CAAA;IACrB,CAAC,CAAC,CAAA;IAEF,EAAE,EAAE,CAAA;AACN,CAAC"}
|