matterbridge 3.0.8-dev-20250626-1445fbd → 3.0.8-dev-20250626-50aa686
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/CHANGELOG.md +3 -2
- package/README-DEV.md +28 -1
- package/README.md +2 -1
- package/dist/matterbridge.js +22 -21
- package/dist/matterbridgeEndpoint.js +17 -6
- package/npm-shrinkwrap.json +44 -44
- package/package.json +2 -2
- package/vitest/matterbridge.test.ts +208 -0
package/CHANGELOG.md
CHANGED
|
@@ -21,8 +21,8 @@ If you like this project and find it useful, please consider giving it a star on
|
|
|
21
21
|
- [ESLint]: Added the plugins `eslint-plugin-promise`, `eslint-plugin-jsdoc`, and `@vitest/eslint-plugin`.
|
|
22
22
|
- [Vitest]: Added Vitest for TypeScript project testing. It will replace Jest, which does not work correctly with ESM module mocks.
|
|
23
23
|
- [JSDoc]: Added missing JSDoc comments, including `@param` and `@returns` tags.
|
|
24
|
-
- [MatterbridgeEndpoint]: Add MatterbridgeEndpoint
|
|
25
|
-
- [MatterbridgeEndpoint]: Add MatterbridgeEndpoint
|
|
24
|
+
- [MatterbridgeEndpoint]: Add MatterbridgeEndpoint mode='server'. It allows to advertise a single device like an autonomous device with its server node to be paired.
|
|
25
|
+
- [MatterbridgeEndpoint]: Add MatterbridgeEndpoint mode='matter'. It allows to add a single device to the Matterbridge server node next to the aggregator. The device is not bridged.
|
|
26
26
|
|
|
27
27
|
### Changed
|
|
28
28
|
|
|
@@ -31,6 +31,7 @@ If you like this project and find it useful, please consider giving it a star on
|
|
|
31
31
|
- [storage]: Bumped `node-storage-manager` to 2.0.0.
|
|
32
32
|
- [logger]: Bumped `node-ansi-logger` to 3.1.1.
|
|
33
33
|
- [matter.js]: Updated to 0.15.0-alpha.0-20250625-c7634df96.
|
|
34
|
+
- [matter.js]: Updated to 0.15.0-alpha.0-20250626-fc3a84ce9.
|
|
34
35
|
|
|
35
36
|
### Fixed
|
|
36
37
|
|
package/README-DEV.md
CHANGED
|
@@ -28,6 +28,14 @@ The Matterbridge Plugin Template has an already configured Jest / Vitest test un
|
|
|
28
28
|
|
|
29
29
|
It also has a workflow configured to run on push and pull request that build, lint and test the plugin on node 20, 22 and 24 with ubuntu, macOS and windows.
|
|
30
30
|
|
|
31
|
+
## Dev Container
|
|
32
|
+
|
|
33
|
+
Using a Dev Container provides a fully isolated, reproducible, and pre-configured development environment. This ensures that all contributors have the same tools, extensions, and dependencies, eliminating "works on my machine" issues. It also makes onboarding new developers fast and hassle-free, as everything needed is set up automatically.
|
|
34
|
+
|
|
35
|
+
For improved efficiency, the setup uses named Docker volumes for `node_modules`. This means dependencies are installed only once and persist across container rebuilds, making installs and rebuilds much faster than with bind mounts or ephemeral volumes.
|
|
36
|
+
|
|
37
|
+
Since Dev Container doesn't run in network mode 'host', it is not possible to pair Mattebridge running inside the Dev Container.
|
|
38
|
+
|
|
31
39
|
## Guidelines on imports/exports
|
|
32
40
|
|
|
33
41
|
Matterbridge exports from:
|
|
@@ -239,7 +247,26 @@ It can be useful to call this method from onShutdown() if you don't want to keep
|
|
|
239
247
|
|
|
240
248
|
## MatterbridgeEndpoint api
|
|
241
249
|
|
|
242
|
-
|
|
250
|
+
You create a device with a new instance of MatterbridgeEndpoint(definition: DeviceTypeDefinition | AtLeastOne<DeviceTypeDefinition>, options: MatterbridgeEndpointOptions = {}, debug: boolean = false).
|
|
251
|
+
|
|
252
|
+
- @param {DeviceTypeDefinition | AtLeastOne<DeviceTypeDefinition>} definition - The DeviceTypeDefinition(s) of the endpoint.
|
|
253
|
+
- @param {MatterbridgeEndpointOptions} [options] - The options for the device.
|
|
254
|
+
- @param {boolean} [debug] - Debug flag.
|
|
255
|
+
|
|
256
|
+
```typescript
|
|
257
|
+
const device = new MatterbridgeEndpoint([contactSensor, powerSource], { uniqueStorageKey: 'Eve door', mode: 'matter' }, this.config.debug as boolean)
|
|
258
|
+
.createDefaultIdentifyClusterServer()
|
|
259
|
+
.createDefaultBasicInformationClusterServer('My contact sensor', '0123456789')
|
|
260
|
+
.createDefaultBooleanStateClusterServer(true)
|
|
261
|
+
.createDefaultPowerSourceReplaceableBatteryClusterServer(75)
|
|
262
|
+
.addRequiredClusterServers(); // Always better to call it at the end of the chain to add all the not already created but required clusters.
|
|
263
|
+
```
|
|
264
|
+
|
|
265
|
+
In the above example we create a contact sensor device type with also a power source device type feature replaceble battery.
|
|
266
|
+
|
|
267
|
+
All device types are defined in src\matterbridgeDeviceTypes.ts and taken from the 'Matter-1.4-Device-Library-Specification.pdf'.
|
|
268
|
+
|
|
269
|
+
All default cluster helpers are available as methods of MatterbridgeEndpoint.
|
|
243
270
|
|
|
244
271
|
# Contribution Guidelines
|
|
245
272
|
|
package/README.md
CHANGED
|
@@ -5,7 +5,8 @@
|
|
|
5
5
|
[](https://hub.docker.com/r/luligu/matterbridge)
|
|
6
6
|
[](https://hub.docker.com/r/luligu/matterbridge)
|
|
7
7
|

|
|
8
|
-

|
|
9
|
+
[](https://codecov.io/gh/Luligu/matterbridge)
|
|
9
10
|
|
|
10
11
|
[](https://www.npmjs.com/package/matter-history)
|
|
11
12
|
[](https://www.npmjs.com/package/node-ansi-logger)
|
package/dist/matterbridge.js
CHANGED
|
@@ -206,7 +206,7 @@ export class Matterbridge extends EventEmitter {
|
|
|
206
206
|
}
|
|
207
207
|
if (this.devices !== undefined) {
|
|
208
208
|
for (const device of this.devices.array()) {
|
|
209
|
-
if (device.
|
|
209
|
+
if (device.mode === 'server' && device.serverNode)
|
|
210
210
|
servers.push(device.serverNode);
|
|
211
211
|
}
|
|
212
212
|
}
|
|
@@ -1082,9 +1082,10 @@ export class Matterbridge extends EventEmitter {
|
|
|
1082
1082
|
}
|
|
1083
1083
|
}
|
|
1084
1084
|
for (const device of this.devices.array()) {
|
|
1085
|
-
if (device.
|
|
1085
|
+
if (device.mode === 'server' && device.serverNode) {
|
|
1086
1086
|
await this.stopServerNode(device.serverNode);
|
|
1087
1087
|
device.serverNode = undefined;
|
|
1088
|
+
device.serverContext = undefined;
|
|
1088
1089
|
}
|
|
1089
1090
|
}
|
|
1090
1091
|
this.log.notice('Stopped matter server nodes');
|
|
@@ -1181,10 +1182,10 @@ export class Matterbridge extends EventEmitter {
|
|
|
1181
1182
|
}
|
|
1182
1183
|
}
|
|
1183
1184
|
async createDeviceServerNode(plugin, device) {
|
|
1184
|
-
if (device.
|
|
1185
|
+
if (device.mode === 'server' && !device.serverNode && device.deviceType && device.deviceName && device.vendorId && device.productId && device.vendorName && device.productName) {
|
|
1185
1186
|
this.log.debug(`Creating device ${plg}${plugin.name}${db}:${dev}${device.deviceName}${db} server node...`);
|
|
1186
|
-
|
|
1187
|
-
device.serverNode = await this.createServerNode(
|
|
1187
|
+
device.serverContext = await this.createServerNodeContext(device.deviceName.replace(/[ .]/g, ''), device.deviceName, DeviceTypeId(device.deviceType), device.vendorId, device.vendorName, device.productId, device.productName);
|
|
1188
|
+
device.serverNode = await this.createServerNode(device.serverContext, this.port ? this.port++ : undefined, this.passcode ? this.passcode++ : undefined, this.discriminator ? this.discriminator++ : undefined);
|
|
1188
1189
|
this.log.debug(`Adding ${plg}${plugin.name}${db}:${dev}${device.deviceName}${db} to server node...`);
|
|
1189
1190
|
await device.serverNode.add(device);
|
|
1190
1191
|
this.log.debug(`Added ${plg}${plugin.name}${db}:${dev}${device.deviceName}${db} to server node`);
|
|
@@ -1256,7 +1257,7 @@ export class Matterbridge extends EventEmitter {
|
|
|
1256
1257
|
this.log.debug('Cleared startMatterInterval interval for Matterbridge');
|
|
1257
1258
|
this.startServerNode(this.serverNode);
|
|
1258
1259
|
for (const device of this.devices.array()) {
|
|
1259
|
-
if (device.
|
|
1260
|
+
if (device.mode === 'server' && device.serverNode) {
|
|
1260
1261
|
this.log.debug(`Starting server node for device ${dev}${device.deviceName}${db} in server mode...`);
|
|
1261
1262
|
await this.startServerNode(device.serverNode);
|
|
1262
1263
|
}
|
|
@@ -1277,13 +1278,15 @@ export class Matterbridge extends EventEmitter {
|
|
|
1277
1278
|
}
|
|
1278
1279
|
}
|
|
1279
1280
|
this.frontend.wssSendRefreshRequired('plugins');
|
|
1280
|
-
}, 30 * 1000);
|
|
1281
|
+
}, 30 * 1000).unref();
|
|
1281
1282
|
this.reachabilityTimeout = setTimeout(() => {
|
|
1282
1283
|
this.log.info(`Setting reachability to true for ${plg}Matterbridge${db}`);
|
|
1283
1284
|
if (this.aggregatorNode)
|
|
1284
1285
|
this.setAggregatorReachability(this.aggregatorNode, true);
|
|
1285
1286
|
this.frontend.wssSendRefreshRequired('reachability');
|
|
1286
|
-
}, 60 * 1000);
|
|
1287
|
+
}, 60 * 1000).unref();
|
|
1288
|
+
this.emit('bridge_started');
|
|
1289
|
+
this.log.notice('Matterbridge bridge started successfully');
|
|
1287
1290
|
}, 1000);
|
|
1288
1291
|
}
|
|
1289
1292
|
async startChildbridge() {
|
|
@@ -1339,7 +1342,7 @@ export class Matterbridge extends EventEmitter {
|
|
|
1339
1342
|
}
|
|
1340
1343
|
}
|
|
1341
1344
|
this.frontend.wssSendRefreshRequired('plugins');
|
|
1342
|
-
}, 30 * 1000);
|
|
1345
|
+
}, 30 * 1000).unref();
|
|
1343
1346
|
for (const plugin of this.plugins.array()) {
|
|
1344
1347
|
if (!plugin.enabled || plugin.error)
|
|
1345
1348
|
continue;
|
|
@@ -1365,14 +1368,16 @@ export class Matterbridge extends EventEmitter {
|
|
|
1365
1368
|
if (plugin.type === 'DynamicPlatform' && plugin.aggregatorNode)
|
|
1366
1369
|
this.setAggregatorReachability(plugin.aggregatorNode, true);
|
|
1367
1370
|
this.frontend.wssSendRefreshRequired('reachability');
|
|
1368
|
-
}, 60 * 1000);
|
|
1371
|
+
}, 60 * 1000).unref();
|
|
1369
1372
|
}
|
|
1370
1373
|
for (const device of this.devices.array()) {
|
|
1371
|
-
if (device.
|
|
1374
|
+
if (device.mode === 'server' && device.serverNode) {
|
|
1372
1375
|
this.log.debug(`***Starting server node for device ${plg}${device.deviceName}${db} in server mode...`);
|
|
1373
1376
|
await this.startServerNode(device.serverNode);
|
|
1374
1377
|
}
|
|
1375
1378
|
}
|
|
1379
|
+
this.emit('childbridge_started');
|
|
1380
|
+
this.log.notice('Matterbridge childbridge started successfully');
|
|
1376
1381
|
}, 1000);
|
|
1377
1382
|
}
|
|
1378
1383
|
async startController() {
|
|
@@ -1597,10 +1602,7 @@ export class Matterbridge extends EventEmitter {
|
|
|
1597
1602
|
this.frontend.wssSendRefreshRequired('fabrics');
|
|
1598
1603
|
});
|
|
1599
1604
|
const sanitizeSessions = (sessions) => {
|
|
1600
|
-
const sanitizedSessions = this.sanitizeSessionInformation(sessions
|
|
1601
|
-
...session,
|
|
1602
|
-
secure: session.name.startsWith('secure'),
|
|
1603
|
-
})));
|
|
1605
|
+
const sanitizedSessions = this.sanitizeSessionInformation(sessions);
|
|
1604
1606
|
this.log.debug(`Sessions: ${debugStringify(sanitizedSessions)}`);
|
|
1605
1607
|
if (this.bridgeMode === 'bridge') {
|
|
1606
1608
|
this.matterbridgeSessionInformations = sanitizedSessions;
|
|
@@ -1702,7 +1704,7 @@ export class Matterbridge extends EventEmitter {
|
|
|
1702
1704
|
this.log.error(`Error adding bridged endpoint ${dev}${device.deviceName}${er} (${zb}${device.id}${er}) plugin ${plg}${pluginName}${er} not found`);
|
|
1703
1705
|
return;
|
|
1704
1706
|
}
|
|
1705
|
-
if (device.
|
|
1707
|
+
if (device.mode === 'server') {
|
|
1706
1708
|
try {
|
|
1707
1709
|
this.log.debug(`Creating server node for device ${dev}${device.deviceName}${db} of plugin ${plg}${plugin.name}${db}...`);
|
|
1708
1710
|
await this.createDeviceServerNode(plugin, device);
|
|
@@ -1715,7 +1717,7 @@ export class Matterbridge extends EventEmitter {
|
|
|
1715
1717
|
}
|
|
1716
1718
|
}
|
|
1717
1719
|
else if (this.bridgeMode === 'bridge') {
|
|
1718
|
-
if (device.
|
|
1720
|
+
if (device.mode === 'matter') {
|
|
1719
1721
|
this.log.debug(`Adding matter endpoint ${plg}${pluginName}${db}:${dev}${device.deviceName}${db} to Matterbridge server node...`);
|
|
1720
1722
|
if (!this.serverNode) {
|
|
1721
1723
|
this.log.error('Server node not found for Matterbridge');
|
|
@@ -1774,7 +1776,7 @@ export class Matterbridge extends EventEmitter {
|
|
|
1774
1776
|
this.log.error(`Aggregator node not found for plugin ${plg}${plugin.name}${er}`);
|
|
1775
1777
|
return;
|
|
1776
1778
|
}
|
|
1777
|
-
if (device.
|
|
1779
|
+
if (device.mode === 'matter')
|
|
1778
1780
|
await plugin.serverNode?.add(device);
|
|
1779
1781
|
else
|
|
1780
1782
|
await plugin.aggregatorNode.add(device);
|
|
@@ -1870,8 +1872,8 @@ export class Matterbridge extends EventEmitter {
|
|
|
1870
1872
|
};
|
|
1871
1873
|
});
|
|
1872
1874
|
}
|
|
1873
|
-
sanitizeSessionInformation(
|
|
1874
|
-
return
|
|
1875
|
+
sanitizeSessionInformation(session) {
|
|
1876
|
+
return session
|
|
1875
1877
|
.filter((session) => session.isPeerActive)
|
|
1876
1878
|
.map((session) => {
|
|
1877
1879
|
return {
|
|
@@ -1890,7 +1892,6 @@ export class Matterbridge extends EventEmitter {
|
|
|
1890
1892
|
}
|
|
1891
1893
|
: undefined,
|
|
1892
1894
|
isPeerActive: session.isPeerActive,
|
|
1893
|
-
secure: session.secure,
|
|
1894
1895
|
lastInteractionTimestamp: session.lastInteractionTimestamp?.toString(),
|
|
1895
1896
|
lastActiveTimestamp: session.lastActiveTimestamp?.toString(),
|
|
1896
1897
|
numberOfActiveSubscriptions: session.numberOfActiveSubscriptions,
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { Endpoint, Lifecycle, MutableEndpoint, NamedHandler, SupportedBehaviors, UINT16_MAX, UINT32_MAX, VendorId } from '@matter/main';
|
|
1
|
+
import { Endpoint, Lifecycle, MutableEndpoint, NamedHandler, SupportedBehaviors, UINT16_MAX, UINT32_MAX, VendorId, } from '@matter/main';
|
|
2
2
|
import { getClusterNameById, MeasurementType } from '@matter/main/types';
|
|
3
3
|
import { Descriptor } from '@matter/main/clusters/descriptor';
|
|
4
4
|
import { PowerSource } from '@matter/main/clusters/power-source';
|
|
@@ -68,7 +68,8 @@ import { addClusterServers, addFixedLabel, addOptionalClusterServers, addRequire
|
|
|
68
68
|
export class MatterbridgeEndpoint extends Endpoint {
|
|
69
69
|
static bridgeMode = '';
|
|
70
70
|
static logLevel = "info";
|
|
71
|
-
|
|
71
|
+
mode = undefined;
|
|
72
|
+
serverContext;
|
|
72
73
|
serverNode;
|
|
73
74
|
log;
|
|
74
75
|
plugin = undefined;
|
|
@@ -126,13 +127,23 @@ export class MatterbridgeEndpoint extends Endpoint {
|
|
|
126
127
|
if (options.uniqueStorageKey && checkNotLatinCharacters(options.uniqueStorageKey)) {
|
|
127
128
|
options.uniqueStorageKey = generateUniqueId(options.uniqueStorageKey);
|
|
128
129
|
}
|
|
130
|
+
if (options.id && checkNotLatinCharacters(options.id)) {
|
|
131
|
+
options.id = generateUniqueId(options.id);
|
|
132
|
+
}
|
|
129
133
|
const optionsV8 = {
|
|
130
134
|
id: options.uniqueStorageKey?.replace(/[ .]/g, ''),
|
|
131
135
|
number: options.endpointId,
|
|
132
136
|
descriptor: options.tagList ? { tagList: options.tagList, deviceTypeList } : { deviceTypeList },
|
|
133
137
|
};
|
|
138
|
+
if (options.id !== undefined) {
|
|
139
|
+
optionsV8.id = options.id.replace(/[ .]/g, '');
|
|
140
|
+
}
|
|
141
|
+
if (options.number !== undefined) {
|
|
142
|
+
optionsV8.number = options.number;
|
|
143
|
+
}
|
|
134
144
|
super(endpointV8, optionsV8);
|
|
135
|
-
this.
|
|
145
|
+
this.mode = options.mode;
|
|
146
|
+
this.uniqueStorageKey = options.id ? options.id : options.uniqueStorageKey;
|
|
136
147
|
this.name = firstDefinition.name;
|
|
137
148
|
this.deviceType = firstDefinition.code;
|
|
138
149
|
this.tagList = options.tagList;
|
|
@@ -442,7 +453,7 @@ export class MatterbridgeEndpoint extends Endpoint {
|
|
|
442
453
|
});
|
|
443
454
|
return this;
|
|
444
455
|
}
|
|
445
|
-
createDefaultBasicInformationClusterServer(deviceName, serialNumber, vendorId, vendorName, productId, productName, softwareVersion = 1, softwareVersionString = '1.0.0', hardwareVersion = 1, hardwareVersionString = '1.0.0') {
|
|
456
|
+
createDefaultBasicInformationClusterServer(deviceName, serialNumber, vendorId = 0xfff1, vendorName = 'Matterbridge', productId = 0x8000, productName = 'Matterbridge device', softwareVersion = 1, softwareVersionString = '1.0.0', hardwareVersion = 1, hardwareVersionString = '1.0.0') {
|
|
446
457
|
this.log.logName = deviceName;
|
|
447
458
|
this.deviceName = deviceName;
|
|
448
459
|
this.serialNumber = serialNumber;
|
|
@@ -455,7 +466,7 @@ export class MatterbridgeEndpoint extends Endpoint {
|
|
|
455
466
|
this.softwareVersionString = softwareVersionString;
|
|
456
467
|
this.hardwareVersion = hardwareVersion;
|
|
457
468
|
this.hardwareVersionString = hardwareVersionString;
|
|
458
|
-
if (MatterbridgeEndpoint.bridgeMode === 'bridge') {
|
|
469
|
+
if (MatterbridgeEndpoint.bridgeMode === 'bridge' && this.mode === undefined) {
|
|
459
470
|
const options = this.getClusterServerOptions(Descriptor.Cluster.id);
|
|
460
471
|
if (options) {
|
|
461
472
|
const deviceTypeList = options.deviceTypeList;
|
|
@@ -465,7 +476,7 @@ export class MatterbridgeEndpoint extends Endpoint {
|
|
|
465
476
|
}
|
|
466
477
|
return this;
|
|
467
478
|
}
|
|
468
|
-
createDefaultBridgedDeviceBasicInformationClusterServer(deviceName, serialNumber, vendorId, vendorName, productName, softwareVersion = 1, softwareVersionString = '1.0.0', hardwareVersion = 1, hardwareVersionString = '1.0.0') {
|
|
479
|
+
createDefaultBridgedDeviceBasicInformationClusterServer(deviceName, serialNumber, vendorId = 0xfff1, vendorName = 'Matterbridge', productName = 'Matterbridge device', softwareVersion = 1, softwareVersionString = '1.0.0', hardwareVersion = 1, hardwareVersionString = '1.0.0') {
|
|
469
480
|
this.log.logName = deviceName;
|
|
470
481
|
this.deviceName = deviceName;
|
|
471
482
|
this.serialNumber = serialNumber;
|
package/npm-shrinkwrap.json
CHANGED
|
@@ -1,15 +1,15 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "matterbridge",
|
|
3
|
-
"version": "3.0.8-dev-20250626-
|
|
3
|
+
"version": "3.0.8-dev-20250626-50aa686",
|
|
4
4
|
"lockfileVersion": 3,
|
|
5
5
|
"requires": true,
|
|
6
6
|
"packages": {
|
|
7
7
|
"": {
|
|
8
8
|
"name": "matterbridge",
|
|
9
|
-
"version": "3.0.8-dev-20250626-
|
|
9
|
+
"version": "3.0.8-dev-20250626-50aa686",
|
|
10
10
|
"license": "Apache-2.0",
|
|
11
11
|
"dependencies": {
|
|
12
|
-
"@matter/main": "0.15.0-alpha.0-
|
|
12
|
+
"@matter/main": "0.15.0-alpha.0-20250626-fc3a84ce9",
|
|
13
13
|
"archiver": "7.0.1",
|
|
14
14
|
"express": "5.1.0",
|
|
15
15
|
"glob": "11.0.3",
|
|
@@ -68,86 +68,86 @@
|
|
|
68
68
|
}
|
|
69
69
|
},
|
|
70
70
|
"node_modules/@matter/general": {
|
|
71
|
-
"version": "0.15.0-alpha.0-
|
|
72
|
-
"resolved": "https://registry.npmjs.org/@matter/general/-/general-0.15.0-alpha.0-
|
|
73
|
-
"integrity": "sha512-
|
|
71
|
+
"version": "0.15.0-alpha.0-20250626-fc3a84ce9",
|
|
72
|
+
"resolved": "https://registry.npmjs.org/@matter/general/-/general-0.15.0-alpha.0-20250626-fc3a84ce9.tgz",
|
|
73
|
+
"integrity": "sha512-fQwZ8NEEdZIiQXNZXHjmNP7X21OzQw424ukSGWlt+GB7CrfZlF4rsiroeKsRQBFO1L+zCE0LYYe+rlM89IqKKg==",
|
|
74
74
|
"license": "Apache-2.0",
|
|
75
75
|
"dependencies": {
|
|
76
76
|
"@noble/curves": "^1.9.2"
|
|
77
77
|
}
|
|
78
78
|
},
|
|
79
79
|
"node_modules/@matter/main": {
|
|
80
|
-
"version": "0.15.0-alpha.0-
|
|
81
|
-
"resolved": "https://registry.npmjs.org/@matter/main/-/main-0.15.0-alpha.0-
|
|
82
|
-
"integrity": "sha512-
|
|
80
|
+
"version": "0.15.0-alpha.0-20250626-fc3a84ce9",
|
|
81
|
+
"resolved": "https://registry.npmjs.org/@matter/main/-/main-0.15.0-alpha.0-20250626-fc3a84ce9.tgz",
|
|
82
|
+
"integrity": "sha512-x9QYTk521l21/ihZTAWz+wE1flyQhYPY/fvM6YPDF6YTfJgd790FT9Ryqk5qVgrui9eVGF3X6i7DrdFkzpTLVw==",
|
|
83
83
|
"license": "Apache-2.0",
|
|
84
84
|
"dependencies": {
|
|
85
|
-
"@matter/general": "0.15.0-alpha.0-
|
|
86
|
-
"@matter/model": "0.15.0-alpha.0-
|
|
87
|
-
"@matter/node": "0.15.0-alpha.0-
|
|
88
|
-
"@matter/protocol": "0.15.0-alpha.0-
|
|
89
|
-
"@matter/types": "0.15.0-alpha.0-
|
|
85
|
+
"@matter/general": "0.15.0-alpha.0-20250626-fc3a84ce9",
|
|
86
|
+
"@matter/model": "0.15.0-alpha.0-20250626-fc3a84ce9",
|
|
87
|
+
"@matter/node": "0.15.0-alpha.0-20250626-fc3a84ce9",
|
|
88
|
+
"@matter/protocol": "0.15.0-alpha.0-20250626-fc3a84ce9",
|
|
89
|
+
"@matter/types": "0.15.0-alpha.0-20250626-fc3a84ce9"
|
|
90
90
|
},
|
|
91
91
|
"optionalDependencies": {
|
|
92
|
-
"@matter/nodejs": "0.15.0-alpha.0-
|
|
92
|
+
"@matter/nodejs": "0.15.0-alpha.0-20250626-fc3a84ce9"
|
|
93
93
|
}
|
|
94
94
|
},
|
|
95
95
|
"node_modules/@matter/model": {
|
|
96
|
-
"version": "0.15.0-alpha.0-
|
|
97
|
-
"resolved": "https://registry.npmjs.org/@matter/model/-/model-0.15.0-alpha.0-
|
|
98
|
-
"integrity": "sha512-
|
|
96
|
+
"version": "0.15.0-alpha.0-20250626-fc3a84ce9",
|
|
97
|
+
"resolved": "https://registry.npmjs.org/@matter/model/-/model-0.15.0-alpha.0-20250626-fc3a84ce9.tgz",
|
|
98
|
+
"integrity": "sha512-MsPhBLOMf+kpzYIHYPp8IO6lf6sbTijzcoCUAq5FLCycuKiqgSQap6mzQKKMMS81FIs/prM5E4dpQQz9aGF6kA==",
|
|
99
99
|
"license": "Apache-2.0",
|
|
100
100
|
"dependencies": {
|
|
101
|
-
"@matter/general": "0.15.0-alpha.0-
|
|
101
|
+
"@matter/general": "0.15.0-alpha.0-20250626-fc3a84ce9"
|
|
102
102
|
}
|
|
103
103
|
},
|
|
104
104
|
"node_modules/@matter/node": {
|
|
105
|
-
"version": "0.15.0-alpha.0-
|
|
106
|
-
"resolved": "https://registry.npmjs.org/@matter/node/-/node-0.15.0-alpha.0-
|
|
107
|
-
"integrity": "sha512-
|
|
105
|
+
"version": "0.15.0-alpha.0-20250626-fc3a84ce9",
|
|
106
|
+
"resolved": "https://registry.npmjs.org/@matter/node/-/node-0.15.0-alpha.0-20250626-fc3a84ce9.tgz",
|
|
107
|
+
"integrity": "sha512-p0ehfBazBnALPKIplEJHibZ+HmszGDszcgq5bsXLlu9MyEfQ6Y3LZK9+hKEH8pavSaJUbMBfQRn5fEzzAMqn+w==",
|
|
108
108
|
"license": "Apache-2.0",
|
|
109
109
|
"dependencies": {
|
|
110
|
-
"@matter/general": "0.15.0-alpha.0-
|
|
111
|
-
"@matter/model": "0.15.0-alpha.0-
|
|
112
|
-
"@matter/protocol": "0.15.0-alpha.0-
|
|
113
|
-
"@matter/types": "0.15.0-alpha.0-
|
|
110
|
+
"@matter/general": "0.15.0-alpha.0-20250626-fc3a84ce9",
|
|
111
|
+
"@matter/model": "0.15.0-alpha.0-20250626-fc3a84ce9",
|
|
112
|
+
"@matter/protocol": "0.15.0-alpha.0-20250626-fc3a84ce9",
|
|
113
|
+
"@matter/types": "0.15.0-alpha.0-20250626-fc3a84ce9"
|
|
114
114
|
}
|
|
115
115
|
},
|
|
116
116
|
"node_modules/@matter/nodejs": {
|
|
117
|
-
"version": "0.15.0-alpha.0-
|
|
118
|
-
"resolved": "https://registry.npmjs.org/@matter/nodejs/-/nodejs-0.15.0-alpha.0-
|
|
119
|
-
"integrity": "sha512-
|
|
117
|
+
"version": "0.15.0-alpha.0-20250626-fc3a84ce9",
|
|
118
|
+
"resolved": "https://registry.npmjs.org/@matter/nodejs/-/nodejs-0.15.0-alpha.0-20250626-fc3a84ce9.tgz",
|
|
119
|
+
"integrity": "sha512-zkCATPiq29m+QRHAeK7+RUS2F2cuVhSQVMqTQjtuQyEVMRAx+8aucJB/3AfOYqLX4DfOLUenxYpt9Mm59bQLYQ==",
|
|
120
120
|
"license": "Apache-2.0",
|
|
121
121
|
"optional": true,
|
|
122
122
|
"dependencies": {
|
|
123
|
-
"@matter/general": "0.15.0-alpha.0-
|
|
124
|
-
"@matter/node": "0.15.0-alpha.0-
|
|
125
|
-
"@matter/protocol": "0.15.0-alpha.0-
|
|
126
|
-
"@matter/types": "0.15.0-alpha.0-
|
|
123
|
+
"@matter/general": "0.15.0-alpha.0-20250626-fc3a84ce9",
|
|
124
|
+
"@matter/node": "0.15.0-alpha.0-20250626-fc3a84ce9",
|
|
125
|
+
"@matter/protocol": "0.15.0-alpha.0-20250626-fc3a84ce9",
|
|
126
|
+
"@matter/types": "0.15.0-alpha.0-20250626-fc3a84ce9"
|
|
127
127
|
},
|
|
128
128
|
"engines": {
|
|
129
129
|
"node": ">=18.0.0"
|
|
130
130
|
}
|
|
131
131
|
},
|
|
132
132
|
"node_modules/@matter/protocol": {
|
|
133
|
-
"version": "0.15.0-alpha.0-
|
|
134
|
-
"resolved": "https://registry.npmjs.org/@matter/protocol/-/protocol-0.15.0-alpha.0-
|
|
135
|
-
"integrity": "sha512-
|
|
133
|
+
"version": "0.15.0-alpha.0-20250626-fc3a84ce9",
|
|
134
|
+
"resolved": "https://registry.npmjs.org/@matter/protocol/-/protocol-0.15.0-alpha.0-20250626-fc3a84ce9.tgz",
|
|
135
|
+
"integrity": "sha512-82cY1+OXoQQZ7wcApdMipO1n8JBRvryI2+WY0Amy+dPRo7fzd1n0EB2bpoiQ+FZAllrFND31KcaFY5BOR63nvw==",
|
|
136
136
|
"license": "Apache-2.0",
|
|
137
137
|
"dependencies": {
|
|
138
|
-
"@matter/general": "0.15.0-alpha.0-
|
|
139
|
-
"@matter/model": "0.15.0-alpha.0-
|
|
140
|
-
"@matter/types": "0.15.0-alpha.0-
|
|
138
|
+
"@matter/general": "0.15.0-alpha.0-20250626-fc3a84ce9",
|
|
139
|
+
"@matter/model": "0.15.0-alpha.0-20250626-fc3a84ce9",
|
|
140
|
+
"@matter/types": "0.15.0-alpha.0-20250626-fc3a84ce9"
|
|
141
141
|
}
|
|
142
142
|
},
|
|
143
143
|
"node_modules/@matter/types": {
|
|
144
|
-
"version": "0.15.0-alpha.0-
|
|
145
|
-
"resolved": "https://registry.npmjs.org/@matter/types/-/types-0.15.0-alpha.0-
|
|
146
|
-
"integrity": "sha512-
|
|
144
|
+
"version": "0.15.0-alpha.0-20250626-fc3a84ce9",
|
|
145
|
+
"resolved": "https://registry.npmjs.org/@matter/types/-/types-0.15.0-alpha.0-20250626-fc3a84ce9.tgz",
|
|
146
|
+
"integrity": "sha512-cxqOVzCxYk7lH9nuP15sJ2xfF9PfSDMFdv33/gmFTny6y85Yf2ZcTNrVfG5G7vNCL42Sj1edc8BLum8KYM3D8w==",
|
|
147
147
|
"license": "Apache-2.0",
|
|
148
148
|
"dependencies": {
|
|
149
|
-
"@matter/general": "0.15.0-alpha.0-
|
|
150
|
-
"@matter/model": "0.15.0-alpha.0-
|
|
149
|
+
"@matter/general": "0.15.0-alpha.0-20250626-fc3a84ce9",
|
|
150
|
+
"@matter/model": "0.15.0-alpha.0-20250626-fc3a84ce9"
|
|
151
151
|
}
|
|
152
152
|
},
|
|
153
153
|
"node_modules/@noble/curves": {
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "matterbridge",
|
|
3
|
-
"version": "3.0.8-dev-20250626-
|
|
3
|
+
"version": "3.0.8-dev-20250626-50aa686",
|
|
4
4
|
"description": "Matterbridge plugin manager for Matter",
|
|
5
5
|
"author": "https://github.com/Luligu",
|
|
6
6
|
"license": "Apache-2.0",
|
|
@@ -98,7 +98,7 @@
|
|
|
98
98
|
}
|
|
99
99
|
},
|
|
100
100
|
"dependencies": {
|
|
101
|
-
"@matter/main": "0.15.0-alpha.0-
|
|
101
|
+
"@matter/main": "0.15.0-alpha.0-20250626-fc3a84ce9",
|
|
102
102
|
"archiver": "7.0.1",
|
|
103
103
|
"express": "5.1.0",
|
|
104
104
|
"glob": "11.0.3",
|
|
@@ -0,0 +1,208 @@
|
|
|
1
|
+
import { vi, describe, it, expect, beforeEach, afterEach, MockInstance } from 'vitest';
|
|
2
|
+
import { Matterbridge } from '../src/matterbridge.ts';
|
|
3
|
+
import { AnsiLogger } from 'node-ansi-logger';
|
|
4
|
+
|
|
5
|
+
// Partial mock for @matter/main, preserving all actual exports except Logger
|
|
6
|
+
vi.mock('@matter/main', async (importOriginal) => {
|
|
7
|
+
const actual = await importOriginal();
|
|
8
|
+
return {
|
|
9
|
+
...(actual as Record<string, unknown>),
|
|
10
|
+
Logger: {
|
|
11
|
+
log: vi.fn(),
|
|
12
|
+
info: vi.fn(),
|
|
13
|
+
debug: vi.fn(),
|
|
14
|
+
warn: vi.fn(),
|
|
15
|
+
error: vi.fn(),
|
|
16
|
+
fatal: vi.fn(),
|
|
17
|
+
addLogger: vi.fn(),
|
|
18
|
+
setLogger: vi.fn(),
|
|
19
|
+
removeLogger: vi.fn(),
|
|
20
|
+
toJSON: vi.fn(() => ''),
|
|
21
|
+
},
|
|
22
|
+
};
|
|
23
|
+
});
|
|
24
|
+
|
|
25
|
+
let loggerLogSpy: MockInstance<typeof AnsiLogger.prototype.log>;
|
|
26
|
+
let consoleLogSpy: MockInstance<typeof console.log>;
|
|
27
|
+
let consoleDebugSpy: MockInstance<typeof console.debug>;
|
|
28
|
+
let consoleInfoSpy: MockInstance<typeof console.info>;
|
|
29
|
+
let consoleWarnSpy: MockInstance<typeof console.warn>;
|
|
30
|
+
let consoleErrorSpy: MockInstance<typeof console.error>;
|
|
31
|
+
const debug = true; // Set to true to enable debug logging
|
|
32
|
+
|
|
33
|
+
if (!debug) {
|
|
34
|
+
loggerLogSpy = vi.spyOn(AnsiLogger.prototype, 'log').mockImplementation((level: string, message: string, ...parameters: any[]) => {});
|
|
35
|
+
consoleLogSpy = vi.spyOn(console, 'log').mockImplementation((...args: any[]) => {});
|
|
36
|
+
consoleDebugSpy = vi.spyOn(console, 'debug').mockImplementation((...args: any[]) => {});
|
|
37
|
+
consoleInfoSpy = vi.spyOn(console, 'info').mockImplementation((...args: any[]) => {});
|
|
38
|
+
consoleWarnSpy = vi.spyOn(console, 'warn').mockImplementation((...args: any[]) => {});
|
|
39
|
+
consoleErrorSpy = vi.spyOn(console, 'error').mockImplementation((...args: any[]) => {});
|
|
40
|
+
} else {
|
|
41
|
+
loggerLogSpy = vi.spyOn(AnsiLogger.prototype, 'log');
|
|
42
|
+
consoleLogSpy = vi.spyOn(console, 'log');
|
|
43
|
+
consoleDebugSpy = vi.spyOn(console, 'debug');
|
|
44
|
+
consoleInfoSpy = vi.spyOn(console, 'info');
|
|
45
|
+
consoleWarnSpy = vi.spyOn(console, 'warn');
|
|
46
|
+
consoleErrorSpy = vi.spyOn(console, 'error');
|
|
47
|
+
}
|
|
48
|
+
|
|
49
|
+
describe('Matterbridge', () => {
|
|
50
|
+
let matterbridge: Matterbridge;
|
|
51
|
+
|
|
52
|
+
beforeEach(async () => {
|
|
53
|
+
matterbridge = await Matterbridge.loadInstance(false);
|
|
54
|
+
// Set up required properties/mocks
|
|
55
|
+
matterbridge.log = { debug: vi.fn(), info: vi.fn(), notice: vi.fn(), warn: vi.fn(), error: vi.fn(), fatal: vi.fn() } as any;
|
|
56
|
+
matterbridge.plugins = { array: () => [], clear: vi.fn(), [Symbol.iterator]: function* () {} } as any;
|
|
57
|
+
matterbridge.devices = { array: () => [], clear: vi.fn(), [Symbol.iterator]: function* () {} } as any;
|
|
58
|
+
matterbridge.frontend = {
|
|
59
|
+
start: vi.fn(),
|
|
60
|
+
stop: vi.fn(),
|
|
61
|
+
wssSendRefreshRequired: vi.fn(),
|
|
62
|
+
wssSendRestartRequired: vi.fn(),
|
|
63
|
+
wssSendSnackbarMessage: vi.fn(),
|
|
64
|
+
} as any;
|
|
65
|
+
});
|
|
66
|
+
|
|
67
|
+
afterEach(() => {
|
|
68
|
+
vi.clearAllMocks();
|
|
69
|
+
});
|
|
70
|
+
|
|
71
|
+
it('should initialize system and matterbridge information', () => {
|
|
72
|
+
expect(matterbridge.systemInformation).toBeDefined();
|
|
73
|
+
expect(matterbridge.matterbridgeInformation).toBeDefined();
|
|
74
|
+
});
|
|
75
|
+
|
|
76
|
+
it('should emit initialize_completed after initialize', async () => {
|
|
77
|
+
const spy = vi.fn();
|
|
78
|
+
matterbridge.on('initialize_completed', spy);
|
|
79
|
+
await matterbridge.initialize();
|
|
80
|
+
expect(spy).toHaveBeenCalled();
|
|
81
|
+
expect((matterbridge as any)['initialized']).toBe(true);
|
|
82
|
+
});
|
|
83
|
+
|
|
84
|
+
it('should call parseCommandLine during initialize', async () => {
|
|
85
|
+
const spy = vi.spyOn(matterbridge as any, 'parseCommandLine').mockResolvedValue(undefined);
|
|
86
|
+
await matterbridge.initialize();
|
|
87
|
+
expect(spy).toHaveBeenCalled();
|
|
88
|
+
});
|
|
89
|
+
|
|
90
|
+
it('should log system info in logNodeAndSystemInfo', async () => {
|
|
91
|
+
await (matterbridge as any)['logNodeAndSystemInfo']();
|
|
92
|
+
expect(matterbridge.log.debug).toHaveBeenCalled();
|
|
93
|
+
});
|
|
94
|
+
|
|
95
|
+
it('should register and deregister process handlers', () => {
|
|
96
|
+
(matterbridge as any)['registerProcessHandlers']();
|
|
97
|
+
(matterbridge as any)['deregisterProcessHandlers']();
|
|
98
|
+
expect(matterbridge.log.error).not.toHaveBeenCalled();
|
|
99
|
+
});
|
|
100
|
+
|
|
101
|
+
it('should call cleanup and emit cleanup events', async () => {
|
|
102
|
+
(matterbridge as any)['initialized'] = true;
|
|
103
|
+
(matterbridge as any)['hasCleanupStarted'] = false;
|
|
104
|
+
const spyStart = vi.fn();
|
|
105
|
+
const spyComplete = vi.fn();
|
|
106
|
+
matterbridge.on('cleanup_started', spyStart);
|
|
107
|
+
matterbridge.on('cleanup_completed', spyComplete);
|
|
108
|
+
await (matterbridge as any)['cleanup']('test cleanup');
|
|
109
|
+
expect(spyStart).toHaveBeenCalled();
|
|
110
|
+
expect(spyComplete).toHaveBeenCalled();
|
|
111
|
+
});
|
|
112
|
+
|
|
113
|
+
it('should not run cleanup if already started', async () => {
|
|
114
|
+
(matterbridge as any)['initialized'] = true;
|
|
115
|
+
(matterbridge as any)['hasCleanupStarted'] = true;
|
|
116
|
+
const debugSpy = matterbridge.log.debug as any;
|
|
117
|
+
await (matterbridge as any)['cleanup']('test cleanup');
|
|
118
|
+
expect(debugSpy).toHaveBeenCalledWith('Cleanup already started...');
|
|
119
|
+
});
|
|
120
|
+
|
|
121
|
+
it('should get devices using getDevices()', () => {
|
|
122
|
+
const fakeDevices = [{ id: 1 }, { id: 2 }];
|
|
123
|
+
matterbridge.devices.array = vi.fn(() => fakeDevices);
|
|
124
|
+
expect(matterbridge.getDevices()).toBe(fakeDevices);
|
|
125
|
+
});
|
|
126
|
+
|
|
127
|
+
it('should get plugins using getPlugins()', () => {
|
|
128
|
+
const fakePlugins = [{ name: 'p1' }, { name: 'p2' }];
|
|
129
|
+
matterbridge.plugins.array = vi.fn(() => fakePlugins);
|
|
130
|
+
expect(matterbridge.getPlugins()).toBe(fakePlugins);
|
|
131
|
+
});
|
|
132
|
+
|
|
133
|
+
it('should set log level and propagate to dependencies', async () => {
|
|
134
|
+
const setLevel = vi.fn();
|
|
135
|
+
matterbridge.frontend.logLevel = undefined;
|
|
136
|
+
matterbridge.devices.logLevel = undefined;
|
|
137
|
+
matterbridge.plugins.logLevel = undefined;
|
|
138
|
+
(global as any).MatterbridgeEndpoint = { logLevel: undefined };
|
|
139
|
+
matterbridge.log = { debug: vi.fn() } as any;
|
|
140
|
+
await matterbridge.setLogLevel(1); // 1 = INFO
|
|
141
|
+
expect(matterbridge.frontend.logLevel).toBe(1);
|
|
142
|
+
expect(matterbridge.devices.logLevel).toBe(1);
|
|
143
|
+
expect(matterbridge.plugins.logLevel).toBe(1);
|
|
144
|
+
expect(matterbridge.log.debug).toHaveBeenCalled();
|
|
145
|
+
});
|
|
146
|
+
|
|
147
|
+
it('should emit and listen to custom events', () => {
|
|
148
|
+
const handler = vi.fn();
|
|
149
|
+
matterbridge.on('online', handler);
|
|
150
|
+
matterbridge.emit('online', 'nodeid');
|
|
151
|
+
expect(handler).toHaveBeenCalledWith('nodeid');
|
|
152
|
+
});
|
|
153
|
+
|
|
154
|
+
it('should call destroyInstance and cleanup', async () => {
|
|
155
|
+
const cleanupSpy = vi.spyOn(matterbridge as any, 'cleanup').mockResolvedValue(undefined);
|
|
156
|
+
matterbridge.log.info = vi.fn();
|
|
157
|
+
await matterbridge.destroyInstance();
|
|
158
|
+
expect(cleanupSpy).toHaveBeenCalled();
|
|
159
|
+
expect(matterbridge.log.info).toHaveBeenCalledWith(expect.stringContaining('Destroy instance...'));
|
|
160
|
+
});
|
|
161
|
+
|
|
162
|
+
it('should call restartProcess and cleanup', async () => {
|
|
163
|
+
const cleanupSpy = vi.spyOn(matterbridge as any, 'cleanup').mockResolvedValue(undefined);
|
|
164
|
+
await matterbridge.restartProcess();
|
|
165
|
+
expect(cleanupSpy).toHaveBeenCalledWith('restarting...', true);
|
|
166
|
+
});
|
|
167
|
+
|
|
168
|
+
it('should call shutdownProcess and cleanup', async () => {
|
|
169
|
+
const cleanupSpy = vi.spyOn(matterbridge as any, 'cleanup').mockResolvedValue(undefined);
|
|
170
|
+
await matterbridge.shutdownProcess();
|
|
171
|
+
expect(cleanupSpy).toHaveBeenCalledWith('shutting down...', false);
|
|
172
|
+
});
|
|
173
|
+
|
|
174
|
+
it('should call updateProcess and cleanup', async () => {
|
|
175
|
+
const cleanupSpy = vi.spyOn(matterbridge as any, 'cleanup').mockResolvedValue(undefined);
|
|
176
|
+
matterbridge.log.info = vi.fn();
|
|
177
|
+
(matterbridge.frontend as any).wssSendRestartRequired = vi.fn();
|
|
178
|
+
await matterbridge.updateProcess();
|
|
179
|
+
expect(cleanupSpy).toHaveBeenCalledWith('updating...', false);
|
|
180
|
+
expect(matterbridge.log.info).toHaveBeenCalledWith(expect.stringContaining('Updating matterbridge...'));
|
|
181
|
+
expect((matterbridge.frontend as any).wssSendRestartRequired).toHaveBeenCalled();
|
|
182
|
+
});
|
|
183
|
+
|
|
184
|
+
it('should call unregisterAndShutdownProcess and cleanup', async () => {
|
|
185
|
+
const cleanupSpy = vi.spyOn(matterbridge as any, 'cleanup').mockResolvedValue(undefined);
|
|
186
|
+
matterbridge.log.info = vi.fn();
|
|
187
|
+
matterbridge.plugins = [{ name: 'p1' }];
|
|
188
|
+
matterbridge.removeAllBridgedEndpoints = vi.fn().mockResolvedValue(undefined);
|
|
189
|
+
matterbridge.devices.clear = vi.fn();
|
|
190
|
+
await matterbridge.unregisterAndShutdownProcess();
|
|
191
|
+
expect(cleanupSpy).toHaveBeenCalledWith('unregistered all devices and shutting down...', false);
|
|
192
|
+
expect(matterbridge.log.info).toHaveBeenCalledWith(expect.stringContaining('Unregistering all devices and shutting down...'));
|
|
193
|
+
});
|
|
194
|
+
|
|
195
|
+
it('should call shutdownProcessAndReset and cleanup', async () => {
|
|
196
|
+
const cleanupSpy = vi.spyOn(matterbridge as any, 'cleanup').mockResolvedValue(undefined);
|
|
197
|
+
await matterbridge.shutdownProcessAndReset();
|
|
198
|
+
expect(cleanupSpy).toHaveBeenCalledWith('shutting down with reset...', false);
|
|
199
|
+
});
|
|
200
|
+
|
|
201
|
+
it('should call shutdownProcessAndFactoryReset and cleanup', async () => {
|
|
202
|
+
const cleanupSpy = vi.spyOn(matterbridge as any, 'cleanup').mockResolvedValue(undefined);
|
|
203
|
+
await matterbridge.shutdownProcessAndFactoryReset();
|
|
204
|
+
expect(cleanupSpy).toHaveBeenCalledWith('shutting down with factory reset...', false);
|
|
205
|
+
});
|
|
206
|
+
|
|
207
|
+
// Add more tests for all public/protected methods to reach 100% coverage
|
|
208
|
+
});
|