@sesamespace/hivemind 0.12.2 → 0.12.3
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/{chunk-ZAPHLG7V.js → chunk-3SIWFXC7.js} +2 -2
- package/dist/{chunk-EJM4KCCY.js → chunk-6W56VBXG.js} +2 -2
- package/dist/{chunk-SNW6Z2W4.js → chunk-7HOPTFRU.js} +2 -2
- package/dist/{chunk-3F7M2BPR.js → chunk-EDSK2CG6.js} +3 -3
- package/dist/{chunk-ZI4AN7GT.js → chunk-KOSNIWPS.js} +2 -2
- package/dist/{chunk-R7RHYYOM.js → chunk-TQYOGZIN.js} +179 -26
- package/dist/{chunk-R7RHYYOM.js.map → chunk-TQYOGZIN.js.map} +1 -1
- package/dist/commands/fleet.js +3 -3
- package/dist/commands/init.js +3 -3
- package/dist/commands/start.js +3 -3
- package/dist/commands/watchdog.js +3 -3
- package/dist/index.js +2 -2
- package/dist/main.js +6 -6
- package/dist/start.js +1 -1
- package/package.json +1 -1
- package/test/claude-integration.test.ts +325 -0
- /package/dist/{chunk-ZAPHLG7V.js.map → chunk-3SIWFXC7.js.map} +0 -0
- /package/dist/{chunk-EJM4KCCY.js.map → chunk-6W56VBXG.js.map} +0 -0
- /package/dist/{chunk-SNW6Z2W4.js.map → chunk-7HOPTFRU.js.map} +0 -0
- /package/dist/{chunk-3F7M2BPR.js.map → chunk-EDSK2CG6.js.map} +0 -0
- /package/dist/{chunk-ZI4AN7GT.js.map → chunk-KOSNIWPS.js.map} +0 -0
package/dist/commands/fleet.js
CHANGED
|
@@ -1,8 +1,8 @@
|
|
|
1
1
|
import {
|
|
2
2
|
runFleetCommand
|
|
3
|
-
} from "../chunk-
|
|
4
|
-
import "../chunk-
|
|
5
|
-
import "../chunk-
|
|
3
|
+
} from "../chunk-6W56VBXG.js";
|
|
4
|
+
import "../chunk-3SIWFXC7.js";
|
|
5
|
+
import "../chunk-TQYOGZIN.js";
|
|
6
6
|
import "../chunk-DGUM43GV.js";
|
|
7
7
|
export {
|
|
8
8
|
runFleetCommand
|
package/dist/commands/init.js
CHANGED
|
@@ -1,8 +1,8 @@
|
|
|
1
1
|
import {
|
|
2
2
|
runInitCommand
|
|
3
|
-
} from "../chunk-
|
|
4
|
-
import "../chunk-
|
|
5
|
-
import "../chunk-
|
|
3
|
+
} from "../chunk-KOSNIWPS.js";
|
|
4
|
+
import "../chunk-3SIWFXC7.js";
|
|
5
|
+
import "../chunk-TQYOGZIN.js";
|
|
6
6
|
import "../chunk-DGUM43GV.js";
|
|
7
7
|
export {
|
|
8
8
|
runInitCommand
|
package/dist/commands/start.js
CHANGED
|
@@ -1,8 +1,8 @@
|
|
|
1
1
|
import {
|
|
2
2
|
runStartCommand
|
|
3
|
-
} from "../chunk-
|
|
4
|
-
import "../chunk-
|
|
5
|
-
import "../chunk-
|
|
3
|
+
} from "../chunk-7HOPTFRU.js";
|
|
4
|
+
import "../chunk-3SIWFXC7.js";
|
|
5
|
+
import "../chunk-TQYOGZIN.js";
|
|
6
6
|
import "../chunk-DGUM43GV.js";
|
|
7
7
|
export {
|
|
8
8
|
runStartCommand
|
|
@@ -1,8 +1,8 @@
|
|
|
1
1
|
import {
|
|
2
2
|
runWatchdogCommand
|
|
3
|
-
} from "../chunk-
|
|
4
|
-
import "../chunk-
|
|
5
|
-
import "../chunk-
|
|
3
|
+
} from "../chunk-EDSK2CG6.js";
|
|
4
|
+
import "../chunk-3SIWFXC7.js";
|
|
5
|
+
import "../chunk-TQYOGZIN.js";
|
|
6
6
|
import "../chunk-DGUM43GV.js";
|
|
7
7
|
export {
|
|
8
8
|
runWatchdogCommand
|
package/dist/index.js
CHANGED
|
@@ -4,7 +4,7 @@ import {
|
|
|
4
4
|
PrimaryMemorySync,
|
|
5
5
|
Watchdog,
|
|
6
6
|
WorkerMemorySync
|
|
7
|
-
} from "./chunk-
|
|
7
|
+
} from "./chunk-3SIWFXC7.js";
|
|
8
8
|
import {
|
|
9
9
|
Agent,
|
|
10
10
|
AutoDebugger,
|
|
@@ -34,7 +34,7 @@ import {
|
|
|
34
34
|
setLogLevel,
|
|
35
35
|
startPipeline,
|
|
36
36
|
startWorker
|
|
37
|
-
} from "./chunk-
|
|
37
|
+
} from "./chunk-TQYOGZIN.js";
|
|
38
38
|
import "./chunk-DGUM43GV.js";
|
|
39
39
|
export {
|
|
40
40
|
Agent,
|
package/dist/main.js
CHANGED
|
@@ -1,13 +1,13 @@
|
|
|
1
1
|
#!/usr/bin/env node
|
|
2
2
|
import {
|
|
3
3
|
runInitCommand
|
|
4
|
-
} from "./chunk-
|
|
4
|
+
} from "./chunk-KOSNIWPS.js";
|
|
5
5
|
import {
|
|
6
6
|
runStartCommand
|
|
7
|
-
} from "./chunk-
|
|
7
|
+
} from "./chunk-7HOPTFRU.js";
|
|
8
8
|
import {
|
|
9
9
|
runFleetCommand
|
|
10
|
-
} from "./chunk-
|
|
10
|
+
} from "./chunk-6W56VBXG.js";
|
|
11
11
|
import {
|
|
12
12
|
runServiceCommand
|
|
13
13
|
} from "./chunk-6QZDXOMW.js";
|
|
@@ -16,9 +16,9 @@ import {
|
|
|
16
16
|
} from "./chunk-ICSJNKI6.js";
|
|
17
17
|
import {
|
|
18
18
|
runWatchdogCommand
|
|
19
|
-
} from "./chunk-
|
|
20
|
-
import "./chunk-
|
|
21
|
-
import "./chunk-
|
|
19
|
+
} from "./chunk-EDSK2CG6.js";
|
|
20
|
+
import "./chunk-3SIWFXC7.js";
|
|
21
|
+
import "./chunk-TQYOGZIN.js";
|
|
22
22
|
import "./chunk-DGUM43GV.js";
|
|
23
23
|
|
|
24
24
|
// packages/cli/src/commands/session.ts
|
package/dist/start.js
CHANGED
package/package.json
CHANGED
|
@@ -0,0 +1,325 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Test Suite for Claude Code Integration
|
|
3
|
+
*
|
|
4
|
+
* Tests the bidirectional context bridge, memory storage,
|
|
5
|
+
* and real-time notification systems.
|
|
6
|
+
*/
|
|
7
|
+
|
|
8
|
+
import { describe, it, expect, beforeEach, afterEach } from "@jest/globals";
|
|
9
|
+
import { ClaudeContextBridge } from "../packages/runtime/src/tools/context-bridge.js";
|
|
10
|
+
import { ClaudeNotifier } from "../packages/runtime/src/tools/claude-notifier.js";
|
|
11
|
+
import { MemoryClient } from "../packages/runtime/src/memory-client.js";
|
|
12
|
+
import { Logger } from "../packages/runtime/src/logger.js";
|
|
13
|
+
import { writeFileSync, unlinkSync, existsSync } from "fs";
|
|
14
|
+
import { join } from "path";
|
|
15
|
+
import { homedir } from "os";
|
|
16
|
+
|
|
17
|
+
describe("Claude Code Integration", () => {
|
|
18
|
+
let contextBridge: ClaudeContextBridge;
|
|
19
|
+
let memoryClient: MemoryClient;
|
|
20
|
+
let logger: Logger;
|
|
21
|
+
let workspaceDir: string;
|
|
22
|
+
let sessionLogPath: string;
|
|
23
|
+
|
|
24
|
+
beforeEach(async () => {
|
|
25
|
+
// Set up test environment
|
|
26
|
+
workspaceDir = "/tmp/test-workspace";
|
|
27
|
+
sessionLogPath = join(homedir(), ".claude", "session.log");
|
|
28
|
+
|
|
29
|
+
// Create mock implementations
|
|
30
|
+
logger = {
|
|
31
|
+
info: jest.fn(),
|
|
32
|
+
warn: jest.fn(),
|
|
33
|
+
error: jest.fn(),
|
|
34
|
+
debug: jest.fn(),
|
|
35
|
+
} as any;
|
|
36
|
+
|
|
37
|
+
memoryClient = {
|
|
38
|
+
search: jest.fn().mockResolvedValue([]),
|
|
39
|
+
storeEpisode: jest.fn().mockResolvedValue({}),
|
|
40
|
+
} as any;
|
|
41
|
+
|
|
42
|
+
// Create context bridge
|
|
43
|
+
contextBridge = new ClaudeContextBridge({
|
|
44
|
+
workspaceDir,
|
|
45
|
+
memoryClient,
|
|
46
|
+
logger,
|
|
47
|
+
});
|
|
48
|
+
|
|
49
|
+
await contextBridge.initialize();
|
|
50
|
+
});
|
|
51
|
+
|
|
52
|
+
afterEach(() => {
|
|
53
|
+
contextBridge.destroy();
|
|
54
|
+
// Clean up test files
|
|
55
|
+
if (existsSync(sessionLogPath)) {
|
|
56
|
+
unlinkSync(sessionLogPath);
|
|
57
|
+
}
|
|
58
|
+
});
|
|
59
|
+
|
|
60
|
+
describe("Context Preparation", () => {
|
|
61
|
+
it("should prepare context with all fields", async () => {
|
|
62
|
+
const context = {
|
|
63
|
+
goal: "Fix authentication bug",
|
|
64
|
+
requirements: ["Must support OAuth", "Handle token refresh"],
|
|
65
|
+
recentErrors: ["401 Unauthorized on /api/user"],
|
|
66
|
+
relevantPatterns: ["Use middleware for auth"],
|
|
67
|
+
workingFiles: ["src/auth.ts", "src/middleware.ts"],
|
|
68
|
+
knownConstraints: ["JWT tokens expire after 1 hour"],
|
|
69
|
+
};
|
|
70
|
+
|
|
71
|
+
await contextBridge.prepareContext(context);
|
|
72
|
+
|
|
73
|
+
const contextFile = join(workspaceDir, "CLAUDE_CONTEXT.md");
|
|
74
|
+
expect(existsSync(contextFile)).toBe(true);
|
|
75
|
+
|
|
76
|
+
const content = require('fs').readFileSync(contextFile, 'utf-8');
|
|
77
|
+
expect(content).toContain("Fix authentication bug");
|
|
78
|
+
expect(content).toContain("Must support OAuth");
|
|
79
|
+
expect(content).toContain("401 Unauthorized");
|
|
80
|
+
expect(content).toContain("Use middleware for auth");
|
|
81
|
+
expect(content).toContain("src/auth.ts");
|
|
82
|
+
expect(content).toContain("JWT tokens expire after 1 hour");
|
|
83
|
+
});
|
|
84
|
+
|
|
85
|
+
it("should include memory search results", async () => {
|
|
86
|
+
// Mock memory search
|
|
87
|
+
(memoryClient.search as jest.Mock).mockResolvedValue([
|
|
88
|
+
{ content: "Previous auth implementation used Passport.js" },
|
|
89
|
+
{ content: "Refresh tokens stored in Redis" },
|
|
90
|
+
]);
|
|
91
|
+
|
|
92
|
+
await contextBridge.prepareContext({ goal: "Implement authentication" });
|
|
93
|
+
|
|
94
|
+
expect(memoryClient.search).toHaveBeenCalledWith("Implement authentication", "global", 5);
|
|
95
|
+
|
|
96
|
+
const contextFile = join(workspaceDir, "CLAUDE_CONTEXT.md");
|
|
97
|
+
const content = require('fs').readFileSync(contextFile, 'utf-8');
|
|
98
|
+
expect(content).toContain("Previous auth implementation used Passport.js");
|
|
99
|
+
expect(content).toContain("Refresh tokens stored in Redis");
|
|
100
|
+
});
|
|
101
|
+
});
|
|
102
|
+
|
|
103
|
+
describe("Session Log Monitoring", () => {
|
|
104
|
+
it("should detect and process DISCOVERY entries", (done) => {
|
|
105
|
+
contextBridge.on('insight', ({ type, content }) => {
|
|
106
|
+
expect(type).toBe('DISCOVERY');
|
|
107
|
+
expect(content).toBe('Found JWT validation in middleware');
|
|
108
|
+
done();
|
|
109
|
+
});
|
|
110
|
+
|
|
111
|
+
// Simulate Claude writing to session log
|
|
112
|
+
setTimeout(() => {
|
|
113
|
+
writeFileSync(sessionLogPath, "DISCOVERY: Found JWT validation in middleware\n", { flag: 'a' });
|
|
114
|
+
}, 100);
|
|
115
|
+
});
|
|
116
|
+
|
|
117
|
+
it("should detect and process NEED entries", (done) => {
|
|
118
|
+
contextBridge.on('context-request', (need) => {
|
|
119
|
+
expect(need).toBe('Database schema for users table');
|
|
120
|
+
done();
|
|
121
|
+
});
|
|
122
|
+
|
|
123
|
+
setTimeout(() => {
|
|
124
|
+
writeFileSync(sessionLogPath, "NEED: Database schema for users table\n", { flag: 'a' });
|
|
125
|
+
}, 100);
|
|
126
|
+
});
|
|
127
|
+
|
|
128
|
+
it("should store PATTERN entries in memory", (done) => {
|
|
129
|
+
contextBridge.on('insight', async ({ type }) => {
|
|
130
|
+
if (type === 'PATTERN') {
|
|
131
|
+
// Give it time to store
|
|
132
|
+
setTimeout(() => {
|
|
133
|
+
expect(memoryClient.storeEpisode).toHaveBeenCalledWith({
|
|
134
|
+
context_name: "claude-code-insights",
|
|
135
|
+
role: "system",
|
|
136
|
+
content: "PATTERN: Always validate JWT in middleware",
|
|
137
|
+
metadata: expect.objectContaining({
|
|
138
|
+
type: "PATTERN",
|
|
139
|
+
source: "claude-code",
|
|
140
|
+
}),
|
|
141
|
+
});
|
|
142
|
+
done();
|
|
143
|
+
}, 100);
|
|
144
|
+
}
|
|
145
|
+
});
|
|
146
|
+
|
|
147
|
+
setTimeout(() => {
|
|
148
|
+
writeFileSync(sessionLogPath, "PATTERN: Always validate JWT in middleware\n", { flag: 'a' });
|
|
149
|
+
}, 100);
|
|
150
|
+
});
|
|
151
|
+
|
|
152
|
+
it("should deduplicate identical patterns", async () => {
|
|
153
|
+
// Write the same pattern twice
|
|
154
|
+
writeFileSync(sessionLogPath, "PATTERN: Use async/await for DB calls\n");
|
|
155
|
+
await new Promise(resolve => setTimeout(resolve, 600));
|
|
156
|
+
writeFileSync(sessionLogPath, "PATTERN: Use async/await for DB calls\n", { flag: 'a' });
|
|
157
|
+
await new Promise(resolve => setTimeout(resolve, 600));
|
|
158
|
+
|
|
159
|
+
// Should only store once
|
|
160
|
+
expect(memoryClient.storeEpisode).toHaveBeenCalledTimes(1);
|
|
161
|
+
});
|
|
162
|
+
});
|
|
163
|
+
|
|
164
|
+
describe("Real-time Context Injection", () => {
|
|
165
|
+
it("should append context when Claude needs it", async () => {
|
|
166
|
+
// Mock memory search for additional context
|
|
167
|
+
(memoryClient.search as jest.Mock).mockResolvedValue([
|
|
168
|
+
{ content: "Users table has columns: id, email, password_hash, created_at" },
|
|
169
|
+
]);
|
|
170
|
+
|
|
171
|
+
// Prepare initial context
|
|
172
|
+
await contextBridge.prepareContext({ goal: "Fix user query" });
|
|
173
|
+
|
|
174
|
+
// Simulate Claude needing more info
|
|
175
|
+
writeFileSync(sessionLogPath, "NEED: Database schema\n", { flag: 'a' });
|
|
176
|
+
|
|
177
|
+
// Wait for processing
|
|
178
|
+
await new Promise(resolve => setTimeout(resolve, 600));
|
|
179
|
+
|
|
180
|
+
// Check that context was appended
|
|
181
|
+
const contextFile = join(workspaceDir, "CLAUDE_CONTEXT.md");
|
|
182
|
+
const content = require('fs').readFileSync(contextFile, 'utf-8');
|
|
183
|
+
expect(content).toContain("Additional Context");
|
|
184
|
+
expect(content).toContain("You asked about: Database schema");
|
|
185
|
+
expect(content).toContain("Users table has columns");
|
|
186
|
+
});
|
|
187
|
+
});
|
|
188
|
+
|
|
189
|
+
describe("Session Summary", () => {
|
|
190
|
+
it("should retrieve categorized insights", async () => {
|
|
191
|
+
// Mock memory with various insight types
|
|
192
|
+
(memoryClient.search as jest.Mock).mockResolvedValue([
|
|
193
|
+
{ content: "DISCOVERY: Auth uses JWT with RS256" },
|
|
194
|
+
{ content: "PATTERN: Validate tokens in middleware" },
|
|
195
|
+
{ content: "ERROR: Missing JWKS endpoint" },
|
|
196
|
+
{ content: "COMPLETE: Implemented token refresh" },
|
|
197
|
+
{ content: "NEED: Public key for verification" },
|
|
198
|
+
]);
|
|
199
|
+
|
|
200
|
+
const summary = await contextBridge.getSessionSummary();
|
|
201
|
+
|
|
202
|
+
expect(summary.discoveries).toContain("Auth uses JWT with RS256");
|
|
203
|
+
expect(summary.patterns).toContain("Validate tokens in middleware");
|
|
204
|
+
expect(summary.errors).toContain("Missing JWKS endpoint");
|
|
205
|
+
expect(summary.completions).toContain("Implemented token refresh");
|
|
206
|
+
expect(summary.needs).toContain("Public key for verification");
|
|
207
|
+
});
|
|
208
|
+
});
|
|
209
|
+
|
|
210
|
+
describe("Notification System", () => {
|
|
211
|
+
it("should emit urgent events for NEED requests", (done) => {
|
|
212
|
+
const notifier = new ClaudeNotifier({
|
|
213
|
+
logger,
|
|
214
|
+
contextBridge,
|
|
215
|
+
onNeed: async (need) => {
|
|
216
|
+
expect(need).toBe("API documentation");
|
|
217
|
+
done();
|
|
218
|
+
},
|
|
219
|
+
});
|
|
220
|
+
|
|
221
|
+
// Simulate Claude needing something
|
|
222
|
+
writeFileSync(sessionLogPath, "NEED: API documentation\n", { flag: 'a' });
|
|
223
|
+
});
|
|
224
|
+
|
|
225
|
+
it("should handle critical errors", (done) => {
|
|
226
|
+
const notifier = new ClaudeNotifier({
|
|
227
|
+
logger,
|
|
228
|
+
contextBridge,
|
|
229
|
+
onError: async (error) => {
|
|
230
|
+
expect(error).toBe("Cannot find module 'auth'");
|
|
231
|
+
done();
|
|
232
|
+
},
|
|
233
|
+
});
|
|
234
|
+
|
|
235
|
+
writeFileSync(sessionLogPath, "ERROR: Cannot find module 'auth'\n", { flag: 'a' });
|
|
236
|
+
});
|
|
237
|
+
|
|
238
|
+
it("should create urgent events", (done) => {
|
|
239
|
+
const notifier = new ClaudeNotifier({
|
|
240
|
+
logger,
|
|
241
|
+
contextBridge,
|
|
242
|
+
});
|
|
243
|
+
|
|
244
|
+
notifier.on('urgent-event', (event) => {
|
|
245
|
+
expect(event.type).toBe("immediate");
|
|
246
|
+
expect(event.text).toContain("[Claude Code Urgent]");
|
|
247
|
+
expect(event.text).toContain("Missing database credentials");
|
|
248
|
+
done();
|
|
249
|
+
});
|
|
250
|
+
|
|
251
|
+
notifier.createUrgentEvent("Missing database credentials", "test-channel");
|
|
252
|
+
});
|
|
253
|
+
});
|
|
254
|
+
|
|
255
|
+
describe("End-to-End Integration", () => {
|
|
256
|
+
it("should handle a complete Claude Code session", async () => {
|
|
257
|
+
// Prepare context
|
|
258
|
+
await contextBridge.prepareContext({
|
|
259
|
+
goal: "Implement user authentication",
|
|
260
|
+
requirements: ["Support JWT", "Handle refresh tokens"],
|
|
261
|
+
});
|
|
262
|
+
|
|
263
|
+
// Simulate Claude Code session
|
|
264
|
+
const sessionLog = [
|
|
265
|
+
"DISCOVERY: Found existing Passport.js setup",
|
|
266
|
+
"PATTERN: Use httpOnly cookies for refresh tokens",
|
|
267
|
+
"NEED: Redis connection details",
|
|
268
|
+
"ERROR: Redis connection failed",
|
|
269
|
+
"COMPLETE: Implemented JWT authentication",
|
|
270
|
+
];
|
|
271
|
+
|
|
272
|
+
for (const line of sessionLog) {
|
|
273
|
+
writeFileSync(sessionLogPath, line + "\n", { flag: 'a' });
|
|
274
|
+
await new Promise(resolve => setTimeout(resolve, 100));
|
|
275
|
+
}
|
|
276
|
+
|
|
277
|
+
// Wait for processing
|
|
278
|
+
await new Promise(resolve => setTimeout(resolve, 1000));
|
|
279
|
+
|
|
280
|
+
// Verify memory storage
|
|
281
|
+
const storeEpisodeCalls = (memoryClient.storeEpisode as jest.Mock).mock.calls;
|
|
282
|
+
expect(storeEpisodeCalls.length).toBeGreaterThanOrEqual(2);
|
|
283
|
+
|
|
284
|
+
// Verify discoveries and patterns were stored
|
|
285
|
+
const storedContent = storeEpisodeCalls.map(call => call[0].content);
|
|
286
|
+
expect(storedContent).toContain("DISCOVERY: Found existing Passport.js setup");
|
|
287
|
+
expect(storedContent).toContain("PATTERN: Use httpOnly cookies for refresh tokens");
|
|
288
|
+
|
|
289
|
+
// Get session summary
|
|
290
|
+
const summary = await contextBridge.getSessionSummary();
|
|
291
|
+
expect(summary.discoveries.length).toBeGreaterThan(0);
|
|
292
|
+
expect(summary.patterns.length).toBeGreaterThan(0);
|
|
293
|
+
expect(summary.errors.length).toBeGreaterThan(0);
|
|
294
|
+
expect(summary.completions.length).toBeGreaterThan(0);
|
|
295
|
+
});
|
|
296
|
+
});
|
|
297
|
+
});
|
|
298
|
+
|
|
299
|
+
describe("Test Suite Requirements", () => {
|
|
300
|
+
it("should cover all critical functionality", () => {
|
|
301
|
+
const testCategories = [
|
|
302
|
+
"Context Preparation",
|
|
303
|
+
"Session Log Monitoring",
|
|
304
|
+
"Real-time Context Injection",
|
|
305
|
+
"Session Summary",
|
|
306
|
+
"Notification System",
|
|
307
|
+
"End-to-End Integration"
|
|
308
|
+
];
|
|
309
|
+
|
|
310
|
+
const criticalFeatures = [
|
|
311
|
+
"Prepare context with memory search",
|
|
312
|
+
"Monitor session log in real-time",
|
|
313
|
+
"Store discoveries and patterns",
|
|
314
|
+
"Deduplicate patterns",
|
|
315
|
+
"Inject context on NEED",
|
|
316
|
+
"Emit notifications for urgent needs",
|
|
317
|
+
"Generate session summaries",
|
|
318
|
+
"Handle complete sessions"
|
|
319
|
+
];
|
|
320
|
+
|
|
321
|
+
// This test just documents what we're testing
|
|
322
|
+
expect(testCategories.length).toBeGreaterThanOrEqual(6);
|
|
323
|
+
expect(criticalFeatures.length).toBeGreaterThanOrEqual(8);
|
|
324
|
+
});
|
|
325
|
+
});
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|