yoto-nodejs-client 0.0.5 → 0.0.7
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/README.md +73 -40
- package/bin/auth.js +4 -3
- package/bin/device-model.js +25 -5
- package/bin/device-tui.js +25 -3
- package/bin/devices.js +25 -9
- package/bin/lib/cli-helpers.d.ts.map +1 -1
- package/bin/lib/cli-helpers.js +3 -1
- package/bin/lib/token-helpers.d.ts +4 -2
- package/bin/lib/token-helpers.d.ts.map +1 -1
- package/bin/lib/token-helpers.js +9 -8
- package/bin/refresh-token.js +4 -2
- package/bin/token-info.js +2 -2
- package/lib/api-client.d.ts +11 -10
- package/lib/api-client.d.ts.map +1 -1
- package/lib/api-client.js +12 -14
- package/lib/api-endpoints/auth.test.js +4 -4
- package/lib/api-endpoints/content.test.js +32 -32
- package/lib/api-endpoints/devices.d.ts +4 -4
- package/lib/api-endpoints/devices.js +2 -2
- package/lib/api-endpoints/devices.test.js +45 -45
- package/lib/api-endpoints/endpoint-test-helpers.d.ts +3 -4
- package/lib/api-endpoints/endpoint-test-helpers.d.ts.map +1 -1
- package/lib/api-endpoints/endpoint-test-helpers.js +21 -5
- package/lib/api-endpoints/family-library-groups.d.ts +3 -3
- package/lib/api-endpoints/family-library-groups.d.ts.map +1 -1
- package/lib/api-endpoints/family-library-groups.js +3 -3
- package/lib/api-endpoints/family-library-groups.test.js +29 -29
- package/lib/api-endpoints/family.test.js +11 -11
- package/lib/api-endpoints/icons.test.js +14 -14
- package/lib/mqtt/client.d.ts +123 -48
- package/lib/mqtt/client.d.ts.map +1 -1
- package/lib/mqtt/client.js +131 -49
- package/lib/mqtt/factory.d.ts +12 -5
- package/lib/mqtt/factory.d.ts.map +1 -1
- package/lib/mqtt/factory.js +39 -11
- package/lib/mqtt/index.js +2 -1
- package/lib/mqtt/mqtt.test.js +25 -22
- package/lib/test-helpers/device-model-test-helpers.d.ts +29 -0
- package/lib/test-helpers/device-model-test-helpers.d.ts.map +1 -0
- package/lib/test-helpers/device-model-test-helpers.js +116 -0
- package/lib/token.d.ts +44 -2
- package/lib/token.d.ts.map +1 -1
- package/lib/token.js +142 -2
- package/lib/yoto-account.d.ts +339 -9
- package/lib/yoto-account.d.ts.map +1 -1
- package/lib/yoto-account.js +411 -39
- package/lib/yoto-account.test.js +139 -0
- package/lib/yoto-device.d.ts +418 -30
- package/lib/yoto-device.d.ts.map +1 -1
- package/lib/yoto-device.js +670 -104
- package/lib/yoto-device.test.js +88 -0
- package/package.json +1 -1
|
@@ -3,10 +3,12 @@
|
|
|
3
3
|
*/
|
|
4
4
|
|
|
5
5
|
import { join } from 'node:path'
|
|
6
|
+
import { RefreshableToken } from '../token.js'
|
|
7
|
+
import { saveTokensToEnv } from '../../bin/lib/token-helpers.js'
|
|
6
8
|
|
|
7
9
|
/**
|
|
8
10
|
* Load tokens from .env file for testing
|
|
9
|
-
* @returns {{
|
|
11
|
+
* @returns {{ token: RefreshableToken }}
|
|
10
12
|
*/
|
|
11
13
|
export function loadTestTokens () {
|
|
12
14
|
const testDir = import.meta.dirname
|
|
@@ -26,18 +28,32 @@ export function loadTestTokens () {
|
|
|
26
28
|
const refreshToken = process.env['YOTO_REFRESH_TOKEN']
|
|
27
29
|
const clientId = process.env['YOTO_CLIENT_ID']
|
|
28
30
|
|
|
29
|
-
if (!accessToken || !refreshToken) {
|
|
31
|
+
if (!accessToken || !refreshToken || !clientId) {
|
|
30
32
|
console.error('Missing required environment variables:')
|
|
31
33
|
console.error(' YOTO_ACCESS_TOKEN:', accessToken ? '✓' : '✗')
|
|
32
34
|
console.error(' YOTO_REFRESH_TOKEN:', refreshToken ? '✓' : '✗')
|
|
35
|
+
console.error(' YOTO_CLIENT_ID:', clientId ? '✓' : '✗')
|
|
33
36
|
console.error('\nRun `yoto-auth` to authenticate first')
|
|
34
37
|
process.exit(1)
|
|
35
38
|
}
|
|
36
39
|
|
|
37
|
-
|
|
38
|
-
|
|
40
|
+
const token = new RefreshableToken({
|
|
41
|
+
clientId,
|
|
39
42
|
refreshToken,
|
|
40
|
-
|
|
43
|
+
accessToken,
|
|
44
|
+
async onTokenRefresh (tokens) {
|
|
45
|
+
const { resolvedPath } = await saveTokensToEnv(envPath, {
|
|
46
|
+
access_token: tokens.updatedAccessToken,
|
|
47
|
+
refresh_token: tokens.updatedRefreshToken,
|
|
48
|
+
token_type: 'Bearer',
|
|
49
|
+
expires_in: tokens.updatedExpiresAt - Math.floor(Date.now() / 1000)
|
|
50
|
+
}, tokens.clientId)
|
|
51
|
+
console.log(`Token Refreshed: ${resolvedPath}`)
|
|
52
|
+
}
|
|
53
|
+
})
|
|
54
|
+
|
|
55
|
+
return {
|
|
56
|
+
token
|
|
41
57
|
}
|
|
42
58
|
}
|
|
43
59
|
|
|
@@ -67,7 +67,7 @@ export function getGroups({ accessToken, userAgent, requestOptions }: {
|
|
|
67
67
|
* Max 20 groups per family. ContentIds must be in family's library (invalid ones filtered out).
|
|
68
68
|
* @see https://yoto.dev/api/createagroup/
|
|
69
69
|
* @param {object} options
|
|
70
|
-
* @param {string} options.
|
|
70
|
+
* @param {string} options.accessToken The API token to request with
|
|
71
71
|
* @param {YotoCreateGroupRequest} options.group The group data to create
|
|
72
72
|
* @param {string} [options.userAgent] Optional user agent string
|
|
73
73
|
* @param {RequestOptions} [options.requestOptions] Additional undici request options
|
|
@@ -86,8 +86,8 @@ export function getGroups({ accessToken, userAgent, requestOptions }: {
|
|
|
86
86
|
* }
|
|
87
87
|
* })
|
|
88
88
|
*/
|
|
89
|
-
export function createGroup({
|
|
90
|
-
|
|
89
|
+
export function createGroup({ accessToken, userAgent, group, requestOptions }: {
|
|
90
|
+
accessToken: string;
|
|
91
91
|
group: YotoCreateGroupRequest;
|
|
92
92
|
userAgent?: string | undefined;
|
|
93
93
|
requestOptions?: ({
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"family-library-groups.d.ts","sourceRoot":"","sources":["family-library-groups.js"],"names":[],"mappings":"AAWA;;;;GAIG;AAEH;;;;;;;;;;;;GAYG;AAEH;;;;;GAKG;AAEH;;;;;;;;;;;;;;;;;;;;GAoBG;AACH,sEAhBG;IAAyB,WAAW,EAA3B,MAAM;IACW,SAAS;IACD,cAAc;;;CAChD,GAAS,OAAO,CAAC,SAAS,EAAE,CAAC,CA6B/B;AAED;;;;;;GAMG;AAEH;;;;GAIG;AAEH;;;;;;;;;;;;;;;;;;;;;;;GAuBG;AACH
|
|
1
|
+
{"version":3,"file":"family-library-groups.d.ts","sourceRoot":"","sources":["family-library-groups.js"],"names":[],"mappings":"AAWA;;;;GAIG;AAEH;;;;;;;;;;;;GAYG;AAEH;;;;;GAKG;AAEH;;;;;;;;;;;;;;;;;;;;GAoBG;AACH,sEAhBG;IAAyB,WAAW,EAA3B,MAAM;IACW,SAAS;IACD,cAAc;;;CAChD,GAAS,OAAO,CAAC,SAAS,EAAE,CAAC,CA6B/B;AAED;;;;;;GAMG;AAEH;;;;GAIG;AAEH;;;;;;;;;;;;;;;;;;;;;;;GAuBG;AACH,+EAnBG;IAAyB,WAAW,EAA3B,MAAM;IAC0B,KAAK,EAArC,sBAAsB;IACL,SAAS;IACD,cAAc;;;CAChD,GAAS,OAAO,CAAC,SAAS,CAAC,CAoC7B;AAED;;;;;;;;;;GAUG;AACH,8EANG;IAAyB,WAAW,EAA3B,MAAM;IACU,OAAO,EAAvB,MAAM;IACW,SAAS;IACD,cAAc;;;CAChD,GAAS,OAAO,CAAC,SAAS,CAAC,CAmB7B;AAED;;;;;;GAMG;AAEH;;;;;;;;;;;GAWG;AACH,wFAPG;IAAyB,WAAW,EAA3B,MAAM;IACU,OAAO,EAAvB,MAAM;IAC0B,KAAK,EAArC,sBAAsB;IACL,SAAS;IACD,cAAc;;;CAChD,GAAS,OAAO,CAAC,SAAS,CAAC,CAwB7B;AAED;;;;GAIG;AAEH;;;;;;;;;;GAUG;AACH,iFANG;IAAyB,WAAW,EAA3B,MAAM;IACU,OAAO,EAAvB,MAAM;IACW,SAAS;IACD,cAAc;;;CAChD,GAAS,OAAO,CAAC,uBAAuB,CAAC,CAmB3C;;;;;YAxOa,SAAS,EAAE;;;;;;QAMX,MAAM;;;;UACN,MAAM;;;;cACN,MAAM;;;;aACN,MAAM;;;;cACN,MAAM;;;;WACN,aAAa,EAAE;;;;WACf,GAAG,EAAE;;;;eACL,MAAM;;;;oBACN,MAAM;;;;;;eAMN,MAAM;;;;aACN,MAAM;;;;;;UA6CN,MAAM;;;;aACN,MAAM;;;;WACN,kBAAkB,EAAE;;;;;;eAMpB,MAAM;;;;;;UAmFN,MAAM;;;;aACN,MAAM;;;;WACN,kBAAkB,EAAE;;;;;;QA0CpB,MAAM"}
|
|
@@ -94,7 +94,7 @@ export async function getGroups ({
|
|
|
94
94
|
* Max 20 groups per family. ContentIds must be in family's library (invalid ones filtered out).
|
|
95
95
|
* @see https://yoto.dev/api/createagroup/
|
|
96
96
|
* @param {object} options
|
|
97
|
-
* @param {string} options.
|
|
97
|
+
* @param {string} options.accessToken The API token to request with
|
|
98
98
|
* @param {YotoCreateGroupRequest} options.group The group data to create
|
|
99
99
|
* @param {string} [options.userAgent] Optional user agent string
|
|
100
100
|
* @param {RequestOptions} [options.requestOptions] Additional undici request options
|
|
@@ -114,7 +114,7 @@ export async function getGroups ({
|
|
|
114
114
|
* })
|
|
115
115
|
*/
|
|
116
116
|
export async function createGroup ({
|
|
117
|
-
|
|
117
|
+
accessToken,
|
|
118
118
|
userAgent,
|
|
119
119
|
group,
|
|
120
120
|
requestOptions
|
|
@@ -124,7 +124,7 @@ export async function createGroup ({
|
|
|
124
124
|
const response = await request(requestUrl, mergeRequestOptions({
|
|
125
125
|
method: 'POST',
|
|
126
126
|
headers: {
|
|
127
|
-
...defaultAuthHeaders({ accessToken
|
|
127
|
+
...defaultAuthHeaders({ accessToken, userAgent }),
|
|
128
128
|
'Content-Type': 'application/json'
|
|
129
129
|
},
|
|
130
130
|
body: JSON.stringify(group)
|
|
@@ -4,12 +4,12 @@ import { getGroups, createGroup, getGroup, updateGroup, deleteGroup } from './fa
|
|
|
4
4
|
import { YotoAPIError } from './helpers.js'
|
|
5
5
|
import { loadTestTokens, logResponse } from './endpoint-test-helpers.js'
|
|
6
6
|
|
|
7
|
-
const {
|
|
7
|
+
const { token } = loadTestTokens()
|
|
8
8
|
|
|
9
9
|
test('getGroups', async (t) => {
|
|
10
10
|
await t.test('should fetch family library groups', async () => {
|
|
11
11
|
const response = await getGroups({
|
|
12
|
-
accessToken
|
|
12
|
+
accessToken: await token.getAccessToken()
|
|
13
13
|
})
|
|
14
14
|
|
|
15
15
|
// Log response for type verification and documentation
|
|
@@ -23,22 +23,22 @@ test('getGroups', async (t) => {
|
|
|
23
23
|
if (response.length > 0) {
|
|
24
24
|
const group = response[0]
|
|
25
25
|
assert.ok(group, 'Group should exist')
|
|
26
|
-
assert.
|
|
27
|
-
assert.
|
|
28
|
-
assert.
|
|
29
|
-
assert.
|
|
30
|
-
assert.
|
|
26
|
+
assert.equal(typeof group.id, 'string', 'Group should have id string')
|
|
27
|
+
assert.equal(typeof group.name, 'string', 'Group should have name string')
|
|
28
|
+
assert.equal(typeof group.familyId, 'string', 'Group should have familyId string')
|
|
29
|
+
assert.equal(typeof group.imageId, 'string', 'Group should have imageId string')
|
|
30
|
+
assert.equal(typeof group.imageUrl, 'string', 'Group should have imageUrl string')
|
|
31
31
|
assert.ok(Array.isArray(group.items), 'Group should have items array')
|
|
32
32
|
assert.ok(Array.isArray(group.cards), 'Group should have cards array')
|
|
33
|
-
assert.
|
|
34
|
-
assert.
|
|
33
|
+
assert.equal(typeof group.createdAt, 'string', 'Group should have createdAt string')
|
|
34
|
+
assert.equal(typeof group.lastModifiedAt, 'string', 'Group should have lastModifiedAt string')
|
|
35
35
|
|
|
36
36
|
// Validate items structure if items exist
|
|
37
37
|
if (group.items.length > 0) {
|
|
38
38
|
const item = group.items[0]
|
|
39
39
|
assert.ok(item, 'Item should exist')
|
|
40
|
-
assert.
|
|
41
|
-
assert.
|
|
40
|
+
assert.equal(typeof item.contentId, 'string', 'Item should have contentId string')
|
|
41
|
+
assert.equal(typeof item.addedAt, 'string', 'Item should have addedAt string')
|
|
42
42
|
}
|
|
43
43
|
}
|
|
44
44
|
})
|
|
@@ -73,7 +73,7 @@ test('CRUD operations - full lifecycle', async (t) => {
|
|
|
73
73
|
console.log('\n🧹 Cleaning up test groups...')
|
|
74
74
|
for (const groupId of createdGroupIds) {
|
|
75
75
|
try {
|
|
76
|
-
await deleteGroup({ accessToken, groupId })
|
|
76
|
+
await deleteGroup({ accessToken: await token.getAccessToken(), groupId })
|
|
77
77
|
console.log(` ✓ Deleted group: ${groupId}`)
|
|
78
78
|
} catch (err) {
|
|
79
79
|
console.log(` ⚠️ Failed to delete group ${groupId}:`, /** @type {Error} */(err).message)
|
|
@@ -83,7 +83,7 @@ test('CRUD operations - full lifecycle', async (t) => {
|
|
|
83
83
|
|
|
84
84
|
await t.test('should create first group', async () => {
|
|
85
85
|
const group = await createGroup({
|
|
86
|
-
|
|
86
|
+
accessToken: await token.getAccessToken(),
|
|
87
87
|
group: {
|
|
88
88
|
name: 'Test Group 1',
|
|
89
89
|
imageId: 'fp-cards',
|
|
@@ -95,15 +95,15 @@ test('CRUD operations - full lifecycle', async (t) => {
|
|
|
95
95
|
|
|
96
96
|
// Validate response structure
|
|
97
97
|
assert.ok(group, 'Response should exist')
|
|
98
|
-
assert.
|
|
98
|
+
assert.equal(typeof group.id, 'string', 'Group should have id string')
|
|
99
99
|
assert.strictEqual(group.name, 'Test Group 1', 'Group name should match')
|
|
100
100
|
assert.strictEqual(group.imageId, 'fp-cards', 'Image ID should match')
|
|
101
101
|
assert.ok(Array.isArray(group.items), 'Group should have items array')
|
|
102
102
|
assert.strictEqual(group.items.length, 0, 'Items should be empty')
|
|
103
103
|
assert.ok(Array.isArray(group.cards), 'Group should have cards array')
|
|
104
|
-
assert.
|
|
105
|
-
assert.
|
|
106
|
-
assert.
|
|
104
|
+
assert.equal(typeof group.familyId, 'string', 'Group should have familyId')
|
|
105
|
+
assert.equal(typeof group.createdAt, 'string', 'Group should have createdAt')
|
|
106
|
+
assert.equal(typeof group.lastModifiedAt, 'string', 'Group should have lastModifiedAt')
|
|
107
107
|
|
|
108
108
|
group1Id = group.id
|
|
109
109
|
createdGroupIds.push(group.id)
|
|
@@ -111,7 +111,7 @@ test('CRUD operations - full lifecycle', async (t) => {
|
|
|
111
111
|
|
|
112
112
|
await t.test('should create second group', async () => {
|
|
113
113
|
const group = await createGroup({
|
|
114
|
-
|
|
114
|
+
accessToken: await token.getAccessToken(),
|
|
115
115
|
group: {
|
|
116
116
|
name: 'Test Group 2',
|
|
117
117
|
imageId: 'fp-cards',
|
|
@@ -123,7 +123,7 @@ test('CRUD operations - full lifecycle', async (t) => {
|
|
|
123
123
|
|
|
124
124
|
// Validate response structure
|
|
125
125
|
assert.ok(group, 'Response should exist')
|
|
126
|
-
assert.
|
|
126
|
+
assert.equal(typeof group.id, 'string', 'Group should have id string')
|
|
127
127
|
assert.strictEqual(group.name, 'Test Group 2', 'Group name should match')
|
|
128
128
|
assert.notStrictEqual(group.id, group1Id, 'Group IDs should be different')
|
|
129
129
|
|
|
@@ -133,7 +133,7 @@ test('CRUD operations - full lifecycle', async (t) => {
|
|
|
133
133
|
|
|
134
134
|
await t.test('should list groups and find both created groups', async () => {
|
|
135
135
|
const groups = await getGroups({
|
|
136
|
-
accessToken
|
|
136
|
+
accessToken: await token.getAccessToken(),
|
|
137
137
|
})
|
|
138
138
|
|
|
139
139
|
logResponse('GET /card/family/library/groups (after creating 2)', groups)
|
|
@@ -153,7 +153,7 @@ test('CRUD operations - full lifecycle', async (t) => {
|
|
|
153
153
|
|
|
154
154
|
await t.test('should get first group by ID', async () => {
|
|
155
155
|
const group = await getGroup({
|
|
156
|
-
accessToken,
|
|
156
|
+
accessToken: await token.getAccessToken(),
|
|
157
157
|
groupId: group1Id
|
|
158
158
|
})
|
|
159
159
|
|
|
@@ -169,7 +169,7 @@ test('CRUD operations - full lifecycle', async (t) => {
|
|
|
169
169
|
|
|
170
170
|
await t.test('should get second group by ID', async () => {
|
|
171
171
|
const group = await getGroup({
|
|
172
|
-
accessToken,
|
|
172
|
+
accessToken: await token.getAccessToken(),
|
|
173
173
|
groupId: group2Id
|
|
174
174
|
})
|
|
175
175
|
|
|
@@ -182,7 +182,7 @@ test('CRUD operations - full lifecycle', async (t) => {
|
|
|
182
182
|
|
|
183
183
|
await t.test('should update first group', async () => {
|
|
184
184
|
const updatedGroup = await updateGroup({
|
|
185
|
-
accessToken,
|
|
185
|
+
accessToken: await token.getAccessToken(),
|
|
186
186
|
groupId: group1Id,
|
|
187
187
|
group: {
|
|
188
188
|
name: 'Test Group 1 - Updated',
|
|
@@ -196,12 +196,12 @@ test('CRUD operations - full lifecycle', async (t) => {
|
|
|
196
196
|
assert.ok(updatedGroup, 'Response should exist')
|
|
197
197
|
assert.strictEqual(updatedGroup.id, group1Id, 'Group ID should remain the same')
|
|
198
198
|
assert.strictEqual(updatedGroup.name, 'Test Group 1 - Updated', 'Group name should be updated')
|
|
199
|
-
assert.
|
|
199
|
+
assert.equal(typeof updatedGroup.lastModifiedAt, 'string', 'Should have lastModifiedAt')
|
|
200
200
|
})
|
|
201
201
|
|
|
202
202
|
await t.test('should get updated group and confirm changes', async () => {
|
|
203
203
|
const group = await getGroup({
|
|
204
|
-
accessToken,
|
|
204
|
+
accessToken: await token.getAccessToken(),
|
|
205
205
|
groupId: group1Id
|
|
206
206
|
})
|
|
207
207
|
|
|
@@ -212,7 +212,7 @@ test('CRUD operations - full lifecycle', async (t) => {
|
|
|
212
212
|
|
|
213
213
|
await t.test('should delete first group', async () => {
|
|
214
214
|
const response = await deleteGroup({
|
|
215
|
-
accessToken,
|
|
215
|
+
accessToken: await token.getAccessToken(),
|
|
216
216
|
groupId: group1Id
|
|
217
217
|
})
|
|
218
218
|
|
|
@@ -227,7 +227,7 @@ test('CRUD operations - full lifecycle', async (t) => {
|
|
|
227
227
|
|
|
228
228
|
await t.test('should delete second group', async () => {
|
|
229
229
|
const response = await deleteGroup({
|
|
230
|
-
accessToken,
|
|
230
|
+
accessToken: await token.getAccessToken(),
|
|
231
231
|
groupId: group2Id
|
|
232
232
|
})
|
|
233
233
|
|
|
@@ -242,7 +242,7 @@ test('CRUD operations - full lifecycle', async (t) => {
|
|
|
242
242
|
|
|
243
243
|
await t.test('should verify groups are deleted from list', async () => {
|
|
244
244
|
const groups = await getGroups({
|
|
245
|
-
accessToken
|
|
245
|
+
accessToken: await token.getAccessToken()
|
|
246
246
|
})
|
|
247
247
|
|
|
248
248
|
logResponse('GET /card/family/library/groups (after deletion)', groups)
|
|
@@ -258,7 +258,7 @@ test('CRUD operations - full lifecycle', async (t) => {
|
|
|
258
258
|
await assert.rejects(
|
|
259
259
|
async () => {
|
|
260
260
|
await getGroup({
|
|
261
|
-
accessToken,
|
|
261
|
+
accessToken: await token.getAccessToken(),
|
|
262
262
|
groupId: group1Id
|
|
263
263
|
})
|
|
264
264
|
},
|
|
@@ -4,12 +4,12 @@ import { getFamilyImages, getAFamilyImage } from './family.js'
|
|
|
4
4
|
import { YotoAPIError } from './helpers.js'
|
|
5
5
|
import { loadTestTokens, logResponse } from './endpoint-test-helpers.js'
|
|
6
6
|
|
|
7
|
-
const {
|
|
7
|
+
const { token } = loadTestTokens()
|
|
8
8
|
|
|
9
9
|
test('getFamilyImages', async (t) => {
|
|
10
10
|
await t.test('should fetch user family images', async () => {
|
|
11
11
|
const response = await getFamilyImages({
|
|
12
|
-
accessToken
|
|
12
|
+
accessToken: await token.getAccessToken()
|
|
13
13
|
})
|
|
14
14
|
|
|
15
15
|
// Log response for type verification and documentation
|
|
@@ -23,7 +23,7 @@ test('getFamilyImages', async (t) => {
|
|
|
23
23
|
if (response.images.length > 0) {
|
|
24
24
|
const image = response.images[0]
|
|
25
25
|
assert.ok(image, 'Image should exist')
|
|
26
|
-
assert.
|
|
26
|
+
assert.equal(typeof image.imageId, 'string', 'Image should have imageId string')
|
|
27
27
|
}
|
|
28
28
|
})
|
|
29
29
|
|
|
@@ -51,7 +51,7 @@ test('getAFamilyImage', async (t) => {
|
|
|
51
51
|
// Get real image IDs to test with
|
|
52
52
|
await t.test('setup - get image IDs from family images', async () => {
|
|
53
53
|
const response = await getFamilyImages({
|
|
54
|
-
accessToken
|
|
54
|
+
accessToken: await token.getAccessToken()
|
|
55
55
|
})
|
|
56
56
|
|
|
57
57
|
if (response.images.length === 0) {
|
|
@@ -73,7 +73,7 @@ test('getAFamilyImage', async (t) => {
|
|
|
73
73
|
assert.ok(imageId, 'Image ID should exist')
|
|
74
74
|
|
|
75
75
|
const response = await getAFamilyImage({
|
|
76
|
-
accessToken,
|
|
76
|
+
accessToken: await token.getAccessToken(),
|
|
77
77
|
imageId,
|
|
78
78
|
size: '640x480'
|
|
79
79
|
})
|
|
@@ -83,7 +83,7 @@ test('getAFamilyImage', async (t) => {
|
|
|
83
83
|
|
|
84
84
|
// Validate response structure matches YotoFamilyImageResponse
|
|
85
85
|
assert.ok(response, 'Response should exist')
|
|
86
|
-
assert.
|
|
86
|
+
assert.equal(typeof response.imageUrl, 'string', 'Response should have imageUrl string')
|
|
87
87
|
assert.ok(response.imageUrl.startsWith('http'), 'Image URL should be a valid URL')
|
|
88
88
|
})
|
|
89
89
|
|
|
@@ -97,13 +97,13 @@ test('getAFamilyImage', async (t) => {
|
|
|
97
97
|
assert.ok(imageId, 'Image ID should exist')
|
|
98
98
|
|
|
99
99
|
const response = await getAFamilyImage({
|
|
100
|
-
accessToken,
|
|
100
|
+
accessToken: await token.getAccessToken(),
|
|
101
101
|
imageId,
|
|
102
102
|
size: '640x480'
|
|
103
103
|
})
|
|
104
104
|
|
|
105
105
|
assert.ok(response, 'Response should exist')
|
|
106
|
-
assert.
|
|
106
|
+
assert.equal(typeof response.imageUrl, 'string', 'Response should have imageUrl string')
|
|
107
107
|
assert.ok(response.imageUrl.startsWith('http'), 'Image URL should be a valid URL')
|
|
108
108
|
})
|
|
109
109
|
|
|
@@ -117,13 +117,13 @@ test('getAFamilyImage', async (t) => {
|
|
|
117
117
|
assert.ok(imageId, 'Image ID should exist')
|
|
118
118
|
|
|
119
119
|
const response = await getAFamilyImage({
|
|
120
|
-
accessToken,
|
|
120
|
+
accessToken: await token.getAccessToken(),
|
|
121
121
|
imageId,
|
|
122
122
|
size: '320x320'
|
|
123
123
|
})
|
|
124
124
|
|
|
125
125
|
assert.ok(response, 'Response should exist')
|
|
126
|
-
assert.
|
|
126
|
+
assert.equal(typeof response.imageUrl, 'string', 'Response should have imageUrl string')
|
|
127
127
|
assert.ok(response.imageUrl.startsWith('http'), 'Image URL should be a valid URL')
|
|
128
128
|
})
|
|
129
129
|
|
|
@@ -131,7 +131,7 @@ test('getAFamilyImage', async (t) => {
|
|
|
131
131
|
await assert.rejects(
|
|
132
132
|
async () => {
|
|
133
133
|
await getAFamilyImage({
|
|
134
|
-
accessToken,
|
|
134
|
+
accessToken: await token.getAccessToken(),
|
|
135
135
|
imageId: 'invalid-image-id-12345',
|
|
136
136
|
size: '640x480'
|
|
137
137
|
})
|
|
@@ -4,12 +4,12 @@ import { getPublicIcons, getUserIcons } from './icons.js'
|
|
|
4
4
|
import { YotoAPIError } from './helpers.js'
|
|
5
5
|
import { loadTestTokens, logResponse } from './endpoint-test-helpers.js'
|
|
6
6
|
|
|
7
|
-
const {
|
|
7
|
+
const { token } = loadTestTokens()
|
|
8
8
|
|
|
9
9
|
test('getPublicIcons', async (t) => {
|
|
10
10
|
await t.test('should fetch public display icons', async () => {
|
|
11
11
|
const response = await getPublicIcons({
|
|
12
|
-
accessToken
|
|
12
|
+
accessToken: await token.getAccessToken(),
|
|
13
13
|
})
|
|
14
14
|
|
|
15
15
|
// Log response for type verification and documentation
|
|
@@ -24,13 +24,13 @@ test('getPublicIcons', async (t) => {
|
|
|
24
24
|
// Validate icon structure
|
|
25
25
|
const icon = response.displayIcons[0]
|
|
26
26
|
assert.ok(icon, 'Icon should exist')
|
|
27
|
-
assert.
|
|
28
|
-
assert.
|
|
29
|
-
assert.
|
|
27
|
+
assert.equal(typeof icon.displayIconId, 'string', 'Icon should have displayIconId string')
|
|
28
|
+
assert.equal(typeof icon.mediaId, 'string', 'Icon should have mediaId string')
|
|
29
|
+
assert.equal(typeof icon.userId, 'string', 'Icon should have userId string')
|
|
30
30
|
assert.strictEqual(icon.userId, 'yoto', 'Public icon userId should be "yoto"')
|
|
31
|
-
assert.
|
|
32
|
-
assert.
|
|
33
|
-
assert.
|
|
31
|
+
assert.equal(typeof icon.createdAt, 'string', 'Icon should have createdAt string')
|
|
32
|
+
assert.equal(typeof icon.title, 'string', 'Icon should have title string')
|
|
33
|
+
assert.equal(typeof icon.url, 'string', 'Icon should have url string')
|
|
34
34
|
assert.ok(icon.url.startsWith('http'), 'Icon URL should be a valid URL')
|
|
35
35
|
assert.strictEqual(icon.public, true, 'Public icon should have public=true')
|
|
36
36
|
// Note: new field may not always be present in public icons
|
|
@@ -60,7 +60,7 @@ test('getPublicIcons', async (t) => {
|
|
|
60
60
|
test('getUserIcons', async (t) => {
|
|
61
61
|
await t.test('should fetch user custom icons', async () => {
|
|
62
62
|
const response = await getUserIcons({
|
|
63
|
-
accessToken
|
|
63
|
+
accessToken: await token.getAccessToken()
|
|
64
64
|
})
|
|
65
65
|
|
|
66
66
|
// Log response for type verification and documentation
|
|
@@ -75,11 +75,11 @@ test('getUserIcons', async (t) => {
|
|
|
75
75
|
if (response.displayIcons.length > 0) {
|
|
76
76
|
const icon = response.displayIcons[0]
|
|
77
77
|
assert.ok(icon, 'Icon should exist')
|
|
78
|
-
assert.
|
|
79
|
-
assert.
|
|
80
|
-
assert.
|
|
81
|
-
assert.
|
|
82
|
-
assert.
|
|
78
|
+
assert.equal(typeof icon.displayIconId, 'string', 'Icon should have displayIconId string')
|
|
79
|
+
assert.equal(typeof icon.mediaId, 'string', 'Icon should have mediaId string')
|
|
80
|
+
assert.equal(typeof icon.userId, 'string', 'Icon should have userId string')
|
|
81
|
+
assert.equal(typeof icon.createdAt, 'string', 'Icon should have createdAt string')
|
|
82
|
+
assert.equal(typeof icon.url, 'string', 'Icon should have url string')
|
|
83
83
|
assert.strictEqual(icon.public, false, 'User icon should have public=false')
|
|
84
84
|
assert.strictEqual('title' in icon, false, 'User icon should not have title')
|
|
85
85
|
assert.strictEqual('publicTags' in icon, false, 'User icon should not have publicTags')
|