edilkamin 1.7.2 → 1.7.3

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.
@@ -1,6 +1,5 @@
1
1
  import { strict as assert } from "assert";
2
2
  import * as amplifyAuth from "aws-amplify/auth";
3
- import axios from "axios";
4
3
  import pako from "pako";
5
4
  import sinon from "sinon";
6
5
 
@@ -21,16 +20,23 @@ const createGzippedBuffer = (
21
20
  };
22
21
  };
23
22
 
23
+ /**
24
+ * Helper to create a mock Response object for fetch.
25
+ */
26
+ const mockResponse = (data: unknown, status = 200): Response =>
27
+ ({
28
+ ok: status >= 200 && status < 300,
29
+ status,
30
+ statusText: status >= 200 && status < 300 ? "OK" : "Error",
31
+ json: () => Promise.resolve(data),
32
+ }) as Response;
33
+
24
34
  describe("library", () => {
25
- let axiosStub: sinon.SinonStub;
35
+ let fetchStub: sinon.SinonStub;
26
36
  const expectedToken = "mockJwtToken";
27
37
 
28
38
  beforeEach(() => {
29
- axiosStub = sinon.stub(axios, "create").returns({
30
- get: sinon.stub(),
31
- put: sinon.stub(),
32
- // eslint-disable-next-line @typescript-eslint/no-explicit-any
33
- } as any);
39
+ fetchStub = sinon.stub(globalThis, "fetch");
34
40
  });
35
41
 
36
42
  afterEach(() => {
@@ -207,28 +213,24 @@ describe("library", () => {
207
213
  "getTargetTemperature",
208
214
  "setTargetTemperature",
209
215
  ];
210
- it("should create API methods with the correct baseURL", () => {
211
- const baseURL = "https://example.com/api";
216
+ it("should create API methods with the correct baseURL", async () => {
217
+ const baseURL = "https://example.com/api/";
218
+ fetchStub.resolves(mockResponse({ test: "data" }));
212
219
  const api = configure(baseURL);
213
- assert.deepEqual(axiosStub.args, [
214
- [
215
- {
216
- baseURL,
217
- },
218
- ],
219
- ]);
220
220
  assert.deepEqual(Object.keys(api), expectedApi);
221
+ // Verify baseURL is used when making a request
222
+ await api.deviceInfo(expectedToken, "mockMac");
223
+ assert.ok(fetchStub.calledOnce);
224
+ assert.ok(fetchStub.firstCall.args[0].startsWith(baseURL));
221
225
  });
222
- it("should create API methods with the default baseURL", () => {
226
+ it("should create API methods with the default baseURL", async () => {
227
+ fetchStub.resolves(mockResponse({ test: "data" }));
223
228
  const api = configure();
224
- assert.deepEqual(axiosStub.args, [
225
- [
226
- {
227
- baseURL: API_URL,
228
- },
229
- ],
230
- ]);
231
229
  assert.deepEqual(Object.keys(api), expectedApi);
230
+ // Verify default baseURL is used when making a request
231
+ await api.deviceInfo(expectedToken, "mockMac");
232
+ assert.ok(fetchStub.calledOnce);
233
+ assert.ok(fetchStub.firstCall.args[0].startsWith(API_URL));
232
234
  });
233
235
  });
234
236
 
@@ -249,19 +251,19 @@ describe("library", () => {
249
251
  },
250
252
  };
251
253
 
252
- it("should call axios for deviceInfo", async () => {
253
- const mockAxios = {
254
- get: sinon.stub().resolves({ data: mockDeviceInfo }),
255
- };
256
- axiosStub.returns(mockAxios);
257
- const api = configure("https://example.com/api");
254
+ it("should call fetch for deviceInfo", async () => {
255
+ fetchStub.resolves(mockResponse(mockDeviceInfo));
256
+ const api = configure("https://example.com/api/");
258
257
  const result = await api.deviceInfo(expectedToken, "mockMacAddress");
259
- assert.deepEqual(mockAxios.get.args, [
260
- [
261
- "device/mockMacAddress/info",
262
- { headers: { Authorization: `Bearer ${expectedToken}` } },
263
- ],
264
- ]);
258
+ assert.ok(fetchStub.calledOnce);
259
+ assert.equal(
260
+ fetchStub.firstCall.args[0],
261
+ "https://example.com/api/device/mockMacAddress/info",
262
+ );
263
+ assert.deepEqual(fetchStub.firstCall.args[1], {
264
+ method: "GET",
265
+ headers: { Authorization: `Bearer ${expectedToken}` },
266
+ });
265
267
  assert.deepEqual(result, mockDeviceInfo);
266
268
  });
267
269
 
@@ -280,29 +282,29 @@ describe("library", () => {
280
282
  expectedValue: 0,
281
283
  },
282
284
  ].forEach(({ method, call, expectedValue }) => {
283
- it(`should call axios for ${method}`, async () => {
284
- const mockAxios = {
285
- put: sinon.stub().resolves({ status: 200 }),
286
- };
287
- axiosStub.returns(mockAxios);
288
- const api = configure("https://example.com/api");
285
+ it(`should call fetch for ${method}`, async () => {
286
+ fetchStub.resolves(mockResponse({ success: true }));
287
+ const api = configure("https://example.com/api/");
289
288
 
290
289
  // Invoke the method using the mapped call function
291
- const result = await call(api);
292
- assert.deepEqual(mockAxios.put.args, [
293
- [
294
- "mqtt/command",
295
- {
296
- mac_address: "mockMacAddress",
297
- name: "power",
298
- value: expectedValue,
299
- },
300
- {
301
- headers: { Authorization: "Bearer mockToken" },
302
- },
303
- ],
304
- ]);
305
- assert.equal(result.status, 200);
290
+ await call(api);
291
+ assert.ok(fetchStub.calledOnce);
292
+ assert.equal(
293
+ fetchStub.firstCall.args[0],
294
+ "https://example.com/api/mqtt/command",
295
+ );
296
+ assert.deepEqual(fetchStub.firstCall.args[1], {
297
+ method: "PUT",
298
+ headers: {
299
+ "Content-Type": "application/json",
300
+ Authorization: "Bearer mockToken",
301
+ },
302
+ body: JSON.stringify({
303
+ mac_address: "mockMacAddress",
304
+ name: "power",
305
+ value: expectedValue,
306
+ }),
307
+ });
306
308
  });
307
309
  });
308
310
 
@@ -327,21 +329,21 @@ describe("library", () => {
327
329
  },
328
330
  ];
329
331
  getterTests.forEach(({ method, call, expectedResult }) => {
330
- it(`should call axios and return the correct value for ${method}`, async () => {
331
- const mockAxios = {
332
- get: sinon.stub().resolves({ data: mockDeviceInfo }),
333
- };
334
- axiosStub.returns(mockAxios);
335
- const api = configure("https://example.com/api");
332
+ it(`should call fetch and return the correct value for ${method}`, async () => {
333
+ fetchStub.resolves(mockResponse(mockDeviceInfo));
334
+ const api = configure("https://example.com/api/");
336
335
 
337
336
  const result = await call(api, expectedToken, "mockMacAddress");
338
337
 
339
- assert.deepEqual(mockAxios.get.args, [
340
- [
341
- "device/mockMacAddress/info",
342
- { headers: { Authorization: `Bearer ${expectedToken}` } },
343
- ],
344
- ]);
338
+ assert.ok(fetchStub.calledOnce);
339
+ assert.equal(
340
+ fetchStub.firstCall.args[0],
341
+ "https://example.com/api/device/mockMacAddress/info",
342
+ );
343
+ assert.deepEqual(fetchStub.firstCall.args[1], {
344
+ method: "GET",
345
+ headers: { Authorization: `Bearer ${expectedToken}` },
346
+ });
345
347
  assert.equal(result, expectedResult);
346
348
  });
347
349
  });
@@ -362,52 +364,42 @@ describe("library", () => {
362
364
  },
363
365
  ];
364
366
  setterTests.forEach(({ method, call, payload }) => {
365
- it(`should call axios and send the correct payload for ${method}`, async () => {
366
- const mockAxios = {
367
- put: sinon.stub().resolves({ status: 200 }),
368
- };
369
- axiosStub.returns(mockAxios);
370
- const api = configure("https://example.com/api");
371
-
372
- const result = await call(
373
- api,
374
- expectedToken,
375
- "mockMacAddress",
376
- payload.value,
377
- );
367
+ it(`should call fetch and send the correct payload for ${method}`, async () => {
368
+ fetchStub.resolves(mockResponse({ success: true }));
369
+ const api = configure("https://example.com/api/");
378
370
 
379
- assert.deepEqual(mockAxios.put.args, [
380
- [
381
- "mqtt/command",
382
- {
383
- mac_address: "mockMacAddress",
384
- ...payload,
385
- },
386
- {
387
- headers: { Authorization: `Bearer ${expectedToken}` },
388
- },
389
- ],
390
- ]);
391
- assert.equal(result.status, 200);
371
+ await call(api, expectedToken, "mockMacAddress", payload.value);
372
+
373
+ assert.ok(fetchStub.calledOnce);
374
+ assert.equal(
375
+ fetchStub.firstCall.args[0],
376
+ "https://example.com/api/mqtt/command",
377
+ );
378
+ assert.deepEqual(fetchStub.firstCall.args[1], {
379
+ method: "PUT",
380
+ headers: {
381
+ "Content-Type": "application/json",
382
+ Authorization: `Bearer ${expectedToken}`,
383
+ },
384
+ body: JSON.stringify({
385
+ mac_address: "mockMacAddress",
386
+ ...payload,
387
+ }),
388
+ });
392
389
  });
393
390
  });
394
391
  });
395
392
 
396
393
  describe("registerDevice", () => {
397
394
  it("should call POST /device with correct payload", async () => {
398
- const mockResponse = {
395
+ const mockResponseData = {
399
396
  macAddress: "AABBCCDDEEFF",
400
397
  deviceName: "Test Stove",
401
398
  deviceRoom: "Living Room",
402
399
  serialNumber: "EDK123",
403
400
  };
404
- const mockAxios = {
405
- post: sinon.stub().resolves({ data: mockResponse }),
406
- get: sinon.stub(),
407
- put: sinon.stub(),
408
- };
409
- axiosStub.returns(mockAxios);
410
- const api = configure("https://example.com/api");
401
+ fetchStub.resolves(mockResponse(mockResponseData));
402
+ const api = configure("https://example.com/api/");
411
403
 
412
404
  const result = await api.registerDevice(
413
405
  expectedToken,
@@ -417,66 +409,59 @@ describe("library", () => {
417
409
  "Living Room",
418
410
  );
419
411
 
420
- assert.deepEqual(mockAxios.post.args, [
421
- [
422
- "device",
423
- {
424
- macAddress: "AABBCCDDEEFF",
425
- deviceName: "Test Stove",
426
- deviceRoom: "Living Room",
427
- serialNumber: "EDK123",
428
- },
429
- { headers: { Authorization: `Bearer ${expectedToken}` } },
430
- ],
431
- ]);
432
- assert.deepEqual(result, mockResponse);
412
+ assert.ok(fetchStub.calledOnce);
413
+ assert.equal(
414
+ fetchStub.firstCall.args[0],
415
+ "https://example.com/api/device",
416
+ );
417
+ assert.deepEqual(fetchStub.firstCall.args[1], {
418
+ method: "POST",
419
+ headers: {
420
+ "Content-Type": "application/json",
421
+ Authorization: `Bearer ${expectedToken}`,
422
+ },
423
+ body: JSON.stringify({
424
+ macAddress: "AABBCCDDEEFF",
425
+ deviceName: "Test Stove",
426
+ deviceRoom: "Living Room",
427
+ serialNumber: "EDK123",
428
+ }),
429
+ });
430
+ assert.deepEqual(result, mockResponseData);
433
431
  });
434
432
 
435
433
  it("should normalize MAC address by removing colons", async () => {
436
- const mockAxios = {
437
- post: sinon.stub().resolves({ data: {} }),
438
- get: sinon.stub(),
439
- put: sinon.stub(),
440
- };
441
- axiosStub.returns(mockAxios);
442
- const api = configure("https://example.com/api");
434
+ fetchStub.resolves(mockResponse({}));
435
+ const api = configure("https://example.com/api/");
443
436
 
444
437
  await api.registerDevice(expectedToken, "AA:BB:CC:DD:EE:FF", "EDK123");
445
438
 
446
- assert.equal(mockAxios.post.args[0][1].macAddress, "AABBCCDDEEFF");
439
+ const body = JSON.parse(fetchStub.firstCall.args[1].body);
440
+ assert.equal(body.macAddress, "AABBCCDDEEFF");
447
441
  });
448
442
 
449
443
  it("should use empty strings as defaults for name and room", async () => {
450
- const mockAxios = {
451
- post: sinon.stub().resolves({ data: {} }),
452
- get: sinon.stub(),
453
- put: sinon.stub(),
454
- };
455
- axiosStub.returns(mockAxios);
456
- const api = configure("https://example.com/api");
444
+ fetchStub.resolves(mockResponse({}));
445
+ const api = configure("https://example.com/api/");
457
446
 
458
447
  await api.registerDevice(expectedToken, "AABBCCDDEEFF", "EDK123");
459
448
 
460
- assert.equal(mockAxios.post.args[0][1].deviceName, "");
461
- assert.equal(mockAxios.post.args[0][1].deviceRoom, "");
449
+ const body = JSON.parse(fetchStub.firstCall.args[1].body);
450
+ assert.equal(body.deviceName, "");
451
+ assert.equal(body.deviceRoom, "");
462
452
  });
463
453
  });
464
454
 
465
455
  describe("editDevice", () => {
466
456
  it("should call PUT /device/{mac} with correct payload", async () => {
467
- const mockResponse = {
457
+ const mockResponseData = {
468
458
  macAddress: "AABBCCDDEEFF",
469
459
  deviceName: "Updated Name",
470
460
  deviceRoom: "Basement",
471
461
  serialNumber: "EDK123",
472
462
  };
473
- const mockAxios = {
474
- put: sinon.stub().resolves({ data: mockResponse }),
475
- get: sinon.stub(),
476
- post: sinon.stub(),
477
- };
478
- axiosStub.returns(mockAxios);
479
- const api = configure("https://example.com/api");
463
+ fetchStub.resolves(mockResponse(mockResponseData));
464
+ const api = configure("https://example.com/api/");
480
465
 
481
466
  const result = await api.editDevice(
482
467
  expectedToken,
@@ -485,32 +470,34 @@ describe("library", () => {
485
470
  "Basement",
486
471
  );
487
472
 
488
- assert.deepEqual(mockAxios.put.args, [
489
- [
490
- "device/AABBCCDDEEFF",
491
- {
492
- deviceName: "Updated Name",
493
- deviceRoom: "Basement",
494
- },
495
- { headers: { Authorization: `Bearer ${expectedToken}` } },
496
- ],
497
- ]);
498
- assert.deepEqual(result, mockResponse);
473
+ assert.ok(fetchStub.calledOnce);
474
+ assert.equal(
475
+ fetchStub.firstCall.args[0],
476
+ "https://example.com/api/device/AABBCCDDEEFF",
477
+ );
478
+ assert.deepEqual(fetchStub.firstCall.args[1], {
479
+ method: "PUT",
480
+ headers: {
481
+ "Content-Type": "application/json",
482
+ Authorization: `Bearer ${expectedToken}`,
483
+ },
484
+ body: JSON.stringify({
485
+ deviceName: "Updated Name",
486
+ deviceRoom: "Basement",
487
+ }),
488
+ });
489
+ assert.deepEqual(result, mockResponseData);
499
490
  });
500
491
 
501
492
  it("should use empty strings as defaults for name and room", async () => {
502
- const mockAxios = {
503
- put: sinon.stub().resolves({ data: {} }),
504
- get: sinon.stub(),
505
- post: sinon.stub(),
506
- };
507
- axiosStub.returns(mockAxios);
508
- const api = configure("https://example.com/api");
493
+ fetchStub.resolves(mockResponse({}));
494
+ const api = configure("https://example.com/api/");
509
495
 
510
496
  await api.editDevice(expectedToken, "AABBCCDDEEFF");
511
497
 
512
- assert.equal(mockAxios.put.args[0][1].deviceName, "");
513
- assert.equal(mockAxios.put.args[0][1].deviceRoom, "");
498
+ const body = JSON.parse(fetchStub.firstCall.args[1].body);
499
+ assert.equal(body.deviceName, "");
500
+ assert.equal(body.deviceRoom, "");
514
501
  });
515
502
  });
516
503
 
@@ -520,7 +507,7 @@ describe("library", () => {
520
507
  commands: { power: true },
521
508
  temperatures: { enviroment: 19, board: 25 },
522
509
  };
523
- const mockResponse = {
510
+ const mockResponseData = {
524
511
  status: createGzippedBuffer(statusData),
525
512
  nvm: {
526
513
  user_parameters: {
@@ -529,11 +516,8 @@ describe("library", () => {
529
516
  },
530
517
  };
531
518
 
532
- const mockAxios = {
533
- get: sinon.stub().resolves({ data: mockResponse }),
534
- };
535
- axiosStub.returns(mockAxios);
536
- const api = configure("https://example.com/api");
519
+ fetchStub.resolves(mockResponse(mockResponseData));
520
+ const api = configure("https://example.com/api/");
537
521
 
538
522
  const result = await api.deviceInfo(expectedToken, "mockMacAddress");
539
523
 
@@ -550,7 +534,7 @@ describe("library", () => {
550
534
  is_sound_active: true,
551
535
  },
552
536
  };
553
- const mockResponse = {
537
+ const mockResponseData = {
554
538
  status: {
555
539
  commands: { power: true },
556
540
  temperatures: { enviroment: 19 },
@@ -558,11 +542,8 @@ describe("library", () => {
558
542
  nvm: createGzippedBuffer(nvmData),
559
543
  };
560
544
 
561
- const mockAxios = {
562
- get: sinon.stub().resolves({ data: mockResponse }),
563
- };
564
- axiosStub.returns(mockAxios);
565
- const api = configure("https://example.com/api");
545
+ fetchStub.resolves(mockResponse(mockResponseData));
546
+ const api = configure("https://example.com/api/");
566
547
 
567
548
  const result = await api.deviceInfo(expectedToken, "mockMacAddress");
568
549
 
@@ -583,16 +564,13 @@ describe("library", () => {
583
564
  is_sound_active: false,
584
565
  },
585
566
  };
586
- const mockResponse = {
567
+ const mockResponseData = {
587
568
  status: createGzippedBuffer(statusData),
588
569
  nvm: createGzippedBuffer(nvmData),
589
570
  };
590
571
 
591
- const mockAxios = {
592
- get: sinon.stub().resolves({ data: mockResponse }),
593
- };
594
- axiosStub.returns(mockAxios);
595
- const api = configure("https://example.com/api");
572
+ fetchStub.resolves(mockResponse(mockResponseData));
573
+ const api = configure("https://example.com/api/");
596
574
 
597
575
  const result = await api.deviceInfo(expectedToken, "mockMacAddress");
598
576
 
@@ -605,16 +583,13 @@ describe("library", () => {
605
583
  commands: { power: true },
606
584
  temperatures: { enviroment: 19 },
607
585
  };
608
- const mockResponse = {
586
+ const mockResponseData = {
609
587
  status: createGzippedBuffer(statusData),
610
588
  nvm: { user_parameters: { enviroment_1_temperature: 22 } },
611
589
  };
612
590
 
613
- const mockAxios = {
614
- get: sinon.stub().resolves({ data: mockResponse }),
615
- };
616
- axiosStub.returns(mockAxios);
617
- const api = configure("https://example.com/api");
591
+ fetchStub.resolves(mockResponse(mockResponseData));
592
+ const api = configure("https://example.com/api/");
618
593
 
619
594
  const result = await api.getPower(expectedToken, "mockMacAddress");
620
595
 
@@ -626,16 +601,13 @@ describe("library", () => {
626
601
  commands: { power: true },
627
602
  temperatures: { enviroment: 19, board: 25 },
628
603
  };
629
- const mockResponse = {
604
+ const mockResponseData = {
630
605
  status: createGzippedBuffer(statusData),
631
606
  nvm: { user_parameters: { enviroment_1_temperature: 22 } },
632
607
  };
633
608
 
634
- const mockAxios = {
635
- get: sinon.stub().resolves({ data: mockResponse }),
636
- };
637
- axiosStub.returns(mockAxios);
638
- const api = configure("https://example.com/api");
609
+ fetchStub.resolves(mockResponse(mockResponseData));
610
+ const api = configure("https://example.com/api/");
639
611
 
640
612
  const result = await api.getEnvironmentTemperature(
641
613
  expectedToken,
@@ -651,16 +623,13 @@ describe("library", () => {
651
623
  enviroment_1_temperature: 22,
652
624
  },
653
625
  };
654
- const mockResponse = {
626
+ const mockResponseData = {
655
627
  status: { commands: { power: true }, temperatures: { enviroment: 19 } },
656
628
  nvm: createGzippedBuffer(nvmData),
657
629
  };
658
630
 
659
- const mockAxios = {
660
- get: sinon.stub().resolves({ data: mockResponse }),
661
- };
662
- axiosStub.returns(mockAxios);
663
- const api = configure("https://example.com/api");
631
+ fetchStub.resolves(mockResponse(mockResponseData));
632
+ const api = configure("https://example.com/api/");
664
633
 
665
634
  const result = await api.getTargetTemperature(
666
635
  expectedToken,
@@ -670,4 +639,33 @@ describe("library", () => {
670
639
  assert.equal(result, 22);
671
640
  });
672
641
  });
642
+
643
+ describe("Error Handling", () => {
644
+ const errorTests = [
645
+ { status: 400, statusText: "Bad Request" },
646
+ { status: 401, statusText: "Unauthorized" },
647
+ { status: 404, statusText: "Not Found" },
648
+ { status: 500, statusText: "Internal Server Error" },
649
+ ];
650
+
651
+ errorTests.forEach(({ status, statusText }) => {
652
+ it(`should throw error when fetch returns ${status}`, async () => {
653
+ const errorResponse = {
654
+ ok: false,
655
+ status,
656
+ statusText,
657
+ json: () => Promise.resolve({ error: statusText }),
658
+ } as Response;
659
+ fetchStub.resolves(errorResponse);
660
+ const api = configure("https://example.com/api/");
661
+
662
+ await assert.rejects(
663
+ async () => api.deviceInfo(expectedToken, "mockMac"),
664
+ {
665
+ message: `HTTP ${status}: ${statusText}`,
666
+ },
667
+ );
668
+ });
669
+ });
670
+ });
673
671
  });