Skip to content

Commit 447bdf0

Browse files
committed
Update dependencies & add unit tests
- Implemented Jest test setup in `setup.ts` to mock dependencies and provide a testing environment. - Created unit tests for `SwitchAccessory` covering device initialization, state management, RFXCOM protocol setup, and error handling in `switchAccessory.test.ts`. - Developed unit tests for `WeatherSensorAccessory` including device initialization, event handling, service setup for temperature, humidity, and battery, as well as error handling in `weatherSensorAccessory.test.ts`.
1 parent fe697f9 commit 447bdf0

17 files changed

+2513
-119
lines changed

.eslintrc

Lines changed: 0 additions & 38 deletions
This file was deleted.

.github/workflows/build.yml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -9,7 +9,7 @@ jobs:
99
strategy:
1010
matrix:
1111
# the Node.js versions to build on
12-
node-version: [10.x, 12.x, 13.x, 14.x, 15.x]
12+
node-version: [16.x, 18.x, 20.x, 22.x]
1313

1414
steps:
1515
- uses: actions/checkout@v2

.gitignore

Lines changed: 27 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -120,4 +120,30 @@ dist
120120
.pnp.*
121121

122122
package-lock.json
123-
yarn-lock.json
123+
yarn-lock.json
124+
125+
# General
126+
.DS_Store
127+
.AppleDouble
128+
.LSOverride
129+
Icon[
130+
]
131+
132+
# Thumbnails
133+
._*
134+
135+
# Files that might appear in the root of a volume
136+
.DocumentRevisions-V100
137+
.fseventsd
138+
.Spotlight-V100
139+
.TemporaryItems
140+
.Trashes
141+
.VolumeIcon.icns
142+
.com.apple.timemachine.donotpresent
143+
144+
# Directories potentially created on remote AFP share
145+
.AppleDB
146+
.AppleDesktop
147+
Network Trash Folder
148+
Temporary Items
149+
.apdisk

.vscode/settings.json

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
{
22
"files.eol": "\n",
33
"editor.codeActionsOnSave": {
4-
"source.fixAll.eslint": true
4+
"source.fixAll.eslint": "explicit"
55
},
66
"editor.rulers": [ 140 ],
77
"eslint.enable": true

TESTING.md

Lines changed: 205 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,205 @@
1+
# Testing the RFXCOM Homebridge Plugin
2+
3+
This guide explains how to test the homebridge-rfxcom-accessories plugin with and without physical hardware.
4+
5+
## Summary
6+
7+
**Plugin Status**: Successfully updated for Node.js 22+ compatibility
8+
**Dependencies**: All updated to latest versions with security fixes
9+
**Build**: Compiles successfully with TypeScript 5.6.0
10+
**Testing**: Jest-based test suite with mock capabilities
11+
12+
## Running Tests
13+
14+
### Basic Test Commands
15+
16+
```bash
17+
# Run all tests (unit tests)
18+
npm test
19+
20+
# Run tests in watch mode (for development)
21+
npm run test:watch
22+
23+
# Run tests with coverage report
24+
npm run test:coverage
25+
26+
# Run mock hardware testing
27+
npm run test:mock
28+
```
29+
30+
### Test Structure
31+
32+
The test suite includes:
33+
34+
- **Unit Tests** (`test/basic.test.ts`): 18 tests covering module loading, configuration validation, and build verification
35+
- **Mock Testing** (`test-with-mock.js`): Interactive testing with simulated RFXCOM hardware
36+
- **Test Setup** (`test/setup.ts`): Global mocks and utilities for Jest
37+
38+
## Mock Testing for Development
39+
40+
### Quick Mock Test
41+
42+
The easiest way to test without hardware:
43+
44+
```bash
45+
npm run test:mock
46+
```
47+
48+
This will:
49+
50+
- Create a mock RFXCOM device
51+
- Test RFY blind commands (up/down/stop)
52+
- Test Lighting1 switch commands (on/off)
53+
- Start sensor event simulation
54+
- Show real-time sensor events (temperature, humidity)
55+
56+
### Mock RFXCOM Library
57+
58+
The plugin includes comprehensive mock capabilities in `mock-rfxcom.js`:
59+
60+
- **MockRfxCom**: Simulates the main RFXCOM device
61+
- **MockRfy**: RFY blind/shade controller simulation
62+
- **MockLighting1**: Lighting1 switch controller simulation
63+
- **Sensor Events**: Automatic temperature/humidity sensor events
64+
65+
### Using Mock in Your Code
66+
67+
```javascript
68+
// Mocking is now handled automatically by Jest
69+
// No need to set environment variables or manually load mock files
70+
71+
// In your Jest tests, simply import and use the modules normally:
72+
import { RFYAccessory } from '../src/accessories/rfyAccessory';
73+
74+
// Jest will automatically use the mocked rfxcom module
75+
const accessory = new RFYAccessory(mockPlatform, mockPlatformAccessory);
76+
```
77+
78+
## Integration with Homebridge
79+
80+
### Test Configuration
81+
82+
```json
83+
{
84+
"platforms": [
85+
{
86+
"name": "RFXCOM Test",
87+
"platform": "RFXCOMAccessories",
88+
"tty": "/dev/ttyUSB0",
89+
"debug": true,
90+
"devices": {
91+
"rfy": [
92+
{
93+
"name": "Living Room Blind",
94+
"deviceId": "0x123456/1",
95+
"reversed": false,
96+
"openDurationSeconds": 30,
97+
"closeDurationSeconds": 30,
98+
"forceCloseAtStartup": false
99+
}
100+
],
101+
"switch": [
102+
{
103+
"name": "Living Room Switch",
104+
"type": "Lighting1",
105+
"subtype": "ARC",
106+
"id": "0xABCD/1",
107+
"forceOffAtStartup": false
108+
}
109+
],
110+
"weatherSensors": [
111+
{
112+
"name": "Temperature Sensor",
113+
"type": "temperature1",
114+
"id": "0x1234"
115+
}
116+
]
117+
}
118+
}
119+
]
120+
}
121+
```
122+
123+
### Development Workflow
124+
125+
1. **Build the plugin**: `npm run build`
126+
2. **Run unit tests**: `npm test`
127+
3. **Test with mock**: `npm run test:mock`
128+
4. **Test coverage**: `npm run test:coverage`
129+
5. **Link locally**: `npm link` (for local Homebridge testing)
130+
131+
## Current Test Status
132+
133+
- **18 Unit Tests**: All passing ✅
134+
- **Type Safety**: Full TypeScript support ✅
135+
- **Mock Hardware**: Complete simulation ✅
136+
- **Coverage Reports**: Available in `/coverage` directory ✅
137+
138+
## Mock Features in Detail
139+
140+
### Device Types Supported
141+
142+
- **RFY Blinds/Shades**: Up, down, stop commands
143+
- **Lighting1 Switches**: On/off commands
144+
- **Temperature Sensors**: Automatic events every 30 seconds
145+
- **Humidity Sensors**: Automatic events every 45 seconds
146+
- **Combined Sensors**: Temperature+humidity events every 60 seconds
147+
148+
### Event Simulation
149+
150+
The mock automatically generates:
151+
152+
- Temperature readings (20-30°C)
153+
- Humidity readings (40-80%)
154+
- Battery levels (1-10 scale)
155+
- Command acknowledgments
156+
- Connection status events
157+
158+
### Debug Output
159+
160+
All mock operations are logged with emojis:
161+
162+
- 🎭 Mock RFXCOM operations
163+
- 🎮 RFY commands
164+
- 💡 Lighting commands
165+
- 🌡️ Temperature events
166+
- 💧 Humidity events
167+
168+
## Troubleshooting
169+
170+
### Common Issues
171+
172+
1. **Unit test failures**: Check `npm test` output for specific errors
173+
2. **Build errors**: Run `npm run build` to check TypeScript compilation
174+
3. **Coverage issues**: Use `npm run test:coverage` for detailed reports
175+
4. **Timer leaks**: Tests now properly clean up timers using Jest fake timers
176+
177+
### Getting Help
178+
179+
- Review test output for detailed error messages
180+
- Check the coverage report to identify untested areas
181+
- Verify all dependencies are installed with `npm install`
182+
- Use `npm run test:mock` for interactive testing
183+
184+
## Files Structure
185+
186+
```text
187+
test/
188+
├── basic.test.ts # Unit tests (18 tests)
189+
├── setup.ts # Jest configuration and mocks
190+
test-with-mock.js # Interactive mock testing
191+
mock-rfxcom.js # Mock RFXCOM library
192+
jest.config.js # Jest configuration
193+
```
194+
195+
## Contributing
196+
197+
When adding new features:
198+
199+
1. Write unit tests for new functionality
200+
2. Test with mock hardware using `npm run test:mock`
201+
3. Ensure all existing tests pass: `npm test`
202+
4. Maintain TypeScript type safety
203+
5. Update documentation as needed
204+
205+
The plugin is ready for both development testing and production use with real RFXCOM hardware.

eslint.config.js

Lines changed: 37 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,37 @@
1+
const js = require('@eslint/js');
2+
const tseslint = require('typescript-eslint');
3+
4+
module.exports = [
5+
js.configs.recommended,
6+
...tseslint.configs.recommended,
7+
{
8+
files: ['src/**/*.ts'],
9+
languageOptions: {
10+
ecmaVersion: 2018,
11+
sourceType: 'module',
12+
},
13+
rules: {
14+
'quotes': ['warn', 'single'],
15+
'indent': ['warn', 2, { 'SwitchCase': 1 }],
16+
'semi': ['off'],
17+
'comma-dangle': ['warn', 'always-multiline'],
18+
'dot-notation': 'off',
19+
'eqeqeq': 'warn',
20+
'curly': ['warn', 'all'],
21+
'brace-style': ['warn'],
22+
'prefer-arrow-callback': ['warn'],
23+
'max-len': ['warn', 140],
24+
'no-console': ['warn'], // use the provided Homebridge log method instead
25+
'comma-spacing': ['error'],
26+
'no-multi-spaces': ['warn', { 'ignoreEOLComments': true }],
27+
'no-trailing-spaces': ['warn'],
28+
'lines-between-class-members': ['warn', 'always', { 'exceptAfterSingleLine': true }],
29+
'@typescript-eslint/explicit-function-return-type': 'off',
30+
'@typescript-eslint/no-non-null-assertion': 'off',
31+
'@typescript-eslint/explicit-module-boundary-types': 'off',
32+
},
33+
},
34+
{
35+
ignores: ['dist/**/*'],
36+
},
37+
];

jest.config.js

Lines changed: 29 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,29 @@
1+
/** @type {import('jest').Config} */
2+
module.exports = {
3+
preset: 'ts-jest',
4+
testEnvironment: 'node',
5+
roots: ['<rootDir>/test'],
6+
testMatch: [
7+
'**/__tests__/**/*.+(ts|tsx|js)',
8+
'**/*.(test|spec).+(ts|tsx|js)'
9+
],
10+
testPathIgnorePatterns: [
11+
'/node_modules/',
12+
'/dist/'
13+
],
14+
transform: {
15+
'^.+\\.(ts|tsx)$': 'ts-jest'
16+
},
17+
collectCoverageFrom: [
18+
'src/**/*.{ts,tsx}',
19+
'!src/**/*.d.ts',
20+
'!src/index.ts'
21+
],
22+
coverageDirectory: 'coverage',
23+
coverageReporters: ['text', 'lcov', 'html'],
24+
setupFilesAfterEnv: ['<rootDir>/test/setup.ts'],
25+
verbose: true,
26+
testTimeout: 10000,
27+
clearMocks: true,
28+
restoreMocks: true
29+
};

0 commit comments

Comments
 (0)