@onlineapps/conn-orch-validator 2.0.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.
Files changed (37) hide show
  1. package/README.md +78 -0
  2. package/TESTING_STRATEGY.md +92 -0
  3. package/docs/DESIGN.md +134 -0
  4. package/examples/service-wrapper-usage.js +250 -0
  5. package/examples/three-tier-testing.js +144 -0
  6. package/jest.config.js +23 -0
  7. package/onlineapps-conn-e2e-testing-1.0.0.tgz +0 -0
  8. package/package.json +43 -0
  9. package/src/CookbookTestRunner.js +434 -0
  10. package/src/CookbookTestUtils.js +237 -0
  11. package/src/ServiceReadinessValidator.js +430 -0
  12. package/src/ServiceTestHarness.js +256 -0
  13. package/src/ServiceValidator.js +387 -0
  14. package/src/TestOrchestrator.js +727 -0
  15. package/src/ValidationOrchestrator.js +506 -0
  16. package/src/WorkflowTestRunner.js +396 -0
  17. package/src/helpers/README.md +235 -0
  18. package/src/helpers/createPreValidationTests.js +321 -0
  19. package/src/helpers/createServiceReadinessTests.js +245 -0
  20. package/src/index.js +62 -0
  21. package/src/mocks/MockMQClient.js +176 -0
  22. package/src/mocks/MockRegistry.js +164 -0
  23. package/src/mocks/MockStorage.js +186 -0
  24. package/src/validators/ServiceStructureValidator.js +487 -0
  25. package/src/validators/ValidationProofGenerator.js +79 -0
  26. package/test-mq-flow.js +72 -0
  27. package/test-orchestrator.js +95 -0
  28. package/tests/component/testing-framework-integration.test.js +313 -0
  29. package/tests/integration/ServiceReadiness.test.js +265 -0
  30. package/tests/monitoring-e2e.test.js +315 -0
  31. package/tests/run-example.js +257 -0
  32. package/tests/unit/CookbookTestRunner.test.js +353 -0
  33. package/tests/unit/MockMQClient.test.js +190 -0
  34. package/tests/unit/MockRegistry.test.js +233 -0
  35. package/tests/unit/MockStorage.test.js +257 -0
  36. package/tests/unit/ServiceValidator.test.js +429 -0
  37. package/tests/unit/WorkflowTestRunner.test.js +546 -0
@@ -0,0 +1,95 @@
1
+ #!/usr/bin/env node
2
+ 'use strict';
3
+
4
+ /**
5
+ * Quick test of ValidationOrchestrator
6
+ *
7
+ * Usage: node test-orchestrator.js <serviceRoot>
8
+ * Example: node test-orchestrator.js /var/www/html/oa_drive/services/hello-service
9
+ *
10
+ * Loads service configuration from conn-config/config.json
11
+ */
12
+
13
+ const fs = require('fs');
14
+ const path = require('path');
15
+ const ValidationOrchestrator = require('./src/ValidationOrchestrator');
16
+
17
+ async function test() {
18
+ // Get service root from CLI or default to hello-service
19
+ const serviceRoot = process.argv[2] || path.resolve(__dirname, '../../../services/hello-service');
20
+
21
+ if (!fs.existsSync(serviceRoot)) {
22
+ console.error(`โŒ Service root not found: ${serviceRoot}`);
23
+ console.error('Usage: node test-orchestrator.js <serviceRoot>');
24
+ process.exit(1);
25
+ }
26
+
27
+ // Load service configuration
28
+ const configPath = path.join(serviceRoot, 'conn-config', 'config.json');
29
+ if (!fs.existsSync(configPath)) {
30
+ console.error(`โŒ Config not found: ${configPath}`);
31
+ console.error('Service must have conn-config/config.json');
32
+ process.exit(1);
33
+ }
34
+
35
+ const config = JSON.parse(fs.readFileSync(configPath, 'utf8'));
36
+ const serviceName = config.service?.name;
37
+ const serviceVersion = config.service?.version;
38
+
39
+ if (!serviceName || !serviceVersion) {
40
+ console.error('โŒ Config must contain service.name and service.version');
41
+ process.exit(1);
42
+ }
43
+
44
+ console.log(`๐Ÿงช Testing ValidationOrchestrator`);
45
+ console.log(` Service: ${serviceName} v${serviceVersion}`);
46
+ console.log(` Root: ${serviceRoot}\n`);
47
+
48
+ const orchestrator = new ValidationOrchestrator({
49
+ serviceRoot,
50
+ serviceName,
51
+ serviceVersion,
52
+ logger: console
53
+ });
54
+
55
+ try {
56
+ const result = await orchestrator.validate();
57
+
58
+ console.log('\n๐Ÿ“Š Validation Results:');
59
+ console.log('Success:', result.success);
60
+ console.log('Duration:', result.durationMs, 'ms');
61
+
62
+ if (result.skipped) {
63
+ console.log('โœ“ Used existing proof (validation skipped)');
64
+ console.log('Fingerprint:', result.proof?.fingerprint);
65
+ } else {
66
+ console.log('Tests run:', result.totalTests);
67
+ console.log('Tests passed:', result.passedTests);
68
+ console.log('Tests failed:', result.failedTests);
69
+
70
+ if (result.errors && result.errors.length > 0) {
71
+ console.log('\nโŒ Errors:');
72
+ result.errors.forEach(err => console.log(' -', err));
73
+ }
74
+
75
+ if (result.warnings && result.warnings.length > 0) {
76
+ console.log('\nโš ๏ธ Warnings:');
77
+ result.warnings.forEach(warn => console.log(' -', warn));
78
+ }
79
+
80
+ if (result.proof) {
81
+ console.log('\nโœ… Proof generated:');
82
+ console.log(' Fingerprint:', result.fingerprint);
83
+ console.log(' Location: conn-runtime/validation-proof.json');
84
+ }
85
+ }
86
+
87
+ process.exit(result.success ? 0 : 1);
88
+ } catch (error) {
89
+ console.error('\nโŒ Test failed:', error.message);
90
+ console.error(error.stack);
91
+ process.exit(1);
92
+ }
93
+ }
94
+
95
+ test();
@@ -0,0 +1,313 @@
1
+ 'use strict';
2
+
3
+ /**
4
+ * Component tests for E2E Testing Framework
5
+ * Tests the integration between different testing utilities
6
+ */
7
+
8
+ describe('E2E Testing Framework Integration @component', () => {
9
+ let framework;
10
+
11
+ beforeEach(() => {
12
+ jest.clearAllMocks();
13
+ delete require.cache[require.resolve('../../src/index.js')];
14
+ framework = require('../../src/index.js');
15
+ });
16
+
17
+ describe('Framework Exports', () => {
18
+ it('should export all mock components', () => {
19
+ expect(framework.MockMQClient).toBeDefined();
20
+ expect(framework.MockRegistry).toBeDefined();
21
+ expect(framework.MockStorage).toBeDefined();
22
+ });
23
+
24
+ it('should export all test utilities', () => {
25
+ expect(framework.ServiceTestHarness).toBeDefined();
26
+ expect(framework.ServiceValidator).toBeDefined();
27
+ expect(framework.WorkflowTestRunner).toBeDefined();
28
+ expect(framework.CookbookTestUtils).toBeDefined();
29
+ expect(framework.ServiceReadinessValidator).toBeDefined();
30
+ expect(framework.TestOrchestrator).toBeDefined();
31
+ });
32
+
33
+ it('should export factory functions', () => {
34
+ expect(typeof framework.createTestHarness).toBe('function');
35
+ expect(typeof framework.createValidator).toBe('function');
36
+ expect(typeof framework.createMockMQ).toBe('function');
37
+ expect(typeof framework.createMockRegistry).toBe('function');
38
+ expect(typeof framework.createMockStorage).toBe('function');
39
+ });
40
+ });
41
+
42
+ describe('Factory Functions', () => {
43
+ it('should create MockMQClient instance', () => {
44
+ const mq = framework.createMockMQ();
45
+ expect(mq.constructor.name).toBe('MockMQClient');
46
+ expect(typeof mq.connect).toBe('function');
47
+ expect(typeof mq.publish).toBe('function');
48
+ });
49
+
50
+ it('should create MockRegistry instance', () => {
51
+ const registry = framework.createMockRegistry();
52
+ expect(registry.constructor.name).toBe('MockRegistry');
53
+ expect(typeof registry.register).toBe('function');
54
+ expect(typeof registry.discover).toBe('function');
55
+ });
56
+
57
+ it('should create MockStorage instance', () => {
58
+ const storage = framework.createMockStorage();
59
+ expect(storage.constructor.name).toBe('MockStorage');
60
+ expect(typeof storage.upload).toBe('function');
61
+ expect(typeof storage.download).toBe('function');
62
+ });
63
+
64
+ it('should create ServiceTestHarness with options', () => {
65
+ const harness = framework.createTestHarness({
66
+ serviceName: 'test-service'
67
+ });
68
+ expect(harness.constructor.name).toBe('ServiceTestHarness');
69
+ expect(harness.serviceName).toBe('test-service');
70
+ });
71
+
72
+ it('should create ServiceValidator with options', () => {
73
+ const validator = framework.createValidator({
74
+ services: ['service1', 'service2']
75
+ });
76
+ expect(validator.constructor.name).toBe('ServiceValidator');
77
+ expect(validator.services).toEqual(['service1', 'service2']);
78
+ });
79
+ });
80
+
81
+ describe('Component Integration', () => {
82
+ it('should allow ServiceTestHarness to use mocks', async () => {
83
+ const harness = new framework.ServiceTestHarness({
84
+ serviceName: 'integration-test'
85
+ });
86
+
87
+ await harness.setup();
88
+
89
+ // Harness should have created mock instances
90
+ expect(harness.mq).toBeDefined();
91
+ expect(harness.registry).toBeDefined();
92
+ expect(harness.storage).toBeDefined();
93
+
94
+ await harness.cleanup();
95
+ });
96
+
97
+ it('should allow WorkflowTestRunner to use MockMQClient', async () => {
98
+ const mq = new framework.MockMQClient();
99
+ const runner = new framework.WorkflowTestRunner({
100
+ mq: mq
101
+ });
102
+
103
+ expect(runner.mq).toBe(mq);
104
+ expect(runner.state).toBeDefined();
105
+ });
106
+
107
+ it('should allow ServiceValidator to work with OpenAPI specs', () => {
108
+ const validator = new framework.ServiceValidator();
109
+
110
+ const spec = {
111
+ openapi: '3.0.0',
112
+ paths: {
113
+ '/test': {
114
+ get: {
115
+ responses: {
116
+ '200': { description: 'Success' }
117
+ }
118
+ }
119
+ }
120
+ }
121
+ };
122
+
123
+ const paths = validator.countEndpoints(spec.paths);
124
+ expect(paths).toBeGreaterThan(0);
125
+ });
126
+
127
+ it('should allow CookbookTestUtils to generate valid cookbooks', () => {
128
+ const utils = new framework.CookbookTestUtils();
129
+
130
+ const cookbook = utils.generateCookbook({
131
+ name: 'test-cookbook',
132
+ steps: 3
133
+ });
134
+
135
+ expect(cookbook.name).toBe('test-cookbook');
136
+ expect(cookbook.version).toBeDefined();
137
+ expect(cookbook.steps).toHaveLength(3);
138
+ expect(cookbook.steps[0]).toHaveProperty('service');
139
+ expect(cookbook.steps[0]).toHaveProperty('operation');
140
+ });
141
+
142
+ it('should allow TestOrchestrator to coordinate components', () => {
143
+ const harness = new framework.ServiceTestHarness({
144
+ serviceName: 'orchestrated-test'
145
+ });
146
+ const validator = new framework.ServiceValidator();
147
+ const runner = new framework.WorkflowTestRunner({
148
+ mq: new framework.MockMQClient()
149
+ });
150
+
151
+ const orchestrator = new framework.TestOrchestrator({
152
+ harness,
153
+ validator,
154
+ runner
155
+ });
156
+
157
+ expect(orchestrator.harness).toBe(harness);
158
+ expect(orchestrator.validator).toBe(validator);
159
+ expect(orchestrator.runner).toBe(runner);
160
+ });
161
+ });
162
+
163
+ describe('Mock Components Behavior', () => {
164
+ it('MockMQClient should handle basic operations', async () => {
165
+ const mq = new framework.MockMQClient();
166
+
167
+ // Should connect
168
+ await mq.connect();
169
+ expect(mq.isConnected).toBe(true);
170
+
171
+ // Should publish messages
172
+ await mq.publish('test-queue', { test: true });
173
+ const messages = mq.getMessages('test-queue');
174
+ expect(messages).toHaveLength(1);
175
+ expect(messages[0]).toEqual({ test: true });
176
+
177
+ // Should disconnect
178
+ await mq.disconnect();
179
+ expect(mq.isConnected).toBe(false);
180
+ });
181
+
182
+ it('MockRegistry should handle service registration', async () => {
183
+ const registry = new framework.MockRegistry();
184
+
185
+ // Should register service
186
+ await registry.register({
187
+ name: 'test-service',
188
+ version: '1.0.0'
189
+ });
190
+
191
+ // Should discover service
192
+ const services = await registry.discover('test-service');
193
+ expect(services).toHaveLength(1);
194
+ expect(services[0].name).toBe('test-service');
195
+ });
196
+
197
+ it('MockStorage should handle file operations', async () => {
198
+ const storage = new framework.MockStorage();
199
+
200
+ // Should upload file
201
+ const data = Buffer.from('test data');
202
+ await storage.upload('bucket', 'key', data);
203
+
204
+ // Should download file
205
+ const retrieved = await storage.download('bucket', 'key');
206
+ expect(retrieved.toString()).toBe('test data');
207
+
208
+ // Should list files
209
+ const files = await storage.list('bucket');
210
+ expect(files).toContain('key');
211
+ });
212
+ });
213
+
214
+ describe('Testing Utilities Behavior', () => {
215
+ it('ServiceReadinessValidator should check readiness', async () => {
216
+ const validator = new framework.ServiceReadinessValidator({
217
+ services: ['api', 'worker']
218
+ });
219
+
220
+ // Mock service readiness
221
+ validator.mockServiceReady('api');
222
+ validator.mockServiceReady('worker');
223
+
224
+ const allReady = await validator.checkAll();
225
+ expect(allReady).toBe(true);
226
+ });
227
+
228
+ it('CookbookTestUtils should validate cookbook structure', () => {
229
+ const utils = new framework.CookbookTestUtils();
230
+
231
+ const validCookbook = {
232
+ name: 'valid-cookbook',
233
+ version: '1.0.0',
234
+ steps: [
235
+ {
236
+ service: 'service1',
237
+ operation: 'process'
238
+ }
239
+ ]
240
+ };
241
+
242
+ const validation = utils.validate(validCookbook);
243
+ expect(validation.valid).toBe(true);
244
+
245
+ const invalidCookbook = { steps: [] };
246
+ const invalidValidation = utils.validate(invalidCookbook);
247
+ expect(invalidValidation.valid).toBe(false);
248
+ });
249
+ });
250
+
251
+ describe('Error Handling', () => {
252
+ it('should handle missing configuration gracefully', () => {
253
+ expect(() => new framework.ServiceTestHarness()).not.toThrow();
254
+ expect(() => new framework.ServiceValidator()).not.toThrow();
255
+ expect(() => new framework.WorkflowTestRunner()).not.toThrow();
256
+ });
257
+
258
+ it('should handle invalid operations gracefully', async () => {
259
+ const mq = new framework.MockMQClient();
260
+
261
+ // Should fail when not connected
262
+ await expect(mq.publish('queue', {}))
263
+ .rejects.toThrow('Not connected');
264
+
265
+ // Storage should fail on non-existent files
266
+ const storage = new framework.MockStorage();
267
+ await expect(storage.download('bucket', 'nonexistent'))
268
+ .rejects.toThrow();
269
+ });
270
+ });
271
+
272
+ describe('Complete Testing Workflow', () => {
273
+ it('should support complete test workflow', async () => {
274
+ // 1. Setup test environment
275
+ const harness = new framework.ServiceTestHarness({
276
+ serviceName: 'complete-test'
277
+ });
278
+ await harness.setup();
279
+
280
+ // 2. Register mock services
281
+ await harness.registry.register({
282
+ name: 'service1',
283
+ version: '1.0.0'
284
+ });
285
+
286
+ // 3. Create test cookbook
287
+ const utils = new framework.CookbookTestUtils();
288
+ const cookbook = utils.generateCookbook({
289
+ name: 'test-workflow',
290
+ steps: 2
291
+ });
292
+
293
+ // 4. Run workflow
294
+ const runner = new framework.WorkflowTestRunner({
295
+ mq: harness.mq
296
+ });
297
+
298
+ // Mock step execution
299
+ runner.mockStepResponse('test-service-0', { success: true });
300
+ runner.mockStepResponse('test-service-1', { complete: true });
301
+
302
+ const result = await runner.runWorkflow(cookbook, { input: 'data' });
303
+ expect(result.status).toBe('completed');
304
+
305
+ // 5. Validate results
306
+ const validator = new framework.ServiceValidator();
307
+ expect(validator).toBeDefined();
308
+
309
+ // 6. Cleanup
310
+ await harness.cleanup();
311
+ });
312
+ });
313
+ });
@@ -0,0 +1,265 @@
1
+ 'use strict';
2
+
3
+ /**
4
+ * Integration test for complete service readiness validation
5
+ * Uses existing connector tests, doesn't duplicate them
6
+ */
7
+
8
+ const { ServiceTestHarness, ServiceValidator, WorkflowTestRunner } = require('../../src');
9
+ const express = require('express');
10
+
11
+ describe('Service Readiness Integration @integration', () => {
12
+ let harness;
13
+ let app;
14
+ let openApiSpec;
15
+
16
+ beforeEach(() => {
17
+ // Create minimal test service
18
+ app = express();
19
+ app.use(express.json());
20
+
21
+ app.get('/health', (req, res) => {
22
+ res.json({ status: 'healthy' });
23
+ });
24
+
25
+ app.post('/process', (req, res) => {
26
+ res.json({ processed: true, data: req.body });
27
+ });
28
+
29
+ openApiSpec = {
30
+ openapi: '3.0.0',
31
+ info: { title: 'Test Service', version: '1.0.0' },
32
+ paths: {
33
+ '/health': {
34
+ get: {
35
+ operationId: 'healthCheck',
36
+ responses: {
37
+ '200': {
38
+ content: {
39
+ 'application/json': {
40
+ schema: {
41
+ type: 'object',
42
+ properties: {
43
+ status: { type: 'string' }
44
+ }
45
+ }
46
+ }
47
+ }
48
+ }
49
+ }
50
+ }
51
+ },
52
+ '/process': {
53
+ post: {
54
+ operationId: 'processData',
55
+ requestBody: {
56
+ content: {
57
+ 'application/json': {
58
+ schema: { type: 'object' }
59
+ }
60
+ }
61
+ },
62
+ responses: {
63
+ '200': {
64
+ content: {
65
+ 'application/json': {
66
+ schema: { type: 'object' }
67
+ }
68
+ }
69
+ }
70
+ }
71
+ }
72
+ }
73
+ }
74
+ };
75
+ });
76
+
77
+ afterEach(async () => {
78
+ if (harness) {
79
+ await harness.stop();
80
+ }
81
+ });
82
+
83
+ describe('Complete Service Validation', () => {
84
+ it('should validate service is ready for production', async () => {
85
+ harness = new ServiceTestHarness({
86
+ service: app,
87
+ serviceName: 'test-service',
88
+ openApiSpec,
89
+ mockInfrastructure: true
90
+ });
91
+
92
+ await harness.start();
93
+
94
+ // 1. Verify service is registered
95
+ const registration = harness.getServiceRegistration();
96
+ expect(registration).toBeDefined();
97
+ expect(registration.name).toBe('test-service');
98
+ expect(registration.status).toBe('active');
99
+
100
+ // 2. Validate OpenAPI compliance
101
+ const validator = new ServiceValidator();
102
+ const validation = await validator.validateService(
103
+ harness.baseUrl,
104
+ openApiSpec
105
+ );
106
+ expect(validation.valid).toBe(true);
107
+ expect(validation.coverage).toBe(100);
108
+
109
+ // 3. Test workflow execution
110
+ const workflow = await harness.simulateWorkflow({
111
+ steps: [
112
+ {
113
+ id: 'step1',
114
+ type: 'task',
115
+ service: 'test-service',
116
+ operation: 'processData',
117
+ input: { test: 'data' }
118
+ }
119
+ ]
120
+ });
121
+ expect(workflow.completed).toBe(true);
122
+
123
+ // 4. Verify message queue integration
124
+ const messages = harness.getPublishedMessages('workflow.completed');
125
+ expect(messages.length).toBeGreaterThan(0);
126
+ });
127
+
128
+ it('should detect service not ready - missing endpoints', async () => {
129
+ // Remove an endpoint
130
+ delete openApiSpec.paths['/process'];
131
+
132
+ harness = new ServiceTestHarness({
133
+ service: app,
134
+ serviceName: 'test-service',
135
+ openApiSpec,
136
+ mockInfrastructure: true
137
+ });
138
+
139
+ await harness.start();
140
+
141
+ const validator = new ServiceValidator();
142
+ const validation = await validator.validateService(
143
+ harness.baseUrl,
144
+ openApiSpec
145
+ );
146
+
147
+ // Service still works but coverage is reduced
148
+ expect(validation.valid).toBe(true);
149
+ expect(validation.coverage).toBeLessThan(100);
150
+ });
151
+ });
152
+
153
+ describe('Cookbook Validation for Production', () => {
154
+ it('should validate cookbook can execute in environment', async () => {
155
+ harness = new ServiceTestHarness({
156
+ service: app,
157
+ serviceName: 'test-service',
158
+ openApiSpec,
159
+ mockInfrastructure: true
160
+ });
161
+
162
+ await harness.start();
163
+
164
+ const cookbook = {
165
+ version: '1.0.0',
166
+ steps: [
167
+ {
168
+ id: 'validate',
169
+ type: 'task',
170
+ service: 'test-service',
171
+ operation: 'healthCheck'
172
+ },
173
+ {
174
+ id: 'process',
175
+ type: 'task',
176
+ service: 'test-service',
177
+ operation: 'processData',
178
+ input: { data: '$steps.validate' }
179
+ }
180
+ ]
181
+ };
182
+
183
+ // Validate cookbook structure
184
+ const validator = new ServiceValidator();
185
+ const cookbookValidation = await validator.validateCookbook(
186
+ cookbook,
187
+ harness.registry
188
+ );
189
+ expect(cookbookValidation.valid).toBe(true);
190
+
191
+ // Execute cookbook
192
+ const runner = new WorkflowTestRunner({
193
+ mqClient: harness.mqClient,
194
+ registry: harness.registry,
195
+ storage: harness.storage
196
+ });
197
+
198
+ const workflow = await runner.runWorkflow(cookbook);
199
+ expect(workflow.status).toBe('completed');
200
+ expect(workflow.results).toHaveLength(2);
201
+ });
202
+ });
203
+
204
+ describe('Production Deployment Readiness', () => {
205
+ it('should verify all production requirements', async () => {
206
+ harness = new ServiceTestHarness({
207
+ service: app,
208
+ serviceName: 'test-service',
209
+ openApiSpec,
210
+ mockInfrastructure: true
211
+ });
212
+
213
+ await harness.start();
214
+
215
+ const readinessChecks = {
216
+ serviceRunning: false,
217
+ apiAccessible: false,
218
+ registryConnected: false,
219
+ mqConnected: false,
220
+ openApiValid: false,
221
+ healthCheckPassing: false
222
+ };
223
+
224
+ // Check service is running
225
+ readinessChecks.serviceRunning = harness.isRunning;
226
+
227
+ // Check API is accessible
228
+ try {
229
+ const response = await harness.callApi('GET', '/health');
230
+ readinessChecks.apiAccessible = true;
231
+ readinessChecks.healthCheckPassing = response.status === 'healthy';
232
+ } catch (e) {
233
+ // API not accessible
234
+ }
235
+
236
+ // Check registry connection
237
+ readinessChecks.registryConnected = !!harness.getServiceRegistration();
238
+
239
+ // Check MQ connection
240
+ readinessChecks.mqConnected = harness.mqClient.isConnected;
241
+
242
+ // Validate OpenAPI
243
+ const validator = new ServiceValidator();
244
+ const validation = await validator.validateService(
245
+ harness.baseUrl,
246
+ openApiSpec
247
+ );
248
+ readinessChecks.openApiValid = validation.valid;
249
+
250
+ // All checks should pass
251
+ expect(readinessChecks).toEqual({
252
+ serviceRunning: true,
253
+ apiAccessible: true,
254
+ registryConnected: true,
255
+ mqConnected: true,
256
+ openApiValid: true,
257
+ healthCheckPassing: true
258
+ });
259
+
260
+ // Get statistics
261
+ const stats = harness.getStats();
262
+ expect(stats).toBeDefined();
263
+ });
264
+ });
265
+ });