Skip to content

Commit c6476ce

Browse files
authored
Release 3.0.6
* Update dependencies * Add createDirectory and Jest test * Update Jest test coverage on addBridgedEndpoint and removeBridgedEndpoint * Fix jsdoc on Evse * Update CHANGELOG for Jest test coverage and jsdoc fixes * Add spawnCommand and Jest test * Jest test on verifyShellyUpdate * Update base.test.ts * Add Jest test on default export missed in plugins * Update copyDirectory * Bump version to 1.0.1 in copyDirectory.ts * Bump version to 1.0.1 in wait.ts and optimize interval check with async * Update Matterbridge to version 1.6.0, add online/offline events, improve backup error handling, and refactor advertising timeout logic * Jest tests * Jest tests * Update Evse * Bump version to 1.0.2 and update default supply state to ChargingEnabled in Evse class * Jest tests * Fix wrong names DeviceEnergyManagement and DeviceEnergyManagementMode * Bump WaterHeater to 1.1.0 * Bump RoboticVacuumCleaner to 1.1.0 * Bump Evse to 1.1.0 * Bump LaundryWasher to 1.1.0 * Bump Evse to 1.1.0 * Bump MatterbridgeEndpoint to 2.1.0 * Bump MatterbridgeEndpoint to 2.1.0 * Bump Matterbridge Behaviors to 1.1.0 * Bump Matterbridge Behaviors to 1.3.0 * Bump Matterbridge Behaviors to 1.3.0 * Bump Matterbridge Behaviors to 1.3.0 * Add invokeSubscribeHandler to run Jest tests * Add logic in MatterbridgeValveConfigurationAndControlServer * Add cluster property to commandHandler data * Update README.md (#326) * Update fan cluster helpers * Update CHANGELOG.md with recent additions and changes * Bump version of MatterbridgeEndpoint to 2.1.1 and update MatterbridgeEndpoint with serverNode and bridgeMode documentation * Add globalMatterbridge module with instance management functions and tests * Add error handling tests for Matterbridge CLI * Release 3.0.6 * Fix typo in cluster helper description in CHANGELOG.md * Add documentation for mb-service integration by Michael Ahern * Update mb-service link in CHANGELOG.md to include service functionality details
1 parent a5046db commit c6476ce

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

48 files changed

+2141
-887
lines changed

.vscode/tasks.json

Lines changed: 11 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -49,7 +49,17 @@
4949
"label": "Test: Matterbridge",
5050
"type": "shell",
5151
"command": "node",
52-
"args": ["--no-warnings", "--experimental-vm-modules", "node_modules/jest/bin/jest.js", "--coverage", "--maxWorkers=100%", "matterbridge.test.ts", "matterbridge.bridge.test.ts", "matterbridge.childbridge.test.ts"],
52+
"args": [
53+
"--no-warnings",
54+
"--experimental-vm-modules",
55+
"node_modules/jest/bin/jest.js",
56+
"--coverage",
57+
"--maxWorkers=100%",
58+
"matterbridge.test.ts",
59+
"matterbridge.matterjs.test.ts",
60+
"matterbridge.bridge.test.ts",
61+
"matterbridge.childbridge.test.ts"
62+
],
5363
"group": {
5464
"kind": "test",
5565
"isDefault": false

CHANGELOG.md

Lines changed: 29 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,35 @@ If you like this project and find it useful, please consider giving it a star on
88
<img src="bmc-button.svg" alt="Buy me a coffee" width="120">
99
</a>
1010

11+
## [3.0.6] - 2025-06-13
12+
13+
### Added
14+
15+
- [tests] Update Jest test coverage on addBridgedEndpoint and removeBridgedEndpoint.
16+
- [fan]: Added createMultiSpeedFanControlClusterServer cluster helper with MultiSpeed feature.
17+
- [fan]: Added all parameters to the fan cluster helpers.
18+
- [valve]: Added logic in MatterbridgeValveConfigurationAndControlServer.
19+
- [command]: Added cluster property to commandHandler data object.
20+
- [mb-service]: Added a link to [mb-service](https://github.com/michaelahern/mb-service) package by [Michael Ahern](https://github.com/michaelahern). It runs matterbridge as a service in macOS.
21+
22+
### Changed
23+
24+
- [package]: Updated dependencies.
25+
- [fan]: The default fan has no more the MultiSpeed feature.
26+
- [behaviors]: Bump Matterbridge Behaviors to 1.3.0
27+
- [evse]: Updated class and behavior to 1.1.0.
28+
- [waterHeater]: Updated class and behavior to 1.1.0.
29+
- [rvc]: Updated class and behavior to 1.1.0.
30+
- [laundryWasher]: Updated class and behavior to 1.1.0.
31+
32+
### Fixed
33+
34+
- [evse]: Fixed jsdoc on Evse.
35+
36+
<a href="https://www.buymeacoffee.com/luligugithub">
37+
<img src="bmc-button.svg" alt="Buy me a coffee" width="80">
38+
</a>
39+
1140
## [3.0.5] - 2025-06-07
1241

1342
### Added

README.md

Lines changed: 7 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -5,7 +5,7 @@
55
[![Docker Version](https://img.shields.io/docker/v/luligu/matterbridge?label=docker%20version&sort=semver)](https://hub.docker.com/r/luligu/matterbridge)
66
[![Docker Pulls](https://img.shields.io/docker/pulls/luligu/matterbridge.svg)](https://hub.docker.com/r/luligu/matterbridge)
77
![Node.js CI](https://github.com/Luligu/matterbridge/actions/workflows/build.yml/badge.svg)
8-
![Coverage](https://img.shields.io/badge/Jest%20coverage-86%25-brightgreen)
8+
![Coverage](https://img.shields.io/badge/Jest%20coverage-88%25-brightgreen)
99

1010
[![power by](https://img.shields.io/badge/powered%20by-matter--history-blue)](https://www.npmjs.com/package/matter-history)
1111
[![power by](https://img.shields.io/badge/powered%20by-node--ansi--logger-blue)](https://www.npmjs.com/package/node-ansi-logger)
@@ -172,6 +172,10 @@ Config editor:
172172

173173
[Podman configurations](README-PODMAN.md)
174174

175+
### Run matterbridge as a service on macOS with mb-service (by [Michael Ahern](https://github.com/michaelahern))
176+
177+
[Matterbridge Service Command for macOS](https://github.com/michaelahern/mb-service)
178+
175179
### Run matterbridge with nginx
176180

177181
[Nginx configurations](README-NGINX.md)
@@ -324,6 +328,8 @@ It exposes 38 devices:
324328
- a microwave Oven device (supported by SmartThings, Alexa and Home Assistant)
325329
- an extractor Hood device (supported by SmartThings, Alexa and Home Assistant)
326330
- a cooktop device (supported by SmartThings, Alexa and Home Assistant)
331+
- a water heater device (supported by SmartThings and Home Assistant)
332+
- a car charger device (supported by Home Assistant)
327333

328334
All these virtual devices continuously change state and position. The plugin also shows how to use all the command handlers (you can control all the devices).
329335

jest.config.js

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -28,6 +28,6 @@ export default {
2828
],
2929
},
3030
transformIgnorePatterns: ['/node_modules/'],
31-
testPathIgnorePatterns: ['/node_modules/', '/dist/', '/frontend/'],
31+
testPathIgnorePatterns: ['/node_modules/', '/dist/', '/frontend/', '/src/crypto/'],
3232
coveragePathIgnorePatterns: ['/node_modules/', '/dist/', '/frontend/', '/src/mock/'],
3333
};

package-lock.json

Lines changed: 18 additions & 18 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

package.json

Lines changed: 5 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
{
22
"name": "matterbridge",
3-
"version": "3.0.5",
3+
"version": "3.0.6",
44
"description": "Matterbridge plugin manager for Matter",
55
"author": "https://github.com/Luligu",
66
"license": "Apache-2.0",
@@ -153,13 +153,13 @@
153153
"devDependencies": {
154154
"@eslint/js": "9.28.0",
155155
"@types/archiver": "6.0.3",
156-
"@types/express": "5.0.2",
156+
"@types/express": "5.0.3",
157157
"@types/jest": "29.5.14",
158-
"@types/multer": "1.4.12",
159-
"@types/node": "22.15.29",
158+
"@types/multer": "1.4.13",
159+
"@types/node": "22.15.30",
160160
"@types/ws": "8.18.1",
161161
"eslint-config-prettier": "10.1.5",
162-
"eslint-plugin-jest": "28.12.0",
162+
"eslint-plugin-jest": "28.13.0",
163163
"eslint-plugin-n": "17.19.0",
164164
"eslint-plugin-prettier": "5.4.1",
165165
"eslint-plugin-react": "7.37.5",

src/base.test.ts

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -84,11 +84,11 @@ describe('Matterbridge ' + NAME, () => {
8484

8585
beforeAll(async () => {
8686
// Cleanup the matter environment
87-
rmSync(path.join('jest', NAME), { recursive: true, force: true });
87+
rmSync(path.join('test', NAME), { recursive: true, force: true });
8888
// Setup the matter environment
8989
environment.vars.set('log.level', MatterLogLevel.DEBUG);
9090
environment.vars.set('log.format', MatterLogFormat.ANSI);
91-
environment.vars.set('path.root', path.join('jest', NAME));
91+
environment.vars.set('path.root', path.join('test', NAME));
9292
environment.vars.set('runtime.signals', false);
9393
environment.vars.set('runtime.exitcode', false);
9494
}, 30000);

src/cli.error.test.ts

Lines changed: 68 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,68 @@
1+
// src\cli.error.test.ts
2+
3+
/* eslint-disable @typescript-eslint/no-empty-function */
4+
/* eslint-disable no-console */
5+
/* eslint-disable @typescript-eslint/no-explicit-any */
6+
/* eslint-disable @typescript-eslint/no-unused-vars */
7+
process.argv = ['node', './cli.js', '-memorycheck', '-frontend', '0', '-profile', 'JestCli', '-debug', '-logger', 'debug', '-matterlogger', 'debug'];
8+
9+
import { jest } from '@jest/globals';
10+
import { AnsiLogger, LogLevel } from 'node-ansi-logger';
11+
12+
import { Matterbridge } from './matterbridge.js';
13+
14+
let loggerLogSpy: jest.SpiedFunction<typeof AnsiLogger.prototype.log>;
15+
let consoleLogSpy: jest.SpiedFunction<typeof console.log>;
16+
let consoleDebugSpy: jest.SpiedFunction<typeof console.log>;
17+
let consoleInfoSpy: jest.SpiedFunction<typeof console.log>;
18+
let consoleWarnSpy: jest.SpiedFunction<typeof console.log>;
19+
let consoleErrorSpy: jest.SpiedFunction<typeof console.log>;
20+
const debug = false; // Set to true to enable debug logging
21+
22+
if (!debug) {
23+
loggerLogSpy = jest.spyOn(AnsiLogger.prototype, 'log').mockImplementation((level: string, message: string, ...parameters: any[]) => {});
24+
consoleLogSpy = jest.spyOn(console, 'log').mockImplementation((...args: any[]) => {});
25+
consoleDebugSpy = jest.spyOn(console, 'debug').mockImplementation((...args: any[]) => {});
26+
consoleInfoSpy = jest.spyOn(console, 'info').mockImplementation((...args: any[]) => {});
27+
consoleWarnSpy = jest.spyOn(console, 'warn').mockImplementation((...args: any[]) => {});
28+
consoleErrorSpy = jest.spyOn(console, 'error').mockImplementation((...args: any[]) => {});
29+
} else {
30+
loggerLogSpy = jest.spyOn(AnsiLogger.prototype, 'log');
31+
consoleLogSpy = jest.spyOn(console, 'log');
32+
consoleDebugSpy = jest.spyOn(console, 'debug');
33+
consoleInfoSpy = jest.spyOn(console, 'info');
34+
consoleWarnSpy = jest.spyOn(console, 'warn');
35+
consoleErrorSpy = jest.spyOn(console, 'error');
36+
}
37+
38+
const loadInstance = jest.spyOn(Matterbridge, 'loadInstance').mockImplementation(async (_initialize?: boolean) => {
39+
console.log('mockImplementation of Matterbridge.loadInstance() called');
40+
throw new Error('Mock implementation of loadInstance called.'); // Simulate an error by throwing an exception
41+
});
42+
43+
const exit = jest.spyOn(process, 'exit').mockImplementation((code?: string | number | null | undefined) => {
44+
console.log('mockImplementation of process.exit() called');
45+
return undefined as never; // Prevent actual exit during tests
46+
});
47+
48+
describe('Matterbridge', () => {
49+
beforeEach(async () => {
50+
// Clear all mocks before each test
51+
jest.clearAllMocks();
52+
});
53+
54+
afterAll(async () => {
55+
// Restore all mocks
56+
jest.restoreAllMocks();
57+
});
58+
59+
it('should start matterbridge and fail', async () => {
60+
// Dynamically import the cli module
61+
const cli = await import('./cli.js');
62+
await new Promise((resolve) => setTimeout(resolve, 100));
63+
expect(cli.instance).toBeUndefined();
64+
expect(loadInstance).toHaveBeenCalledTimes(1);
65+
expect(exit).toHaveBeenCalledTimes(0);
66+
expect(loggerLogSpy).toHaveBeenCalledWith(LogLevel.ERROR, expect.stringContaining(`Matterbridge.loadInstance() failed with error:`));
67+
});
68+
});

src/cli.error2.test.ts

Lines changed: 68 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,68 @@
1+
// src\cli.error2.test.ts
2+
3+
/* eslint-disable @typescript-eslint/no-empty-function */
4+
/* eslint-disable no-console */
5+
/* eslint-disable @typescript-eslint/no-explicit-any */
6+
/* eslint-disable @typescript-eslint/no-unused-vars */
7+
process.argv = ['node', './cli.js', '-memorycheck', '-frontend', '0', '-profile', 'JestCli', '-debug', '-logger', 'debug', '-matterlogger', 'debug'];
8+
9+
import { jest } from '@jest/globals';
10+
import { AnsiLogger, LogLevel } from 'node-ansi-logger';
11+
12+
import { Matterbridge } from './matterbridge.js';
13+
14+
let loggerLogSpy: jest.SpiedFunction<typeof AnsiLogger.prototype.log>;
15+
let consoleLogSpy: jest.SpiedFunction<typeof console.log>;
16+
let consoleDebugSpy: jest.SpiedFunction<typeof console.log>;
17+
let consoleInfoSpy: jest.SpiedFunction<typeof console.log>;
18+
let consoleWarnSpy: jest.SpiedFunction<typeof console.log>;
19+
let consoleErrorSpy: jest.SpiedFunction<typeof console.log>;
20+
const debug = false; // Set to true to enable debug logging
21+
22+
if (!debug) {
23+
loggerLogSpy = jest.spyOn(AnsiLogger.prototype, 'log').mockImplementation((level: string, message: string, ...parameters: any[]) => {});
24+
consoleLogSpy = jest.spyOn(console, 'log').mockImplementation((...args: any[]) => {});
25+
consoleDebugSpy = jest.spyOn(console, 'debug').mockImplementation((...args: any[]) => {});
26+
consoleInfoSpy = jest.spyOn(console, 'info').mockImplementation((...args: any[]) => {});
27+
consoleWarnSpy = jest.spyOn(console, 'warn').mockImplementation((...args: any[]) => {});
28+
consoleErrorSpy = jest.spyOn(console, 'error').mockImplementation((...args: any[]) => {});
29+
} else {
30+
loggerLogSpy = jest.spyOn(AnsiLogger.prototype, 'log');
31+
consoleLogSpy = jest.spyOn(console, 'log');
32+
consoleDebugSpy = jest.spyOn(console, 'debug');
33+
consoleInfoSpy = jest.spyOn(console, 'info');
34+
consoleWarnSpy = jest.spyOn(console, 'warn');
35+
consoleErrorSpy = jest.spyOn(console, 'error');
36+
}
37+
38+
const loadInstance = jest.spyOn(Matterbridge, 'loadInstance').mockImplementation(async (_initialize?: boolean) => {
39+
console.log('mockImplementation of Matterbridge.loadInstance() called');
40+
return undefined as never; // Simulate an error by returning undefined
41+
});
42+
43+
const exit = jest.spyOn(process, 'exit').mockImplementation((code?: string | number | null | undefined) => {
44+
console.log('mockImplementation of process.exit() called');
45+
return undefined as never; // Prevent actual exit during tests
46+
});
47+
48+
describe('Matterbridge', () => {
49+
beforeEach(async () => {
50+
// Clear all mocks before each test
51+
jest.clearAllMocks();
52+
});
53+
54+
afterAll(async () => {
55+
// Restore all mocks
56+
jest.restoreAllMocks();
57+
});
58+
59+
it('should start matterbridge and return undefined', async () => {
60+
// Dynamically import the cli module
61+
const cli = await import('./cli.js');
62+
await new Promise((resolve) => setTimeout(resolve, 100));
63+
expect(cli.instance).toBeUndefined();
64+
expect(loadInstance).toHaveBeenCalledTimes(1);
65+
expect(exit).toHaveBeenCalledTimes(1);
66+
expect(loggerLogSpy).toHaveBeenCalledWith(LogLevel.DEBUG, expect.stringContaining('Received shutdown event, exiting...'));
67+
});
68+
});

0 commit comments

Comments
 (0)