@omnidev-ai/core 0.6.0 → 0.6.2
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/package.json +39 -42
- package/dist/test-utils/index.d.ts +0 -138
- package/dist/test-utils/index.js +0 -230
- package/src/test-utils/helpers.ts +0 -289
- package/src/test-utils/index.ts +0 -34
- package/src/test-utils/mocks.ts +0 -101
package/package.json
CHANGED
|
@@ -1,44 +1,41 @@
|
|
|
1
1
|
{
|
|
2
|
-
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
"devDependencies": {
|
|
42
|
-
"bunup": "^0.16.20"
|
|
43
|
-
}
|
|
2
|
+
"name": "@omnidev-ai/core",
|
|
3
|
+
"version": "0.6.2",
|
|
4
|
+
"type": "module",
|
|
5
|
+
"license": "MIT",
|
|
6
|
+
"repository": {
|
|
7
|
+
"type": "git",
|
|
8
|
+
"url": "https://github.com/Nikola-Milovic/omnidev.git",
|
|
9
|
+
"directory": "packages/core"
|
|
10
|
+
},
|
|
11
|
+
"exports": {
|
|
12
|
+
".": {
|
|
13
|
+
"types": "./dist/index.d.ts",
|
|
14
|
+
"bun": "./src/index.ts",
|
|
15
|
+
"default": "./dist/index.js"
|
|
16
|
+
}
|
|
17
|
+
},
|
|
18
|
+
"files": [
|
|
19
|
+
"dist",
|
|
20
|
+
"!dist/test-utils/**",
|
|
21
|
+
"src",
|
|
22
|
+
"!src/test-utils/**",
|
|
23
|
+
"!src/**/*.test.ts",
|
|
24
|
+
"README.md"
|
|
25
|
+
],
|
|
26
|
+
"publishConfig": {
|
|
27
|
+
"access": "public",
|
|
28
|
+
"registry": "https://registry.npmjs.org"
|
|
29
|
+
},
|
|
30
|
+
"scripts": {
|
|
31
|
+
"typecheck": "tsc --noEmit",
|
|
32
|
+
"build": "bunup"
|
|
33
|
+
},
|
|
34
|
+
"dependencies": {
|
|
35
|
+
"@stricli/core": "^1.2.5",
|
|
36
|
+
"smol-toml": "^1.6.0"
|
|
37
|
+
},
|
|
38
|
+
"devDependencies": {
|
|
39
|
+
"bunup": "^0.16.20"
|
|
40
|
+
}
|
|
44
41
|
}
|
|
@@ -1,138 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* Expects an async function to throw an error
|
|
3
|
-
* @param fn - Async function that should throw
|
|
4
|
-
* @param errorMatch - Optional string or regex to match against error message
|
|
5
|
-
* @throws If the function doesn't throw
|
|
6
|
-
*/
|
|
7
|
-
declare function expectToThrowAsync(fn: () => Promise<unknown>, errorMatch?: string | RegExp): Promise<void>;
|
|
8
|
-
/**
|
|
9
|
-
* Waits for a condition to be true
|
|
10
|
-
* @param condition - Function that returns true when condition is met
|
|
11
|
-
* @param timeout - Maximum time to wait in milliseconds (default: 1000)
|
|
12
|
-
* @param interval - Check interval in milliseconds (default: 50)
|
|
13
|
-
* @throws If timeout is reached before condition is met
|
|
14
|
-
*/
|
|
15
|
-
declare function waitForCondition(condition: () => boolean | Promise<boolean>, timeout?: number, interval?: number): Promise<void>;
|
|
16
|
-
/**
|
|
17
|
-
* Delays execution for a specified amount of time
|
|
18
|
-
* @param ms - Milliseconds to delay
|
|
19
|
-
*/
|
|
20
|
-
declare function delay(ms: number): Promise<void>;
|
|
21
|
-
/**
|
|
22
|
-
* Creates a spy function that records calls and arguments
|
|
23
|
-
* @returns Spy function with call tracking
|
|
24
|
-
*/
|
|
25
|
-
declare function createSpy<
|
|
26
|
-
TArgs extends unknown[],
|
|
27
|
-
TReturn
|
|
28
|
-
>(implementation?: (...args: TArgs) => TReturn): {
|
|
29
|
-
(...args: TArgs): TReturn;
|
|
30
|
-
calls: TArgs[];
|
|
31
|
-
callCount: number;
|
|
32
|
-
reset: () => void;
|
|
33
|
-
};
|
|
34
|
-
/**
|
|
35
|
-
* Creates a mock function that returns predefined values
|
|
36
|
-
* @param returnValues - Array of values to return on consecutive calls
|
|
37
|
-
* @returns Mock function
|
|
38
|
-
*/
|
|
39
|
-
declare function createMockFn<T>(...returnValues: T[]): () => T;
|
|
40
|
-
/**
|
|
41
|
-
* Creates a mock promise that can be resolved or rejected manually
|
|
42
|
-
* @returns Object with promise and resolve/reject functions
|
|
43
|
-
*/
|
|
44
|
-
declare function createDeferredPromise<T>(): {
|
|
45
|
-
promise: Promise<T>;
|
|
46
|
-
resolve: (value: T) => void;
|
|
47
|
-
reject: (reason?: unknown) => void;
|
|
48
|
-
};
|
|
49
|
-
/**
|
|
50
|
-
* Captures console output during test execution
|
|
51
|
-
* @param fn - Function to execute while capturing output
|
|
52
|
-
* @returns Object with stdout and stderr arrays
|
|
53
|
-
*/
|
|
54
|
-
declare function captureConsole<T>(fn: () => Promise<T> | T): Promise<{
|
|
55
|
-
stdout: string[];
|
|
56
|
-
stderr: string[];
|
|
57
|
-
result: T;
|
|
58
|
-
}>;
|
|
59
|
-
/**
|
|
60
|
-
* Creates a unique temporary directory for tests in /tmp
|
|
61
|
-
* @param prefix - Optional prefix for the directory name (default: "omnidev-test-")
|
|
62
|
-
* @returns Path to the created temporary directory
|
|
63
|
-
*/
|
|
64
|
-
declare function tmpdir(prefix?: string): string;
|
|
65
|
-
type TestDirOptions = {
|
|
66
|
-
chdir?: boolean;
|
|
67
|
-
createOmniDir?: boolean;
|
|
68
|
-
};
|
|
69
|
-
type TestDirController = {
|
|
70
|
-
readonly path: string;
|
|
71
|
-
readonly originalCwd: string;
|
|
72
|
-
setPath: (path: string, options?: TestDirOptions) => void;
|
|
73
|
-
reset: (prefix?: string, options?: TestDirOptions & {
|
|
74
|
-
cleanupPrevious?: boolean;
|
|
75
|
-
}) => string;
|
|
76
|
-
};
|
|
77
|
-
/**
|
|
78
|
-
* Sets up a temporary directory for each test and cleans it up automatically.
|
|
79
|
-
* Registers beforeEach/afterEach hooks on call.
|
|
80
|
-
*/
|
|
81
|
-
declare function setupTestDir(prefix?: string, options?: TestDirOptions): TestDirController;
|
|
82
|
-
/**
|
|
83
|
-
* Mock factories for creating test data
|
|
84
|
-
*/
|
|
85
|
-
interface MockCapability {
|
|
86
|
-
id: string;
|
|
87
|
-
name: string;
|
|
88
|
-
version: string;
|
|
89
|
-
enabled?: boolean;
|
|
90
|
-
metadata?: Record<string, unknown>;
|
|
91
|
-
}
|
|
92
|
-
interface MockConfig {
|
|
93
|
-
project: string;
|
|
94
|
-
capabilities: {
|
|
95
|
-
enable: string[];
|
|
96
|
-
disable?: string[];
|
|
97
|
-
};
|
|
98
|
-
profiles?: Record<string, unknown>;
|
|
99
|
-
env?: Record<string, string>;
|
|
100
|
-
}
|
|
101
|
-
interface MockSkill {
|
|
102
|
-
id: string;
|
|
103
|
-
name: string;
|
|
104
|
-
description: string;
|
|
105
|
-
instructions: string;
|
|
106
|
-
triggers?: string[];
|
|
107
|
-
}
|
|
108
|
-
interface MockRule {
|
|
109
|
-
id: string;
|
|
110
|
-
name: string;
|
|
111
|
-
content: string;
|
|
112
|
-
priority?: number;
|
|
113
|
-
}
|
|
114
|
-
/**
|
|
115
|
-
* Creates a mock capability with default values
|
|
116
|
-
* @param overrides - Partial capability object to override defaults
|
|
117
|
-
* @returns Mock capability object
|
|
118
|
-
*/
|
|
119
|
-
declare function createMockCapability(overrides?: Partial<MockCapability>): MockCapability;
|
|
120
|
-
/**
|
|
121
|
-
* Creates a mock config with default values
|
|
122
|
-
* @param overrides - Partial config object to override defaults
|
|
123
|
-
* @returns Mock config object
|
|
124
|
-
*/
|
|
125
|
-
declare function createMockConfig(overrides?: Partial<MockConfig>): MockConfig;
|
|
126
|
-
/**
|
|
127
|
-
* Creates a mock skill with default values
|
|
128
|
-
* @param overrides - Partial skill object to override defaults
|
|
129
|
-
* @returns Mock skill object
|
|
130
|
-
*/
|
|
131
|
-
declare function createMockSkill(overrides?: Partial<MockSkill>): MockSkill;
|
|
132
|
-
/**
|
|
133
|
-
* Creates a mock rule with default values
|
|
134
|
-
* @param overrides - Partial rule object to override defaults
|
|
135
|
-
* @returns Mock rule object
|
|
136
|
-
*/
|
|
137
|
-
declare function createMockRule(overrides?: Partial<MockRule>): MockRule;
|
|
138
|
-
export { waitForCondition, tmpdir, setupTestDir, expectToThrowAsync, delay, createSpy, createMockSkill, createMockRule, createMockFn, createMockConfig, createMockCapability, createDeferredPromise, captureConsole, TestDirOptions, TestDirController, MockSkill, MockRule, MockConfig, MockCapability };
|
package/dist/test-utils/index.js
DELETED
|
@@ -1,230 +0,0 @@
|
|
|
1
|
-
import"../shared/chunk-1dqs11h6.js";
|
|
2
|
-
|
|
3
|
-
// src/test-utils/helpers.ts
|
|
4
|
-
import { afterEach, beforeEach, expect } from "bun:test";
|
|
5
|
-
import { existsSync, mkdirSync, mkdtempSync, rmSync } from "node:fs";
|
|
6
|
-
import { tmpdir as osTmpdir } from "node:os";
|
|
7
|
-
import { join } from "node:path";
|
|
8
|
-
async function expectToThrowAsync(fn, errorMatch) {
|
|
9
|
-
let threw = false;
|
|
10
|
-
let caughtError;
|
|
11
|
-
try {
|
|
12
|
-
await fn();
|
|
13
|
-
} catch (e) {
|
|
14
|
-
threw = true;
|
|
15
|
-
caughtError = e;
|
|
16
|
-
}
|
|
17
|
-
expect(threw).toBe(true);
|
|
18
|
-
if (errorMatch && caughtError) {
|
|
19
|
-
if (typeof errorMatch === "string") {
|
|
20
|
-
expect(caughtError.message).toContain(errorMatch);
|
|
21
|
-
} else {
|
|
22
|
-
expect(caughtError.message).toMatch(errorMatch);
|
|
23
|
-
}
|
|
24
|
-
}
|
|
25
|
-
}
|
|
26
|
-
async function waitForCondition(condition, timeout = 1000, interval = 50) {
|
|
27
|
-
const startTime = Date.now();
|
|
28
|
-
while (Date.now() - startTime < timeout) {
|
|
29
|
-
const result = await condition();
|
|
30
|
-
if (result) {
|
|
31
|
-
return;
|
|
32
|
-
}
|
|
33
|
-
await delay(interval);
|
|
34
|
-
}
|
|
35
|
-
throw new Error(`Condition not met within ${timeout}ms`);
|
|
36
|
-
}
|
|
37
|
-
function delay(ms) {
|
|
38
|
-
return new Promise((resolve) => setTimeout(resolve, ms));
|
|
39
|
-
}
|
|
40
|
-
function createSpy(implementation) {
|
|
41
|
-
const calls = [];
|
|
42
|
-
const spy = (...args) => {
|
|
43
|
-
calls.push(args);
|
|
44
|
-
if (implementation) {
|
|
45
|
-
return implementation(...args);
|
|
46
|
-
}
|
|
47
|
-
return;
|
|
48
|
-
};
|
|
49
|
-
Object.defineProperty(spy, "calls", {
|
|
50
|
-
get: () => calls
|
|
51
|
-
});
|
|
52
|
-
Object.defineProperty(spy, "callCount", {
|
|
53
|
-
get: () => calls.length
|
|
54
|
-
});
|
|
55
|
-
spy.reset = () => {
|
|
56
|
-
calls.length = 0;
|
|
57
|
-
};
|
|
58
|
-
return spy;
|
|
59
|
-
}
|
|
60
|
-
function createMockFn(...returnValues) {
|
|
61
|
-
let callIndex = 0;
|
|
62
|
-
return () => {
|
|
63
|
-
if (callIndex >= returnValues.length) {
|
|
64
|
-
throw new Error("Mock function called more times than return values provided");
|
|
65
|
-
}
|
|
66
|
-
const value = returnValues[callIndex++];
|
|
67
|
-
if (value === undefined) {
|
|
68
|
-
throw new Error("Mock function returned undefined");
|
|
69
|
-
}
|
|
70
|
-
return value;
|
|
71
|
-
};
|
|
72
|
-
}
|
|
73
|
-
function createDeferredPromise() {
|
|
74
|
-
let resolveRef;
|
|
75
|
-
let rejectRef;
|
|
76
|
-
const promise = new Promise((res, rej) => {
|
|
77
|
-
resolveRef = res;
|
|
78
|
-
rejectRef = rej;
|
|
79
|
-
});
|
|
80
|
-
return {
|
|
81
|
-
promise,
|
|
82
|
-
resolve: resolveRef,
|
|
83
|
-
reject: rejectRef
|
|
84
|
-
};
|
|
85
|
-
}
|
|
86
|
-
async function captureConsole(fn) {
|
|
87
|
-
const stdout = [];
|
|
88
|
-
const stderr = [];
|
|
89
|
-
const originalLog = console.log;
|
|
90
|
-
const originalError = console.error;
|
|
91
|
-
const originalWarn = console.warn;
|
|
92
|
-
console.log = (...args) => {
|
|
93
|
-
stdout.push(args.map(String).join(" "));
|
|
94
|
-
};
|
|
95
|
-
console.error = (...args) => {
|
|
96
|
-
stderr.push(args.map(String).join(" "));
|
|
97
|
-
};
|
|
98
|
-
console.warn = (...args) => {
|
|
99
|
-
stderr.push(args.map(String).join(" "));
|
|
100
|
-
};
|
|
101
|
-
try {
|
|
102
|
-
const result = await fn();
|
|
103
|
-
return { stdout, stderr, result };
|
|
104
|
-
} finally {
|
|
105
|
-
console.log = originalLog;
|
|
106
|
-
console.error = originalError;
|
|
107
|
-
console.warn = originalWarn;
|
|
108
|
-
}
|
|
109
|
-
}
|
|
110
|
-
function tmpdir(prefix = "omnidev-test-") {
|
|
111
|
-
return mkdtempSync(join(osTmpdir(), prefix));
|
|
112
|
-
}
|
|
113
|
-
function setupTestDir(prefix = "omnidev-test-", options = {}) {
|
|
114
|
-
let currentDir = "";
|
|
115
|
-
let originalCwd = "";
|
|
116
|
-
let shouldChdir = options.chdir ?? false;
|
|
117
|
-
let shouldCreateOmniDir = options.createOmniDir ?? false;
|
|
118
|
-
const applyOptions = (dir, nextOptions) => {
|
|
119
|
-
if (nextOptions) {
|
|
120
|
-
if (typeof nextOptions.chdir === "boolean") {
|
|
121
|
-
shouldChdir = nextOptions.chdir;
|
|
122
|
-
}
|
|
123
|
-
if (typeof nextOptions.createOmniDir === "boolean") {
|
|
124
|
-
shouldCreateOmniDir = nextOptions.createOmniDir;
|
|
125
|
-
}
|
|
126
|
-
}
|
|
127
|
-
if (shouldCreateOmniDir) {
|
|
128
|
-
mkdirSync(join(dir, ".omni"), { recursive: true });
|
|
129
|
-
}
|
|
130
|
-
if (shouldChdir) {
|
|
131
|
-
process.chdir(dir);
|
|
132
|
-
}
|
|
133
|
-
};
|
|
134
|
-
beforeEach(() => {
|
|
135
|
-
originalCwd = process.cwd();
|
|
136
|
-
currentDir = tmpdir(prefix);
|
|
137
|
-
applyOptions(currentDir);
|
|
138
|
-
});
|
|
139
|
-
afterEach(() => {
|
|
140
|
-
if (shouldChdir) {
|
|
141
|
-
process.chdir(originalCwd);
|
|
142
|
-
}
|
|
143
|
-
if (currentDir && existsSync(currentDir)) {
|
|
144
|
-
rmSync(currentDir, { recursive: true, force: true });
|
|
145
|
-
}
|
|
146
|
-
});
|
|
147
|
-
return {
|
|
148
|
-
get path() {
|
|
149
|
-
return currentDir;
|
|
150
|
-
},
|
|
151
|
-
get originalCwd() {
|
|
152
|
-
return originalCwd;
|
|
153
|
-
},
|
|
154
|
-
setPath(path, nextOptions) {
|
|
155
|
-
currentDir = path;
|
|
156
|
-
applyOptions(currentDir, nextOptions);
|
|
157
|
-
},
|
|
158
|
-
reset(nextPrefix = prefix, nextOptions) {
|
|
159
|
-
const cleanupPrevious = nextOptions?.cleanupPrevious ?? true;
|
|
160
|
-
if (cleanupPrevious && currentDir && existsSync(currentDir)) {
|
|
161
|
-
if (shouldChdir) {
|
|
162
|
-
process.chdir(originalCwd);
|
|
163
|
-
}
|
|
164
|
-
rmSync(currentDir, { recursive: true, force: true });
|
|
165
|
-
}
|
|
166
|
-
currentDir = tmpdir(nextPrefix);
|
|
167
|
-
applyOptions(currentDir, nextOptions);
|
|
168
|
-
return currentDir;
|
|
169
|
-
}
|
|
170
|
-
};
|
|
171
|
-
}
|
|
172
|
-
// src/test-utils/mocks.ts
|
|
173
|
-
function createMockCapability(overrides = {}) {
|
|
174
|
-
return {
|
|
175
|
-
id: "test-capability",
|
|
176
|
-
name: "Test Capability",
|
|
177
|
-
version: "1.0.0",
|
|
178
|
-
enabled: true,
|
|
179
|
-
metadata: {},
|
|
180
|
-
...overrides
|
|
181
|
-
};
|
|
182
|
-
}
|
|
183
|
-
function createMockConfig(overrides = {}) {
|
|
184
|
-
return {
|
|
185
|
-
project: "test-project",
|
|
186
|
-
capabilities: {
|
|
187
|
-
enable: [],
|
|
188
|
-
disable: []
|
|
189
|
-
},
|
|
190
|
-
profiles: {},
|
|
191
|
-
env: {},
|
|
192
|
-
...overrides
|
|
193
|
-
};
|
|
194
|
-
}
|
|
195
|
-
function createMockSkill(overrides = {}) {
|
|
196
|
-
return {
|
|
197
|
-
id: "test-skill",
|
|
198
|
-
name: "Test Skill",
|
|
199
|
-
description: "A test skill for unit testing",
|
|
200
|
-
instructions: "Test instructions",
|
|
201
|
-
triggers: [],
|
|
202
|
-
...overrides
|
|
203
|
-
};
|
|
204
|
-
}
|
|
205
|
-
function createMockRule(overrides = {}) {
|
|
206
|
-
return {
|
|
207
|
-
id: "test-rule",
|
|
208
|
-
name: "Test Rule",
|
|
209
|
-
content: `# Test Rule
|
|
210
|
-
|
|
211
|
-
Test rule content`,
|
|
212
|
-
priority: 1,
|
|
213
|
-
...overrides
|
|
214
|
-
};
|
|
215
|
-
}
|
|
216
|
-
export {
|
|
217
|
-
waitForCondition,
|
|
218
|
-
tmpdir,
|
|
219
|
-
setupTestDir,
|
|
220
|
-
expectToThrowAsync,
|
|
221
|
-
delay,
|
|
222
|
-
createSpy,
|
|
223
|
-
createMockSkill,
|
|
224
|
-
createMockRule,
|
|
225
|
-
createMockFn,
|
|
226
|
-
createMockConfig,
|
|
227
|
-
createMockCapability,
|
|
228
|
-
createDeferredPromise,
|
|
229
|
-
captureConsole
|
|
230
|
-
};
|
|
@@ -1,289 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* Helper functions for testing
|
|
3
|
-
*/
|
|
4
|
-
|
|
5
|
-
import { afterEach, beforeEach, expect } from "bun:test";
|
|
6
|
-
import { existsSync, mkdirSync, mkdtempSync, rmSync } from "node:fs";
|
|
7
|
-
import { tmpdir as osTmpdir } from "node:os";
|
|
8
|
-
import { join } from "node:path";
|
|
9
|
-
|
|
10
|
-
/**
|
|
11
|
-
* Expects an async function to throw an error
|
|
12
|
-
* @param fn - Async function that should throw
|
|
13
|
-
* @param errorMatch - Optional string or regex to match against error message
|
|
14
|
-
* @throws If the function doesn't throw
|
|
15
|
-
*/
|
|
16
|
-
export async function expectToThrowAsync(
|
|
17
|
-
fn: () => Promise<unknown>,
|
|
18
|
-
errorMatch?: string | RegExp,
|
|
19
|
-
): Promise<void> {
|
|
20
|
-
let threw = false;
|
|
21
|
-
let caughtError: Error | undefined;
|
|
22
|
-
|
|
23
|
-
try {
|
|
24
|
-
await fn();
|
|
25
|
-
} catch (e) {
|
|
26
|
-
threw = true;
|
|
27
|
-
caughtError = e as Error;
|
|
28
|
-
}
|
|
29
|
-
|
|
30
|
-
expect(threw).toBe(true);
|
|
31
|
-
|
|
32
|
-
if (errorMatch && caughtError) {
|
|
33
|
-
if (typeof errorMatch === "string") {
|
|
34
|
-
expect(caughtError.message).toContain(errorMatch);
|
|
35
|
-
} else {
|
|
36
|
-
expect(caughtError.message).toMatch(errorMatch);
|
|
37
|
-
}
|
|
38
|
-
}
|
|
39
|
-
}
|
|
40
|
-
|
|
41
|
-
/**
|
|
42
|
-
* Waits for a condition to be true
|
|
43
|
-
* @param condition - Function that returns true when condition is met
|
|
44
|
-
* @param timeout - Maximum time to wait in milliseconds (default: 1000)
|
|
45
|
-
* @param interval - Check interval in milliseconds (default: 50)
|
|
46
|
-
* @throws If timeout is reached before condition is met
|
|
47
|
-
*/
|
|
48
|
-
export async function waitForCondition(
|
|
49
|
-
condition: () => boolean | Promise<boolean>,
|
|
50
|
-
timeout = 1000,
|
|
51
|
-
interval = 50,
|
|
52
|
-
): Promise<void> {
|
|
53
|
-
const startTime = Date.now();
|
|
54
|
-
|
|
55
|
-
while (Date.now() - startTime < timeout) {
|
|
56
|
-
const result = await condition();
|
|
57
|
-
if (result) {
|
|
58
|
-
return;
|
|
59
|
-
}
|
|
60
|
-
await delay(interval);
|
|
61
|
-
}
|
|
62
|
-
|
|
63
|
-
throw new Error(`Condition not met within ${timeout}ms`);
|
|
64
|
-
}
|
|
65
|
-
|
|
66
|
-
/**
|
|
67
|
-
* Delays execution for a specified amount of time
|
|
68
|
-
* @param ms - Milliseconds to delay
|
|
69
|
-
*/
|
|
70
|
-
export function delay(ms: number): Promise<void> {
|
|
71
|
-
return new Promise((resolve) => setTimeout(resolve, ms));
|
|
72
|
-
}
|
|
73
|
-
|
|
74
|
-
/**
|
|
75
|
-
* Creates a spy function that records calls and arguments
|
|
76
|
-
* @returns Spy function with call tracking
|
|
77
|
-
*/
|
|
78
|
-
export function createSpy<TArgs extends unknown[], TReturn>(
|
|
79
|
-
implementation?: (...args: TArgs) => TReturn,
|
|
80
|
-
): {
|
|
81
|
-
(...args: TArgs): TReturn;
|
|
82
|
-
calls: TArgs[];
|
|
83
|
-
callCount: number;
|
|
84
|
-
reset: () => void;
|
|
85
|
-
} {
|
|
86
|
-
const calls: TArgs[] = [];
|
|
87
|
-
|
|
88
|
-
const spy = ((...args: TArgs) => {
|
|
89
|
-
calls.push(args);
|
|
90
|
-
if (implementation) {
|
|
91
|
-
return implementation(...args);
|
|
92
|
-
}
|
|
93
|
-
return undefined as TReturn;
|
|
94
|
-
}) as {
|
|
95
|
-
(...args: TArgs): TReturn;
|
|
96
|
-
calls: TArgs[];
|
|
97
|
-
callCount: number;
|
|
98
|
-
reset: () => void;
|
|
99
|
-
};
|
|
100
|
-
|
|
101
|
-
Object.defineProperty(spy, "calls", {
|
|
102
|
-
get: () => calls,
|
|
103
|
-
});
|
|
104
|
-
|
|
105
|
-
Object.defineProperty(spy, "callCount", {
|
|
106
|
-
get: () => calls.length,
|
|
107
|
-
});
|
|
108
|
-
|
|
109
|
-
spy.reset = () => {
|
|
110
|
-
calls.length = 0;
|
|
111
|
-
};
|
|
112
|
-
|
|
113
|
-
return spy;
|
|
114
|
-
}
|
|
115
|
-
|
|
116
|
-
/**
|
|
117
|
-
* Creates a mock function that returns predefined values
|
|
118
|
-
* @param returnValues - Array of values to return on consecutive calls
|
|
119
|
-
* @returns Mock function
|
|
120
|
-
*/
|
|
121
|
-
export function createMockFn<T>(...returnValues: T[]): () => T {
|
|
122
|
-
let callIndex = 0;
|
|
123
|
-
|
|
124
|
-
return () => {
|
|
125
|
-
if (callIndex >= returnValues.length) {
|
|
126
|
-
throw new Error("Mock function called more times than return values provided");
|
|
127
|
-
}
|
|
128
|
-
const value = returnValues[callIndex++];
|
|
129
|
-
if (value === undefined) {
|
|
130
|
-
throw new Error("Mock function returned undefined");
|
|
131
|
-
}
|
|
132
|
-
return value;
|
|
133
|
-
};
|
|
134
|
-
}
|
|
135
|
-
|
|
136
|
-
/**
|
|
137
|
-
* Creates a mock promise that can be resolved or rejected manually
|
|
138
|
-
* @returns Object with promise and resolve/reject functions
|
|
139
|
-
*/
|
|
140
|
-
export function createDeferredPromise<T>(): {
|
|
141
|
-
promise: Promise<T>;
|
|
142
|
-
resolve: (value: T) => void;
|
|
143
|
-
reject: (reason?: unknown) => void;
|
|
144
|
-
} {
|
|
145
|
-
let resolveRef!: (value: T) => void;
|
|
146
|
-
let rejectRef!: (reason?: unknown) => void;
|
|
147
|
-
|
|
148
|
-
const promise = new Promise<T>((res, rej) => {
|
|
149
|
-
resolveRef = res;
|
|
150
|
-
rejectRef = rej;
|
|
151
|
-
});
|
|
152
|
-
|
|
153
|
-
return {
|
|
154
|
-
promise: promise,
|
|
155
|
-
resolve: resolveRef,
|
|
156
|
-
reject: rejectRef,
|
|
157
|
-
};
|
|
158
|
-
}
|
|
159
|
-
|
|
160
|
-
/**
|
|
161
|
-
* Captures console output during test execution
|
|
162
|
-
* @param fn - Function to execute while capturing output
|
|
163
|
-
* @returns Object with stdout and stderr arrays
|
|
164
|
-
*/
|
|
165
|
-
export async function captureConsole<T>(
|
|
166
|
-
fn: () => Promise<T> | T,
|
|
167
|
-
): Promise<{ stdout: string[]; stderr: string[]; result: T }> {
|
|
168
|
-
const stdout: string[] = [];
|
|
169
|
-
const stderr: string[] = [];
|
|
170
|
-
|
|
171
|
-
const originalLog = console.log;
|
|
172
|
-
const originalError = console.error;
|
|
173
|
-
const originalWarn = console.warn;
|
|
174
|
-
|
|
175
|
-
console.log = (...args: unknown[]) => {
|
|
176
|
-
stdout.push(args.map(String).join(" "));
|
|
177
|
-
};
|
|
178
|
-
|
|
179
|
-
console.error = (...args: unknown[]) => {
|
|
180
|
-
stderr.push(args.map(String).join(" "));
|
|
181
|
-
};
|
|
182
|
-
|
|
183
|
-
console.warn = (...args: unknown[]) => {
|
|
184
|
-
stderr.push(args.map(String).join(" "));
|
|
185
|
-
};
|
|
186
|
-
|
|
187
|
-
try {
|
|
188
|
-
const result = await fn();
|
|
189
|
-
return { stdout, stderr, result };
|
|
190
|
-
} finally {
|
|
191
|
-
console.log = originalLog;
|
|
192
|
-
console.error = originalError;
|
|
193
|
-
console.warn = originalWarn;
|
|
194
|
-
}
|
|
195
|
-
}
|
|
196
|
-
|
|
197
|
-
/**
|
|
198
|
-
* Creates a unique temporary directory for tests in /tmp
|
|
199
|
-
* @param prefix - Optional prefix for the directory name (default: "omnidev-test-")
|
|
200
|
-
* @returns Path to the created temporary directory
|
|
201
|
-
*/
|
|
202
|
-
export function tmpdir(prefix = "omnidev-test-"): string {
|
|
203
|
-
return mkdtempSync(join(osTmpdir(), prefix));
|
|
204
|
-
}
|
|
205
|
-
|
|
206
|
-
export type TestDirOptions = {
|
|
207
|
-
chdir?: boolean;
|
|
208
|
-
createOmniDir?: boolean;
|
|
209
|
-
};
|
|
210
|
-
|
|
211
|
-
export type TestDirController = {
|
|
212
|
-
readonly path: string;
|
|
213
|
-
readonly originalCwd: string;
|
|
214
|
-
setPath: (path: string, options?: TestDirOptions) => void;
|
|
215
|
-
reset: (prefix?: string, options?: TestDirOptions & { cleanupPrevious?: boolean }) => string;
|
|
216
|
-
};
|
|
217
|
-
|
|
218
|
-
/**
|
|
219
|
-
* Sets up a temporary directory for each test and cleans it up automatically.
|
|
220
|
-
* Registers beforeEach/afterEach hooks on call.
|
|
221
|
-
*/
|
|
222
|
-
export function setupTestDir(
|
|
223
|
-
prefix = "omnidev-test-",
|
|
224
|
-
options: TestDirOptions = {},
|
|
225
|
-
): TestDirController {
|
|
226
|
-
let currentDir = "";
|
|
227
|
-
let originalCwd = "";
|
|
228
|
-
let shouldChdir = options.chdir ?? false;
|
|
229
|
-
let shouldCreateOmniDir = options.createOmniDir ?? false;
|
|
230
|
-
|
|
231
|
-
const applyOptions = (dir: string, nextOptions?: TestDirOptions) => {
|
|
232
|
-
if (nextOptions) {
|
|
233
|
-
if (typeof nextOptions.chdir === "boolean") {
|
|
234
|
-
shouldChdir = nextOptions.chdir;
|
|
235
|
-
}
|
|
236
|
-
if (typeof nextOptions.createOmniDir === "boolean") {
|
|
237
|
-
shouldCreateOmniDir = nextOptions.createOmniDir;
|
|
238
|
-
}
|
|
239
|
-
}
|
|
240
|
-
|
|
241
|
-
if (shouldCreateOmniDir) {
|
|
242
|
-
mkdirSync(join(dir, ".omni"), { recursive: true });
|
|
243
|
-
}
|
|
244
|
-
|
|
245
|
-
if (shouldChdir) {
|
|
246
|
-
process.chdir(dir);
|
|
247
|
-
}
|
|
248
|
-
};
|
|
249
|
-
|
|
250
|
-
beforeEach(() => {
|
|
251
|
-
originalCwd = process.cwd();
|
|
252
|
-
currentDir = tmpdir(prefix);
|
|
253
|
-
applyOptions(currentDir);
|
|
254
|
-
});
|
|
255
|
-
|
|
256
|
-
afterEach(() => {
|
|
257
|
-
if (shouldChdir) {
|
|
258
|
-
process.chdir(originalCwd);
|
|
259
|
-
}
|
|
260
|
-
if (currentDir && existsSync(currentDir)) {
|
|
261
|
-
rmSync(currentDir, { recursive: true, force: true });
|
|
262
|
-
}
|
|
263
|
-
});
|
|
264
|
-
|
|
265
|
-
return {
|
|
266
|
-
get path() {
|
|
267
|
-
return currentDir;
|
|
268
|
-
},
|
|
269
|
-
get originalCwd() {
|
|
270
|
-
return originalCwd;
|
|
271
|
-
},
|
|
272
|
-
setPath(path: string, nextOptions?: TestDirOptions) {
|
|
273
|
-
currentDir = path;
|
|
274
|
-
applyOptions(currentDir, nextOptions);
|
|
275
|
-
},
|
|
276
|
-
reset(nextPrefix = prefix, nextOptions?: TestDirOptions & { cleanupPrevious?: boolean }) {
|
|
277
|
-
const cleanupPrevious = nextOptions?.cleanupPrevious ?? true;
|
|
278
|
-
if (cleanupPrevious && currentDir && existsSync(currentDir)) {
|
|
279
|
-
if (shouldChdir) {
|
|
280
|
-
process.chdir(originalCwd);
|
|
281
|
-
}
|
|
282
|
-
rmSync(currentDir, { recursive: true, force: true });
|
|
283
|
-
}
|
|
284
|
-
currentDir = tmpdir(nextPrefix);
|
|
285
|
-
applyOptions(currentDir, nextOptions);
|
|
286
|
-
return currentDir;
|
|
287
|
-
},
|
|
288
|
-
};
|
|
289
|
-
}
|
package/src/test-utils/index.ts
DELETED
|
@@ -1,34 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* Test utilities for OmniDev
|
|
3
|
-
*
|
|
4
|
-
* This module provides shared test utilities including:
|
|
5
|
-
* - Mock factories for creating test data
|
|
6
|
-
* - Helper functions for async testing
|
|
7
|
-
* - Spy and mock function utilities
|
|
8
|
-
*/
|
|
9
|
-
|
|
10
|
-
// Re-export all helper functions
|
|
11
|
-
export {
|
|
12
|
-
captureConsole,
|
|
13
|
-
createDeferredPromise,
|
|
14
|
-
createMockFn,
|
|
15
|
-
createSpy,
|
|
16
|
-
delay,
|
|
17
|
-
expectToThrowAsync,
|
|
18
|
-
setupTestDir,
|
|
19
|
-
type TestDirController,
|
|
20
|
-
type TestDirOptions,
|
|
21
|
-
tmpdir,
|
|
22
|
-
waitForCondition,
|
|
23
|
-
} from "./helpers";
|
|
24
|
-
// Re-export all mock factories
|
|
25
|
-
export {
|
|
26
|
-
createMockCapability,
|
|
27
|
-
createMockConfig,
|
|
28
|
-
createMockRule,
|
|
29
|
-
createMockSkill,
|
|
30
|
-
type MockCapability,
|
|
31
|
-
type MockConfig,
|
|
32
|
-
type MockRule,
|
|
33
|
-
type MockSkill,
|
|
34
|
-
} from "./mocks";
|
package/src/test-utils/mocks.ts
DELETED
|
@@ -1,101 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* Mock factories for creating test data
|
|
3
|
-
*/
|
|
4
|
-
|
|
5
|
-
export interface MockCapability {
|
|
6
|
-
id: string;
|
|
7
|
-
name: string;
|
|
8
|
-
version: string;
|
|
9
|
-
enabled?: boolean;
|
|
10
|
-
metadata?: Record<string, unknown>;
|
|
11
|
-
}
|
|
12
|
-
|
|
13
|
-
export interface MockConfig {
|
|
14
|
-
project: string;
|
|
15
|
-
capabilities: {
|
|
16
|
-
enable: string[];
|
|
17
|
-
disable?: string[];
|
|
18
|
-
};
|
|
19
|
-
profiles?: Record<string, unknown>;
|
|
20
|
-
env?: Record<string, string>;
|
|
21
|
-
}
|
|
22
|
-
|
|
23
|
-
export interface MockSkill {
|
|
24
|
-
id: string;
|
|
25
|
-
name: string;
|
|
26
|
-
description: string;
|
|
27
|
-
instructions: string;
|
|
28
|
-
triggers?: string[];
|
|
29
|
-
}
|
|
30
|
-
|
|
31
|
-
export interface MockRule {
|
|
32
|
-
id: string;
|
|
33
|
-
name: string;
|
|
34
|
-
content: string;
|
|
35
|
-
priority?: number;
|
|
36
|
-
}
|
|
37
|
-
|
|
38
|
-
/**
|
|
39
|
-
* Creates a mock capability with default values
|
|
40
|
-
* @param overrides - Partial capability object to override defaults
|
|
41
|
-
* @returns Mock capability object
|
|
42
|
-
*/
|
|
43
|
-
export function createMockCapability(overrides: Partial<MockCapability> = {}): MockCapability {
|
|
44
|
-
return {
|
|
45
|
-
id: "test-capability",
|
|
46
|
-
name: "Test Capability",
|
|
47
|
-
version: "1.0.0",
|
|
48
|
-
enabled: true,
|
|
49
|
-
metadata: {},
|
|
50
|
-
...overrides,
|
|
51
|
-
};
|
|
52
|
-
}
|
|
53
|
-
|
|
54
|
-
/**
|
|
55
|
-
* Creates a mock config with default values
|
|
56
|
-
* @param overrides - Partial config object to override defaults
|
|
57
|
-
* @returns Mock config object
|
|
58
|
-
*/
|
|
59
|
-
export function createMockConfig(overrides: Partial<MockConfig> = {}): MockConfig {
|
|
60
|
-
return {
|
|
61
|
-
project: "test-project",
|
|
62
|
-
capabilities: {
|
|
63
|
-
enable: [],
|
|
64
|
-
disable: [],
|
|
65
|
-
},
|
|
66
|
-
profiles: {},
|
|
67
|
-
env: {},
|
|
68
|
-
...overrides,
|
|
69
|
-
};
|
|
70
|
-
}
|
|
71
|
-
|
|
72
|
-
/**
|
|
73
|
-
* Creates a mock skill with default values
|
|
74
|
-
* @param overrides - Partial skill object to override defaults
|
|
75
|
-
* @returns Mock skill object
|
|
76
|
-
*/
|
|
77
|
-
export function createMockSkill(overrides: Partial<MockSkill> = {}): MockSkill {
|
|
78
|
-
return {
|
|
79
|
-
id: "test-skill",
|
|
80
|
-
name: "Test Skill",
|
|
81
|
-
description: "A test skill for unit testing",
|
|
82
|
-
instructions: "Test instructions",
|
|
83
|
-
triggers: [],
|
|
84
|
-
...overrides,
|
|
85
|
-
};
|
|
86
|
-
}
|
|
87
|
-
|
|
88
|
-
/**
|
|
89
|
-
* Creates a mock rule with default values
|
|
90
|
-
* @param overrides - Partial rule object to override defaults
|
|
91
|
-
* @returns Mock rule object
|
|
92
|
-
*/
|
|
93
|
-
export function createMockRule(overrides: Partial<MockRule> = {}): MockRule {
|
|
94
|
-
return {
|
|
95
|
-
id: "test-rule",
|
|
96
|
-
name: "Test Rule",
|
|
97
|
-
content: "# Test Rule\n\nTest rule content",
|
|
98
|
-
priority: 1,
|
|
99
|
-
...overrides,
|
|
100
|
-
};
|
|
101
|
-
}
|