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.
- package/.github/workflows/cli-tests.yml +1 -1
- package/.github/workflows/documentation.yml +1 -1
- package/.github/workflows/publish.yml +6 -4
- package/.github/workflows/tests.yml +1 -1
- package/README.md +31 -7
- package/dist/esm/browser-bundle.test.d.ts +1 -0
- package/dist/esm/browser-bundle.test.js +29 -0
- package/dist/esm/cli.js +69 -10
- package/dist/esm/configureAmplify.test.d.ts +1 -0
- package/dist/esm/configureAmplify.test.js +37 -0
- package/dist/esm/index.d.ts +2 -2
- package/dist/esm/index.js +1 -1
- package/dist/esm/library.d.ts +18 -6
- package/dist/esm/library.js +87 -55
- package/dist/esm/library.test.js +230 -192
- package/dist/esm/token-storage.d.ts +14 -0
- package/dist/esm/token-storage.js +81 -0
- package/eslint.config.mjs +12 -1
- package/package.json +15 -3
- package/src/browser-bundle.test.ts +21 -0
- package/src/buffer-utils.test.ts +1 -1
- package/src/cli.ts +113 -40
- package/src/configureAmplify.test.ts +47 -0
- package/src/index.ts +1 -1
- package/src/library.test.ts +279 -206
- package/src/library.ts +125 -70
- package/src/token-storage.ts +78 -0
package/src/library.test.ts
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import { strict as assert } from "assert";
|
|
2
|
-
import
|
|
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
|
|
35
|
+
let fetchStub: sinon.SinonStub;
|
|
25
36
|
const expectedToken = "mockJwtToken";
|
|
26
37
|
|
|
27
38
|
beforeEach(() => {
|
|
28
|
-
|
|
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
|
|
178
|
-
|
|
179
|
-
|
|
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.
|
|
185
|
-
|
|
186
|
-
|
|
187
|
-
|
|
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
|
|
209
|
-
|
|
210
|
-
|
|
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
|
-
|
|
217
|
-
assert.
|
|
218
|
-
|
|
219
|
-
|
|
220
|
-
|
|
221
|
-
|
|
222
|
-
|
|
223
|
-
|
|
224
|
-
|
|
225
|
-
|
|
226
|
-
|
|
227
|
-
|
|
228
|
-
|
|
229
|
-
|
|
230
|
-
|
|
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
|
|
256
|
-
|
|
257
|
-
|
|
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.
|
|
265
|
-
|
|
266
|
-
|
|
267
|
-
|
|
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
|
|
291
|
-
|
|
292
|
-
|
|
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
|
-
|
|
305
|
-
|
|
306
|
-
|
|
307
|
-
|
|
308
|
-
|
|
309
|
-
|
|
310
|
-
|
|
311
|
-
|
|
312
|
-
|
|
313
|
-
|
|
314
|
-
|
|
315
|
-
|
|
316
|
-
|
|
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
|
|
395
|
+
const mockResponseData = {
|
|
324
396
|
macAddress: "AABBCCDDEEFF",
|
|
325
397
|
deviceName: "Test Stove",
|
|
326
398
|
deviceRoom: "Living Room",
|
|
327
399
|
serialNumber: "EDK123",
|
|
328
400
|
};
|
|
329
|
-
|
|
330
|
-
|
|
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.
|
|
346
|
-
|
|
347
|
-
|
|
348
|
-
|
|
349
|
-
|
|
350
|
-
|
|
351
|
-
|
|
352
|
-
|
|
353
|
-
|
|
354
|
-
|
|
355
|
-
|
|
356
|
-
|
|
357
|
-
|
|
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
|
-
|
|
362
|
-
|
|
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
|
-
|
|
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
|
-
|
|
376
|
-
|
|
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
|
-
|
|
386
|
-
assert.equal(
|
|
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
|
|
457
|
+
const mockResponseData = {
|
|
393
458
|
macAddress: "AABBCCDDEEFF",
|
|
394
459
|
deviceName: "Updated Name",
|
|
395
460
|
deviceRoom: "Basement",
|
|
396
461
|
serialNumber: "EDK123",
|
|
397
462
|
};
|
|
398
|
-
|
|
399
|
-
|
|
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.
|
|
414
|
-
|
|
415
|
-
|
|
416
|
-
|
|
417
|
-
|
|
418
|
-
|
|
419
|
-
|
|
420
|
-
|
|
421
|
-
|
|
422
|
-
|
|
423
|
-
|
|
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
|
-
|
|
428
|
-
|
|
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
|
-
|
|
438
|
-
assert.equal(
|
|
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
|
|
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
|
-
|
|
458
|
-
|
|
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
|
|
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
|
-
|
|
487
|
-
|
|
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
|
|
567
|
+
const mockResponseData = {
|
|
512
568
|
status: createGzippedBuffer(statusData),
|
|
513
569
|
nvm: createGzippedBuffer(nvmData),
|
|
514
570
|
};
|
|
515
571
|
|
|
516
|
-
|
|
517
|
-
|
|
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
|
|
586
|
+
const mockResponseData = {
|
|
534
587
|
status: createGzippedBuffer(statusData),
|
|
535
588
|
nvm: { user_parameters: { enviroment_1_temperature: 22 } },
|
|
536
589
|
};
|
|
537
590
|
|
|
538
|
-
|
|
539
|
-
|
|
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
|
|
604
|
+
const mockResponseData = {
|
|
555
605
|
status: createGzippedBuffer(statusData),
|
|
556
606
|
nvm: { user_parameters: { enviroment_1_temperature: 22 } },
|
|
557
607
|
};
|
|
558
608
|
|
|
559
|
-
|
|
560
|
-
|
|
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
|
|
626
|
+
const mockResponseData = {
|
|
580
627
|
status: { commands: { power: true }, temperatures: { enviroment: 19 } },
|
|
581
628
|
nvm: createGzippedBuffer(nvmData),
|
|
582
629
|
};
|
|
583
630
|
|
|
584
|
-
|
|
585
|
-
|
|
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
|
});
|