• Home
  • Features
  • Pricing
  • Docs
  • Announcements
  • Sign In

suculent / thinx-device-api / #252646769

01 Nov 2025 03:54PM UTC coverage: 71.357% (+25.1%) from 46.298%
#252646769

push

suculent
testing fixed broker URL configuration after MQTT upgrade

1841 of 3538 branches covered (52.04%)

Branch coverage included in aggregate %.

27 of 38 new or added lines in 1 file covered. (71.05%)

25 existing lines in 13 files now uncovered.

8169 of 10490 relevant lines covered (77.87%)

7.39 hits per line

Source File
Press 'n' to go to next uncovered line, 'b' for previous

99.48
/spec/jasmine/ZZ-RouterDeviceAPISpec.js
1
/* Router integration test only; does not have to cover full unit functionality. */
2

3
const THiNX = require("../../thinx-core.js");
1✔
4

5
let chai = require('chai');
1✔
6
var expect = require('chai').expect;
1✔
7
let chaiHttp = require('chai-http');
1✔
8
var envi = require("../_envi.json");
1✔
9
chai.use(chaiHttp);
1✔
10

11
let thx;
12

13
describe("Device API (noauth)", function () {
1✔
14

15
    beforeAll((done) => {
1✔
16
        console.log(`🚸 [chai] >>> running Device API (noauth) spec`);
1✔
17
        thx = new THiNX();
1✔
18
        thx.init(() => {
1✔
19
            done();
1✔
20
        });
21
    });
22

23
    it("POST /device/register A", function (done) {
1✔
24
        chai.request(thx.app)
1✔
25
            .post('/device/register')
26
            .send()
27
            .end((err, res) => {
28
                console.log("🚸 [chai] POST /device/register A response:", res.text);
1✔
29
                expect(res.status).to.equal(400);
1✔
30
                //expect(res.text).to.be.a('string');
31
                done();
1✔
32
            });
33
    }, 30000);
34

35
    it("POST /device/register B", function (done) {
1✔
36
        chai.request(thx.app)
1✔
37
            .post('/device/register')
38
            .send({ registration: {} })
39
            .end((err, res) => {
40
                console.log("🚸 [chai] POST /device/register B response:", res.text);
1✔
41
                expect(res.status).to.equal(400);
1✔
42
                //expect(res.text).to.be.a('string');
43
                done();
1✔
44
            });
45
    }, 30000);
46

47
    // must be fully mocked or run after build completes
48
    it("POST /device/firmware", function (done) {
1✔
49
        chai.request(thx.app)
1✔
50
            .post('/device/firmware')
51
            .send({})
52
            .end((err, res) => {
53
                expect(res.status).to.equal(200);
1✔
54
                expect(res.text).to.be.a('string');
1✔
55
                //{"success":false,"response":"missing_mac"}
56
                done();
1✔
57
            });
58
    }, 30000);
59

60
    it("POST /device/firmware OTT request", function (done) {
1✔
61
        chai.request(thx.app)
1✔
62
            .post('/device/firmware')
63
            .send({ use: "ott"})
64
            .end((err, res) => {
65
                console.log("🚸 [chai] POST /device/firmware OTT request", res.text, res.status);
1✔
66
                expect(res.status).to.equal(200);
1✔
67
                expect(res.text).to.be.a('string');
1✔
68
                //{"success":false,"response":"missing_mac"}
69
                done();
1✔
70
            });
71
    }, 30000);
72

73
    it("POST /device/addpush", function (done) {
1✔
74
        chai.request(thx.app)
1✔
75
            .post('/device/addpush')
76
            .send({ push: "31b1f6bf498d7cec463ff2588aca59a52df6f880e60e8d4d6bcda0d8e6e87823" })
77
            .end((err, res) => {
78
                console.log("🚸 [chai] device add Push registration", res.text, res.status);
1✔
79
                expect(res.status).to.equal(403);
1✔
80
                //expect(res.text).to.be.a('string');
81
                done();
1✔
82
            });
83
    }, 30000);
84

85

86

87
    // POST /api/device/envs
88
    it("POST /api/device/envs", function (done) {
1✔
89
        chai.request(thx.app)
1✔
90
            .post('/api/device/envs')
91
            .send({})
92
            .end((err, res) => {
93
                expect(res.status).to.equal(401);
1✔
94
                done();
1✔
95
            });
96
    }, 30000);
97

98
    it("POST /api/device/detail", function (done) {
1✔
99
        chai.request(thx.app)
1✔
100
            .post('/api/device/detail')
101
            .send({})
102
            .end((err, res) => {
103
                expect(res.status).to.equal(401);
1✔
104
                done();
1✔
105
            });
106
    }, 30000);
107

108
    it("POST /api/device/edit", function (done) {
1✔
109
        chai.request(thx.app)
1✔
110
            .post('/api/device/edit')
111
            .send({ changes: { alias: "edited-alias" } })
112
            .end((err, res) => {
113
                expect(res.status).to.equal(401);
1✔
114
                done();
1✔
115
            });
116
    }, 30000);
117

118
    it("GET /device/firmware", function (done) {
1✔
119
        chai.request(thx.app)
1✔
120
            .get('/device/firmware?ott=foo')
121
            .end((err, res) => {
122
                expect(res.status).to.equal(200);
1✔
123
                expect(res.text).to.be.a('string');
1✔
124
                expect(res.text).to.equal('OTT_UPDATE_NOT_FOUND');
1✔
125
                done();
1✔
126
            });
127
    }, 30000);
128
});
129

130
//
131
// Authenticated (requires JWT login and creating valid API Key as well for /device/ requests)
132
//
133

134
describe("Device + API (JWT+Key)", function () {
1✔
135

136
    let agent;
137
    let jwt = null;
1✔
138
    let ak = null;
1✔
139

140
    beforeAll((done) => {
1✔
141
        console.log(`🚸 [chai] >>> running Device + API (JWT+Key) spec`);
1✔
142
        agent = chai.request.agent(thx.app);
1✔
143
        agent
1✔
144
            .post('/api/login')
145
            .send({ username: 'dynamic', password: 'dynamic', remember: false })
146
            .then(function (res) {
147
                expect(res).to.have.cookie('x-thx-core');
1✔
148
                let body = JSON.parse(res.text);
1✔
149
                jwt = 'Bearer ' + body.access_token;
1✔
150

151

152
                agent
1✔
153
                    .post('/api/user/apikey')
154
                    .set('Authorization', jwt)
155
                    .send({
156
                        'alias': 'mock-apikey-alias'
157
                    })
158
                    .end((err, res) => {
159
                        //  {"success":true,"api_key":"9b7bd4f4eacf63d8453b32dbe982eea1fb8bbc4fc8e3bcccf2fc998f96138629","hash":"0a920b2e99a917a04d7961a28b49d05524d10cd8bdc2356c026cfc1c280ca22c"}
160
                        console.log("🚸 [chai] POST /api/user/apikey (authenticated), response...");
1✔
161
                        expect(res.status).to.equal(200);
1✔
162
                        let j = JSON.parse(res.text);
1✔
163
                        expect(j.success).to.equal(true);
1✔
164
                        expect(j.response.api_key).to.be.a('string');
1✔
165
                        expect(j.response.hash).to.be.a('string');
1✔
166
                        ak = j.response.hash;
1✔
167
                        console.log("[spec] saving apikey's hash (3) for device testing", j.response.hash);
1✔
168
                        done();
1✔
169
                    });
170
            })
UNCOV
171
            .catch((e) => { console.log(e); });
×
172
    });
173

174
    afterAll((done) => {
1✔
175
        agent.close();
1✔
176
        console.log(`🚸 [chai] <<< completed Device + API (JWT+Key) spec`);
1✔
177
        done();
1✔
178
    });
179

180
    var JRS6 = {
1✔
181
        mac: "66:66:66:66:66:66",
182
        firmware: "ZZ-RouterDeviceApiSpec.js",
183
        version: "1.0.0",
184
        alias: "test-device-6-dynamic",
185
        owner: envi.dynamic.owner,
186
        platform: "arduino"
187
      };
188

189
    it("POST /device/register (jwt, invalid body)", function (done) {
1✔
190
        chai.request(thx.app)
1✔
191
            .post('/device/register')
192
            .set('Authentication', ak)
193
            .send({ registration: {} })
194
            .end((err, res) => {
195
                expect(res.status).to.equal(400);
1✔
196
                expect(res.text).to.be.a('string');
1✔
197
                let j = JSON.parse(res.text);
1✔
198
                expect(j.success).to.equal(false);
1✔
199
                done();
1✔
200
            });
201
    }, 30000);
202

203
    it("POST /device/register (jwt, valid) 6", function (done) {
1✔
204

205
        chai.request(thx.app)
1✔
206
          .post('/device/register')
207
          .set('Authentication', ak)
208
          .send({ registration: JRS6 })
209
          .end((err, res) => {
210
            console.log("🚸 [chai] POST /device/register (jwt, valid) 6 response:", res.text);
1✔
211
            expect(res.status).to.equal(200);
1✔
212
            let r = JSON.parse(res.text);
1✔
213
            console.log("🚸 [chai] POST /device/register (jwt, valid) 6 response:", JSON.stringify(r));
1✔
214
            JRS6.udid = r.registration.udid;
1✔
215
            expect(res.text).to.be.a('string');
1✔
216
            done();
1✔
217
          });
218
      }, 30000);
219

220
    // must be fully mocked or run after build completes
221
    it("POST /device/firmware (jwt, invalid)", function (done) {
1✔
222
        chai.request(thx.app)
1✔
223
            .post('/device/firmware')
224
            .set('Authentication', ak)
225
            .send({})
226
            .end((err, res) => {
227
                expect(res.status).to.equal(200);
1✔
228
                expect(res.text).to.be.a('string');
1✔
229
                //{"success":false,"response":"missing_mac"}
230
                done();
1✔
231
            });
232
    }, 30000);
233

234
    it("POST /device/addpush (jwt, invalid)", function (done) {
1✔
235
        chai.request(thx.app)
1✔
236
            .post('/device/addpush')
237
            .set('Authentication', ak)
238
            .send({})
239
            .end((err, res) => {
240
                expect(res.status).to.equal(200);
1✔
241
                //expect(res.text).to.be.a('string');
242
                done();
1✔
243
            });
244
    }, 30000);
245

246
    it("POST /device/addpush (jwt, valid)", function (done) {
1✔
247
        chai.request(thx.app)
1✔
248
            .post('/device/addpush')
249
            .set('Authentication', ak)
250
            .send({ push: "31b1f6bf498d7cec463ff2588aca59a52df6f880e60e8d4d6bcda0d8e6e87823", udid: envi.udid })
251
            .end((err, res) => {
252
                console.log("🚸 [chai] POST /device/addpush (jwt, valid)", res.status, res.text);
1✔
253
                expect(res.status).to.equal(200);
1✔
254
                //expect(res.text).to.equal('false'); // in case of no error
255
                done();
1✔
256
            });
257
    }, 30000);
258

259
    it("GET /device/firmware (ak, invalid)", function (done) {
1✔
260
        chai.request(thx.app)
1✔
261
            .get('/device/firmware?ott=foo')
262
            .end((err, res) => {
263
                console.log("🚸 [chai] GET /device/firmware (ak, invalid)", res.status, res.text);
1✔
264
                expect(res.status).to.equal(200);
1✔
265
                expect(res.text).to.be.a('string');
1✔
266
                expect(res.text).to.equal('OTT_UPDATE_NOT_FOUND');
1✔
267
                done();
1✔
268
            });
269
    }, 30000);
270

271
    it("GET /device/firmware (ak, none)", function (done) {
1✔
272
        chai.request(thx.app)
1✔
273
            .get('/device/firmware')
274
            .set('Authentication', ak)
275
            .end((err, res) => {
276
                console.log("🚸 [chai] GET /device/firmware (ak, none)", res.status, res.text);
1✔
277
                expect(res.status).to.equal(200);
1✔
278
                expect(res.text).to.be.a('string');
1✔
279
                expect(res.text).to.equal('{"success":false,"response":"OTT_MISSING"}');
1✔
280
                done();
1✔
281
            });
282
    }, 30000);
283

284
    it("GET /device/firmware (ak, valid)", function (done) {
1✔
285
        chai.request(thx.app)
1✔
286
            .get('/device/firmware?ott=foo')
287
            .set('Authentication', ak)
288
            .end((err, res) => {
289
                console.log("🚸 [chai] GET /device/firmware (ak, valid)", res.status, res.text);
1✔
290
                expect(res.status).to.equal(200);
1✔
291
                expect(res.text).to.be.a('string');
1✔
292
                expect(res.text).to.equal('OTT_UPDATE_NOT_FOUND');
1✔
293
                done();
1✔
294
            });
295
    }, 30000);
296

297
    // Device Control API
298

299
    it("POST /api/device/envs (jwt, invalid)", function (done) {
1✔
300
        chai.request(thx.app)
1✔
301
            .post('/api/device/envs')
302
            .set('Authorization', jwt)
303
            .send({})
304
            .end((err, res) => {
305
                console.log("🚸 [chai] POST /api/device/envs (jwt, invalid) response:", res.text, " status:", res.status);
1✔
306
                //expect(res.status).to.equal(200);
307
                //expect(res.text).to.be.a('string');
308
                done();
1✔
309
            });
310
    }, 30000);
311

312
    it("POST /api/device/envs (jwt, valid)", function (done) {
1✔
313
        chai.request(thx.app)
1✔
314
            .post('/api/device/envs')
315
            .set('Authorization', jwt)
316
            .send({ udid: JRS6.udid })
317
            .end((err, res) => {
318
                console.log("🚸 [chai] POST /api/device/envs (jwt, valid) response:", res.text, " status:", res.status);
1✔
319
                //expect(res.status).to.equal(200);
320
                //expect(res.text).to.be.a('string');
321
                done();
1✔
322
            });
323
    }, 30000);
324

325
    it("POST /api/device/detail (jwt, invalid)", function (done) {
1✔
326
        chai.request(thx.app)
1✔
327
            .post('/api/device/detail')
328
            .set('Authorization', jwt)
329
            .send({})
330
            .end((err, res) => {
331
                expect(res.status).to.equal(400);
1✔
332
                //expect(res.text).to.be.a('string');
333
                done();
1✔
334
            });
335
    }, 30000);
336

337
    it("POST /api/device/detail (jwt, valid)", function (done) {
1✔
338
        chai.request(thx.app)
1✔
339
            .post('/api/device/detail')
340
            .set('Authorization', jwt)
341
            .send({ udid: JRS6.udid })
342
            .end((err, res) => {
343
                expect(res.status).to.equal(200);
1✔
344
                expect(res.text).to.be.a('string');
1✔
345
                done();
1✔
346
            });
347
    }, 30000);
348

349
    it("POST /api/device/edit (jwt, invalid)", function (done) {
1✔
350
        chai.request(thx.app)
1✔
351
            .post('/api/device/edit')
352
            .set('Authentication', ak)
353
            .send({ changes: { alias: "edited-alias" } })
354
            .end((err, res) => {
355
                console.log("🚸 [chai] POST /api/device/edit (jwt, invalid) response:", res.text, "status", res.status);
1✔
356
                //expect(res.status).to.equal(401);
357
                done();
1✔
358
            });
359
    }, 30000);
360

361
    it("POST /api/device/edit (jwt, valid)", function (done) {
1✔
362
        chai.request(thx.app)
1✔
363
            .post('/api/device/edit')
364
            .set('Authentication', ak)
365
            .send({ changes: { alias: "edited-alias" }, udid: JRS6.udid })
366
            .end((err, res) => {
367
                console.log("🚸 [chai] POST /api/device/edit (jwt, valid) response:", res.text, " status:", res.status);
1✔
368
                //expect(res.status).to.equal(200);
369
                //expect(res.text).to.be.a('string');
370
                done();
1✔
371
            });
372
    }, 30000);
373

374
    //
375
    // Authenticated (Session)
376
    //
377

378
    it("POST /api/device/envs (session, invalid)", function (done) {
1✔
379
        agent
1✔
380
            .post('/api/device/envs')
381
            .send({})
382
            .end((err, res) => {
383
                console.log("🚸 [chai] POST /api/device/envs (session, invalid) response:", res.text, " status:", res.status);
1✔
384
                //expect(res.status).to.equal(401);
385
                done();
1✔
386
            });
387
    }, 30000);
388

389
    it("POST /api/device/envs (session, valid)", function (done) {
1✔
390
        agent
1✔
391
            .post('/api/device/envs')
392
            .send({ udid: envi.udid })
393
            .end((err, res) => {
394
                console.log("🚸 [chai] POST /api/device/envs (session, valid) response:", res.text, " status:", res.status);
1✔
395
                //expect(res.status).to.equal(200);
396
                //expect(res.text).to.be.a('string');
397
                done();
1✔
398
            });
399
    }, 30000);
400

401
    it("POST /api/device/envs (session, valid, no-such-device) 2", function (done) {
1✔
402
        agent
1✔
403
            .post('/api/device/envs')
404
            .send({ udid: envi.dynamic.udid })
405
            .end((err, res) => {
406
                console.log("🚸 [chai] POST /api/device/envs (session, valid) 2 response:", res.text, " status:", res.status);
1✔
407
                //expect(res.status).to.equal(200);
408
                //expect(res.text).to.be.a('string');
409
                done();
1✔
410
            });
411
    }, 30000);
412

413
    it("POST /api/device/detail (session, valid)", function (done) {
1✔
414
        agent
1✔
415
            .post('/api/device/detail')
416
            .send({})
417
            .end((err, res) => {
418
                console.log("🚸 [chai] POST /api/device/detail (session, valid) response:", res.text, " status:", res.status);
1✔
419
                //expect(res.status).to.equal(200);
420
                //expect(res.text).to.be.a('string');
421
                done();
1✔
422
            });
423
    }, 30000);
424

425
    it("POST /api/device/detail (session, dynamic)", function (done) {
1✔
426
        agent
1✔
427
            .post('/api/device/detail')
428
            .send({ udid: envi.dynamic.udid })
429
            .end((err, res) => {
430
                expect(res.status).to.equal(401);
1✔
431
                expect(res.text).to.be.a('string');
1✔
432
                done();
1✔
433
            });
434
    }, 30000);
435

436
    it("POST /api/device/detail (session, udid) 2", function (done) {
1✔
437
        agent
1✔
438
            .post('/api/device/detail')
439
            .send({ udid: envi.udid })
440
            .end((err, res) => {
441
                console.log("🚸 [chai] POST /api/device/detail (session, udid) 2 response:", res.text, " status:", res.status);
1✔
442
                done();
1✔
443
            });
444
    }, 30000);
445

446
    it("POST /api/device/edit (session, invalid)", function (done) {
1✔
447
        agent
1✔
448
            .post('/api/device/edit')
449
            .send({ changes: { alias: "edited-alias" } })
450
            .end((err, res) => {
451
                console.log("🚸 [chai] POST /api/device/edit (session, invalid) response:", res.text, " status:", res.status);
1✔
452
                done();
1✔
453
            });
454
    }, 30000);
455

456
    it("POST /api/device/edit (session, valid)", function (done) {
1✔
457
        agent
1✔
458
            .post('/api/device/edit')
459
            .send({ changes: { alias: "edited-alias" }, udid: JRS6.udid })
460
            .end((err, res) => {
461
                console.log("🚸 [chai] POST /api/device/edit (session, valid) response:", res.text, " status:", res.status);
1✔
462
                //expect(res.status).to.equal(200);
463
                //expect(res.text).to.be.a('string');
464
                done();
1✔
465
            });
466
    }, 30000);
467

468
    
469

470

471
});
STATUS · Troubleshooting · Open an Issue · Sales · Support · CAREERS · ENTERPRISE · START FREE · SCHEDULE DEMO
ANNOUNCEMENTS · TWITTER · TOS & SLA · Supported CI Services · What's a CI service? · Automated Testing

© 2026 Coveralls, Inc