@matterbridge/vitest-utils 3.8.0-dev-20260526-20ee3dc → 3.8.0-dev-20260527-b4148f4
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/export.d.ts +5 -1
- package/dist/export.js +5 -1
- package/dist/flushAsync.d.ts +1 -0
- package/dist/flushAsync.js +8 -0
- package/dist/logKeepAlives.d.ts +2 -0
- package/dist/logKeepAlives.js +31 -0
- package/dist/matterRequest.d.ts +10 -0
- package/dist/matterRequest.js +78 -0
- package/dist/vitestMatterTest.d.ts +21 -0
- package/dist/vitestMatterTest.js +280 -0
- package/dist/{vitestHelpers.js → vitestSetupTest.js} +2 -1
- package/package.json +2 -1
- /package/dist/{vitestHelpers.d.ts → vitestSetupTest.d.ts} +0 -0
package/dist/export.d.ts
CHANGED
package/dist/export.js
CHANGED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export declare function flushAsync(ticks?: number, microTurns?: number, pause?: number): Promise<void>;
|
|
@@ -0,0 +1,8 @@
|
|
|
1
|
+
export async function flushAsync(ticks = 3, microTurns = 10, pause = 250) {
|
|
2
|
+
for (let i = 0; i < ticks; i++)
|
|
3
|
+
await new Promise((resolve) => setImmediate(resolve));
|
|
4
|
+
for (let i = 0; i < microTurns; i++)
|
|
5
|
+
await Promise.resolve();
|
|
6
|
+
if (pause)
|
|
7
|
+
await new Promise((resolve) => setTimeout(resolve, pause));
|
|
8
|
+
}
|
|
@@ -0,0 +1,31 @@
|
|
|
1
|
+
import { inspect } from 'node:util';
|
|
2
|
+
import { rs } from 'node-ansi-logger';
|
|
3
|
+
export function logKeepAlives(log) {
|
|
4
|
+
const handles = process._getActiveHandles?.() ?? [];
|
|
5
|
+
const requests = process._getActiveRequests?.() ?? [];
|
|
6
|
+
const fmtHandle = (h, i) => {
|
|
7
|
+
const ctor = h?.constructor?.name ?? 'Unknown';
|
|
8
|
+
const hasRef = typeof h?.hasRef === 'function' ? h.hasRef() : undefined;
|
|
9
|
+
const isPort = h?.constructor?.name?.includes('MessagePort');
|
|
10
|
+
const fd = h?.fd ?? h?._handle?.fd;
|
|
11
|
+
return { i, type: ctor, hasRef, isPort, fd };
|
|
12
|
+
};
|
|
13
|
+
const fmtReq = (r, i) => {
|
|
14
|
+
const ctor = r?.constructor?.name ?? 'Unknown';
|
|
15
|
+
return { i, type: ctor };
|
|
16
|
+
};
|
|
17
|
+
const summary = {
|
|
18
|
+
handles: handles.map(fmtHandle),
|
|
19
|
+
requests: requests.map(fmtReq),
|
|
20
|
+
};
|
|
21
|
+
if (summary.handles.length === 0 && summary.requests.length === 0) {
|
|
22
|
+
log?.debug('KeepAlive: no active handles or requests.');
|
|
23
|
+
}
|
|
24
|
+
else {
|
|
25
|
+
log?.debug(`KeepAlive:${rs}\n${inspect(summary, { depth: 5, colors: true })}`);
|
|
26
|
+
if (!log) {
|
|
27
|
+
process.stdout.write(`KeepAlive:\n${inspect(summary, { depth: 5, colors: true })}\n`);
|
|
28
|
+
}
|
|
29
|
+
}
|
|
30
|
+
return summary.handles.length + summary.requests.length;
|
|
31
|
+
}
|
|
@@ -0,0 +1,10 @@
|
|
|
1
|
+
import { ColorControl } from '@matter/types/clusters/color-control';
|
|
2
|
+
import { LevelControl } from '@matter/types/clusters/level-control';
|
|
3
|
+
export declare function getMoveToLevelRequest(level: number, transitionTime: number, executeIfOff: boolean): LevelControl.MoveToLevelRequest;
|
|
4
|
+
export declare function getMoveToColorTemperatureRequest(colorTemperatureMireds: number, transitionTime: number, executeIfOff: boolean): ColorControl.MoveToColorTemperatureRequest;
|
|
5
|
+
export declare function getMoveToHueRequest(hue: number, transitionTime: number, executeIfOff: boolean): ColorControl.MoveToHueRequest;
|
|
6
|
+
export declare function getEnhancedMoveToHueRequest(enhancedHue: number, transitionTime: number, executeIfOff: boolean): ColorControl.EnhancedMoveToHueRequest;
|
|
7
|
+
export declare function getMoveToSaturationRequest(saturation: number, transitionTime: number, executeIfOff: boolean): ColorControl.MoveToSaturationRequest;
|
|
8
|
+
export declare function getMoveToHueAndSaturationRequest(hue: number, saturation: number, transitionTime: number, executeIfOff: boolean): ColorControl.MoveToHueAndSaturationRequest;
|
|
9
|
+
export declare function getEnhancedMoveToHueAndSaturationRequest(enhancedHue: number, saturation: number, transitionTime: number, executeIfOff: boolean): ColorControl.EnhancedMoveToHueAndSaturationRequest;
|
|
10
|
+
export declare function getMoveToColorRequest(colorX: number, colorY: number, transitionTime: number, executeIfOff: boolean): ColorControl.MoveToColorRequest;
|
|
@@ -0,0 +1,78 @@
|
|
|
1
|
+
import { ColorControl } from '@matter/types/clusters/color-control';
|
|
2
|
+
export function getMoveToLevelRequest(level, transitionTime, executeIfOff) {
|
|
3
|
+
const request = {
|
|
4
|
+
level,
|
|
5
|
+
transitionTime,
|
|
6
|
+
optionsMask: { executeIfOff, coupleColorTempToLevel: false },
|
|
7
|
+
optionsOverride: { executeIfOff, coupleColorTempToLevel: false },
|
|
8
|
+
};
|
|
9
|
+
return request;
|
|
10
|
+
}
|
|
11
|
+
export function getMoveToColorTemperatureRequest(colorTemperatureMireds, transitionTime, executeIfOff) {
|
|
12
|
+
const request = {
|
|
13
|
+
colorTemperatureMireds,
|
|
14
|
+
transitionTime,
|
|
15
|
+
optionsMask: { executeIfOff },
|
|
16
|
+
optionsOverride: { executeIfOff },
|
|
17
|
+
};
|
|
18
|
+
return request;
|
|
19
|
+
}
|
|
20
|
+
export function getMoveToHueRequest(hue, transitionTime, executeIfOff) {
|
|
21
|
+
const request = {
|
|
22
|
+
hue,
|
|
23
|
+
transitionTime,
|
|
24
|
+
direction: ColorControl.Direction.Shortest,
|
|
25
|
+
optionsMask: { executeIfOff },
|
|
26
|
+
optionsOverride: { executeIfOff },
|
|
27
|
+
};
|
|
28
|
+
return request;
|
|
29
|
+
}
|
|
30
|
+
export function getEnhancedMoveToHueRequest(enhancedHue, transitionTime, executeIfOff) {
|
|
31
|
+
const request = {
|
|
32
|
+
enhancedHue,
|
|
33
|
+
transitionTime,
|
|
34
|
+
direction: ColorControl.Direction.Shortest,
|
|
35
|
+
optionsMask: { executeIfOff },
|
|
36
|
+
optionsOverride: { executeIfOff },
|
|
37
|
+
};
|
|
38
|
+
return request;
|
|
39
|
+
}
|
|
40
|
+
export function getMoveToSaturationRequest(saturation, transitionTime, executeIfOff) {
|
|
41
|
+
const request = {
|
|
42
|
+
saturation,
|
|
43
|
+
transitionTime,
|
|
44
|
+
optionsMask: { executeIfOff },
|
|
45
|
+
optionsOverride: { executeIfOff },
|
|
46
|
+
};
|
|
47
|
+
return request;
|
|
48
|
+
}
|
|
49
|
+
export function getMoveToHueAndSaturationRequest(hue, saturation, transitionTime, executeIfOff) {
|
|
50
|
+
const request = {
|
|
51
|
+
hue,
|
|
52
|
+
saturation,
|
|
53
|
+
transitionTime,
|
|
54
|
+
optionsMask: { executeIfOff },
|
|
55
|
+
optionsOverride: { executeIfOff },
|
|
56
|
+
};
|
|
57
|
+
return request;
|
|
58
|
+
}
|
|
59
|
+
export function getEnhancedMoveToHueAndSaturationRequest(enhancedHue, saturation, transitionTime, executeIfOff) {
|
|
60
|
+
const request = {
|
|
61
|
+
enhancedHue,
|
|
62
|
+
saturation,
|
|
63
|
+
transitionTime,
|
|
64
|
+
optionsMask: { executeIfOff },
|
|
65
|
+
optionsOverride: { executeIfOff },
|
|
66
|
+
};
|
|
67
|
+
return request;
|
|
68
|
+
}
|
|
69
|
+
export function getMoveToColorRequest(colorX, colorY, transitionTime, executeIfOff) {
|
|
70
|
+
const request = {
|
|
71
|
+
colorX,
|
|
72
|
+
colorY,
|
|
73
|
+
transitionTime,
|
|
74
|
+
optionsMask: { executeIfOff },
|
|
75
|
+
optionsOverride: { executeIfOff },
|
|
76
|
+
};
|
|
77
|
+
return request;
|
|
78
|
+
}
|
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
import '@matter/nodejs';
|
|
2
|
+
import { Environment } from '@matter/general';
|
|
3
|
+
import { Endpoint, ServerNode } from '@matter/node';
|
|
4
|
+
import { AggregatorEndpoint } from '@matter/node/endpoints';
|
|
5
|
+
import { DeviceTypeId } from '@matter/types/datatype';
|
|
6
|
+
import { type PlatformMatterbridge } from '@matterbridge/types';
|
|
7
|
+
export declare let environment: Environment;
|
|
8
|
+
export declare let server: ServerNode<ServerNode.RootEndpoint>;
|
|
9
|
+
export declare let aggregator: Endpoint<AggregatorEndpoint>;
|
|
10
|
+
export declare function createTestEnvironment(): Promise<Environment>;
|
|
11
|
+
export declare function destroyTestEnvironment(): Promise<void>;
|
|
12
|
+
export declare function getPlatformMatterbridge(): PlatformMatterbridge;
|
|
13
|
+
export declare function flushAllEndpointNumberPersistence(targetServer: ServerNode, rounds?: number, ticks?: number, microTurns?: number, pause?: number): Promise<void>;
|
|
14
|
+
export declare function assertAllEndpointNumbersPersisted(targetServer: ServerNode): Promise<number>;
|
|
15
|
+
export declare function closeServerNodeStores(targetServer?: ServerNode): Promise<void>;
|
|
16
|
+
export declare function createServerNode(port: number, deviceType?: DeviceTypeId, ticks?: number, microTurns?: number, pause?: number): Promise<[ServerNode<ServerNode.RootEndpoint>, Endpoint<AggregatorEndpoint>]>;
|
|
17
|
+
export declare function startServerNode(ticks?: number, microTurns?: number, pause?: number): Promise<[ServerNode<ServerNode.RootEndpoint>, Endpoint<AggregatorEndpoint>]>;
|
|
18
|
+
export declare function stopServerNode(ticks?: number, microTurns?: number, pause?: number): Promise<void>;
|
|
19
|
+
export declare function flushServerNode(ticks?: number, microTurns?: number, pause?: number): Promise<void>;
|
|
20
|
+
export declare function addDevice(owner: ServerNode<ServerNode.RootEndpoint> | Endpoint<AggregatorEndpoint>, device: Endpoint, rounds?: number, pause?: number): Promise<boolean>;
|
|
21
|
+
export declare function deleteDevice(owner: ServerNode<ServerNode.RootEndpoint> | Endpoint<AggregatorEndpoint>, device: Endpoint, rounds?: number, pause?: number): Promise<boolean>;
|
|
@@ -0,0 +1,280 @@
|
|
|
1
|
+
import '@matter/nodejs';
|
|
2
|
+
import path from 'node:path';
|
|
3
|
+
import { inspect } from 'node:util';
|
|
4
|
+
import { Environment, Lifecycle, LogFormat as MatterLogFormat, LogLevel as MatterLogLevel } from '@matter/general';
|
|
5
|
+
import { Endpoint, ServerNode, ServerNodeStore } from '@matter/node';
|
|
6
|
+
import { AggregatorEndpoint } from '@matter/node/endpoints';
|
|
7
|
+
import { DeviceTypeId, VendorId } from '@matter/types/datatype';
|
|
8
|
+
import { MATTER_STORAGE_DIR } from '@matterbridge/types';
|
|
9
|
+
import { er, rs } from 'node-ansi-logger';
|
|
10
|
+
import { flushAsync } from './flushAsync.js';
|
|
11
|
+
import { HOMEDIR, NAME } from './vitestSetupTest.js';
|
|
12
|
+
export let environment;
|
|
13
|
+
export let server;
|
|
14
|
+
export let aggregator;
|
|
15
|
+
export async function createTestEnvironment() {
|
|
16
|
+
expect(NAME).toBeDefined();
|
|
17
|
+
expect(typeof NAME).toBe('string');
|
|
18
|
+
expect(NAME.length).toBeGreaterThanOrEqual(4);
|
|
19
|
+
environment = Environment.default;
|
|
20
|
+
environment.vars.set('log.level', MatterLogLevel.DEBUG);
|
|
21
|
+
environment.vars.set('log.format', MatterLogFormat.ANSI);
|
|
22
|
+
environment.vars.set('path.root', path.join(HOMEDIR, '.matterbridge', MATTER_STORAGE_DIR));
|
|
23
|
+
environment.vars.set('runtime.signals', false);
|
|
24
|
+
environment.vars.set('runtime.exitcode', false);
|
|
25
|
+
return environment;
|
|
26
|
+
}
|
|
27
|
+
export async function destroyTestEnvironment() {
|
|
28
|
+
}
|
|
29
|
+
export function getPlatformMatterbridge() {
|
|
30
|
+
return {
|
|
31
|
+
systemInformation: {
|
|
32
|
+
interfaceName: 'eth0',
|
|
33
|
+
macAddress: 'aa:bb:cc:dd:ee:ff',
|
|
34
|
+
ipv4Address: '',
|
|
35
|
+
ipv6Address: '',
|
|
36
|
+
osRelease: 'xx.xx.xx.xx.xx.xx',
|
|
37
|
+
nodeVersion: '22.1.10',
|
|
38
|
+
hostname: 'jest',
|
|
39
|
+
user: 'matterbridge',
|
|
40
|
+
osType: 'Linux',
|
|
41
|
+
osPlatform: 'linux',
|
|
42
|
+
osArch: 'x64',
|
|
43
|
+
totalMemory: '0 B',
|
|
44
|
+
freeMemory: '0 B',
|
|
45
|
+
systemUptime: '0s',
|
|
46
|
+
processUptime: '0s',
|
|
47
|
+
cpuUsage: '0%',
|
|
48
|
+
processCpuUsage: '0%',
|
|
49
|
+
rss: '0 B',
|
|
50
|
+
heapTotal: '0 B',
|
|
51
|
+
heapUsed: '0 B',
|
|
52
|
+
},
|
|
53
|
+
rootDirectory: HOMEDIR,
|
|
54
|
+
homeDirectory: HOMEDIR,
|
|
55
|
+
matterbridgeDirectory: path.join(HOMEDIR, '.matterbridge'),
|
|
56
|
+
matterbridgePluginDirectory: path.join(HOMEDIR, 'Matterbridge'),
|
|
57
|
+
matterbridgeCertDirectory: path.join(HOMEDIR, '.mattercert'),
|
|
58
|
+
globalModulesDirectory: path.join(HOMEDIR, 'node_modules'),
|
|
59
|
+
matterbridgeVersion: '3.8.0',
|
|
60
|
+
matterbridgeLatestVersion: '3.8.0',
|
|
61
|
+
matterbridgeDevVersion: '3.8.0',
|
|
62
|
+
frontendVersion: '3.8.0',
|
|
63
|
+
bridgeMode: '',
|
|
64
|
+
restartMode: '',
|
|
65
|
+
virtualMode: 'mounted_switch',
|
|
66
|
+
aggregatorVendorId: 0xfff1,
|
|
67
|
+
aggregatorVendorName: 'Matterbridge',
|
|
68
|
+
aggregatorProductId: 0x8000,
|
|
69
|
+
aggregatorProductName: 'Matterbridge Jest',
|
|
70
|
+
addBridgedEndpoint: jest.fn(async () => {
|
|
71
|
+
return Promise.resolve(true);
|
|
72
|
+
}),
|
|
73
|
+
removeBridgedEndpoint: jest.fn(async () => {
|
|
74
|
+
return Promise.resolve(true);
|
|
75
|
+
}),
|
|
76
|
+
removeAllBridgedEndpoints: jest.fn(async () => {
|
|
77
|
+
return Promise.resolve(true);
|
|
78
|
+
}),
|
|
79
|
+
addVirtualEndpoint: jest.fn(async () => {
|
|
80
|
+
return Promise.resolve();
|
|
81
|
+
}),
|
|
82
|
+
};
|
|
83
|
+
}
|
|
84
|
+
export async function flushAllEndpointNumberPersistence(targetServer, rounds = 3, ticks = 1, microTurns = 1, pause = 10) {
|
|
85
|
+
const nodeStore = targetServer.env.get(ServerNodeStore);
|
|
86
|
+
for (let i = 0; i < rounds; i++) {
|
|
87
|
+
await flushAsync(ticks, microTurns, pause);
|
|
88
|
+
await nodeStore.endpointStores.close();
|
|
89
|
+
}
|
|
90
|
+
}
|
|
91
|
+
function getRootServerNode(endpoint) {
|
|
92
|
+
let current = endpoint;
|
|
93
|
+
while (current.owner) {
|
|
94
|
+
current = current.owner;
|
|
95
|
+
}
|
|
96
|
+
return current;
|
|
97
|
+
}
|
|
98
|
+
function collectAllEndpoints(root) {
|
|
99
|
+
const list = [];
|
|
100
|
+
const walk = (ep) => {
|
|
101
|
+
list.push(ep);
|
|
102
|
+
if (ep.parts) {
|
|
103
|
+
for (const child of ep.parts) {
|
|
104
|
+
walk(child);
|
|
105
|
+
}
|
|
106
|
+
}
|
|
107
|
+
};
|
|
108
|
+
walk(root);
|
|
109
|
+
return list;
|
|
110
|
+
}
|
|
111
|
+
export async function assertAllEndpointNumbersPersisted(targetServer) {
|
|
112
|
+
const nodeStore = targetServer.env.get(ServerNodeStore);
|
|
113
|
+
await nodeStore.endpointStores.close();
|
|
114
|
+
const all = collectAllEndpoints(targetServer);
|
|
115
|
+
for (const ep of all) {
|
|
116
|
+
const store = nodeStore.storeForEndpoint(ep);
|
|
117
|
+
if (ep.maybeNumber === 0) {
|
|
118
|
+
expect(store.number ?? 0).toBe(0);
|
|
119
|
+
}
|
|
120
|
+
else {
|
|
121
|
+
expect(store.number).toBeGreaterThan(0);
|
|
122
|
+
}
|
|
123
|
+
}
|
|
124
|
+
return all.length;
|
|
125
|
+
}
|
|
126
|
+
export async function closeServerNodeStores(targetServer) {
|
|
127
|
+
if (!targetServer)
|
|
128
|
+
targetServer = server;
|
|
129
|
+
await targetServer?.env.get(ServerNodeStore)?.endpointStores.close();
|
|
130
|
+
}
|
|
131
|
+
export async function createServerNode(port, deviceType = DeviceTypeId(0x000e), ticks = 1, microTurns = 1, pause = 10) {
|
|
132
|
+
const { randomBytes } = await import('node:crypto');
|
|
133
|
+
const random = randomBytes(8).toString('hex');
|
|
134
|
+
server = await ServerNode.create({
|
|
135
|
+
id: NAME + 'ServerNode',
|
|
136
|
+
environment,
|
|
137
|
+
productDescription: {
|
|
138
|
+
name: NAME + 'ServerNode',
|
|
139
|
+
deviceType: DeviceTypeId(deviceType),
|
|
140
|
+
vendorId: VendorId(0xfff1),
|
|
141
|
+
productId: 0x8000,
|
|
142
|
+
},
|
|
143
|
+
basicInformation: {
|
|
144
|
+
vendorId: VendorId(0xfff1),
|
|
145
|
+
vendorName: 'Matterbridge',
|
|
146
|
+
productId: 0x8000,
|
|
147
|
+
productName: 'Matterbridge ' + NAME,
|
|
148
|
+
nodeLabel: NAME + 'ServerNode',
|
|
149
|
+
hardwareVersion: 1,
|
|
150
|
+
softwareVersion: 1,
|
|
151
|
+
reachable: true,
|
|
152
|
+
serialNumber: 'SN' + random,
|
|
153
|
+
uniqueId: 'UI' + random,
|
|
154
|
+
},
|
|
155
|
+
network: {
|
|
156
|
+
listeningAddressIpv4: undefined,
|
|
157
|
+
listeningAddressIpv6: undefined,
|
|
158
|
+
port,
|
|
159
|
+
tcp: true,
|
|
160
|
+
transportPreference: 'udp',
|
|
161
|
+
},
|
|
162
|
+
operationalCredentials: {
|
|
163
|
+
certification: undefined,
|
|
164
|
+
},
|
|
165
|
+
});
|
|
166
|
+
expect(server).toBeDefined();
|
|
167
|
+
expect(server.lifecycle.isReady).toBeTruthy();
|
|
168
|
+
aggregator = new Endpoint(AggregatorEndpoint, {
|
|
169
|
+
id: NAME + 'AggregatorNode',
|
|
170
|
+
});
|
|
171
|
+
expect(aggregator).toBeDefined();
|
|
172
|
+
await server.add(aggregator);
|
|
173
|
+
expect(server.parts.has(aggregator.id)).toBeTruthy();
|
|
174
|
+
expect(server.parts.has(aggregator)).toBeTruthy();
|
|
175
|
+
expect(aggregator.lifecycle.isReady).toBeTruthy();
|
|
176
|
+
expect(server.lifecycle.isOnline).toBeFalsy();
|
|
177
|
+
await flushAsync(ticks, microTurns, pause);
|
|
178
|
+
return [server, aggregator];
|
|
179
|
+
}
|
|
180
|
+
export async function startServerNode(ticks = 1, microTurns = 1, pause = 10) {
|
|
181
|
+
if (!server || !aggregator) {
|
|
182
|
+
throw new Error('Server node and aggregator must be created before starting the server. Call createServerNode() first.');
|
|
183
|
+
}
|
|
184
|
+
await new Promise((resolve, reject) => {
|
|
185
|
+
server.lifecycle.online.on(async () => {
|
|
186
|
+
resolve();
|
|
187
|
+
});
|
|
188
|
+
server.start().catch((err) => reject(err));
|
|
189
|
+
});
|
|
190
|
+
expect(server.lifecycle.isReady).toBeTruthy();
|
|
191
|
+
expect(server.lifecycle.isOnline).toBeTruthy();
|
|
192
|
+
expect(server.lifecycle.isCommissioned).toBeFalsy();
|
|
193
|
+
expect(server.lifecycle.isPartsReady).toBeTruthy();
|
|
194
|
+
expect(server.lifecycle.hasId).toBeTruthy();
|
|
195
|
+
expect(server.lifecycle.hasNumber).toBeTruthy();
|
|
196
|
+
expect(aggregator.lifecycle.isReady).toBeTruthy();
|
|
197
|
+
expect(aggregator.lifecycle.isInstalled).toBeTruthy();
|
|
198
|
+
expect(aggregator.lifecycle.isPartsReady).toBeTruthy();
|
|
199
|
+
expect(aggregator.lifecycle.hasId).toBeTruthy();
|
|
200
|
+
expect(aggregator.lifecycle.hasNumber).toBeTruthy();
|
|
201
|
+
await flushAsync(ticks, microTurns, pause);
|
|
202
|
+
return [server, aggregator];
|
|
203
|
+
}
|
|
204
|
+
export async function stopServerNode(ticks = 1, microTurns = 1, pause = 10) {
|
|
205
|
+
await flushAllEndpointNumberPersistence(server);
|
|
206
|
+
await assertAllEndpointNumbersPersisted(server);
|
|
207
|
+
expect(server).toBeDefined();
|
|
208
|
+
expect(server.lifecycle.isReady).toBeTruthy();
|
|
209
|
+
expect(server.lifecycle.isOnline).toBeTruthy();
|
|
210
|
+
await server.close();
|
|
211
|
+
expect(server.lifecycle.isReady).toBeFalsy();
|
|
212
|
+
expect(server.lifecycle.isOnline).toBeFalsy();
|
|
213
|
+
await flushAsync(ticks, microTurns, pause);
|
|
214
|
+
}
|
|
215
|
+
export async function flushServerNode(ticks = 1, microTurns = 1, pause = 10) {
|
|
216
|
+
await flushAllEndpointNumberPersistence(server);
|
|
217
|
+
await assertAllEndpointNumbersPersisted(server);
|
|
218
|
+
expect(server).toBeDefined();
|
|
219
|
+
expect(server.lifecycle.isReady).toBeTruthy();
|
|
220
|
+
expect(server.lifecycle.isOnline).toBeFalsy();
|
|
221
|
+
await server.close();
|
|
222
|
+
expect(server.lifecycle.isReady).toBeFalsy();
|
|
223
|
+
expect(server.lifecycle.isOnline).toBeFalsy();
|
|
224
|
+
await flushAsync(ticks, microTurns, pause);
|
|
225
|
+
}
|
|
226
|
+
export async function addDevice(owner, device, rounds = 3, pause = 10) {
|
|
227
|
+
expect(owner).toBeDefined();
|
|
228
|
+
expect(device).toBeDefined();
|
|
229
|
+
expect(owner.lifecycle.isReady).toBeTruthy();
|
|
230
|
+
expect(owner.construction.status).toBe(Lifecycle.Status.Active);
|
|
231
|
+
expect(owner.lifecycle.isPartsReady).toBeTruthy();
|
|
232
|
+
const rootServerNode = getRootServerNode(owner);
|
|
233
|
+
await flushAllEndpointNumberPersistence(rootServerNode, rounds, pause);
|
|
234
|
+
try {
|
|
235
|
+
await owner.add(device);
|
|
236
|
+
}
|
|
237
|
+
catch (error) {
|
|
238
|
+
const errorMessage = error instanceof Error ? error.message : error;
|
|
239
|
+
const errorInspect = inspect(error, { depth: 10 });
|
|
240
|
+
process.stderr.write(`${er}Error adding device ${device.maybeId}.${device.maybeNumber}: ${errorMessage}${rs}\nStack: ${errorInspect}\n`);
|
|
241
|
+
return false;
|
|
242
|
+
}
|
|
243
|
+
await device.construction.ready;
|
|
244
|
+
expect(owner.parts.has(device)).toBeTruthy();
|
|
245
|
+
expect(owner.lifecycle.isPartsReady).toBeTruthy();
|
|
246
|
+
expect(device.lifecycle.isReady).toBeTruthy();
|
|
247
|
+
expect(device.lifecycle.isInstalled).toBeTruthy();
|
|
248
|
+
expect(device.lifecycle.hasId).toBeTruthy();
|
|
249
|
+
expect(device.lifecycle.hasNumber).toBeTruthy();
|
|
250
|
+
expect(device.construction.status).toBe(Lifecycle.Status.Active);
|
|
251
|
+
await flushAllEndpointNumberPersistence(rootServerNode, rounds, pause);
|
|
252
|
+
return true;
|
|
253
|
+
}
|
|
254
|
+
export async function deleteDevice(owner, device, rounds = 3, pause = 10) {
|
|
255
|
+
expect(owner).toBeDefined();
|
|
256
|
+
expect(device).toBeDefined();
|
|
257
|
+
expect(owner.lifecycle.isReady).toBeTruthy();
|
|
258
|
+
expect(owner.construction.status).toBe(Lifecycle.Status.Active);
|
|
259
|
+
expect(owner.lifecycle.isPartsReady).toBeTruthy();
|
|
260
|
+
const rootServerNode = getRootServerNode(owner);
|
|
261
|
+
await flushAllEndpointNumberPersistence(rootServerNode, rounds, pause);
|
|
262
|
+
try {
|
|
263
|
+
await device.delete();
|
|
264
|
+
}
|
|
265
|
+
catch (error) {
|
|
266
|
+
const errorMessage = error instanceof Error ? error.message : error;
|
|
267
|
+
const errorInspect = inspect(error, { depth: 10 });
|
|
268
|
+
process.stderr.write(`${er}Error deleting device ${device.maybeId}.${device.maybeNumber}: ${errorMessage}${rs}\nStack: ${errorInspect}\n`);
|
|
269
|
+
return false;
|
|
270
|
+
}
|
|
271
|
+
expect(owner.parts.has(device)).toBeFalsy();
|
|
272
|
+
expect(owner.lifecycle.isPartsReady).toBeTruthy();
|
|
273
|
+
expect(device.lifecycle.isReady).toBeFalsy();
|
|
274
|
+
expect(device.lifecycle.isInstalled).toBeFalsy();
|
|
275
|
+
expect(device.lifecycle.hasId).toBeTruthy();
|
|
276
|
+
expect(device.lifecycle.hasNumber).toBeTruthy();
|
|
277
|
+
expect(device.construction.status).toBe(Lifecycle.Status.Destroyed);
|
|
278
|
+
await flushAllEndpointNumberPersistence(rootServerNode, rounds, pause);
|
|
279
|
+
return true;
|
|
280
|
+
}
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { rmSync } from 'node:fs';
|
|
1
|
+
import { mkdirSync, rmSync } from 'node:fs';
|
|
2
2
|
import path from 'node:path';
|
|
3
3
|
import { AnsiLogger } from 'node-ansi-logger';
|
|
4
4
|
export const originalProcessArgv = Object.freeze([...process.argv]);
|
|
@@ -27,6 +27,7 @@ export async function setupTest(name, debug = false) {
|
|
|
27
27
|
process.argv = ['vitest', name];
|
|
28
28
|
log = new AnsiLogger({ logName: 'Vitest', logTimestampFormat: 4, logLevel: "info" });
|
|
29
29
|
rmSync(HOMEDIR, { recursive: true, force: true });
|
|
30
|
+
mkdirSync(HOMEDIR, { recursive: true });
|
|
30
31
|
const { vi } = await import('vitest');
|
|
31
32
|
loggerDebugSpy = vi.spyOn(AnsiLogger.prototype, 'debug');
|
|
32
33
|
loggerInfoSpy = vi.spyOn(AnsiLogger.prototype, 'info');
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@matterbridge/vitest-utils",
|
|
3
|
-
"version": "3.8.0-dev-
|
|
3
|
+
"version": "3.8.0-dev-20260527-b4148f4",
|
|
4
4
|
"description": "Matterbridge vitest utility library",
|
|
5
5
|
"author": "https://github.com/Luligu",
|
|
6
6
|
"homepage": "https://matterbridge.io/",
|
|
@@ -61,6 +61,7 @@
|
|
|
61
61
|
"CHANGELOG.md"
|
|
62
62
|
],
|
|
63
63
|
"dependencies": {
|
|
64
|
+
"@matterbridge/types": "3.8.0-dev-20260527-b4148f4",
|
|
64
65
|
"node-ansi-logger": "3.3.0-dev-20260524-cac9dd5"
|
|
65
66
|
}
|
|
66
67
|
}
|
|
File without changes
|