@iobroker/testing 2.5.0 → 2.5.4
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 +10 -1
- package/LICENSE +1 -1
- package/build/lib/adapterTools.js +27 -38
- package/build/lib/executeCommand.js +3 -4
- package/build/tests/index.js +1 -0
- package/build/tests/integration/index.js +59 -76
- package/build/tests/integration/lib/adapterSetup.d.ts +4 -5
- package/build/tests/integration/lib/adapterSetup.js +81 -97
- package/build/tests/integration/lib/controllerSetup.d.ts +4 -7
- package/build/tests/integration/lib/controllerSetup.js +90 -105
- package/build/tests/integration/lib/dbConnection.d.ts +46 -22
- package/build/tests/integration/lib/dbConnection.js +259 -65
- package/build/tests/integration/lib/harness.d.ts +6 -11
- package/build/tests/integration/lib/harness.js +107 -192
- package/build/tests/integration/lib/tools.js +1 -1
- package/build/tests/packageFiles/index.js +32 -26
- package/build/tests/unit/index.js +2 -11
- package/build/tests/unit/mocks/mockAdapter.d.ts +1 -1
- package/build/tests/unit/mocks/mockAdapter.js +17 -18
- package/build/tests/unit/mocks/mockAdapterCore.d.ts +1 -1
- package/build/tests/unit/mocks/mockDatabase.d.ts +2 -2
- package/build/tests/unit/mocks/mockDatabase.js +10 -10
- package/build/tests/unit/mocks/mockLogger.js +8 -8
- package/build/tests/unit/mocks/tools.d.ts +1 -1
- package/build/tests/unit/mocks/tools.js +2 -2
- package/package.json +27 -25
|
@@ -18,22 +18,11 @@ var __importStar = (this && this.__importStar) || function (mod) {
|
|
|
18
18
|
__setModuleDefault(result, mod);
|
|
19
19
|
return result;
|
|
20
20
|
};
|
|
21
|
-
var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, generator) {
|
|
22
|
-
function adopt(value) { return value instanceof P ? value : new P(function (resolve) { resolve(value); }); }
|
|
23
|
-
return new (P || (P = Promise))(function (resolve, reject) {
|
|
24
|
-
function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } }
|
|
25
|
-
function rejected(value) { try { step(generator["throw"](value)); } catch (e) { reject(e); } }
|
|
26
|
-
function step(result) { result.done ? resolve(result.value) : adopt(result.value).then(fulfilled, rejected); }
|
|
27
|
-
step((generator = generator.apply(thisArg, _arguments || [])).next());
|
|
28
|
-
});
|
|
29
|
-
};
|
|
30
21
|
var __importDefault = (this && this.__importDefault) || function (mod) {
|
|
31
22
|
return (mod && mod.__esModule) ? mod : { "default": mod };
|
|
32
23
|
};
|
|
33
24
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
34
25
|
exports.TestHarness = void 0;
|
|
35
|
-
/* eslint-disable @typescript-eslint/camelcase */
|
|
36
|
-
/* eslint-disable @typescript-eslint/no-var-requires */
|
|
37
26
|
const async_1 = require("alcalzone-shared/async");
|
|
38
27
|
const objects_1 = require("alcalzone-shared/objects");
|
|
39
28
|
const child_process_1 = require("child_process");
|
|
@@ -41,18 +30,9 @@ const debug_1 = __importDefault(require("debug"));
|
|
|
41
30
|
const events_1 = require("events");
|
|
42
31
|
const path = __importStar(require("path"));
|
|
43
32
|
const adapterTools_1 = require("../../../lib/adapterTools");
|
|
44
|
-
const dbConnection_1 = require("./dbConnection");
|
|
45
33
|
const tools_1 = require("./tools");
|
|
46
|
-
const debug = debug_1.default("testing:integration:TestHarness");
|
|
34
|
+
const debug = (0, debug_1.default)("testing:integration:TestHarness");
|
|
47
35
|
const isWindows = /^win/.test(process.platform);
|
|
48
|
-
/** The logger instance for the objects and states DB */
|
|
49
|
-
const logger = {
|
|
50
|
-
silly: console.log,
|
|
51
|
-
debug: console.log,
|
|
52
|
-
info: console.log,
|
|
53
|
-
warn: console.warn,
|
|
54
|
-
error: console.error,
|
|
55
|
-
};
|
|
56
36
|
const fromAdapterID = "system.adapter.test.0";
|
|
57
37
|
/**
|
|
58
38
|
* The test harness capsules the execution of the JS-Controller and the adapter instance and monitors their status.
|
|
@@ -63,30 +43,42 @@ class TestHarness extends events_1.EventEmitter {
|
|
|
63
43
|
* @param adapterDir The root directory of the adapter
|
|
64
44
|
* @param testDir The directory the integration tests are executed in
|
|
65
45
|
*/
|
|
66
|
-
constructor(adapterDir, testDir) {
|
|
46
|
+
constructor(adapterDir, testDir, dbConnection) {
|
|
67
47
|
super();
|
|
68
48
|
this.adapterDir = adapterDir;
|
|
69
49
|
this.testDir = testDir;
|
|
50
|
+
this.dbConnection = dbConnection;
|
|
70
51
|
this.sendToID = 1;
|
|
71
52
|
debug("Creating instance");
|
|
72
|
-
this.adapterName = adapterTools_1.getAdapterName(this.adapterDir);
|
|
73
|
-
this.appName = adapterTools_1.getAppName(adapterDir);
|
|
74
|
-
this.testControllerDir = tools_1.getTestControllerDir(this.appName, testDir);
|
|
75
|
-
this.testAdapterDir = tools_1.getTestAdapterDir(this.adapterDir, testDir);
|
|
53
|
+
this.adapterName = (0, adapterTools_1.getAdapterName)(this.adapterDir);
|
|
54
|
+
this.appName = (0, adapterTools_1.getAppName)(adapterDir);
|
|
55
|
+
this.testControllerDir = (0, tools_1.getTestControllerDir)(this.appName, testDir);
|
|
56
|
+
this.testAdapterDir = (0, tools_1.getTestAdapterDir)(this.adapterDir, testDir);
|
|
76
57
|
debug(` directories:`);
|
|
77
58
|
debug(` controller: ${this.testControllerDir}`);
|
|
78
59
|
debug(` adapter: ${this.testAdapterDir}`);
|
|
79
60
|
debug(` appName: ${this.appName}`);
|
|
80
61
|
debug(` adapterName: ${this.adapterName}`);
|
|
81
|
-
|
|
62
|
+
dbConnection.on("objectChange", (id, obj) => {
|
|
63
|
+
this.emit("objectChange", id, obj);
|
|
64
|
+
});
|
|
65
|
+
dbConnection.on("stateChange", (id, state) => {
|
|
66
|
+
this.emit("stateChange", id, state);
|
|
67
|
+
});
|
|
82
68
|
}
|
|
83
|
-
/**
|
|
69
|
+
/** Gives direct access to the Objects DB */
|
|
84
70
|
get objects() {
|
|
85
|
-
|
|
71
|
+
if (!this.dbConnection.objectsClient) {
|
|
72
|
+
throw new Error("Objects DB is not running");
|
|
73
|
+
}
|
|
74
|
+
return this.dbConnection.objectsClient;
|
|
86
75
|
}
|
|
87
|
-
/**
|
|
76
|
+
/** Gives direct access to the States DB */
|
|
88
77
|
get states() {
|
|
89
|
-
|
|
78
|
+
if (!this.dbConnection.statesClient) {
|
|
79
|
+
throw new Error("States DB is not running");
|
|
80
|
+
}
|
|
81
|
+
return this.dbConnection.statesClient;
|
|
90
82
|
}
|
|
91
83
|
/** The process the adapter is running in */
|
|
92
84
|
get adapterProcess() {
|
|
@@ -96,160 +88,86 @@ class TestHarness extends events_1.EventEmitter {
|
|
|
96
88
|
get adapterExit() {
|
|
97
89
|
return this._adapterExit;
|
|
98
90
|
}
|
|
99
|
-
/** Creates the objects DB and sets up listeners for it */
|
|
100
|
-
createObjectsDB() {
|
|
101
|
-
return __awaiter(this, void 0, void 0, function* () {
|
|
102
|
-
debug("creating objects DB");
|
|
103
|
-
const Objects = require(path.join(this.testControllerDir, "lib/objects/objectsInMemServer"));
|
|
104
|
-
return new Promise((resolve) => {
|
|
105
|
-
this._objects = new Objects({
|
|
106
|
-
connection: {
|
|
107
|
-
type: "file",
|
|
108
|
-
host: "127.0.0.1",
|
|
109
|
-
port: 19001,
|
|
110
|
-
user: "",
|
|
111
|
-
pass: "",
|
|
112
|
-
noFileCache: false,
|
|
113
|
-
connectTimeout: 2000,
|
|
114
|
-
},
|
|
115
|
-
logger,
|
|
116
|
-
connected: () => {
|
|
117
|
-
debug(" => done!");
|
|
118
|
-
this._objects.subscribe("*");
|
|
119
|
-
resolve();
|
|
120
|
-
},
|
|
121
|
-
change: this.emit.bind(this, "objectChange"),
|
|
122
|
-
});
|
|
123
|
-
});
|
|
124
|
-
});
|
|
125
|
-
}
|
|
126
|
-
/** Creates the states DB and sets up listeners for it */
|
|
127
|
-
createStatesDB() {
|
|
128
|
-
return __awaiter(this, void 0, void 0, function* () {
|
|
129
|
-
debug("creating states DB");
|
|
130
|
-
const States = require(path.join(this.testControllerDir, "lib/states/statesInMemServer"));
|
|
131
|
-
return new Promise((resolve) => {
|
|
132
|
-
this._states = new States({
|
|
133
|
-
connection: {
|
|
134
|
-
type: "file",
|
|
135
|
-
host: "127.0.0.1",
|
|
136
|
-
port: 19000,
|
|
137
|
-
options: {
|
|
138
|
-
auth_pass: null,
|
|
139
|
-
retry_max_delay: 15000,
|
|
140
|
-
},
|
|
141
|
-
},
|
|
142
|
-
logger,
|
|
143
|
-
connected: () => {
|
|
144
|
-
debug(" => done!");
|
|
145
|
-
this._states.subscribe("*");
|
|
146
|
-
resolve();
|
|
147
|
-
},
|
|
148
|
-
change: this.emit.bind(this, "stateChange"),
|
|
149
|
-
});
|
|
150
|
-
});
|
|
151
|
-
});
|
|
152
|
-
}
|
|
153
91
|
/** Checks if the controller instance is running */
|
|
154
92
|
isControllerRunning() {
|
|
155
|
-
|
|
93
|
+
// The "controller instance" is just the databases, so if they are running,
|
|
94
|
+
// the "controller" is.
|
|
95
|
+
return this.dbConnection.isRunning;
|
|
156
96
|
}
|
|
157
97
|
/** Starts the controller instance by creating the databases */
|
|
158
|
-
startController() {
|
|
159
|
-
|
|
160
|
-
debug("starting controller instance...");
|
|
161
|
-
if (this.isControllerRunning())
|
|
162
|
-
throw new Error("The Controller is already running!");
|
|
163
|
-
yield this.createObjectsDB();
|
|
164
|
-
yield this.createStatesDB();
|
|
165
|
-
debug("controller instance created");
|
|
166
|
-
});
|
|
98
|
+
async startController() {
|
|
99
|
+
await this.dbConnection.start();
|
|
167
100
|
}
|
|
168
101
|
/** Stops the controller instance (and the adapter if it is running) */
|
|
169
|
-
stopController() {
|
|
170
|
-
|
|
171
|
-
|
|
172
|
-
|
|
173
|
-
|
|
174
|
-
|
|
175
|
-
|
|
176
|
-
|
|
177
|
-
|
|
178
|
-
|
|
179
|
-
stopTimeout += 1000;
|
|
180
|
-
}
|
|
181
|
-
catch (_a) { }
|
|
182
|
-
stopTimeout || (stopTimeout = 5000); // default 5s
|
|
183
|
-
debug(` => giving it ${stopTimeout}ms to terminate`);
|
|
184
|
-
yield Promise.race([this.stopAdapter(), async_1.wait(stopTimeout)]);
|
|
185
|
-
if (this.isAdapterRunning()) {
|
|
186
|
-
debug("Adapter did not terminate, killing it");
|
|
187
|
-
this._adapterProcess.kill("SIGKILL");
|
|
188
|
-
}
|
|
189
|
-
else {
|
|
190
|
-
debug("Adapter terminated");
|
|
191
|
-
}
|
|
192
|
-
}
|
|
193
|
-
else {
|
|
194
|
-
debug("Adapter failed to start - no need to terminate!");
|
|
102
|
+
async stopController() {
|
|
103
|
+
if (!this.isControllerRunning())
|
|
104
|
+
return;
|
|
105
|
+
if (!this.didAdapterStop()) {
|
|
106
|
+
debug("Stopping adapter instance...");
|
|
107
|
+
// Give the adapter time to stop (as long as configured in the io-package.json)
|
|
108
|
+
let stopTimeout;
|
|
109
|
+
try {
|
|
110
|
+
stopTimeout = (await this.dbConnection.getObject(`system.adapter.${this.adapterName}.0`)).common.stopTimeout;
|
|
111
|
+
stopTimeout += 1000;
|
|
195
112
|
}
|
|
196
|
-
|
|
197
|
-
|
|
198
|
-
|
|
199
|
-
|
|
113
|
+
catch { }
|
|
114
|
+
stopTimeout || (stopTimeout = 5000); // default 5s
|
|
115
|
+
debug(` => giving it ${stopTimeout}ms to terminate`);
|
|
116
|
+
await Promise.race([this.stopAdapter(), (0, async_1.wait)(stopTimeout)]);
|
|
117
|
+
if (this.isAdapterRunning()) {
|
|
118
|
+
debug("Adapter did not terminate, killing it");
|
|
119
|
+
this._adapterProcess.kill("SIGKILL");
|
|
200
120
|
}
|
|
201
|
-
|
|
202
|
-
|
|
203
|
-
this._states = null;
|
|
121
|
+
else {
|
|
122
|
+
debug("Adapter terminated");
|
|
204
123
|
}
|
|
205
|
-
|
|
206
|
-
|
|
124
|
+
}
|
|
125
|
+
else {
|
|
126
|
+
debug("Adapter failed to start - no need to terminate!");
|
|
127
|
+
}
|
|
128
|
+
await this.dbConnection.stop();
|
|
207
129
|
}
|
|
208
130
|
/**
|
|
209
131
|
* Starts the adapter in a separate process and monitors its status
|
|
210
132
|
* @param env Additional environment variables to set
|
|
211
133
|
*/
|
|
212
|
-
startAdapter(env = {}) {
|
|
213
|
-
|
|
214
|
-
|
|
215
|
-
|
|
216
|
-
|
|
217
|
-
|
|
218
|
-
|
|
219
|
-
|
|
220
|
-
|
|
221
|
-
|
|
222
|
-
|
|
223
|
-
|
|
224
|
-
|
|
225
|
-
this.
|
|
226
|
-
|
|
227
|
-
|
|
228
|
-
|
|
229
|
-
|
|
230
|
-
|
|
231
|
-
.on("exit", onClose);
|
|
232
|
-
});
|
|
134
|
+
async startAdapter(env = {}) {
|
|
135
|
+
if (this.isAdapterRunning())
|
|
136
|
+
throw new Error("The adapter is already running!");
|
|
137
|
+
else if (this.didAdapterStop())
|
|
138
|
+
throw new Error("This test harness has already been used. Please create a new one for each test!");
|
|
139
|
+
const mainFileAbsolute = await (0, adapterTools_1.locateAdapterMainFile)(this.testAdapterDir);
|
|
140
|
+
const mainFileRelative = path.relative(this.testAdapterDir, mainFileAbsolute);
|
|
141
|
+
const onClose = (code, signal) => {
|
|
142
|
+
this._adapterProcess.removeAllListeners();
|
|
143
|
+
this._adapterExit = code != undefined ? code : signal;
|
|
144
|
+
this.emit("failed", this._adapterExit);
|
|
145
|
+
};
|
|
146
|
+
this._adapterProcess = (0, child_process_1.spawn)(isWindows ? "node.exe" : "node", [mainFileRelative, "--console"], {
|
|
147
|
+
cwd: this.testAdapterDir,
|
|
148
|
+
stdio: ["inherit", "inherit", "inherit"],
|
|
149
|
+
env: { ...process.env, ...env },
|
|
150
|
+
})
|
|
151
|
+
.on("close", onClose)
|
|
152
|
+
.on("exit", onClose);
|
|
233
153
|
}
|
|
234
154
|
/**
|
|
235
155
|
* Starts the adapter in a separate process and resolves after it has started
|
|
236
156
|
* @param env Additional environment variables to set
|
|
237
157
|
*/
|
|
238
|
-
startAdapterAndWait(env = {}) {
|
|
239
|
-
return
|
|
240
|
-
|
|
241
|
-
|
|
242
|
-
|
|
243
|
-
|
|
244
|
-
|
|
245
|
-
|
|
246
|
-
|
|
247
|
-
|
|
248
|
-
|
|
249
|
-
|
|
250
|
-
|
|
251
|
-
.startAdapter(env);
|
|
252
|
-
});
|
|
158
|
+
async startAdapterAndWait(env = {}) {
|
|
159
|
+
return new Promise((resolve, reject) => {
|
|
160
|
+
this.on("stateChange", async (id, state) => {
|
|
161
|
+
if (id === `system.adapter.${this.adapterName}.0.alive` &&
|
|
162
|
+
state &&
|
|
163
|
+
state.val === true) {
|
|
164
|
+
resolve();
|
|
165
|
+
}
|
|
166
|
+
})
|
|
167
|
+
.on("failed", (code) => {
|
|
168
|
+
reject(new Error(`The adapter startup was interrupted unexpectedly with ${typeof code === "number" ? "code" : "signal"} ${code}`));
|
|
169
|
+
})
|
|
170
|
+
.startAdapter(env);
|
|
253
171
|
});
|
|
254
172
|
}
|
|
255
173
|
/** Tests if the adapter process is still running */
|
|
@@ -264,7 +182,7 @@ class TestHarness extends events_1.EventEmitter {
|
|
|
264
182
|
stopAdapter() {
|
|
265
183
|
if (!this.isAdapterRunning())
|
|
266
184
|
return;
|
|
267
|
-
return new Promise((resolve) =>
|
|
185
|
+
return new Promise(async (resolve) => {
|
|
268
186
|
var _a;
|
|
269
187
|
const onClose = (code, signal) => {
|
|
270
188
|
if (!this._adapterProcess)
|
|
@@ -281,45 +199,42 @@ class TestHarness extends events_1.EventEmitter {
|
|
|
281
199
|
.on("close", onClose)
|
|
282
200
|
.on("exit", onClose);
|
|
283
201
|
// Tell adapter to stop
|
|
284
|
-
|
|
285
|
-
|
|
202
|
+
try {
|
|
203
|
+
await this.dbConnection.setState(`system.adapter.${this.adapterName}.0.sigKill`, {
|
|
286
204
|
val: -1,
|
|
287
205
|
from: "system.host.testing",
|
|
288
206
|
});
|
|
289
207
|
}
|
|
290
|
-
|
|
208
|
+
catch {
|
|
209
|
+
// DB connection may be closed already, kill the process
|
|
291
210
|
(_a = this._adapterProcess) === null || _a === void 0 ? void 0 : _a.kill("SIGTERM");
|
|
292
211
|
}
|
|
293
|
-
})
|
|
212
|
+
});
|
|
294
213
|
}
|
|
295
214
|
/**
|
|
296
215
|
* Updates the adapter config. The changes can be a subset of the target object
|
|
297
216
|
*/
|
|
298
|
-
changeAdapterConfig(
|
|
299
|
-
|
|
300
|
-
|
|
301
|
-
|
|
302
|
-
|
|
303
|
-
|
|
304
|
-
|
|
305
|
-
yield this.dbConnection.writeObjectsDB(objects);
|
|
306
|
-
}
|
|
307
|
-
});
|
|
217
|
+
async changeAdapterConfig(adapterName, changes) {
|
|
218
|
+
const adapterInstanceId = `system.adapter.${adapterName}.0`;
|
|
219
|
+
const obj = await this.dbConnection.getObject(adapterInstanceId);
|
|
220
|
+
if (obj) {
|
|
221
|
+
(0, objects_1.extend)(obj, changes);
|
|
222
|
+
await this.dbConnection.setObject(adapterInstanceId, obj);
|
|
223
|
+
}
|
|
308
224
|
}
|
|
309
225
|
/** Enables the sendTo method */
|
|
310
|
-
enableSendTo() {
|
|
311
|
-
|
|
312
|
-
|
|
313
|
-
|
|
314
|
-
|
|
315
|
-
}, () => {
|
|
316
|
-
this._states.subscribeMessage(fromAdapterID);
|
|
317
|
-
resolve();
|
|
318
|
-
});
|
|
226
|
+
async enableSendTo() {
|
|
227
|
+
await this.dbConnection.setObject(fromAdapterID, {
|
|
228
|
+
type: "instance",
|
|
229
|
+
common: {},
|
|
230
|
+
native: {},
|
|
319
231
|
});
|
|
232
|
+
this.dbConnection.subscribeMessage(fromAdapterID);
|
|
320
233
|
}
|
|
321
234
|
/** Sends a message to an adapter instance */
|
|
322
|
-
sendTo(target, command,
|
|
235
|
+
sendTo(target, command,
|
|
236
|
+
// eslint-disable-next-line @typescript-eslint/explicit-module-boundary-types
|
|
237
|
+
message, callback) {
|
|
323
238
|
const stateChangedHandler = (id, state) => {
|
|
324
239
|
if (id === `messagebox.${fromAdapterID}`) {
|
|
325
240
|
callback(state.message);
|
|
@@ -327,7 +242,7 @@ class TestHarness extends events_1.EventEmitter {
|
|
|
327
242
|
}
|
|
328
243
|
};
|
|
329
244
|
this.addListener("stateChange", stateChangedHandler);
|
|
330
|
-
this.
|
|
245
|
+
this.dbConnection.pushMessage(`system.adapter.${target}`, {
|
|
331
246
|
command: command,
|
|
332
247
|
message: message,
|
|
333
248
|
from: fromAdapterID,
|
|
@@ -64,7 +64,7 @@ exports.getTestDBDir = getTestDBDir;
|
|
|
64
64
|
* @param testDir The directory the integration tests are executed in
|
|
65
65
|
*/
|
|
66
66
|
function getTestAdapterDir(adapterDir, testDir) {
|
|
67
|
-
const adapterName = adapterTools_1.getAdapterFullName(adapterDir);
|
|
67
|
+
const adapterName = (0, adapterTools_1.getAdapterFullName)(adapterDir);
|
|
68
68
|
return path.resolve(testDir, "node_modules", adapterName);
|
|
69
69
|
}
|
|
70
70
|
exports.getTestAdapterDir = getTestAdapterDir;
|
|
@@ -54,7 +54,7 @@ function validatePackageFiles(adapterDir) {
|
|
|
54
54
|
it(`The property "${propertyPath}" exists`, () => {
|
|
55
55
|
let prev = targetObj;
|
|
56
56
|
for (const part of propertyParts) {
|
|
57
|
-
chai_1.expect(prev[part]).to.not.be.undefined;
|
|
57
|
+
(0, chai_1.expect)(prev[part]).to.not.be.undefined;
|
|
58
58
|
prev = prev[part];
|
|
59
59
|
}
|
|
60
60
|
});
|
|
@@ -71,15 +71,15 @@ function validatePackageFiles(adapterDir) {
|
|
|
71
71
|
skipIfInvalid.call(this, filename);
|
|
72
72
|
});
|
|
73
73
|
it("exists", () => {
|
|
74
|
-
chai_1.expect(fs.existsSync(packagePath), `${filename} is missing in the adapter dir. Please create it!`).to.be.true;
|
|
74
|
+
(0, chai_1.expect)(fs.existsSync(packagePath), `${filename} is missing in the adapter dir. Please create it!`).to.be.true;
|
|
75
75
|
});
|
|
76
76
|
it("contains valid JSON", () => {
|
|
77
|
-
chai_1.expect(() => {
|
|
77
|
+
(0, chai_1.expect)(() => {
|
|
78
78
|
JSON.parse(fs.readFileSync(packagePath, "utf8"));
|
|
79
79
|
}, `${filename} contains invalid JSON!`).not.to.throw();
|
|
80
80
|
});
|
|
81
81
|
it("is an object", () => {
|
|
82
|
-
chai_1.expect(require(packagePath), `${filename} must contain an object!`).to.be.an("object");
|
|
82
|
+
(0, chai_1.expect)(require(packagePath), `${filename} must contain an object!`).to.be.an("object");
|
|
83
83
|
});
|
|
84
84
|
});
|
|
85
85
|
}
|
|
@@ -102,17 +102,18 @@ function validatePackageFiles(adapterDir) {
|
|
|
102
102
|
requiredProperties.forEach((prop) => ensurePropertyExists(prop, packageContent));
|
|
103
103
|
it("The package name is correct", () => {
|
|
104
104
|
let name = packageContent.name;
|
|
105
|
-
chai_1.expect(name).to.match(/^iobroker\./, `The npm package name must start with lowercase "iobroker."!`);
|
|
105
|
+
(0, chai_1.expect)(name).to.match(/^iobroker\./, `The npm package name must start with lowercase "iobroker."!`);
|
|
106
106
|
name = name.replace(/^iobroker\./, "");
|
|
107
|
-
chai_1.expect(name).to.match(/[a-z0-9_\-]+/, `The adapter name must only contain lowercase letters, numbers, "-" and "_"!`);
|
|
108
|
-
chai_1.expect(name).to.match(/^[a-z]/, `The adapter name must start with a letter!`);
|
|
109
|
-
chai_1.expect(name).to.match(/[a-z0-9]$/, `The adapter name must end with a letter or number!`);
|
|
107
|
+
(0, chai_1.expect)(name).to.match(/[a-z0-9_\-]+/, `The adapter name must only contain lowercase letters, numbers, "-" and "_"!`);
|
|
108
|
+
(0, chai_1.expect)(name).to.match(/^[a-z]/, `The adapter name must start with a letter!`);
|
|
109
|
+
(0, chai_1.expect)(name).to.match(/[a-z0-9]$/, `The adapter name must end with a letter or number!`);
|
|
110
110
|
});
|
|
111
111
|
it(`The repository type is "git"`, () => {
|
|
112
|
-
chai_1.expect(packageContent.repository.type).to.equal("git");
|
|
112
|
+
(0, chai_1.expect)(packageContent.repository.type).to.equal("git");
|
|
113
113
|
});
|
|
114
114
|
});
|
|
115
115
|
describe(`Check contents of io-package.json`, () => {
|
|
116
|
+
var _a;
|
|
116
117
|
beforeEach(function () {
|
|
117
118
|
skipIfInvalid.call(this, "io-package.json");
|
|
118
119
|
});
|
|
@@ -134,35 +135,40 @@ function validatePackageFiles(adapterDir) {
|
|
|
134
135
|
it(`The title does not contain "adapter" or "iobroker"`, () => {
|
|
135
136
|
if (!iopackContent.title)
|
|
136
137
|
return;
|
|
137
|
-
chai_1.expect(iopackContent.common.title).not.to.match(/iobroker|adapter/i);
|
|
138
|
+
(0, chai_1.expect)(iopackContent.common.title).not.to.match(/iobroker|adapter/i);
|
|
138
139
|
});
|
|
139
140
|
it(`titleLang is an object to support multiple languages`, () => {
|
|
140
|
-
chai_1.expect(iopackContent.common.titleLang).to.be.an("object");
|
|
141
|
+
(0, chai_1.expect)(iopackContent.common.titleLang).to.be.an("object");
|
|
141
142
|
});
|
|
142
143
|
it(`titleLang does not contain "adapter" or "iobroker"`, () => {
|
|
143
144
|
for (const title of Object.values(iopackContent.common.titleLang)) {
|
|
144
|
-
chai_1.expect(title).not.to.match(/iobroker|adapter/i);
|
|
145
|
+
(0, chai_1.expect)(title).not.to.match(/iobroker|adapter/i);
|
|
145
146
|
}
|
|
146
147
|
});
|
|
147
148
|
it(`The description is an object to support multiple languages`, () => {
|
|
148
|
-
chai_1.expect(iopackContent.common.desc).to.be.an("object");
|
|
149
|
+
(0, chai_1.expect)(iopackContent.common.desc).to.be.an("object");
|
|
149
150
|
});
|
|
150
151
|
it(`common.authors is an array that is not empty`, () => {
|
|
151
152
|
const authors = iopackContent.common.authors;
|
|
152
|
-
chai_1.expect(typeguards_1.isArray(authors)).to.be.true;
|
|
153
|
-
chai_1.expect(authors.length).to.be.at.least(1);
|
|
153
|
+
(0, chai_1.expect)((0, typeguards_1.isArray)(authors)).to.be.true;
|
|
154
|
+
(0, chai_1.expect)(authors.length).to.be.at.least(1);
|
|
154
155
|
});
|
|
155
156
|
it(`common.news is an object that contains maximum 20 entries`, () => {
|
|
156
157
|
const news = iopackContent.common.news;
|
|
157
|
-
chai_1.expect(typeguards_1.isObject(news)).to.be.true;
|
|
158
|
-
chai_1.expect(Object.keys(news).length).to.be.at.most(20);
|
|
158
|
+
(0, chai_1.expect)((0, typeguards_1.isObject)(news)).to.be.true;
|
|
159
|
+
(0, chai_1.expect)(Object.keys(news).length).to.be.at.most(20);
|
|
159
160
|
});
|
|
160
|
-
|
|
161
|
-
|
|
162
|
-
|
|
163
|
-
iopackContent.common.
|
|
164
|
-
|
|
165
|
-
|
|
161
|
+
// If the adapter has a configuration page, check that a supported admin UI is used
|
|
162
|
+
const hasNoConfigPage = iopackContent.common.noConfig === true ||
|
|
163
|
+
iopackContent.common.noConfig === "true" ||
|
|
164
|
+
((_a = iopackContent.common.adminUI) === null || _a === void 0 ? void 0 : _a.config) === "none";
|
|
165
|
+
if (!hasNoConfigPage) {
|
|
166
|
+
it("The adapter uses Material UI or JSON Config for the admin UI", () => {
|
|
167
|
+
var _a, _b;
|
|
168
|
+
const hasSupportedUI = !!iopackContent.common.materialize ||
|
|
169
|
+
((_a = iopackContent.common.adminUI) === null || _a === void 0 ? void 0 : _a.config) === "json" ||
|
|
170
|
+
((_b = iopackContent.common.adminUI) === null || _b === void 0 ? void 0 : _b.config) === "materialize";
|
|
171
|
+
(0, chai_1.expect)(hasSupportedUI, "Unsupported Admin UI, must be materialize or json config!").to.be.true;
|
|
166
172
|
});
|
|
167
173
|
}
|
|
168
174
|
});
|
|
@@ -173,13 +179,13 @@ function validatePackageFiles(adapterDir) {
|
|
|
173
179
|
const packageContent = require(packageJsonPath);
|
|
174
180
|
const iopackContent = require(ioPackageJsonPath);
|
|
175
181
|
it("The name matches", () => {
|
|
176
|
-
chai_1.expect("iobroker." + iopackContent.common.name).to.equal(packageContent.name);
|
|
182
|
+
(0, chai_1.expect)("iobroker." + iopackContent.common.name).to.equal(packageContent.name);
|
|
177
183
|
});
|
|
178
184
|
it("The version matches", () => {
|
|
179
|
-
chai_1.expect(iopackContent.common.version).to.equal(packageContent.version);
|
|
185
|
+
(0, chai_1.expect)(iopackContent.common.version).to.equal(packageContent.version);
|
|
180
186
|
});
|
|
181
187
|
it("The license matches", () => {
|
|
182
|
-
chai_1.expect(iopackContent.common.license).to.equal(packageContent.license);
|
|
188
|
+
(0, chai_1.expect)(iopackContent.common.license).to.equal(packageContent.license);
|
|
183
189
|
});
|
|
184
190
|
});
|
|
185
191
|
});
|
|
@@ -1,13 +1,4 @@
|
|
|
1
1
|
"use strict";
|
|
2
|
-
var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, generator) {
|
|
3
|
-
function adopt(value) { return value instanceof P ? value : new P(function (resolve) { resolve(value); }); }
|
|
4
|
-
return new (P || (P = Promise))(function (resolve, reject) {
|
|
5
|
-
function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } }
|
|
6
|
-
function rejected(value) { try { step(generator["throw"](value)); } catch (e) { reject(e); } }
|
|
7
|
-
function step(result) { result.done ? resolve(result.value) : adopt(result.value).then(fulfilled, rejected); }
|
|
8
|
-
step((generator = generator.apply(thisArg, _arguments || [])).next());
|
|
9
|
-
});
|
|
10
|
-
};
|
|
11
2
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
12
3
|
exports.testAdapterWithMocks = void 0;
|
|
13
4
|
/**
|
|
@@ -16,7 +7,7 @@ exports.testAdapterWithMocks = void 0;
|
|
|
16
7
|
* This is meant to be executed in a mocha context.
|
|
17
8
|
*/
|
|
18
9
|
function testAdapterWithMocks(_adapterDir, options = {}) {
|
|
19
|
-
describe(`Unit tests`, () =>
|
|
10
|
+
describe(`Unit tests`, async () => {
|
|
20
11
|
// Call the user's tests
|
|
21
12
|
if (typeof options.defineAdditionalTests === "function") {
|
|
22
13
|
options.defineAdditionalTests();
|
|
@@ -28,6 +19,6 @@ function testAdapterWithMocks(_adapterDir, options = {}) {
|
|
|
28
19
|
console.warn(`from package.json and from your Travis/Github Actions workflow.\u001b[0m`);
|
|
29
20
|
});
|
|
30
21
|
}
|
|
31
|
-
})
|
|
22
|
+
});
|
|
32
23
|
}
|
|
33
24
|
exports.testAdapterWithMocks = testAdapterWithMocks;
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
/// <reference types="iobroker" />
|
|
2
|
-
import { MockDatabase } from "./mockDatabase";
|
|
2
|
+
import type { MockDatabase } from "./mockDatabase";
|
|
3
3
|
import { MockLogger } from "./mockLogger";
|
|
4
4
|
import { Mock } from "./tools";
|
|
5
5
|
export declare type MockAdapter = Mock<ioBroker.Adapter> & {
|