zwave-js
Version:
Z-Wave driver written entirely in JavaScript/TypeScript
106 lines • 4.52 kB
JavaScript
import { fs } from "@zwave-js/core/bindings/fs/node";
import { copyFilesRecursive, noop } from "@zwave-js/shared";
import { wait } from "alcalzone-shared/async";
import crypto from "node:crypto";
import fsp from "node:fs/promises";
import os from "node:os";
import path from "node:path";
import { test } from "vitest";
import { prepareDriver, prepareMocks } from "./integrationTestSuiteShared.js";
function suite(name, options, modifier) {
const { controllerCapabilities, nodeCapabilities, customSetup, testBody, debug = false, provisioningDirectory, clearMessageStatsBeforeTest = true, additionalDriverOptions, } = options;
let driver;
let mockPort;
let serial;
let continueStartup;
let mockController;
let mockNodes;
let nodes;
const cacheDir = path.join(os.tmpdir(), `zjs_test_cache_${crypto.randomBytes(4).toString("hex")}`);
async function prepareTest() {
if (debug) {
console.log(`Running integration test in directory ${cacheDir}`);
}
// Make sure every test is starting fresh
await fsp.rm(cacheDir, { recursive: true, force: true }).catch(noop);
await fsp.mkdir(cacheDir, { recursive: true });
// And potentially provision the cache
if (provisioningDirectory) {
await copyFilesRecursive(fs, provisioningDirectory, cacheDir);
}
({ driver, continueStartup, mockPort, serial } = await prepareDriver(cacheDir, debug, additionalDriverOptions));
({ mockController, mockNodes } = await prepareMocks(mockPort, serial, {
capabilities: controllerCapabilities,
securityKeys: driver.options.securityKeys,
},
// TODO: This isn't ideal as it requires us to provide the
// node capabilities in addition to the provisioning directory
nodeCapabilities));
if (customSetup) {
await customSetup(driver, mockController, mockNodes);
}
// Wait for all nodes to be ready
return new Promise((resolve) => {
driver.once("driver ready", async () => {
const promises = [];
nodes = [];
for (const mockNode of mockNodes) {
const node = driver.controller.nodes.getOrThrow(mockNode.id);
nodes.push(node);
const onReady = (resolve) => {
if (clearMessageStatsBeforeTest) {
mockNode.clearReceivedControllerFrames();
mockNode.clearSentControllerFrames();
}
process.nextTick(resolve);
};
promises.push(new Promise((resolve) => {
if (options.additionalDriverOptions?.testingHooks
?.skipNodeInterview) {
onReady(resolve);
}
else {
node.once("ready", () => onReady(resolve));
}
}));
}
await Promise.all(promises);
if (clearMessageStatsBeforeTest) {
mockController.clearReceivedHostMessages();
}
process.nextTick(resolve);
});
continueStartup();
});
}
// Integration tests need to run in serial, or they might block the serial port on CI
const fn = modifier === "only"
? test.sequential.only
: modifier === "skip"
? test.sequential.skip
: test.sequential;
fn(name, async (t) => {
t.onTestFinished(async () => {
// Give everything a chance to settle before destroying the driver.
await wait(100);
await driver.destroy();
if (!debug) {
await fsp.rm(cacheDir, { recursive: true, force: true })
.catch(noop);
}
});
await prepareTest();
await testBody(t, driver, nodes, mockController, mockNodes);
}, 30000);
}
/** Performs an integration test with a real driver using a mock controller and one mock node */
export const integrationTest = ((name, options) => {
suite(name, options);
});
integrationTest.only = (name, options) => {
suite(name, options, "only");
};
integrationTest.skip = (name, options) => {
suite(name, options, "skip");
};
//# sourceMappingURL=integrationTestSuiteMulti.js.map