@ya-modbus/mqtt-bridge 0.4.1-refactor-scope-driver-packages.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 (65) hide show
  1. package/CHANGELOG.md +41 -0
  2. package/LICENSE +674 -0
  3. package/README.md +190 -0
  4. package/dist/bin/ya-modbus-bridge.d.ts +9 -0
  5. package/dist/bin/ya-modbus-bridge.d.ts.map +1 -0
  6. package/dist/bin/ya-modbus-bridge.js +10 -0
  7. package/dist/bin/ya-modbus-bridge.js.map +1 -0
  8. package/dist/src/cli.d.ts +4 -0
  9. package/dist/src/cli.d.ts.map +1 -0
  10. package/dist/src/cli.js +109 -0
  11. package/dist/src/cli.js.map +1 -0
  12. package/dist/src/device-manager.d.ts +17 -0
  13. package/dist/src/device-manager.d.ts.map +1 -0
  14. package/dist/src/device-manager.js +79 -0
  15. package/dist/src/device-manager.js.map +1 -0
  16. package/dist/src/driver-loader.d.ts +53 -0
  17. package/dist/src/driver-loader.d.ts.map +1 -0
  18. package/dist/src/driver-loader.js +120 -0
  19. package/dist/src/driver-loader.js.map +1 -0
  20. package/dist/src/index.d.ts +13 -0
  21. package/dist/src/index.d.ts.map +1 -0
  22. package/dist/src/index.js +285 -0
  23. package/dist/src/index.js.map +1 -0
  24. package/dist/src/polling-scheduler.d.ts +48 -0
  25. package/dist/src/polling-scheduler.d.ts.map +1 -0
  26. package/dist/src/polling-scheduler.js +128 -0
  27. package/dist/src/polling-scheduler.js.map +1 -0
  28. package/dist/src/types.d.ts +86 -0
  29. package/dist/src/types.d.ts.map +1 -0
  30. package/dist/src/types.js +2 -0
  31. package/dist/src/types.js.map +1 -0
  32. package/dist/src/utils/__mocks__/package-info.d.ts +9 -0
  33. package/dist/src/utils/__mocks__/package-info.d.ts.map +1 -0
  34. package/dist/src/utils/__mocks__/package-info.js +11 -0
  35. package/dist/src/utils/__mocks__/package-info.js.map +1 -0
  36. package/dist/src/utils/__mocks__/process.d.ts +20 -0
  37. package/dist/src/utils/__mocks__/process.d.ts.map +1 -0
  38. package/dist/src/utils/__mocks__/process.js +37 -0
  39. package/dist/src/utils/__mocks__/process.js.map +1 -0
  40. package/dist/src/utils/config-validator.d.ts +3 -0
  41. package/dist/src/utils/config-validator.d.ts.map +1 -0
  42. package/dist/src/utils/config-validator.js +32 -0
  43. package/dist/src/utils/config-validator.js.map +1 -0
  44. package/dist/src/utils/config.d.ts +3 -0
  45. package/dist/src/utils/config.d.ts.map +1 -0
  46. package/dist/src/utils/config.js +52 -0
  47. package/dist/src/utils/config.js.map +1 -0
  48. package/dist/src/utils/device-validation.d.ts +31 -0
  49. package/dist/src/utils/device-validation.d.ts.map +1 -0
  50. package/dist/src/utils/device-validation.js +70 -0
  51. package/dist/src/utils/device-validation.js.map +1 -0
  52. package/dist/src/utils/package-info.d.ts +5 -0
  53. package/dist/src/utils/package-info.d.ts.map +1 -0
  54. package/dist/src/utils/package-info.js +11 -0
  55. package/dist/src/utils/package-info.js.map +1 -0
  56. package/dist/src/utils/process.d.ts +10 -0
  57. package/dist/src/utils/process.d.ts.map +1 -0
  58. package/dist/src/utils/process.js +13 -0
  59. package/dist/src/utils/process.js.map +1 -0
  60. package/dist/src/utils/test-utils.d.ts +313 -0
  61. package/dist/src/utils/test-utils.d.ts.map +1 -0
  62. package/dist/src/utils/test-utils.js +535 -0
  63. package/dist/src/utils/test-utils.js.map +1 -0
  64. package/dist/tsconfig.tsbuildinfo +1 -0
  65. package/package.json +63 -0
@@ -0,0 +1,535 @@
1
+ // Non-null assertions are used for event handler cleanup where the handlers are guaranteed to be defined
2
+ // by control flow. Using optional chaining would create untestable branches for impossible null cases.
3
+ import { createServer } from 'node:net';
4
+ import { jest } from '@jest/globals';
5
+ import Aedes from 'aedes';
6
+ import { DriverLoader } from '../driver-loader.js';
7
+ import { createBridge } from '../index.js';
8
+ /**
9
+ * Race a promise against a timeout, properly cleaning up the timer
10
+ *
11
+ * This ensures Jest can exit cleanly by clearing the timeout when the promise settles.
12
+ * Always use this instead of bare Promise.race with setTimeout.
13
+ *
14
+ * @param promise - The promise to race
15
+ * @param timeoutMs - Timeout in milliseconds
16
+ * @param errorMessage - Error message if timeout occurs, or a function that returns the message
17
+ * @returns Promise that resolves/rejects with the first settled result
18
+ *
19
+ * @example
20
+ * // With static message
21
+ * await withTimeout(
22
+ * clientReadyPromise,
23
+ * 5000,
24
+ * 'Client ready timeout'
25
+ * )
26
+ *
27
+ * @example
28
+ * // With dynamic message (evaluated when timeout occurs)
29
+ * await withTimeout(
30
+ * disconnectPromise,
31
+ * 5000,
32
+ * () => `Still connected: ${broker.connectedClients}`
33
+ * )
34
+ */
35
+ export function withTimeout(promise, timeoutMs, errorMessage) {
36
+ let timeoutId;
37
+ const timeoutPromise = new Promise((_, reject) => {
38
+ timeoutId = setTimeout(() => {
39
+ const message = typeof errorMessage === 'function' ? errorMessage() : errorMessage;
40
+ reject(new Error(message));
41
+ }, timeoutMs);
42
+ });
43
+ return Promise.race([promise, timeoutPromise]).finally(() => {
44
+ clearTimeout(timeoutId);
45
+ });
46
+ }
47
+ /**
48
+ * Wait for all MQTT clients to disconnect from a test broker
49
+ *
50
+ * @param broker - The test broker to monitor
51
+ * @param timeoutMs - Maximum time to wait in milliseconds (default: 5000)
52
+ * @returns Promise that resolves when all clients disconnect or rejects on timeout
53
+ *
54
+ * @example
55
+ * await waitForAllClientsToDisconnect(broker, 5000)
56
+ */
57
+ export function waitForAllClientsToDisconnect(broker, timeoutMs = 5000) {
58
+ if (broker.broker.connectedClients === 0) {
59
+ return Promise.resolve();
60
+ }
61
+ let onDisconnect;
62
+ const disconnectPromise = new Promise((resolve) => {
63
+ onDisconnect = () => {
64
+ if (broker.broker.connectedClients === 0) {
65
+ broker.broker.off('clientDisconnect', onDisconnect);
66
+ resolve();
67
+ }
68
+ };
69
+ broker.broker.on('clientDisconnect', onDisconnect);
70
+ });
71
+ return withTimeout(disconnectPromise, timeoutMs, () => `Timeout waiting for clients to disconnect. Still connected: ${broker.broker.connectedClients}`).finally(() => {
72
+ broker.broker.off('clientDisconnect', onDisconnect);
73
+ });
74
+ }
75
+ /**
76
+ * Wait for a client to be ready
77
+ *
78
+ * @param broker - The test broker to monitor
79
+ * @param timeoutMs - Maximum time to wait in milliseconds (default: 2000)
80
+ * @returns Promise that resolves when a client is ready or rejects on timeout
81
+ *
82
+ * @example
83
+ * await waitForClientReady(broker)
84
+ */
85
+ export function waitForClientReady(broker, timeoutMs = 2000) {
86
+ let onClientReady;
87
+ const clientReadyPromise = new Promise((resolve) => {
88
+ onClientReady = () => {
89
+ broker.broker.off('clientReady', onClientReady);
90
+ resolve();
91
+ };
92
+ broker.broker.on('clientReady', onClientReady);
93
+ });
94
+ return withTimeout(clientReadyPromise, timeoutMs, () => `Timeout waiting for client to be ready (connected: ${broker.broker.connectedClients})`).finally(() => {
95
+ broker.broker.off('clientReady', onClientReady);
96
+ });
97
+ }
98
+ /**
99
+ * Wait for a client to disconnect
100
+ *
101
+ * @param broker - The test broker to monitor
102
+ * @param timeoutMs - Maximum time to wait in milliseconds (default: 2000)
103
+ * @returns Promise that resolves when a client disconnects or rejects on timeout
104
+ *
105
+ * @example
106
+ * await waitForClientDisconnect(broker)
107
+ */
108
+ export function waitForClientDisconnect(broker, timeoutMs = 2000) {
109
+ let onClientDisconnect;
110
+ const clientDisconnectPromise = new Promise((resolve) => {
111
+ onClientDisconnect = () => {
112
+ broker.broker.off('clientDisconnect', onClientDisconnect);
113
+ resolve();
114
+ };
115
+ broker.broker.on('clientDisconnect', onClientDisconnect);
116
+ });
117
+ return withTimeout(clientDisconnectPromise, timeoutMs, () => `Timeout waiting for client to disconnect (connected: ${broker.broker.connectedClients})`).finally(() => {
118
+ broker.broker.off('clientDisconnect', onClientDisconnect);
119
+ });
120
+ }
121
+ /**
122
+ * Wait for a publish event on the broker
123
+ *
124
+ * @param broker - The test broker to monitor
125
+ * @param topicPattern - Optional topic to match (supports wildcards)
126
+ * @param timeoutMs - Maximum time to wait in milliseconds (default: 1000)
127
+ * @returns Promise that resolves with the published packet or rejects on timeout
128
+ *
129
+ * @example
130
+ * const packet = await waitForPublish(broker, 'test/topic')
131
+ */
132
+ export function waitForPublish(broker, topicPattern, timeoutMs = 1000) {
133
+ let onPublish;
134
+ const publishPromise = new Promise((resolve) => {
135
+ onPublish = (packet, _client) => {
136
+ if (!topicPattern || matchTopic(packet.topic, topicPattern)) {
137
+ broker.broker.off('publish', onPublish);
138
+ const payload = typeof packet.payload === 'string' ? Buffer.from(packet.payload) : packet.payload;
139
+ resolve({ topic: packet.topic, payload });
140
+ }
141
+ };
142
+ broker.broker.on('publish', onPublish);
143
+ });
144
+ return withTimeout(publishPromise, timeoutMs, `Timeout waiting for publish${topicPattern ? ` on topic ${topicPattern}` : ''}`).finally(() => {
145
+ broker.broker.off('publish', onPublish);
146
+ });
147
+ }
148
+ /**
149
+ * Wait for a subscribe event on the broker
150
+ *
151
+ * @param broker - The test broker to monitor
152
+ * @param topicPattern - Optional topic to match
153
+ * @param timeoutMs - Maximum time to wait in milliseconds (default: 1000)
154
+ * @returns Promise that resolves with subscriptions or rejects on timeout
155
+ *
156
+ * @example
157
+ * await waitForSubscribe(broker, 'test/topic')
158
+ */
159
+ export function waitForSubscribe(broker, topicPattern, timeoutMs = 1000) {
160
+ let onSubscribe;
161
+ const subscribePromise = new Promise((resolve) => {
162
+ onSubscribe = (subscriptions) => {
163
+ if (!topicPattern || subscriptions.some((s) => matchTopic(s.topic, topicPattern))) {
164
+ broker.broker.off('subscribe', onSubscribe);
165
+ resolve(subscriptions);
166
+ }
167
+ };
168
+ broker.broker.on('subscribe', onSubscribe);
169
+ });
170
+ return withTimeout(subscribePromise, timeoutMs, `Timeout waiting for subscribe${topicPattern ? ` on topic ${topicPattern}` : ''}`).finally(() => {
171
+ broker.broker.off('subscribe', onSubscribe);
172
+ });
173
+ }
174
+ /**
175
+ * Wait for an unsubscribe event on the broker
176
+ *
177
+ * @param broker - The test broker to monitor
178
+ * @param topicPattern - Optional topic to match
179
+ * @param timeoutMs - Maximum time to wait in milliseconds (default: 1000)
180
+ * @returns Promise that resolves with unsubscriptions or rejects on timeout
181
+ *
182
+ * @example
183
+ * await waitForUnsubscribe(broker, 'test/topic')
184
+ */
185
+ export function waitForUnsubscribe(broker, topicPattern, timeoutMs = 1000) {
186
+ let onUnsubscribe;
187
+ const unsubscribePromise = new Promise((resolve) => {
188
+ onUnsubscribe = (unsubscriptions) => {
189
+ if (!topicPattern || unsubscriptions.some((topic) => matchTopic(topic, topicPattern))) {
190
+ broker.broker.off('unsubscribe', onUnsubscribe);
191
+ resolve(unsubscriptions);
192
+ }
193
+ };
194
+ broker.broker.on('unsubscribe', onUnsubscribe);
195
+ });
196
+ return withTimeout(unsubscribePromise, timeoutMs, `Timeout waiting for unsubscribe${topicPattern ? ` on topic ${topicPattern}` : ''}`).finally(() => {
197
+ broker.broker.off('unsubscribe', onUnsubscribe);
198
+ });
199
+ }
200
+ /**
201
+ * Simple topic matcher that supports MQTT wildcards
202
+ *
203
+ * @param topic - The actual topic
204
+ * @param pattern - The pattern to match (supports + and # wildcards)
205
+ * @returns True if topic matches pattern
206
+ */
207
+ function matchTopic(topic, pattern) {
208
+ if (topic === pattern)
209
+ return true;
210
+ const topicParts = topic.split('/');
211
+ const patternParts = pattern.split('/');
212
+ for (let i = 0; i < patternParts.length; i++) {
213
+ if (patternParts[i] === '#') {
214
+ return true;
215
+ }
216
+ if (patternParts[i] !== '+' && patternParts[i] !== topicParts[i]) {
217
+ return false;
218
+ }
219
+ }
220
+ return topicParts.length === patternParts.length;
221
+ }
222
+ /**
223
+ * Create a test bridge configuration with optional overrides
224
+ *
225
+ * @param broker - The test broker to connect to
226
+ * @param overrides - Optional configuration overrides
227
+ * @returns Bridge configuration for testing
228
+ *
229
+ * @example
230
+ * const config = createTestBridgeConfig(broker, { topicPrefix: 'custom' })
231
+ */
232
+ export function createTestBridgeConfig(broker, overrides) {
233
+ const { mqtt, ...otherOverrides } = overrides ?? {};
234
+ return {
235
+ mqtt: {
236
+ url: broker.url,
237
+ ...mqtt,
238
+ },
239
+ ...otherOverrides,
240
+ };
241
+ }
242
+ /**
243
+ * Subscribe to a topic and wait for the subscription to be registered with the broker
244
+ *
245
+ * @param bridge - The MQTT bridge instance
246
+ * @param broker - The test broker to monitor
247
+ * @param topic - Topic to subscribe to (without prefix)
248
+ * @param handler - Message handler function
249
+ * @param options - Subscribe options and topic prefix
250
+ * @returns Promise that resolves when subscription is registered
251
+ *
252
+ * @example
253
+ * await subscribeAndWait(bridge, broker, 'test/topic', (msg) => { ... })
254
+ */
255
+ export async function subscribeAndWait(bridge, broker, topic, handler, options) {
256
+ const prefix = options?.prefix ?? 'modbus';
257
+ const subscribePromise = waitForSubscribe(broker, `${prefix}/${topic}`);
258
+ await bridge.subscribe(topic, handler, options);
259
+ await subscribePromise;
260
+ }
261
+ /**
262
+ * Publish a message and wait for it to be published to the broker
263
+ *
264
+ * @param bridge - The MQTT bridge instance
265
+ * @param broker - The test broker to monitor
266
+ * @param topic - Topic to publish to (without prefix)
267
+ * @param message - Message payload
268
+ * @param options - Publish options and topic prefix
269
+ * @returns Promise that resolves when message is published
270
+ *
271
+ * @example
272
+ * await publishAndWait(bridge, broker, 'test/topic', 'Hello', { qos: 1 })
273
+ */
274
+ export async function publishAndWait(bridge, broker, topic, message, options) {
275
+ const prefix = options?.prefix ?? 'modbus';
276
+ const publishPromise = waitForPublish(broker, `${prefix}/${topic}`);
277
+ await bridge.publish(topic, message, options);
278
+ await publishPromise;
279
+ }
280
+ /**
281
+ * Create a message collector for capturing messages in tests
282
+ *
283
+ * @returns Message collector with handler and utilities
284
+ *
285
+ * @example
286
+ * const collector = createMessageCollector()
287
+ * await bridge.subscribe('test/topic', collector.handler)
288
+ * expect(collector.messages).toContain('Expected message')
289
+ */
290
+ export function createMessageCollector() {
291
+ const messages = [];
292
+ return {
293
+ messages,
294
+ handler: (message) => messages.push(message.payload.toString()),
295
+ clear: () => {
296
+ messages.length = 0;
297
+ },
298
+ };
299
+ }
300
+ /**
301
+ * Execute a test function with a running bridge, ensuring proper cleanup
302
+ *
303
+ * Automatically starts the bridge before the test and stops it after,
304
+ * even if the test throws an error. This eliminates boilerplate and
305
+ * ensures resources are properly cleaned up.
306
+ *
307
+ * @param config - Bridge configuration
308
+ * @param testFn - Test function to execute with the running bridge (can be sync or async)
309
+ * @returns Promise that resolves when test completes and bridge is stopped
310
+ *
311
+ * @example
312
+ * await withBridge(createTestBridgeConfig(broker), async (bridge) => {
313
+ * const status = bridge.getStatus()
314
+ * expect(status.state).toBe('running')
315
+ * })
316
+ */
317
+ export async function withBridge(config, testFn) {
318
+ const bridge = createBridge(config);
319
+ await bridge.start();
320
+ try {
321
+ await testFn(bridge);
322
+ }
323
+ finally {
324
+ await bridge.stop();
325
+ }
326
+ }
327
+ /**
328
+ * Execute a test function with a running bridge using mock driver DI
329
+ *
330
+ * Automatically sets up the bridge with injected mocks, starts it before the test,
331
+ * and stops it after. This eliminates boilerplate for tests that need to verify
332
+ * driver lifecycle with dependency injection.
333
+ *
334
+ * @param broker - The test broker to connect to
335
+ * @param testFn - Test function with bridge and mocks
336
+ * @param overrides - Optional configuration overrides
337
+ * @returns Promise that resolves when test completes and bridge is stopped
338
+ *
339
+ * @example
340
+ * await withBridgeAndMockDriver(broker, async (bridge, mocks) => {
341
+ * await bridge.addDevice({ deviceId: 'test', driver: 'mock', connection: {...} })
342
+ * expect(mocks.mockDriver.initialize).toHaveBeenCalled()
343
+ * })
344
+ */
345
+ export async function withBridgeAndMockDriver(broker, testFn, overrides) {
346
+ const { config, driverLoader, mockDriver, mockTransport, mockLoadDriverFn, mockTransportManager, } = createTestBridgeWithMockDriver(broker, overrides);
347
+ const bridge = createBridge(config, { driverLoader });
348
+ await bridge.start();
349
+ try {
350
+ await testFn(bridge, { mockDriver, mockTransport, mockLoadDriverFn, mockTransportManager });
351
+ }
352
+ finally {
353
+ await bridge.stop();
354
+ }
355
+ }
356
+ /**
357
+ * Start an Aedes MQTT broker on a dynamic port for testing
358
+ */
359
+ export async function startTestBroker(options) {
360
+ const broker = new Aedes();
361
+ const server = createServer(broker.handle);
362
+ return new Promise((resolve, reject) => {
363
+ server.listen(options?.port, () => {
364
+ const address = server.address();
365
+ resolve({
366
+ address,
367
+ url: `mqtt://localhost:${address.port}`,
368
+ port: address.port,
369
+ broker,
370
+ server,
371
+ close: () => new Promise((resolveClose, rejectClose) => {
372
+ broker.close(() => {
373
+ server.close((err) => {
374
+ if (err) {
375
+ rejectClose(err);
376
+ }
377
+ else {
378
+ resolveClose();
379
+ }
380
+ });
381
+ });
382
+ }),
383
+ });
384
+ });
385
+ server.on('error', reject);
386
+ });
387
+ }
388
+ /**
389
+ * Create a mock transport for testing
390
+ *
391
+ * Returns a transport mock that implements the Transport interface
392
+ * with jest.fn() for all methods, allowing verification of calls.
393
+ *
394
+ * @returns Mock transport with trackable method calls
395
+ *
396
+ * @example
397
+ * const mockTransport = createMockTransport()
398
+ * mockTransport.readHoldingRegisters.mockResolvedValue([1, 2, 3])
399
+ */
400
+ export function createMockTransport() {
401
+ return {
402
+ readHoldingRegisters: jest.fn().mockResolvedValue([0, 0]),
403
+ readInputRegisters: jest.fn().mockResolvedValue([0, 0]),
404
+ readCoils: jest.fn().mockResolvedValue([false]),
405
+ readDiscreteInputs: jest.fn().mockResolvedValue([false]),
406
+ writeSingleCoil: jest.fn().mockResolvedValue(undefined),
407
+ writeSingleRegister: jest.fn().mockResolvedValue(undefined),
408
+ writeMultipleRegisters: jest.fn().mockResolvedValue(undefined),
409
+ writeMultipleCoils: jest.fn().mockResolvedValue(undefined),
410
+ close: jest.fn().mockResolvedValue(undefined),
411
+ };
412
+ }
413
+ /**
414
+ * Create a mock TransportManager for testing
415
+ *
416
+ * Returns a TransportManager mock that implements the TransportManager interface
417
+ * with jest.fn() for all methods, allowing verification of calls.
418
+ *
419
+ * @returns Mock TransportManager with trackable method calls
420
+ *
421
+ * @example
422
+ * const mockTransportManager = createMockTransportManager()
423
+ * const loader = new DriverLoader(mockLoadDriver, mockTransportManager)
424
+ */
425
+ export function createMockTransportManager() {
426
+ const mockTransport = createMockTransport();
427
+ return {
428
+ getTransport: jest.fn().mockResolvedValue(mockTransport),
429
+ getStats: jest
430
+ .fn()
431
+ .mockReturnValue({ totalTransports: 0, rtuTransports: 0, tcpTransports: 0 }),
432
+ closeAll: jest.fn().mockResolvedValue(undefined),
433
+ };
434
+ }
435
+ /**
436
+ * Create a mock driver for testing
437
+ *
438
+ * Returns a mock driver that implements the DeviceDriver interface
439
+ * with jest.fn() for all methods, allowing verification of calls.
440
+ *
441
+ * @param overrides - Optional property overrides
442
+ * @returns Mock driver with trackable method calls
443
+ *
444
+ * @example
445
+ * const mockDriver = createMockDriver({
446
+ * dataPoints: [{ id: 'voltage', name: 'Voltage', type: 'number', unit: 'V' }]
447
+ * })
448
+ * mockDriver.readDataPoints.mockResolvedValue({ voltage: 230 })
449
+ */
450
+ export function createMockDriver(overrides) {
451
+ return {
452
+ name: overrides?.name ?? 'test-device',
453
+ manufacturer: overrides?.manufacturer ?? 'Test Manufacturer',
454
+ model: overrides?.model ?? 'TEST-001',
455
+ dataPoints: (overrides?.dataPoints ?? [
456
+ {
457
+ id: 'test-value',
458
+ name: 'Test Value',
459
+ type: 'number',
460
+ unit: 'unit',
461
+ },
462
+ ]),
463
+ readDataPoint: jest.fn().mockResolvedValue(123),
464
+ writeDataPoint: jest.fn().mockResolvedValue(undefined),
465
+ readDataPoints: jest.fn().mockResolvedValue({ 'test-value': 123 }),
466
+ initialize: jest.fn().mockResolvedValue(undefined),
467
+ destroy: jest.fn().mockResolvedValue(undefined),
468
+ };
469
+ }
470
+ /**
471
+ * Create a test bridge configuration with mock driver injection
472
+ *
473
+ * This configures the bridge with dependency injection for testing,
474
+ * allowing integration tests to verify driver lifecycle without
475
+ * loading real driver packages.
476
+ *
477
+ * **Note**: Returns fresh mock instances on each call. Mock state does
478
+ * not persist between invocations. Each test gets independent mocks.
479
+ *
480
+ * @param broker - The test broker to connect to
481
+ * @param overrides - Optional configuration overrides
482
+ * @returns Object with bridge config and driver loader
483
+ *
484
+ * @example
485
+ * const { config, driverLoader, mockDriver } = createTestBridgeWithMockDriver(broker)
486
+ * const bridge = createBridge(config, { driverLoader })
487
+ * await bridge.addDevice({
488
+ * deviceId: 'test-device',
489
+ * driver: 'ya-modbus-driver-test',
490
+ * connection: { type: 'tcp', host: 'localhost', port: 502, slaveId: 1 },
491
+ * })
492
+ * // Verify driver lifecycle with injected mocks
493
+ * expect(mockDriver.initialize).toHaveBeenCalled()
494
+ */
495
+ export function createTestBridgeWithMockDriver(broker, overrides) {
496
+ // Create first instances for single-device test convenience
497
+ const mockDriver = createMockDriver();
498
+ const mockTransport = createMockTransport();
499
+ // Mock loadDriverFn that creates NEW instances on each call for driver isolation
500
+ // First call returns the pre-created mockDriver for backward compatibility
501
+ let isFirstDriverCall = true;
502
+ const mockLoadDriverFn = jest.fn().mockImplementation(() => {
503
+ return Promise.resolve({
504
+ createDriver: jest.fn().mockImplementation(() => {
505
+ if (isFirstDriverCall) {
506
+ isFirstDriverCall = false;
507
+ return Promise.resolve(mockDriver);
508
+ }
509
+ return Promise.resolve(createMockDriver());
510
+ }),
511
+ });
512
+ });
513
+ // Create mock TransportManager that returns NEW transport instances for isolation
514
+ // First call returns the pre-created mockTransport for backward compatibility
515
+ let isFirstTransportCall = true;
516
+ const mockTransportManager = createMockTransportManager();
517
+ mockTransportManager.getTransport.mockImplementation(() => {
518
+ if (isFirstTransportCall) {
519
+ isFirstTransportCall = false;
520
+ return Promise.resolve(mockTransport);
521
+ }
522
+ return Promise.resolve(createMockTransport());
523
+ });
524
+ // Create DriverLoader with mocked dependencies
525
+ const driverLoader = new DriverLoader(mockLoadDriverFn, mockTransportManager);
526
+ return {
527
+ config: createTestBridgeConfig(broker, overrides),
528
+ driverLoader,
529
+ mockDriver,
530
+ mockTransport,
531
+ mockLoadDriverFn,
532
+ mockTransportManager,
533
+ };
534
+ }
535
+ //# sourceMappingURL=test-utils.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"test-utils.js","sourceRoot":"","sources":["../../../src/utils/test-utils.ts"],"names":[],"mappings":"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"}