github.com/simpleiot/simpleiot@v0.18.3/frontend/lib/test.mjs (about) 1 import assert from "node:assert" 2 import WebSocket from "ws" 3 import { connect } from "./siot-nats.mjs" 4 5 import { inspect } from "node:util" 6 inspect.defaultOptions.depth = 10 7 // Using the Mocha test framework: https://mochajs.org/ 8 9 // Tell eslint about the additional globals that will be used 10 /* global global, it, describe, before */ 11 12 global.WebSocket = WebSocket 13 let c, rootID, adminID 14 15 it("connects", async () => { 16 c = await connect() 17 }) 18 describe("simpleiot-js", () => { 19 // abort tests if connection failed 20 before(function () { 21 if (!c) { 22 this.skip() 23 } 24 }) 25 26 it("gets root node", async () => { 27 const roots = await c.getNodeChildren("root") 28 assert.strictEqual(roots.length, 1, "should have 1 root") 29 30 // Check root node 31 const [root] = roots 32 assert.strictEqual(root.type, "device", "root type should be 'device'") 33 assert.strictEqual(root.parent, "root", "root parent should be 'root'") 34 assert.strictEqual(root.edgepointsList.length, 1, "should have 1 edgepoint") 35 const [tombstone] = root.edgepointsList 36 assert.strictEqual(tombstone.type, "tombstone", "should have tombstone") 37 assert.strictEqual(tombstone.tombstone, 0, "tombstone is 0") 38 39 rootID = root.id 40 }) 41 42 it("gets root node by ID", async function () { 43 if (!rootID) { 44 return this.skip() 45 } 46 47 const roots = await c.getNode(rootID) 48 assert.strictEqual(roots.length, 1, "should have 1 root") 49 50 const [root] = roots 51 assert.strictEqual(root.id, rootID, "root id should match") 52 assert.strictEqual(root.type, "device", "root type should be 'device'") 53 assert.strictEqual(root.parent, "root", "parent should be root") 54 assert.strictEqual( 55 root.edgepointsList.length, 56 1, 57 "only tombstone edge point" 58 ) 59 assert.strictEqual( 60 root.edgepointsList[0].type, 61 "tombstone", 62 "edge point should be tombstone" 63 ) 64 assert.strictEqual(root.edgepointsList[0].value, 0, "tombstone should be 0") 65 }) 66 67 it("gets nodes recursively", async () => { 68 const roots = await c.getNodeChildren("root", { recursive: true }) 69 assert.strictEqual(roots.length, 1, "should have 1 root") 70 71 // Check root node 72 const [root] = roots 73 assert.strictEqual(root.children.length, 1, "root should have 1 child") 74 const [user] = root.children 75 assert.strictEqual(user.type, "user", "child node type should be 'user'") 76 assert.strictEqual(user.parent, root.id, "invalid parent") 77 const [tombstone] = root.edgepointsList 78 assert.strictEqual(tombstone.type, "tombstone", "should have tombstone") 79 assert.strictEqual(tombstone.tombstone, 0, "tombstone is 0") 80 81 // Check default points 82 const { text: first } = user.pointsList.find((p) => p.type === "firstName") 83 assert.strictEqual( 84 first, 85 "admin", 86 "firstName of admin user is not default value" 87 ) 88 const { text: email } = user.pointsList.find((p) => p.type === "email") 89 assert.strictEqual( 90 email, 91 "admin", 92 "email of admin user is not default value" 93 ) 94 95 adminID = user.id 96 }) 97 98 it("publishes points for user name", async function () { 99 if (!adminID) { 100 return this.skip() 101 } 102 await c.sendNodePoints( 103 adminID, 104 [ 105 { type: "firstName", text: "John" }, 106 { type: "lastName", text: "Doe" }, 107 ], 108 { ack: true } 109 ) 110 111 // Get updated node 112 const [user] = await c.getNode(adminID) 113 const first = user.pointsList.find((p) => p.type === "firstName") 114 const last = user.pointsList.find((p) => p.type === "lastName") 115 assert.strictEqual(first.text, "John", "unchanged firstName " + first.text) 116 assert.strictEqual(last.text, "Doe", "unchanged lastName " + last.text) 117 }) 118 119 const nodeID = "faux-sensor-1" 120 it("creates a device node", async function () { 121 if (!rootID) { 122 return this.skip() 123 } 124 125 // Create `nodeID` 126 await c.sendNodePoints( 127 nodeID, 128 [{ type: "description", text: nodeID + " (created by test suite)" }], 129 { ack: true } 130 ) 131 await c.sendEdgePoints( 132 nodeID, 133 rootID, 134 [{ type: "tombstone" }, { type: "nodeType", text: "device" }], 135 { 136 ack: true, 137 } 138 ) 139 }) 140 141 it("subscribes / publishes node points", async function () { 142 const ITERATIONS = 10 143 let temperature = 30 144 let humidity = 55 145 let pointsRx = 0 146 147 // Subscribe and start reading points asynchronously 148 const sub = c.subscribePoints(nodeID) 149 const readPromise = (async function readPoints() { 150 for await (const { points } of sub) { 151 points.forEach((p) => { 152 if (p.type === "temperature") { 153 assert.strictEqual(p.value, temperature) 154 } else if (p.type === "humidity") { 155 assert.strictEqual(p.value, humidity) 156 } else { 157 throw new Error("unknown point type: " + p.type) 158 } 159 pointsRx++ 160 }) 161 } 162 })() 163 // Note: Add no-op `catch` to avoid unhandled Promise rejection 164 readPromise.catch((err) => {}) 165 166 // Send out node points 167 for (let i = 0; i < ITERATIONS; i++) { 168 await c.sendNodePoints( 169 nodeID, 170 [ 171 { type: "temperature", value: ++temperature }, 172 { type: "humidity", value: ++humidity }, 173 ], 174 { ack: true } 175 ) 176 } 177 178 // Close subscription and handle errors 179 await sub.close() 180 await readPromise 181 182 // Check to ensure we read all points 183 assert.strictEqual( 184 pointsRx, 185 ITERATIONS * 2, 186 "did not receive all published points" 187 ) 188 }) 189 190 it("closes", async () => { 191 await c.close() 192 }) 193 })