edilkamin 1.6.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,5 +1,5 @@
1
1
  import { strict as assert } from "assert";
2
- import axios from "axios";
2
+ import * as amplifyAuth from "aws-amplify/auth";
3
3
  import pako from "pako";
4
4
  import sinon from "sinon";
5
5
 
@@ -10,7 +10,7 @@ import { API_URL } from "./constants";
10
10
  * Helper to create a gzip-compressed Buffer object for testing.
11
11
  */
12
12
  const createGzippedBuffer = (
13
- data: unknown
13
+ data: unknown,
14
14
  ): { type: "Buffer"; data: number[] } => {
15
15
  const json = JSON.stringify(data);
16
16
  const compressed = pako.gzip(json);
@@ -20,16 +20,23 @@ const createGzippedBuffer = (
20
20
  };
21
21
  };
22
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
+
23
34
  describe("library", () => {
24
- let axiosStub: sinon.SinonStub;
35
+ let fetchStub: sinon.SinonStub;
25
36
  const expectedToken = "mockJwtToken";
26
37
 
27
38
  beforeEach(() => {
28
- axiosStub = sinon.stub(axios, "create").returns({
29
- get: sinon.stub(),
30
- put: sinon.stub(),
31
- // eslint-disable-next-line @typescript-eslint/no-explicit-any
32
- } as any);
39
+ fetchStub = sinon.stub(globalThis, "fetch");
33
40
  });
34
41
 
35
42
  afterEach(() => {
@@ -57,7 +64,7 @@ describe("library", () => {
57
64
  const authService = createAuthService(authStub as any);
58
65
  const token = await authService.signIn(
59
66
  expectedUsername,
60
- expectedPassword
67
+ expectedPassword,
61
68
  );
62
69
  assert.deepEqual(authStub.signOut.args, [[]]);
63
70
  assert.deepEqual(signIn.args, [
@@ -87,7 +94,7 @@ describe("library", () => {
87
94
  const token = await authService.signIn(
88
95
  expectedUsername,
89
96
  expectedPassword,
90
- true // legacy mode
97
+ true, // legacy mode
91
98
  );
92
99
  assert.equal(token, expectedToken);
93
100
  });
@@ -114,8 +121,82 @@ describe("library", () => {
114
121
  {
115
122
  name: "AssertionError",
116
123
  message: "Sign-in failed",
117
- }
124
+ },
125
+ );
126
+ });
127
+ });
128
+
129
+ describe("getSession", () => {
130
+ it("should return idToken by default", async () => {
131
+ const mockAuth = {
132
+ signIn: sinon.stub().resolves({ isSignedIn: true }),
133
+ signOut: sinon.stub().resolves(),
134
+ fetchAuthSession: sinon.stub().resolves({
135
+ tokens: {
136
+ idToken: { toString: () => "mock-id-token" },
137
+ accessToken: { toString: () => "mock-access-token" },
138
+ },
139
+ }),
140
+ };
141
+ const { getSession, signIn } = createAuthService(
142
+ mockAuth as unknown as typeof amplifyAuth,
143
+ );
144
+ await signIn("user", "pass");
145
+ const token = await getSession();
146
+ assert.equal(token, "mock-id-token");
147
+ });
148
+
149
+ it("should return accessToken when legacy=true", async () => {
150
+ const mockAuth = {
151
+ signIn: sinon.stub().resolves({ isSignedIn: true }),
152
+ signOut: sinon.stub().resolves(),
153
+ fetchAuthSession: sinon.stub().resolves({
154
+ tokens: {
155
+ idToken: { toString: () => "mock-id-token" },
156
+ accessToken: { toString: () => "mock-access-token" },
157
+ },
158
+ }),
159
+ };
160
+ const { getSession, signIn } = createAuthService(
161
+ mockAuth as unknown as typeof amplifyAuth,
162
+ );
163
+ await signIn("user", "pass");
164
+ const token = await getSession(false, true);
165
+ assert.equal(token, "mock-access-token");
166
+ });
167
+
168
+ it("should throw error when no session exists", async () => {
169
+ const mockAuth = {
170
+ signIn: sinon.stub().resolves({ isSignedIn: true }),
171
+ signOut: sinon.stub().resolves(),
172
+ fetchAuthSession: sinon.stub().resolves({ tokens: null }),
173
+ };
174
+ const { getSession } = createAuthService(
175
+ mockAuth as unknown as typeof amplifyAuth,
176
+ );
177
+ await assert.rejects(async () => getSession(), {
178
+ name: "AssertionError",
179
+ message: "No session found - please sign in first",
180
+ });
181
+ });
182
+
183
+ it("should pass forceRefresh to fetchAuthSession", async () => {
184
+ const mockAuth = {
185
+ signIn: sinon.stub().resolves({ isSignedIn: true }),
186
+ signOut: sinon.stub().resolves(),
187
+ fetchAuthSession: sinon.stub().resolves({
188
+ tokens: {
189
+ idToken: { toString: () => "mock-id-token" },
190
+ accessToken: { toString: () => "mock-access-token" },
191
+ },
192
+ }),
193
+ };
194
+ const { getSession, signIn } = createAuthService(
195
+ mockAuth as unknown as typeof amplifyAuth,
118
196
  );
197
+ await signIn("user", "pass");
198
+ await getSession(true);
199
+ assert.ok(mockAuth.fetchAuthSession.calledWith({ forceRefresh: true }));
119
200
  });
120
201
  });
121
202
 
@@ -132,28 +213,24 @@ describe("library", () => {
132
213
  "getTargetTemperature",
133
214
  "setTargetTemperature",
134
215
  ];
135
- it("should create API methods with the correct baseURL", () => {
136
- 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" }));
137
219
  const api = configure(baseURL);
138
- assert.deepEqual(axiosStub.args, [
139
- [
140
- {
141
- baseURL,
142
- },
143
- ],
144
- ]);
145
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));
146
225
  });
147
- 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" }));
148
228
  const api = configure();
149
- assert.deepEqual(axiosStub.args, [
150
- [
151
- {
152
- baseURL: API_URL,
153
- },
154
- ],
155
- ]);
156
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));
157
234
  });
158
235
  });
159
236
 
@@ -174,19 +251,19 @@ describe("library", () => {
174
251
  },
175
252
  };
176
253
 
177
- it("should call axios for deviceInfo", async () => {
178
- const mockAxios = {
179
- get: sinon.stub().resolves({ data: mockDeviceInfo }),
180
- };
181
- axiosStub.returns(mockAxios);
182
- 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/");
183
257
  const result = await api.deviceInfo(expectedToken, "mockMacAddress");
184
- assert.deepEqual(mockAxios.get.args, [
185
- [
186
- "device/mockMacAddress/info",
187
- { headers: { Authorization: `Bearer ${expectedToken}` } },
188
- ],
189
- ]);
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
+ });
190
267
  assert.deepEqual(result, mockDeviceInfo);
191
268
  });
192
269
 
@@ -205,29 +282,29 @@ describe("library", () => {
205
282
  expectedValue: 0,
206
283
  },
207
284
  ].forEach(({ method, call, expectedValue }) => {
208
- it(`should call axios for ${method}`, async () => {
209
- const mockAxios = {
210
- put: sinon.stub().resolves({ status: 200 }),
211
- };
212
- axiosStub.returns(mockAxios);
213
- 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/");
214
288
 
215
289
  // Invoke the method using the mapped call function
216
- const result = await call(api);
217
- assert.deepEqual(mockAxios.put.args, [
218
- [
219
- "mqtt/command",
220
- {
221
- mac_address: "mockMacAddress",
222
- name: "power",
223
- value: expectedValue,
224
- },
225
- {
226
- headers: { Authorization: "Bearer mockToken" },
227
- },
228
- ],
229
- ]);
230
- 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
+ });
231
308
  });
232
309
  });
233
310
 
@@ -252,21 +329,21 @@ describe("library", () => {
252
329
  },
253
330
  ];
254
331
  getterTests.forEach(({ method, call, expectedResult }) => {
255
- it(`should call axios and return the correct value for ${method}`, async () => {
256
- const mockAxios = {
257
- get: sinon.stub().resolves({ data: mockDeviceInfo }),
258
- };
259
- axiosStub.returns(mockAxios);
260
- 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/");
261
335
 
262
336
  const result = await call(api, expectedToken, "mockMacAddress");
263
337
 
264
- assert.deepEqual(mockAxios.get.args, [
265
- [
266
- "device/mockMacAddress/info",
267
- { headers: { Authorization: `Bearer ${expectedToken}` } },
268
- ],
269
- ]);
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
+ });
270
347
  assert.equal(result, expectedResult);
271
348
  });
272
349
  });
@@ -278,7 +355,7 @@ describe("library", () => {
278
355
  api: ReturnType<typeof configure>,
279
356
  token: string,
280
357
  mac: string,
281
- value: number
358
+ value: number,
282
359
  ) => api.setTargetTemperature(token, mac, value),
283
360
  payload: {
284
361
  name: "enviroment_1_temperature",
@@ -287,155 +364,140 @@ describe("library", () => {
287
364
  },
288
365
  ];
289
366
  setterTests.forEach(({ method, call, payload }) => {
290
- it(`should call axios and send the correct payload for ${method}`, async () => {
291
- const mockAxios = {
292
- put: sinon.stub().resolves({ status: 200 }),
293
- };
294
- axiosStub.returns(mockAxios);
295
- const api = configure("https://example.com/api");
296
-
297
- const result = await call(
298
- api,
299
- expectedToken,
300
- "mockMacAddress",
301
- payload.value
302
- );
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/");
303
370
 
304
- assert.deepEqual(mockAxios.put.args, [
305
- [
306
- "mqtt/command",
307
- {
308
- mac_address: "mockMacAddress",
309
- ...payload,
310
- },
311
- {
312
- headers: { Authorization: `Bearer ${expectedToken}` },
313
- },
314
- ],
315
- ]);
316
- 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
+ });
317
389
  });
318
390
  });
319
391
  });
320
392
 
321
393
  describe("registerDevice", () => {
322
394
  it("should call POST /device with correct payload", async () => {
323
- const mockResponse = {
395
+ const mockResponseData = {
324
396
  macAddress: "AABBCCDDEEFF",
325
397
  deviceName: "Test Stove",
326
398
  deviceRoom: "Living Room",
327
399
  serialNumber: "EDK123",
328
400
  };
329
- const mockAxios = {
330
- post: sinon.stub().resolves({ data: mockResponse }),
331
- get: sinon.stub(),
332
- put: sinon.stub(),
333
- };
334
- axiosStub.returns(mockAxios);
335
- const api = configure("https://example.com/api");
401
+ fetchStub.resolves(mockResponse(mockResponseData));
402
+ const api = configure("https://example.com/api/");
336
403
 
337
404
  const result = await api.registerDevice(
338
405
  expectedToken,
339
406
  "AA:BB:CC:DD:EE:FF",
340
407
  "EDK123",
341
408
  "Test Stove",
342
- "Living Room"
409
+ "Living Room",
343
410
  );
344
411
 
345
- assert.deepEqual(mockAxios.post.args, [
346
- [
347
- "device",
348
- {
349
- macAddress: "AABBCCDDEEFF",
350
- deviceName: "Test Stove",
351
- deviceRoom: "Living Room",
352
- serialNumber: "EDK123",
353
- },
354
- { headers: { Authorization: `Bearer ${expectedToken}` } },
355
- ],
356
- ]);
357
- 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);
358
431
  });
359
432
 
360
433
  it("should normalize MAC address by removing colons", async () => {
361
- const mockAxios = {
362
- post: sinon.stub().resolves({ data: {} }),
363
- get: sinon.stub(),
364
- put: sinon.stub(),
365
- };
366
- axiosStub.returns(mockAxios);
367
- const api = configure("https://example.com/api");
434
+ fetchStub.resolves(mockResponse({}));
435
+ const api = configure("https://example.com/api/");
368
436
 
369
437
  await api.registerDevice(expectedToken, "AA:BB:CC:DD:EE:FF", "EDK123");
370
438
 
371
- 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");
372
441
  });
373
442
 
374
443
  it("should use empty strings as defaults for name and room", async () => {
375
- const mockAxios = {
376
- post: sinon.stub().resolves({ data: {} }),
377
- get: sinon.stub(),
378
- put: sinon.stub(),
379
- };
380
- axiosStub.returns(mockAxios);
381
- const api = configure("https://example.com/api");
444
+ fetchStub.resolves(mockResponse({}));
445
+ const api = configure("https://example.com/api/");
382
446
 
383
447
  await api.registerDevice(expectedToken, "AABBCCDDEEFF", "EDK123");
384
448
 
385
- assert.equal(mockAxios.post.args[0][1].deviceName, "");
386
- 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, "");
387
452
  });
388
453
  });
389
454
 
390
455
  describe("editDevice", () => {
391
456
  it("should call PUT /device/{mac} with correct payload", async () => {
392
- const mockResponse = {
457
+ const mockResponseData = {
393
458
  macAddress: "AABBCCDDEEFF",
394
459
  deviceName: "Updated Name",
395
460
  deviceRoom: "Basement",
396
461
  serialNumber: "EDK123",
397
462
  };
398
- const mockAxios = {
399
- put: sinon.stub().resolves({ data: mockResponse }),
400
- get: sinon.stub(),
401
- post: sinon.stub(),
402
- };
403
- axiosStub.returns(mockAxios);
404
- const api = configure("https://example.com/api");
463
+ fetchStub.resolves(mockResponse(mockResponseData));
464
+ const api = configure("https://example.com/api/");
405
465
 
406
466
  const result = await api.editDevice(
407
467
  expectedToken,
408
468
  "AA:BB:CC:DD:EE:FF",
409
469
  "Updated Name",
410
- "Basement"
470
+ "Basement",
411
471
  );
412
472
 
413
- assert.deepEqual(mockAxios.put.args, [
414
- [
415
- "device/AABBCCDDEEFF",
416
- {
417
- deviceName: "Updated Name",
418
- deviceRoom: "Basement",
419
- },
420
- { headers: { Authorization: `Bearer ${expectedToken}` } },
421
- ],
422
- ]);
423
- 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);
424
490
  });
425
491
 
426
492
  it("should use empty strings as defaults for name and room", async () => {
427
- const mockAxios = {
428
- put: sinon.stub().resolves({ data: {} }),
429
- get: sinon.stub(),
430
- post: sinon.stub(),
431
- };
432
- axiosStub.returns(mockAxios);
433
- const api = configure("https://example.com/api");
493
+ fetchStub.resolves(mockResponse({}));
494
+ const api = configure("https://example.com/api/");
434
495
 
435
496
  await api.editDevice(expectedToken, "AABBCCDDEEFF");
436
497
 
437
- assert.equal(mockAxios.put.args[0][1].deviceName, "");
438
- 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, "");
439
501
  });
440
502
  });
441
503
 
@@ -445,7 +507,7 @@ describe("library", () => {
445
507
  commands: { power: true },
446
508
  temperatures: { enviroment: 19, board: 25 },
447
509
  };
448
- const mockResponse = {
510
+ const mockResponseData = {
449
511
  status: createGzippedBuffer(statusData),
450
512
  nvm: {
451
513
  user_parameters: {
@@ -454,11 +516,8 @@ describe("library", () => {
454
516
  },
455
517
  };
456
518
 
457
- const mockAxios = {
458
- get: sinon.stub().resolves({ data: mockResponse }),
459
- };
460
- axiosStub.returns(mockAxios);
461
- const api = configure("https://example.com/api");
519
+ fetchStub.resolves(mockResponse(mockResponseData));
520
+ const api = configure("https://example.com/api/");
462
521
 
463
522
  const result = await api.deviceInfo(expectedToken, "mockMacAddress");
464
523
 
@@ -475,7 +534,7 @@ describe("library", () => {
475
534
  is_sound_active: true,
476
535
  },
477
536
  };
478
- const mockResponse = {
537
+ const mockResponseData = {
479
538
  status: {
480
539
  commands: { power: true },
481
540
  temperatures: { enviroment: 19 },
@@ -483,11 +542,8 @@ describe("library", () => {
483
542
  nvm: createGzippedBuffer(nvmData),
484
543
  };
485
544
 
486
- const mockAxios = {
487
- get: sinon.stub().resolves({ data: mockResponse }),
488
- };
489
- axiosStub.returns(mockAxios);
490
- const api = configure("https://example.com/api");
545
+ fetchStub.resolves(mockResponse(mockResponseData));
546
+ const api = configure("https://example.com/api/");
491
547
 
492
548
  const result = await api.deviceInfo(expectedToken, "mockMacAddress");
493
549
 
@@ -508,16 +564,13 @@ describe("library", () => {
508
564
  is_sound_active: false,
509
565
  },
510
566
  };
511
- const mockResponse = {
567
+ const mockResponseData = {
512
568
  status: createGzippedBuffer(statusData),
513
569
  nvm: createGzippedBuffer(nvmData),
514
570
  };
515
571
 
516
- const mockAxios = {
517
- get: sinon.stub().resolves({ data: mockResponse }),
518
- };
519
- axiosStub.returns(mockAxios);
520
- const api = configure("https://example.com/api");
572
+ fetchStub.resolves(mockResponse(mockResponseData));
573
+ const api = configure("https://example.com/api/");
521
574
 
522
575
  const result = await api.deviceInfo(expectedToken, "mockMacAddress");
523
576
 
@@ -530,16 +583,13 @@ describe("library", () => {
530
583
  commands: { power: true },
531
584
  temperatures: { enviroment: 19 },
532
585
  };
533
- const mockResponse = {
586
+ const mockResponseData = {
534
587
  status: createGzippedBuffer(statusData),
535
588
  nvm: { user_parameters: { enviroment_1_temperature: 22 } },
536
589
  };
537
590
 
538
- const mockAxios = {
539
- get: sinon.stub().resolves({ data: mockResponse }),
540
- };
541
- axiosStub.returns(mockAxios);
542
- const api = configure("https://example.com/api");
591
+ fetchStub.resolves(mockResponse(mockResponseData));
592
+ const api = configure("https://example.com/api/");
543
593
 
544
594
  const result = await api.getPower(expectedToken, "mockMacAddress");
545
595
 
@@ -551,20 +601,17 @@ describe("library", () => {
551
601
  commands: { power: true },
552
602
  temperatures: { enviroment: 19, board: 25 },
553
603
  };
554
- const mockResponse = {
604
+ const mockResponseData = {
555
605
  status: createGzippedBuffer(statusData),
556
606
  nvm: { user_parameters: { enviroment_1_temperature: 22 } },
557
607
  };
558
608
 
559
- const mockAxios = {
560
- get: sinon.stub().resolves({ data: mockResponse }),
561
- };
562
- axiosStub.returns(mockAxios);
563
- const api = configure("https://example.com/api");
609
+ fetchStub.resolves(mockResponse(mockResponseData));
610
+ const api = configure("https://example.com/api/");
564
611
 
565
612
  const result = await api.getEnvironmentTemperature(
566
613
  expectedToken,
567
- "mockMacAddress"
614
+ "mockMacAddress",
568
615
  );
569
616
 
570
617
  assert.equal(result, 19);
@@ -576,23 +623,49 @@ describe("library", () => {
576
623
  enviroment_1_temperature: 22,
577
624
  },
578
625
  };
579
- const mockResponse = {
626
+ const mockResponseData = {
580
627
  status: { commands: { power: true }, temperatures: { enviroment: 19 } },
581
628
  nvm: createGzippedBuffer(nvmData),
582
629
  };
583
630
 
584
- const mockAxios = {
585
- get: sinon.stub().resolves({ data: mockResponse }),
586
- };
587
- axiosStub.returns(mockAxios);
588
- const api = configure("https://example.com/api");
631
+ fetchStub.resolves(mockResponse(mockResponseData));
632
+ const api = configure("https://example.com/api/");
589
633
 
590
634
  const result = await api.getTargetTemperature(
591
635
  expectedToken,
592
- "mockMacAddress"
636
+ "mockMacAddress",
593
637
  );
594
638
 
595
639
  assert.equal(result, 22);
596
640
  });
597
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
+ });
598
671
  });