@iobroker/testing 4.1.3 → 5.0.2
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/LICENSE +1 -1
- package/README.md +2 -2
- package/build/index.d.ts +1 -1
- package/build/lib/adapterTools.d.ts +7 -2
- package/build/lib/adapterTools.js +47 -31
- package/build/lib/executeCommand.d.ts +3 -3
- package/build/lib/executeCommand.js +32 -32
- package/build/lib/str2regex.js +5 -6
- package/build/lib/testAdapter.d.ts +1 -0
- package/build/lib/testAdapter.js +1 -0
- package/build/tests/index.d.ts +9 -9
- package/build/tests/index.js +0 -1
- package/build/tests/integration/index.d.ts +1 -3
- package/build/tests/integration/index.js +46 -41
- package/build/tests/integration/lib/adapterSetup.d.ts +1 -1
- package/build/tests/integration/lib/adapterSetup.js +55 -42
- package/build/tests/integration/lib/controllerSetup.d.ts +1 -10
- package/build/tests/integration/lib/controllerSetup.js +59 -56
- package/build/tests/integration/lib/dbConnection.d.ts +12 -16
- package/build/tests/integration/lib/dbConnection.js +71 -69
- package/build/tests/integration/lib/harness.d.ts +9 -12
- package/build/tests/integration/lib/harness.js +70 -50
- package/build/tests/integration/lib/logger.d.ts +0 -1
- package/build/tests/integration/lib/logger.js +2 -4
- package/build/tests/integration/lib/tools.d.ts +6 -1
- package/build/tests/integration/lib/tools.js +32 -18
- package/build/tests/packageFiles/index.js +93 -77
- package/build/tests/unit/harness/createMocks.d.ts +3 -3
- package/build/tests/unit/harness/createMocks.js +1 -3
- package/build/tests/unit/index.js +6 -6
- package/build/tests/unit/mocks/mockAdapter.d.ts +3 -4
- package/build/tests/unit/mocks/mockAdapter.js +198 -164
- package/build/tests/unit/mocks/mockAdapterCore.d.ts +4 -10
- package/build/tests/unit/mocks/mockAdapterCore.js +24 -16
- package/build/tests/unit/mocks/mockDatabase.d.ts +13 -14
- package/build/tests/unit/mocks/mockDatabase.js +41 -45
- package/build/tests/unit/mocks/mockLogger.d.ts +1 -2
- package/build/tests/unit/mocks/mockLogger.js +2 -3
- package/build/tests/unit/mocks/tools.d.ts +2 -3
- package/build/tests/unit/mocks/tools.js +17 -15
- package/package.json +28 -32
package/LICENSE
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
MIT License
|
|
2
2
|
|
|
3
|
-
Copyright (c) 2024 AlCalzone <d.griesel@gmx.net>
|
|
3
|
+
Copyright (c) 2024-2025 AlCalzone <d.griesel@gmx.net>
|
|
4
4
|
|
|
5
5
|
Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
6
6
|
of this software and associated documentation files (the "Software"), to deal
|
package/README.md
CHANGED
|
@@ -2,7 +2,7 @@
|
|
|
2
2
|
|
|
3
3
|
This repo provides utilities for testing of ioBroker adapters and other ioBroker-related modules. It supports:
|
|
4
4
|
|
|
5
|
-
- **Unit tests** using mocks (without a running JS-Controller)
|
|
5
|
+
- **Unit tests** using mocks (without a running JS-Controller) **deprecated** and no longer used
|
|
6
6
|
- **Integration tests** that test against a running JS-Controller instance.
|
|
7
7
|
|
|
8
8
|
The unit tests are realized using the following tools that are provided by this module:
|
|
@@ -136,7 +136,7 @@ This method creates a mock database and a mock adapter. See below for a more det
|
|
|
136
136
|
const asserts = utils.unit.createAsserts(database, adapter);
|
|
137
137
|
```
|
|
138
138
|
|
|
139
|
-
|
|
139
|
+
These methods take a mock database and adapter and create a set of asserts for your tests. All IDs may either be a string, which is taken literally, or an array of strings which are concatenated with `"."`. If an ID is not fully qualified, the adapter namespace is prepended automatically.
|
|
140
140
|
|
|
141
141
|
- `assertObjectExists(id: string | string[])` asserts that an object with the given ID exists in the database.
|
|
142
142
|
- `assertStateExists(id: string | string[])` asserts that a state with the given ID exists in the database.
|
package/build/index.d.ts
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
export * from
|
|
1
|
+
export * from './tests';
|
|
@@ -1,32 +1,37 @@
|
|
|
1
|
-
/// <reference types="iobroker" />
|
|
2
1
|
/**
|
|
3
2
|
* Loads an adapter's package.json
|
|
3
|
+
*
|
|
4
4
|
* @param adapterDir The directory the adapter resides in
|
|
5
5
|
*/
|
|
6
6
|
export declare function loadNpmPackage(adapterDir: string): Record<string, any>;
|
|
7
7
|
/**
|
|
8
8
|
* Loads an adapter's io-package.json
|
|
9
|
+
*
|
|
9
10
|
* @param adapterDir The directory the adapter resides in
|
|
10
11
|
*/
|
|
11
12
|
export declare function loadIoPackage(adapterDir: string): Record<string, any>;
|
|
12
|
-
export declare function getAdapterExecutionMode(adapterDir: string): ioBroker.AdapterCommon[
|
|
13
|
+
export declare function getAdapterExecutionMode(adapterDir: string): ioBroker.AdapterCommon['mode'];
|
|
13
14
|
/**
|
|
14
15
|
* Locates an adapter's main file
|
|
16
|
+
*
|
|
15
17
|
* @param adapterDir The directory the adapter resides in
|
|
16
18
|
*/
|
|
17
19
|
export declare function locateAdapterMainFile(adapterDir: string): Promise<string>;
|
|
18
20
|
/**
|
|
19
21
|
* Locates an adapter's config to populate the `adapter.config` object with
|
|
22
|
+
*
|
|
20
23
|
* @param adapterDir The directory the adapter resides in
|
|
21
24
|
*/
|
|
22
25
|
export declare function loadAdapterConfig(adapterDir: string): Record<string, any>;
|
|
23
26
|
/**
|
|
24
27
|
* Loads the adapter's common configuration from `io-package.json`
|
|
28
|
+
*
|
|
25
29
|
* @param adapterDir The directory the adapter resides in
|
|
26
30
|
*/
|
|
27
31
|
export declare function loadAdapterCommon(adapterDir: string): Record<string, any>;
|
|
28
32
|
/**
|
|
29
33
|
* Loads the instanceObjects for an adapter from its `io-package.json`
|
|
34
|
+
*
|
|
30
35
|
* @param adapterDir The directory the adapter resides in
|
|
31
36
|
*/
|
|
32
37
|
export declare function loadInstanceObjects(adapterDir: string): ioBroker.Object[];
|
|
@@ -15,47 +15,67 @@ var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (
|
|
|
15
15
|
}) : function(o, v) {
|
|
16
16
|
o["default"] = v;
|
|
17
17
|
});
|
|
18
|
-
var __importStar = (this && this.__importStar) || function (
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
};
|
|
18
|
+
var __importStar = (this && this.__importStar) || (function () {
|
|
19
|
+
var ownKeys = function(o) {
|
|
20
|
+
ownKeys = Object.getOwnPropertyNames || function (o) {
|
|
21
|
+
var ar = [];
|
|
22
|
+
for (var k in o) if (Object.prototype.hasOwnProperty.call(o, k)) ar[ar.length] = k;
|
|
23
|
+
return ar;
|
|
24
|
+
};
|
|
25
|
+
return ownKeys(o);
|
|
26
|
+
};
|
|
27
|
+
return function (mod) {
|
|
28
|
+
if (mod && mod.__esModule) return mod;
|
|
29
|
+
var result = {};
|
|
30
|
+
if (mod != null) for (var k = ownKeys(mod), i = 0; i < k.length; i++) if (k[i] !== "default") __createBinding(result, mod, k[i]);
|
|
31
|
+
__setModuleDefault(result, mod);
|
|
32
|
+
return result;
|
|
33
|
+
};
|
|
34
|
+
})();
|
|
25
35
|
var __importDefault = (this && this.__importDefault) || function (mod) {
|
|
26
36
|
return (mod && mod.__esModule) ? mod : { "default": mod };
|
|
27
37
|
};
|
|
28
38
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
29
|
-
exports.
|
|
39
|
+
exports.loadNpmPackage = loadNpmPackage;
|
|
40
|
+
exports.loadIoPackage = loadIoPackage;
|
|
41
|
+
exports.getAdapterExecutionMode = getAdapterExecutionMode;
|
|
42
|
+
exports.locateAdapterMainFile = locateAdapterMainFile;
|
|
43
|
+
exports.loadAdapterConfig = loadAdapterConfig;
|
|
44
|
+
exports.loadAdapterCommon = loadAdapterCommon;
|
|
45
|
+
exports.loadInstanceObjects = loadInstanceObjects;
|
|
46
|
+
exports.getAppName = getAppName;
|
|
47
|
+
exports.getAdapterName = getAdapterName;
|
|
48
|
+
exports.getAdapterFullName = getAdapterFullName;
|
|
49
|
+
exports.getAdapterDependencies = getAdapterDependencies;
|
|
30
50
|
// Add debug logging for tests
|
|
31
51
|
const typeguards_1 = require("alcalzone-shared/typeguards");
|
|
32
52
|
const debug_1 = __importDefault(require("debug"));
|
|
33
53
|
const fs_extra_1 = require("fs-extra");
|
|
34
54
|
const path = __importStar(require("path"));
|
|
35
|
-
const debug = (0, debug_1.default)(
|
|
55
|
+
const debug = (0, debug_1.default)('testing:unit:adapterTools');
|
|
36
56
|
/**
|
|
37
57
|
* Loads an adapter's package.json
|
|
58
|
+
*
|
|
38
59
|
* @param adapterDir The directory the adapter resides in
|
|
39
60
|
*/
|
|
40
61
|
function loadNpmPackage(adapterDir) {
|
|
41
|
-
return require(path.join(adapterDir,
|
|
62
|
+
return require(path.join(adapterDir, 'package.json'));
|
|
42
63
|
}
|
|
43
|
-
exports.loadNpmPackage = loadNpmPackage;
|
|
44
64
|
/**
|
|
45
65
|
* Loads an adapter's io-package.json
|
|
66
|
+
*
|
|
46
67
|
* @param adapterDir The directory the adapter resides in
|
|
47
68
|
*/
|
|
48
69
|
function loadIoPackage(adapterDir) {
|
|
49
|
-
return require(path.join(adapterDir,
|
|
70
|
+
return require(path.join(adapterDir, 'io-package.json'));
|
|
50
71
|
}
|
|
51
|
-
exports.loadIoPackage = loadIoPackage;
|
|
52
72
|
function getAdapterExecutionMode(adapterDir) {
|
|
53
73
|
const ioPackage = loadIoPackage(adapterDir);
|
|
54
74
|
return ioPackage.common.mode;
|
|
55
75
|
}
|
|
56
|
-
exports.getAdapterExecutionMode = getAdapterExecutionMode;
|
|
57
76
|
/**
|
|
58
77
|
* Locates an adapter's main file
|
|
78
|
+
*
|
|
59
79
|
* @param adapterDir The directory the adapter resides in
|
|
60
80
|
*/
|
|
61
81
|
async function locateAdapterMainFile(adapterDir) {
|
|
@@ -63,11 +83,11 @@ async function locateAdapterMainFile(adapterDir) {
|
|
|
63
83
|
const ioPackage = loadIoPackage(adapterDir);
|
|
64
84
|
const npmPackage = loadNpmPackage(adapterDir);
|
|
65
85
|
// First look for the file defined in io-package.json or package.json or use "main.js" as a fallback
|
|
66
|
-
const mainFile = typeof ioPackage.common.main ===
|
|
86
|
+
const mainFile = typeof ioPackage.common.main === 'string'
|
|
67
87
|
? ioPackage.common.main
|
|
68
|
-
: typeof npmPackage.main ===
|
|
88
|
+
: typeof npmPackage.main === 'string'
|
|
69
89
|
? npmPackage.main
|
|
70
|
-
:
|
|
90
|
+
: 'main.js';
|
|
71
91
|
let ret = path.join(adapterDir, mainFile);
|
|
72
92
|
debug(` => trying ${ret}`);
|
|
73
93
|
if (await (0, fs_extra_1.pathExists)(ret)) {
|
|
@@ -75,7 +95,7 @@ async function locateAdapterMainFile(adapterDir) {
|
|
|
75
95
|
return ret;
|
|
76
96
|
}
|
|
77
97
|
// If both don't exist, JS-Controller uses <adapter name>.js as another fallback
|
|
78
|
-
ret = path.join(adapterDir, ioPackage.common.name
|
|
98
|
+
ret = path.join(adapterDir, `${ioPackage.common.name}.js`);
|
|
79
99
|
debug(` => trying ${ret}`);
|
|
80
100
|
if (await (0, fs_extra_1.pathExists)(ret)) {
|
|
81
101
|
debug(` => found ${mainFile}`);
|
|
@@ -83,68 +103,64 @@ async function locateAdapterMainFile(adapterDir) {
|
|
|
83
103
|
}
|
|
84
104
|
throw new Error(`The adapter main file was not found in ${adapterDir}`);
|
|
85
105
|
}
|
|
86
|
-
exports.locateAdapterMainFile = locateAdapterMainFile;
|
|
87
106
|
/**
|
|
88
107
|
* Locates an adapter's config to populate the `adapter.config` object with
|
|
108
|
+
*
|
|
89
109
|
* @param adapterDir The directory the adapter resides in
|
|
90
110
|
*/
|
|
91
111
|
function loadAdapterConfig(adapterDir) {
|
|
92
112
|
const ioPackage = loadIoPackage(adapterDir);
|
|
93
113
|
return ioPackage.native || {};
|
|
94
114
|
}
|
|
95
|
-
exports.loadAdapterConfig = loadAdapterConfig;
|
|
96
115
|
/**
|
|
97
116
|
* Loads the adapter's common configuration from `io-package.json`
|
|
117
|
+
*
|
|
98
118
|
* @param adapterDir The directory the adapter resides in
|
|
99
119
|
*/
|
|
100
120
|
function loadAdapterCommon(adapterDir) {
|
|
101
121
|
const ioPackage = loadIoPackage(adapterDir);
|
|
102
122
|
return ioPackage.common || {};
|
|
103
123
|
}
|
|
104
|
-
exports.loadAdapterCommon = loadAdapterCommon;
|
|
105
124
|
/**
|
|
106
125
|
* Loads the instanceObjects for an adapter from its `io-package.json`
|
|
126
|
+
*
|
|
107
127
|
* @param adapterDir The directory the adapter resides in
|
|
108
128
|
*/
|
|
109
129
|
function loadInstanceObjects(adapterDir) {
|
|
110
130
|
const ioPackage = loadIoPackage(adapterDir);
|
|
111
131
|
return ioPackage.instanceObjects || [];
|
|
112
132
|
}
|
|
113
|
-
exports.loadInstanceObjects = loadInstanceObjects;
|
|
114
133
|
/** Returns the branded name of "iobroker" */
|
|
115
134
|
function getAppName(adapterDir) {
|
|
116
135
|
const npmPackage = loadNpmPackage(adapterDir);
|
|
117
|
-
return npmPackage.name.split(
|
|
136
|
+
return npmPackage.name.split('.')[0] || 'iobroker';
|
|
118
137
|
}
|
|
119
|
-
exports.getAppName = getAppName;
|
|
120
138
|
/** Returns the name of an adapter without the prefix */
|
|
121
139
|
function getAdapterName(adapterDir) {
|
|
122
140
|
const ioPackage = loadIoPackage(adapterDir);
|
|
123
141
|
return ioPackage.common.name;
|
|
124
142
|
}
|
|
125
|
-
exports.getAdapterName = getAdapterName;
|
|
126
143
|
/** Returns the full name of an adapter, including the prefix */
|
|
127
144
|
function getAdapterFullName(adapterDir) {
|
|
128
145
|
const npmPackage = loadNpmPackage(adapterDir);
|
|
129
146
|
return npmPackage.name;
|
|
130
147
|
}
|
|
131
|
-
exports.getAdapterFullName = getAdapterFullName;
|
|
132
148
|
/** Reads other ioBroker modules this adapter depends on from io-package.json */
|
|
133
149
|
function getAdapterDependencies(adapterDir) {
|
|
134
150
|
const ioPackage = loadIoPackage(adapterDir);
|
|
135
151
|
const ret = {};
|
|
136
152
|
if ((0, typeguards_1.isArray)(ioPackage.common.dependencies)) {
|
|
137
153
|
for (const dep of ioPackage.common.dependencies) {
|
|
138
|
-
if (typeof dep ===
|
|
139
|
-
ret[dep] =
|
|
154
|
+
if (typeof dep === 'string') {
|
|
155
|
+
ret[dep] = 'latest';
|
|
140
156
|
}
|
|
141
157
|
else if ((0, typeguards_1.isObject)(dep)) {
|
|
142
158
|
const key = Object.keys(dep)[0];
|
|
143
|
-
if (key)
|
|
144
|
-
ret[key] = dep[key] ||
|
|
159
|
+
if (key) {
|
|
160
|
+
ret[key] = dep[key] || 'latest';
|
|
161
|
+
}
|
|
145
162
|
}
|
|
146
163
|
}
|
|
147
164
|
}
|
|
148
165
|
return ret;
|
|
149
166
|
}
|
|
150
|
-
exports.getAdapterDependencies = getAdapterDependencies;
|
|
@@ -1,4 +1,3 @@
|
|
|
1
|
-
/// <reference types="node" />
|
|
2
1
|
export interface ExecuteCommandOptions {
|
|
3
2
|
/** Whether the executed command should be logged to the stdout. Default: false */
|
|
4
3
|
logCommandExecution: boolean;
|
|
@@ -7,9 +6,9 @@ export interface ExecuteCommandOptions {
|
|
|
7
6
|
/** Where to redirect the stdin. Default: process.stdin */
|
|
8
7
|
stdin: NodeJS.ReadStream;
|
|
9
8
|
/** A write stream to redirect the stdout, "ignore" to ignore it or "pipe" to return it as a string. Default: process.stdout */
|
|
10
|
-
stdout: NodeJS.WriteStream |
|
|
9
|
+
stdout: NodeJS.WriteStream | 'pipe' | 'ignore';
|
|
11
10
|
/** A write stream to redirect the stderr, "ignore" to ignore it or "pipe" to return it as a string. Default: process.stderr */
|
|
12
|
-
stderr: NodeJS.WriteStream |
|
|
11
|
+
stderr: NodeJS.WriteStream | 'pipe' | 'ignore';
|
|
13
12
|
}
|
|
14
13
|
export interface ExecuteCommandResult {
|
|
15
14
|
/** The exit code of the spawned process */
|
|
@@ -24,6 +23,7 @@ export interface ExecuteCommandResult {
|
|
|
24
23
|
export declare function executeCommand(command: string, options?: Partial<ExecuteCommandOptions>): Promise<ExecuteCommandResult>;
|
|
25
24
|
/**
|
|
26
25
|
* Executes a command and returns the exit code and (if requested) the stdout
|
|
26
|
+
*
|
|
27
27
|
* @param command The command to execute
|
|
28
28
|
* @param args The command line arguments for the command
|
|
29
29
|
* @param options (optional) Some options for the command execution
|
|
@@ -1,55 +1,54 @@
|
|
|
1
1
|
"use strict";
|
|
2
2
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
-
exports.executeCommand =
|
|
4
|
-
const typeguards_1 = require("alcalzone-shared/typeguards");
|
|
3
|
+
exports.executeCommand = executeCommand;
|
|
5
4
|
const child_process_1 = require("child_process");
|
|
6
5
|
const isWindows = /^win/.test(process.platform);
|
|
7
6
|
function executeCommand(command, argsOrOptions, options) {
|
|
8
|
-
return new Promise(
|
|
7
|
+
return new Promise(resolve => {
|
|
9
8
|
let args;
|
|
10
|
-
if (
|
|
9
|
+
if (Array.isArray(argsOrOptions)) {
|
|
11
10
|
args = argsOrOptions;
|
|
12
11
|
}
|
|
13
|
-
else if (
|
|
12
|
+
else if (argsOrOptions && typeof argsOrOptions === 'object') {
|
|
14
13
|
// no args were given
|
|
15
14
|
options = argsOrOptions;
|
|
16
15
|
}
|
|
17
|
-
if (options == null)
|
|
16
|
+
if (options == null) {
|
|
18
17
|
options = {};
|
|
19
|
-
|
|
18
|
+
}
|
|
19
|
+
if (args == null) {
|
|
20
20
|
args = [];
|
|
21
|
+
}
|
|
21
22
|
const spawnOptions = {
|
|
22
|
-
stdio: [
|
|
23
|
-
options.stdin || process.stdin,
|
|
24
|
-
options.stdout || process.stdout,
|
|
25
|
-
options.stderr || process.stderr,
|
|
26
|
-
],
|
|
23
|
+
stdio: [options.stdin || process.stdin, options.stdout || process.stdout, options.stderr || process.stderr],
|
|
27
24
|
windowsHide: true,
|
|
28
25
|
};
|
|
29
|
-
if (options.cwd != null)
|
|
26
|
+
if (options.cwd != null) {
|
|
30
27
|
spawnOptions.cwd = options.cwd;
|
|
28
|
+
}
|
|
31
29
|
// Fix npm / node executable paths on Windows
|
|
32
30
|
if (isWindows) {
|
|
33
|
-
if (command ===
|
|
34
|
-
command +=
|
|
31
|
+
if (command === 'npm') {
|
|
32
|
+
command += '.cmd';
|
|
35
33
|
// Needed since Node.js v18.20.2 and v20.12.2
|
|
36
34
|
// https://github.com/nodejs/node/releases/tag/v18.20.2
|
|
37
35
|
spawnOptions.shell = true;
|
|
38
36
|
}
|
|
39
|
-
else if (command ===
|
|
40
|
-
command +=
|
|
37
|
+
else if (command === 'node') {
|
|
38
|
+
command += '.exe';
|
|
41
39
|
}
|
|
42
40
|
}
|
|
43
|
-
if (options.logCommandExecution == null)
|
|
41
|
+
if (options.logCommandExecution == null) {
|
|
44
42
|
options.logCommandExecution = false;
|
|
43
|
+
}
|
|
45
44
|
if (options.logCommandExecution) {
|
|
46
|
-
console.log(
|
|
45
|
+
console.log(`executing: ${command} ${args.join(' ')}`);
|
|
47
46
|
}
|
|
48
47
|
// Now execute the npm process and avoid throwing errors
|
|
49
48
|
try {
|
|
50
49
|
let bufferedStdout;
|
|
51
50
|
let bufferedStderr;
|
|
52
|
-
const cmd = (0, child_process_1.spawn)(command, args, spawnOptions).on(
|
|
51
|
+
const cmd = (0, child_process_1.spawn)(command, args, spawnOptions).on('close', (code, signal) => {
|
|
53
52
|
resolve({
|
|
54
53
|
exitCode: code ?? undefined,
|
|
55
54
|
signal: signal ?? undefined,
|
|
@@ -58,26 +57,27 @@ function executeCommand(command, argsOrOptions, options) {
|
|
|
58
57
|
});
|
|
59
58
|
});
|
|
60
59
|
// Capture stdout/stderr if requested
|
|
61
|
-
if (options.stdout ===
|
|
62
|
-
bufferedStdout =
|
|
63
|
-
cmd.stdout.on(
|
|
64
|
-
if (Buffer.isBuffer(chunk))
|
|
65
|
-
chunk = chunk.toString(
|
|
60
|
+
if (options.stdout === 'pipe') {
|
|
61
|
+
bufferedStdout = '';
|
|
62
|
+
cmd.stdout.on('data', (chunk) => {
|
|
63
|
+
if (Buffer.isBuffer(chunk)) {
|
|
64
|
+
chunk = chunk.toString('utf8');
|
|
65
|
+
}
|
|
66
66
|
bufferedStdout += chunk;
|
|
67
67
|
});
|
|
68
68
|
}
|
|
69
|
-
if (options.stderr ===
|
|
70
|
-
bufferedStderr =
|
|
71
|
-
cmd.stderr.on(
|
|
72
|
-
if (Buffer.isBuffer(chunk))
|
|
73
|
-
chunk = chunk.toString(
|
|
69
|
+
if (options.stderr === 'pipe') {
|
|
70
|
+
bufferedStderr = '';
|
|
71
|
+
cmd.stderr.on('data', (chunk) => {
|
|
72
|
+
if (Buffer.isBuffer(chunk)) {
|
|
73
|
+
chunk = chunk.toString('utf8');
|
|
74
|
+
}
|
|
74
75
|
bufferedStderr += chunk;
|
|
75
76
|
});
|
|
76
77
|
}
|
|
77
78
|
}
|
|
78
|
-
catch
|
|
79
|
+
catch {
|
|
79
80
|
// doesn't matter, we return the exit code in the "close" handler
|
|
80
81
|
}
|
|
81
82
|
});
|
|
82
83
|
}
|
|
83
|
-
exports.executeCommand = executeCommand;
|
package/build/lib/str2regex.js
CHANGED
|
@@ -1,11 +1,10 @@
|
|
|
1
1
|
"use strict";
|
|
2
2
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
-
exports.str2regex =
|
|
3
|
+
exports.str2regex = str2regex;
|
|
4
4
|
function str2regex(pattern) {
|
|
5
5
|
return new RegExp(pattern
|
|
6
|
-
.replace(/\\/g,
|
|
7
|
-
.replace(/\./g,
|
|
8
|
-
.replace(/\*/g,
|
|
9
|
-
.replace(/!/g,
|
|
6
|
+
.replace(/\\/g, '\\\\') // Backslashes escapen
|
|
7
|
+
.replace(/\./g, '\\.') // Punkte als solche matchen
|
|
8
|
+
.replace(/\*/g, '.*') // Wildcard in Regex umsetzen
|
|
9
|
+
.replace(/!/g, '?!'));
|
|
10
10
|
}
|
|
11
|
-
exports.str2regex = str2regex;
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export {};
|
package/build/lib/testAdapter.js
CHANGED
package/build/tests/index.d.ts
CHANGED
|
@@ -1,11 +1,11 @@
|
|
|
1
|
-
import { testAdapter } from
|
|
2
|
-
import { validatePackageFiles } from
|
|
3
|
-
import { testAdapterWithMocks } from
|
|
4
|
-
import { createMocks } from
|
|
5
|
-
import { createAsserts } from
|
|
6
|
-
export { TestHarness as IntegrationTestHarness } from
|
|
7
|
-
export { MockAdapter } from
|
|
8
|
-
export { MockDatabase } from
|
|
1
|
+
import { testAdapter } from './integration';
|
|
2
|
+
import { validatePackageFiles } from './packageFiles';
|
|
3
|
+
import { testAdapterWithMocks } from './unit';
|
|
4
|
+
import { createMocks } from './unit/harness/createMocks';
|
|
5
|
+
import { createAsserts } from './unit/mocks/mockDatabase';
|
|
6
|
+
export { TestHarness as IntegrationTestHarness } from './integration/lib/harness';
|
|
7
|
+
export type { MockAdapter } from './unit/mocks/mockAdapter';
|
|
8
|
+
export { MockDatabase } from './unit/mocks/mockDatabase';
|
|
9
9
|
/** Predefined test sets */
|
|
10
10
|
export declare const tests: {
|
|
11
11
|
/** @deprecated Adapter startup unit tests are no longer supported */
|
|
@@ -19,6 +19,6 @@ export declare const utils: {
|
|
|
19
19
|
createMocks: typeof createMocks;
|
|
20
20
|
createAsserts: typeof createAsserts;
|
|
21
21
|
/** @deprecated Adapter startup unit tests are no longer supported */
|
|
22
|
-
startMockAdapter: () =>
|
|
22
|
+
startMockAdapter: () => any;
|
|
23
23
|
};
|
|
24
24
|
};
|
package/build/tests/index.js
CHANGED
|
@@ -8,7 +8,6 @@ const createMocks_1 = require("./unit/harness/createMocks");
|
|
|
8
8
|
const mockDatabase_1 = require("./unit/mocks/mockDatabase");
|
|
9
9
|
var harness_1 = require("./integration/lib/harness");
|
|
10
10
|
Object.defineProperty(exports, "IntegrationTestHarness", { enumerable: true, get: function () { return harness_1.TestHarness; } });
|
|
11
|
-
var mockAdapter_1 = require("./unit/mocks/mockAdapter");
|
|
12
11
|
var mockDatabase_2 = require("./unit/mocks/mockDatabase");
|
|
13
12
|
Object.defineProperty(exports, "MockDatabase", { enumerable: true, get: function () { return mockDatabase_2.MockDatabase; } });
|
|
14
13
|
/** Predefined test sets */
|
|
@@ -1,6 +1,4 @@
|
|
|
1
|
-
|
|
2
|
-
/// <reference types="mocha" />
|
|
3
|
-
import { TestHarness } from "./lib/harness";
|
|
1
|
+
import { TestHarness } from './lib/harness';
|
|
4
2
|
export interface TestAdapterOptions {
|
|
5
3
|
allowedExitCodes?: (number | string)[];
|
|
6
4
|
/** The loglevel to use for DB and adapter related logs */
|
|
@@ -15,16 +15,25 @@ var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (
|
|
|
15
15
|
}) : function(o, v) {
|
|
16
16
|
o["default"] = v;
|
|
17
17
|
});
|
|
18
|
-
var __importStar = (this && this.__importStar) || function (
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
};
|
|
18
|
+
var __importStar = (this && this.__importStar) || (function () {
|
|
19
|
+
var ownKeys = function(o) {
|
|
20
|
+
ownKeys = Object.getOwnPropertyNames || function (o) {
|
|
21
|
+
var ar = [];
|
|
22
|
+
for (var k in o) if (Object.prototype.hasOwnProperty.call(o, k)) ar[ar.length] = k;
|
|
23
|
+
return ar;
|
|
24
|
+
};
|
|
25
|
+
return ownKeys(o);
|
|
26
|
+
};
|
|
27
|
+
return function (mod) {
|
|
28
|
+
if (mod && mod.__esModule) return mod;
|
|
29
|
+
var result = {};
|
|
30
|
+
if (mod != null) for (var k = ownKeys(mod), i = 0; i < k.length; i++) if (k[i] !== "default") __createBinding(result, mod, k[i]);
|
|
31
|
+
__setModuleDefault(result, mod);
|
|
32
|
+
return result;
|
|
33
|
+
};
|
|
34
|
+
})();
|
|
25
35
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
26
|
-
exports.testAdapter =
|
|
27
|
-
const async_1 = require("alcalzone-shared/async");
|
|
36
|
+
exports.testAdapter = testAdapter;
|
|
28
37
|
const os = __importStar(require("os"));
|
|
29
38
|
const path = __importStar(require("path"));
|
|
30
39
|
const adapterTools_1 = require("../../lib/adapterTools");
|
|
@@ -52,7 +61,7 @@ function testAdapter(adapterDir, options = {}) {
|
|
|
52
61
|
const oneMinute = 60000;
|
|
53
62
|
this.timeout(30 * oneMinute);
|
|
54
63
|
if (await controllerSetup.isJsControllerRunning()) {
|
|
55
|
-
throw new Error(
|
|
64
|
+
throw new Error('JS-Controller is already running! Stop it for the first test run and try again!');
|
|
56
65
|
}
|
|
57
66
|
const adapterSetup = new adapterSetup_1.AdapterSetup(adapterDir, testDir);
|
|
58
67
|
// Installation happens in two steps:
|
|
@@ -62,7 +71,7 @@ function testAdapter(adapterDir, options = {}) {
|
|
|
62
71
|
// Only then we can install the adapter, because some (including VIS) try to access
|
|
63
72
|
// the databases if JS Controller is installed
|
|
64
73
|
await adapterSetup.installAdapterInTestDir();
|
|
65
|
-
const dbConnection = new dbConnection_1.DBConnection(appName, testDir, (0, logger_1.createLogger)(options.loglevel ??
|
|
74
|
+
const dbConnection = new dbConnection_1.DBConnection(appName, testDir, (0, logger_1.createLogger)(options.loglevel ?? 'debug'));
|
|
66
75
|
await dbConnection.start();
|
|
67
76
|
controllerSetup.setupSystemConfig(dbConnection);
|
|
68
77
|
await controllerSetup.disableAdminInstances(dbConnection);
|
|
@@ -70,8 +79,7 @@ function testAdapter(adapterDir, options = {}) {
|
|
|
70
79
|
await adapterSetup.addAdapterInstance();
|
|
71
80
|
await dbConnection.stop();
|
|
72
81
|
// Create a copy of the databases that we can restore later
|
|
73
|
-
({ objects: objectsBackup, states: statesBackup } =
|
|
74
|
-
await dbConnection.backup());
|
|
82
|
+
({ objects: objectsBackup, states: statesBackup } = await dbConnection.backup());
|
|
75
83
|
}
|
|
76
84
|
async function shutdownTests() {
|
|
77
85
|
// Stopping the processes may take a while
|
|
@@ -82,7 +90,7 @@ function testAdapter(adapterDir, options = {}) {
|
|
|
82
90
|
}
|
|
83
91
|
async function resetDbAndStartHarness() {
|
|
84
92
|
this.timeout(30000);
|
|
85
|
-
dbConnection = new dbConnection_1.DBConnection(appName, testDir, (0, logger_1.createLogger)(options.loglevel ??
|
|
93
|
+
dbConnection = new dbConnection_1.DBConnection(appName, testDir, (0, logger_1.createLogger)(options.loglevel ?? 'debug'));
|
|
86
94
|
// Clean up before every single test
|
|
87
95
|
await Promise.all([
|
|
88
96
|
controllerSetup.clearDBDir(),
|
|
@@ -96,7 +104,7 @@ function testAdapter(adapterDir, options = {}) {
|
|
|
96
104
|
await harness.changeAdapterConfig(adapterName, {
|
|
97
105
|
common: {
|
|
98
106
|
enabled: true,
|
|
99
|
-
loglevel: options.loglevel ??
|
|
107
|
+
loglevel: options.loglevel ?? 'debug',
|
|
100
108
|
},
|
|
101
109
|
});
|
|
102
110
|
// And enable the sendTo emulation
|
|
@@ -104,59 +112,57 @@ function testAdapter(adapterDir, options = {}) {
|
|
|
104
112
|
}
|
|
105
113
|
describe(`Adapter integration tests`, () => {
|
|
106
114
|
before(prepareTests);
|
|
107
|
-
describe(
|
|
115
|
+
describe('Adapter startup', () => {
|
|
108
116
|
beforeEach(resetDbAndStartHarness);
|
|
109
117
|
afterEach(shutdownTests);
|
|
110
|
-
it(
|
|
118
|
+
it('The adapter starts', function () {
|
|
111
119
|
this.timeout(60000);
|
|
112
120
|
const allowedExitCodes = new Set(options.allowedExitCodes ?? []);
|
|
113
121
|
// Adapters with these modes are allowed to "immediately" exit with code 0
|
|
114
122
|
switch (harness.getAdapterExecutionMode()) {
|
|
115
|
-
case
|
|
116
|
-
|
|
117
|
-
|
|
123
|
+
case 'schedule':
|
|
124
|
+
allowedExitCodes.add(0);
|
|
125
|
+
break;
|
|
126
|
+
case 'once':
|
|
118
127
|
allowedExitCodes.add(0);
|
|
128
|
+
break;
|
|
129
|
+
// @ts-expect-error subscribe was deprecated
|
|
130
|
+
case 'subscribe':
|
|
131
|
+
allowedExitCodes.add(0);
|
|
132
|
+
break;
|
|
119
133
|
}
|
|
120
134
|
return new Promise((resolve, reject) => {
|
|
121
135
|
// Register a handler to check the alive state and exit codes
|
|
122
136
|
harness
|
|
123
|
-
.on(
|
|
124
|
-
if (id ===
|
|
125
|
-
`system.adapter.${adapterName}.0.alive` &&
|
|
126
|
-
state &&
|
|
127
|
-
state.val === true) {
|
|
137
|
+
.on('stateChange', async (id, state) => {
|
|
138
|
+
if (id === `system.adapter.${adapterName}.0.alive` && state && state.val === true) {
|
|
128
139
|
// Wait a bit so we can catch errors that do not happen immediately
|
|
129
|
-
await (
|
|
130
|
-
undefined
|
|
140
|
+
await new Promise(resolve => setTimeout(resolve, options.waitBeforeStartupSuccess !== undefined
|
|
131
141
|
? options.waitBeforeStartupSuccess
|
|
132
|
-
: 5000);
|
|
142
|
+
: 5000));
|
|
133
143
|
resolve(`The adapter started successfully.`);
|
|
134
144
|
}
|
|
135
145
|
})
|
|
136
|
-
.on(
|
|
146
|
+
.on('failed', code => {
|
|
137
147
|
if (!allowedExitCodes.has(code)) {
|
|
138
|
-
reject(new Error(`The adapter startup was interrupted unexpectedly with ${typeof code ===
|
|
139
|
-
? "code"
|
|
140
|
-
: "signal"} ${code}`));
|
|
148
|
+
reject(new Error(`The adapter startup was interrupted unexpectedly with ${typeof code === 'number' ? 'code' : 'signal'} ${code}`));
|
|
141
149
|
}
|
|
142
150
|
else {
|
|
143
151
|
// This was a valid exit code
|
|
144
|
-
resolve(`The expected ${typeof code ===
|
|
145
|
-
? "exit code"
|
|
146
|
-
: "signal"} ${code} was received.`);
|
|
152
|
+
resolve(`The expected ${typeof code === 'number' ? 'exit code' : 'signal'} ${code} was received.`);
|
|
147
153
|
}
|
|
148
154
|
});
|
|
149
|
-
harness.startAdapter();
|
|
150
|
-
}).then(
|
|
155
|
+
void harness.startAdapter();
|
|
156
|
+
}).then(msg => console.log(msg));
|
|
151
157
|
});
|
|
152
158
|
});
|
|
153
159
|
// Call the user's tests
|
|
154
|
-
if (typeof options.defineAdditionalTests ===
|
|
160
|
+
if (typeof options.defineAdditionalTests === 'function') {
|
|
155
161
|
const originalIt = global.it;
|
|
156
162
|
// Ensure no it() gets called outside of a suite()
|
|
157
163
|
function assertSuite() {
|
|
158
164
|
if (!isInSuite) {
|
|
159
|
-
throw new Error(
|
|
165
|
+
throw new Error('In user-defined adapter tests, it() must NOT be called outside of a suite()');
|
|
160
166
|
}
|
|
161
167
|
}
|
|
162
168
|
const patchedIt = new Proxy(originalIt, {
|
|
@@ -169,7 +175,7 @@ function testAdapter(adapterDir, options = {}) {
|
|
|
169
175
|
return target[propKey];
|
|
170
176
|
},
|
|
171
177
|
});
|
|
172
|
-
describe(
|
|
178
|
+
describe('User-defined tests', () => {
|
|
173
179
|
// patch the global it() function so nobody can bypass the checks
|
|
174
180
|
global.it = patchedIt;
|
|
175
181
|
// a test suite is a special describe which sets up and tears down the test environment before and after ALL tests
|
|
@@ -201,4 +207,3 @@ function testAdapter(adapterDir, options = {}) {
|
|
|
201
207
|
}
|
|
202
208
|
});
|
|
203
209
|
}
|
|
204
|
-
exports.testAdapter = testAdapter;
|