pryv 3.0.0 → 3.0.2

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.
@@ -5,7 +5,7 @@
5
5
  /* global describe, it, before, after, beforeEach, afterEach, expect, JSDOM, pryv, Blob, FormData */
6
6
 
7
7
  // URL and URLSearchParams are native in Node.js and browsers
8
- const cuid = require('cuid');
8
+ const { createId: cuid } = require('@paralleldrive/cuid2');
9
9
  const testData = require('../../../test/test-data');
10
10
 
11
11
  let conn = null;
@@ -17,15 +17,15 @@ if (isNode) { // node
17
17
  readFileSync = require('fs').readFileSync;
18
18
  }
19
19
 
20
- describe('Connection', () => {
20
+ describe('[CONX] Connection', () => {
21
21
  before(async function () {
22
22
  this.timeout(15000);
23
23
  await testData.prepare();
24
24
  conn = new pryv.Connection(testData.apiEndpointWithToken);
25
25
 
26
- // create some events
27
- const toBeDeletedId = cuid();
28
- const toBeTrashed = cuid();
26
+ // create some events (prefix with 'c' for v2 event ID pattern)
27
+ const toBeDeletedId = 'c' + cuid();
28
+ const toBeTrashed = 'c' + cuid();
29
29
  await conn.api([
30
30
  {
31
31
  method: 'events.create',
@@ -74,35 +74,35 @@ describe('Connection', () => {
74
74
  ]);
75
75
  });
76
76
 
77
- describe('.service', function () {
78
- it('return a pryv.Service object', async () => {
77
+ describe('[CSRV] .service', function () {
78
+ it('[CSRA] return a pryv.Service object', async () => {
79
79
  const service = conn.service;
80
80
  expect(service instanceof pryv.Service).to.equal(true);
81
81
  });
82
82
  });
83
83
 
84
- describe('.username() ', function () {
85
- it('return the username of this connection', async () => {
84
+ describe('[CUSR] .username() ', function () {
85
+ it('[CUSA] return the username of this connection', async () => {
86
86
  const username = await conn.username();
87
87
  expect(username).to.equal(testData.username);
88
88
  });
89
89
  });
90
90
 
91
- describe('.apiOne()', function () {
91
+ describe('[CAOX] .apiOne()', function () {
92
92
  this.timeout(15000);
93
- it('.apiOne("events.get")', async () => {
93
+ it('[CAOA] .apiOne("events.get")', async () => {
94
94
  const res = await conn.apiOne('events.get');
95
95
  expect(res.events).to.exist;
96
96
  });
97
- it('.apiOne("events.get")', async () => {
97
+ it('[CAOB] .apiOne("events.get") with path', async () => {
98
98
  const res = await conn.apiOne('events.get', {}, 'events');
99
99
  expect(Array.isArray(res)).to.equal(true);
100
100
  });
101
101
  });
102
102
 
103
- describe('.api()', function () {
103
+ describe('[CAPX] .api()', function () {
104
104
  this.timeout(15000);
105
- it('.api() events.get', async () => {
105
+ it('[CAPA] .api() events.get', async () => {
106
106
  const res = await conn.api(
107
107
  [
108
108
  {
@@ -113,7 +113,7 @@ describe('Connection', () => {
113
113
  expect(res.length).to.equal(1);
114
114
  });
115
115
 
116
- it('.api() events.get split in chunks', async () => {
116
+ it('[CAPB] .api() events.get split in chunks', async () => {
117
117
  conn.options.chunkSize = 2;
118
118
  const res = await conn.api(
119
119
  [
@@ -124,7 +124,7 @@ describe('Connection', () => {
124
124
  expect(res.length).to.equal(3);
125
125
  });
126
126
 
127
- it('.api() events.get with handleResult call', async () => {
127
+ it('[CAPC] .api() events.get with handleResult call', async () => {
128
128
  conn.options.chunkSize = 2;
129
129
 
130
130
  let resultsReceivedCount = 0;
@@ -144,7 +144,7 @@ describe('Connection', () => {
144
144
  expect(res.length).to.equal(resultsReceivedCount);
145
145
  });
146
146
 
147
- it('.api() events.get with async handleResult call', async () => {
147
+ it('[CAPD] .api() events.get with async handleResult call', async () => {
148
148
  conn.options.chunkSize = 2;
149
149
 
150
150
  let resultsReceivedCount = 0;
@@ -169,7 +169,7 @@ describe('Connection', () => {
169
169
  expect(res.length).to.equal(resultsReceivedCount);
170
170
  });
171
171
 
172
- it('.api() events.get split in chunks and send percentages', async () => {
172
+ it('[CAPE] .api() events.get split in chunks and send percentages', async () => {
173
173
  conn.options.chunkSize = 2;
174
174
  const percentres = { 1: 67, 2: 100 };
175
175
  let count = 1;
@@ -185,7 +185,7 @@ describe('Connection', () => {
185
185
  expect(res.length).to.equal(3);
186
186
  });
187
187
 
188
- it('.api() with callbacks', (done) => {
188
+ it('[CAPF] .api() with callbacks', (done) => {
189
189
  conn.api(
190
190
  [
191
191
  { method: 'events.get', params: {} }
@@ -199,8 +199,8 @@ describe('Connection', () => {
199
199
  });
200
200
  });
201
201
 
202
- describe('Attachments', () => {
203
- it('Node Only: Create event with attachment from file', async function () {
202
+ describe('[CATX] Attachments', () => {
203
+ it('[CATA] Node Only: Create event with attachment from file', async function () {
204
204
  if (!isNode) { this.skip(); }
205
205
  const res = await conn.createEventWithFile({
206
206
  type: 'picture/attached',
@@ -216,7 +216,7 @@ describe('Connection', () => {
216
216
  expect(res.event.attachments[0].fileName).to.equal('Y.png');
217
217
  });
218
218
 
219
- it('Node Only: Create event with attachment from Buffer', async function () {
219
+ it('[CATB] Node Only: Create event with attachment from Buffer', async function () {
220
220
  if (!isNode) { this.skip(); }
221
221
 
222
222
  const fileData = readFileSync('./test/Y.png');
@@ -234,7 +234,7 @@ describe('Connection', () => {
234
234
  expect(res.event.attachments[0].fileName).to.equal('Y.png');
235
235
  });
236
236
 
237
- it('Browser Only: Create event with attachment from Buffer', async function () {
237
+ it('[CATC] Browser Only: Create event with attachment from Buffer', async function () {
238
238
  if (isNode) { this.skip(); }
239
239
 
240
240
  const blob = new Blob(['Hello'], { type: 'text/txt' });
@@ -252,7 +252,7 @@ describe('Connection', () => {
252
252
  expect(res.event.attachments[0].fileName).to.equal('Hello.txt');
253
253
  });
254
254
 
255
- it('Browser Only: Create event with attachment formData', async function () {
255
+ it('[CATD] Browser Only: Create event with attachment formData', async function () {
256
256
  if (isNode) { this.skip(); }
257
257
 
258
258
  const formData = new FormData();
@@ -274,14 +274,14 @@ describe('Connection', () => {
274
274
  });
275
275
  });
276
276
 
277
- describe('HF events', async function () {
277
+ describe('[CHFX] HF events', async function () {
278
278
  before(async function () {
279
279
  if (!await conn.service.supportsHF()) {
280
280
  this.skip();
281
281
  }
282
282
  });
283
283
 
284
- it('Add data points to HF event', async () => {
284
+ it('[CHFA] Add data points to HF event', async () => {
285
285
  const res = await conn.api([{
286
286
  method: 'events.create',
287
287
  params: {
@@ -305,22 +305,30 @@ describe('Connection', () => {
305
305
  });
306
306
  });
307
307
 
308
- describe('.get()', () => {
309
- it('/events', async () => {
308
+ describe('[CGTX] .get()', () => {
309
+ it('[CGTA] /events', async () => {
310
310
  const res = await conn.get('events', { limit: 1 });
311
311
  expect(res.events.length).to.equal(1);
312
312
  });
313
+
314
+ it('[CGTB] /events with params', async () => {
315
+ const res = await conn.get('events', { fromTime: 0, toTime: Date.now() / 1000, limit: 10000, types: ['note/txt'], streams: ['data', 'monitor-test'] });
316
+ expect(res.events.length > 0).to.be.true;
317
+ for (const event of res.events) {
318
+ expect(event.type).to.equal('note/txt');
319
+ }
320
+ });
313
321
  });
314
322
 
315
- describe('time', () => {
316
- it('deltatime property', async () => {
323
+ describe('[CTMX] time', () => {
324
+ it('[CTMA] deltatime property', async () => {
317
325
  await conn.get('events', { limit: 1 });
318
326
  expect(conn.deltaTime).to.be.within(-2, 2);
319
327
  });
320
328
  });
321
329
 
322
- describe('API', () => {
323
- it('endpoint property', async () => {
330
+ describe('[CEPX] API', () => {
331
+ it('[CEPA] endpoint property', async () => {
324
332
  const [protocol, hostPath] = testData.serviceInfo.api.split('://');
325
333
  const challenge = protocol + '://' + conn.token + '@' + hostPath.replace('{username}', testData.username);
326
334
  const apiEndpoint = conn.apiEndpoint;
@@ -328,12 +336,12 @@ describe('Connection', () => {
328
336
  });
329
337
  });
330
338
 
331
- describe('Streamed event get', function () {
339
+ describe('[CSTX] Streamed event get', function () {
332
340
  this.timeout(15000);
333
341
  const now = (new Date()).getTime() / 1000 + 1000;
334
342
 
335
- describe('Node & Browser', function () {
336
- it('streaming ', async () => {
343
+ describe('[CSNX] Node & Browser', function () {
344
+ it('[CSNA] streaming ', async () => {
337
345
  const queryParams = { fromTime: 0, toTime: now, limit: 10000 };
338
346
  let eventsCount = 0;
339
347
  function forEachEvent (event) { eventsCount++; }
@@ -341,7 +349,44 @@ describe('Connection', () => {
341
349
  expect(eventsCount).to.equal(res.eventsCount);
342
350
  });
343
351
 
344
- it('streaming includesDeletion', async () => {
352
+ it('[CSNZ] streaming with query params', async () => {
353
+ const queryParams = { fromTime: 0, toTime: Date.now() / 1000, limit: 10000, types: ['note/txt'], streams: ['data', 'monitor-test'] };
354
+ let eventsCount = 0;
355
+ function forEachEvent (event) {
356
+ eventsCount++;
357
+ }
358
+ const res = await conn.getEventsStreamed(queryParams, forEachEvent);
359
+ expect(eventsCount).to.equal(res.eventsCount);
360
+ });
361
+
362
+ it('[CSNY] streaming with roneous query params', async () => {
363
+ const queryParams = { fromTime: 0, toTime: Date.now() / 1000, limit: 10000, types: ['note/txt'], streams: ['bogus', 'bogus2'] };
364
+ let eventsCount = 0;
365
+ function forEachEvent (event) {
366
+ eventsCount++;
367
+ }
368
+ try {
369
+ const res = await conn.getEventsStreamed(queryParams, forEachEvent);
370
+ expect(eventsCount).to.equal(res.eventsCount);
371
+ } catch (e) {
372
+ return;
373
+ }
374
+ throw new Error('Should fail');
375
+ });
376
+
377
+ it('[CSNB] streaming includesDeletion', async () => {
378
+ // Create, trash, and delete events to ensure we have all three states
379
+ const trashId = 'c' + cuid();
380
+ const deleteId = 'c' + cuid();
381
+ const setupRes = await conn.api([
382
+ { method: 'events.create', params: { id: trashId, streamIds: ['data'], type: 'note/txt', content: 'to trash' } },
383
+ { method: 'events.create', params: { id: deleteId, streamIds: ['data'], type: 'note/txt', content: 'to delete' } },
384
+ { method: 'events.delete', params: { id: trashId } },
385
+ { method: 'events.delete', params: { id: deleteId } },
386
+ { method: 'events.delete', params: { id: deleteId } }
387
+ ]);
388
+ // Verify setup succeeded
389
+ expect(setupRes[0].event, 'event creation failed: ' + JSON.stringify(setupRes[0].error)).to.exist;
345
390
  const queryParams = { fromTime: 0, toTime: now, limit: 10000, includeDeletions: true, modifiedSince: 0, state: 'all' };
346
391
  let eventsCount = 0;
347
392
  let trashedCount = 0;
@@ -363,14 +408,14 @@ describe('Connection', () => {
363
408
  expect(trashedCount).to.be.gt(0);
364
409
  });
365
410
 
366
- it('no-events ', async () => {
411
+ it('[CSNC] no-events ', async () => {
367
412
  const queryParams = { fromTime: 0, toTime: now, types: ['type/unexistent'] };
368
413
  function forEachEvent (event) { }
369
414
  const res = await conn.getEventsStreamed(queryParams, forEachEvent);
370
415
  expect(0).to.equal(res.eventsCount);
371
416
  });
372
417
 
373
- it('no-events includeDeletions', async () => {
418
+ it('[CSND] no-events includeDeletions', async () => {
374
419
  const queryParams = { fromTime: 0, toTime: now, types: ['type/unexistent'], includeDeletions: true, modifiedSince: 0 };
375
420
  function forEachEvent (event) { }
376
421
  const res = await conn.getEventsStreamed(queryParams, forEachEvent);
@@ -380,7 +425,7 @@ describe('Connection', () => {
380
425
  });
381
426
 
382
427
  if (typeof window === 'undefined') {
383
- describe('Browser mock', function () {
428
+ describe('[CSBX] Browser mock', function () {
384
429
  beforeEach(function () {
385
430
  const dom = new JSDOM('<!DOCTYPE html>', { url: 'http://localhost/' });
386
431
  global.document = dom.window.document;
@@ -394,7 +439,7 @@ describe('Connection', () => {
394
439
  delete global.location;
395
440
  });
396
441
 
397
- it(' with fetch', async () => {
442
+ it('[CSBA] with fetch', async () => {
398
443
  const queryParams = { fromTime: 0, toTime: now, limit: 10000 };
399
444
  let eventsCount = 0;
400
445
  function forEachEvent (event) { eventsCount++; }
@@ -405,7 +450,7 @@ describe('Connection', () => {
405
450
  }
406
451
  });
407
452
 
408
- describe('Access Info', () => {
453
+ describe('[CAIX] Access Info', () => {
409
454
  let newUser;
410
455
  let accessInfoUser;
411
456
  before(async () => {
@@ -444,13 +489,13 @@ describe('Connection', () => {
444
489
  ]);
445
490
  });
446
491
 
447
- it('has same username', () => {
492
+ it('[CAIA] has same username', () => {
448
493
  expect(accessInfoUser).to.exist;
449
494
  expect(accessInfoUser.name).to.exist;
450
495
  expect(newUser.access.name).to.equal(accessInfoUser.name);
451
496
  });
452
497
 
453
- it('has same token', () => {
498
+ it('[CAIB] has same token', () => {
454
499
  expect(accessInfoUser.token).to.exist;
455
500
  expect(newUser.access.token).to.equal(accessInfoUser.token);
456
501
  });
@@ -0,0 +1,69 @@
1
+ /**
2
+ * @license
3
+ * [BSD-3-Clause](https://github.com/pryv/lib-js/blob/master/LICENSE)
4
+ */
5
+ /* global describe, it, before, after, expect, JSDOM */
6
+
7
+ const CookieUtils = require('../src/Browser/CookieUtils');
8
+
9
+ describe('[COKX] CookieUtils', function () {
10
+ let cleanupDom = false;
11
+
12
+ before(async () => {
13
+ if (typeof document !== 'undefined') return; // in browser
14
+ cleanupDom = true;
15
+ const dom = new JSDOM('<!DOCTYPE html>', {
16
+ url: 'http://localhost/'
17
+ });
18
+ global.document = dom.window.document;
19
+ global.window = dom.window;
20
+ });
21
+
22
+ after(async () => {
23
+ if (!cleanupDom) return;
24
+ delete global.document;
25
+ delete global.window;
26
+ });
27
+
28
+ it('[COKA] set() and get() cookie', async function () {
29
+ const testKey = 'test-cookie-key';
30
+ const testValue = { foo: 'bar', num: 123 };
31
+ CookieUtils.set(testKey, testValue);
32
+ const retrieved = CookieUtils.get(testKey);
33
+ expect(retrieved).to.deep.equal(testValue);
34
+ });
35
+
36
+ it('[COKB] get() returns undefined for non-existent cookie', async function () {
37
+ const result = CookieUtils.get('non-existent-cookie-key');
38
+ expect(result).to.be.undefined;
39
+ });
40
+
41
+ it('[COKC] del() removes cookie', async function () {
42
+ const testKey = 'cookie-to-delete';
43
+ CookieUtils.set(testKey, { data: 'test' });
44
+ expect(CookieUtils.get(testKey)).to.exist;
45
+ CookieUtils.del(testKey);
46
+ // After deletion, the cookie is set to { deleted: true } with expiration in the past
47
+ // The cookie may still exist but with deleted flag
48
+ const afterDel = CookieUtils.get(testKey);
49
+ if (afterDel) {
50
+ expect(afterDel.deleted).to.be.true;
51
+ }
52
+ });
53
+
54
+ it('[COKD] set() with custom expiration', async function () {
55
+ const testKey = 'cookie-with-expiry';
56
+ const testValue = 'expires-soon';
57
+ CookieUtils.set(testKey, testValue, 30);
58
+ const retrieved = CookieUtils.get(testKey);
59
+ expect(retrieved).to.equal(testValue);
60
+ });
61
+
62
+ it('[COKE] handles special characters in values', async function () {
63
+ const testKey = 'special-chars';
64
+ const testValue = { text: 'hello=world&foo=bar', unicode: '日本語' };
65
+ CookieUtils.set(testKey, testValue);
66
+ const retrieved = CookieUtils.get(testKey);
67
+ expect(retrieved).to.deep.equal(testValue);
68
+ });
69
+ });
@@ -0,0 +1,196 @@
1
+ /**
2
+ * @license
3
+ * [BSD-3-Clause](https://github.com/pryv/lib-js/blob/master/LICENSE)
4
+ */
5
+ /* global describe, it, before, after, expect, JSDOM, testData */
6
+
7
+ const LoginButton = require('../src/Browser/LoginButton');
8
+ const Service = require('../src/Service');
9
+ const AuthStates = require('../src/Auth/AuthStates');
10
+
11
+ describe('[LBTX] LoginButton', function () {
12
+ this.timeout(20000);
13
+
14
+ let service;
15
+ let cleanupDom = false;
16
+ let dom;
17
+
18
+ before(async function () {
19
+ await testData.prepare();
20
+ service = new Service(testData.serviceInfoUrl);
21
+ await service.info();
22
+ });
23
+
24
+ before(async () => {
25
+ if (typeof document !== 'undefined') return;
26
+ cleanupDom = true;
27
+ dom = new JSDOM('<!DOCTYPE html><body><span id="loginButton"></span></body>', {
28
+ url: 'http://localhost/'
29
+ });
30
+ global.document = dom.window.document;
31
+ global.window = dom.window;
32
+ global.location = dom.window.location;
33
+ global.navigator = { userAgent: 'Safari' };
34
+ global.confirm = () => true;
35
+ });
36
+
37
+ after(async () => {
38
+ if (!cleanupDom) return;
39
+ delete global.document;
40
+ delete global.window;
41
+ delete global.location;
42
+ delete global.confirm;
43
+ });
44
+
45
+ describe('[LBCX] Constructor and Init', function () {
46
+ it('[LBCA] creates LoginButton with valid settings', async function () {
47
+ const settings = {
48
+ spanButtonID: 'loginButton',
49
+ authRequest: {
50
+ requestingAppId: 'test-app',
51
+ requestedPermissions: []
52
+ }
53
+ };
54
+ const loginBtn = new LoginButton(settings, service);
55
+ expect(loginBtn.authSettings).to.equal(settings);
56
+ expect(loginBtn.service).to.equal(service);
57
+ });
58
+
59
+ it('[LBCB] init() sets up button and auth controller', async function () {
60
+ const settings = {
61
+ spanButtonID: 'loginButton',
62
+ authRequest: {
63
+ requestingAppId: 'test-app',
64
+ requestedPermissions: []
65
+ }
66
+ };
67
+ const loginBtn = new LoginButton(settings, service);
68
+ await loginBtn.init();
69
+ expect(loginBtn.auth).to.exist;
70
+ expect(loginBtn._cookieKey).to.include('pryv-libjs-');
71
+ });
72
+ });
73
+
74
+ describe('[LBAX] Authorization data', function () {
75
+ let loginBtn;
76
+
77
+ before(async function () {
78
+ const settings = {
79
+ spanButtonID: 'loginButton',
80
+ authRequest: {
81
+ requestingAppId: 'test-app-auth',
82
+ requestedPermissions: []
83
+ }
84
+ };
85
+ loginBtn = new LoginButton(settings, service);
86
+ await loginBtn.init();
87
+ });
88
+
89
+ it('[LBAA] saveAuthorizationData and getAuthorizationData work', function () {
90
+ const authData = { apiEndpoint: 'https://test.pryv.me', username: 'testuser' };
91
+ loginBtn.saveAuthorizationData(authData);
92
+ const retrieved = loginBtn.getAuthorizationData();
93
+ expect(retrieved).to.deep.equal(authData);
94
+ });
95
+
96
+ it('[LBAB] deleteAuthorizationData removes data', async function () {
97
+ loginBtn.saveAuthorizationData({ test: 'data' });
98
+ await loginBtn.deleteAuthorizationData();
99
+ const retrieved = loginBtn.getAuthorizationData();
100
+ // After deletion, either undefined or has deleted flag
101
+ if (retrieved) {
102
+ expect(retrieved.deleted).to.be.true;
103
+ }
104
+ });
105
+ });
106
+
107
+ describe('[LBOX] onClick', function () {
108
+ it('[LBOA] onClick calls auth.handleClick', async function () {
109
+ const settings = {
110
+ spanButtonID: 'loginButton',
111
+ authRequest: {
112
+ requestingAppId: 'test-app-click',
113
+ requestedPermissions: []
114
+ }
115
+ };
116
+ const loginBtn = new LoginButton(settings, service);
117
+ await loginBtn.init();
118
+
119
+ let handleClickCalled = false;
120
+ loginBtn.auth.handleClick = function () { handleClickCalled = true; };
121
+
122
+ loginBtn.onClick();
123
+ expect(handleClickCalled).to.be.true;
124
+ });
125
+ });
126
+
127
+ describe('[LBSX] onStateChange', function () {
128
+ let loginBtn;
129
+
130
+ before(async function () {
131
+ const settings = {
132
+ spanButtonID: 'loginButton',
133
+ authRequest: {
134
+ requestingAppId: 'test-app-state',
135
+ requestedPermissions: []
136
+ }
137
+ };
138
+ loginBtn = new LoginButton(settings, service);
139
+ await loginBtn.init();
140
+ });
141
+
142
+ it('[LBSA] handles LOADING state', async function () {
143
+ await loginBtn.onStateChange({ status: AuthStates.LOADING });
144
+ expect(loginBtn.text).to.equal('...');
145
+ });
146
+
147
+ it('[LBSB] handles INITIALIZED state', async function () {
148
+ await loginBtn.onStateChange({ status: AuthStates.INITIALIZED });
149
+ expect(loginBtn.text).to.include('Signin');
150
+ });
151
+
152
+ it('[LBSC] handles AUTHORIZED state', async function () {
153
+ await loginBtn.onStateChange({
154
+ status: AuthStates.AUTHORIZED,
155
+ username: 'testuser',
156
+ apiEndpoint: 'https://test.pryv.me'
157
+ });
158
+ expect(loginBtn.text).to.equal('testuser');
159
+ });
160
+
161
+ it('[LBSD] handles ERROR state', async function () {
162
+ await loginBtn.onStateChange({
163
+ status: AuthStates.ERROR,
164
+ message: 'Test error'
165
+ });
166
+ expect(loginBtn.text).to.include('Error');
167
+ expect(loginBtn.text).to.include('Test error');
168
+ });
169
+
170
+ it('[LBSE] handles SIGNOUT state when confirmed', async function () {
171
+ // Save some auth data first
172
+ loginBtn.saveAuthorizationData({ test: 'data' });
173
+ await loginBtn.onStateChange({ status: AuthStates.SIGNOUT });
174
+ // Confirm is mocked to return true
175
+ });
176
+
177
+ it('[LBSF] handles unknown state gracefully', async function () {
178
+ // Should log warning but not throw
179
+ await loginBtn.onStateChange({ status: 'UNKNOWN_STATE' });
180
+ });
181
+ });
182
+
183
+ describe('[LBWX] Without spanButtonID', function () {
184
+ it('[LBWA] init works without span (logs warning)', async function () {
185
+ const settings = {
186
+ authRequest: {
187
+ requestingAppId: 'test-app-no-span',
188
+ requestedPermissions: []
189
+ }
190
+ };
191
+ const loginBtn = new LoginButton(settings, service);
192
+ await loginBtn.init();
193
+ expect(loginBtn.loginButtonSpan).to.be.null;
194
+ });
195
+ });
196
+ });
@@ -0,0 +1,48 @@
1
+ /**
2
+ * @license
3
+ * [BSD-3-Clause](https://github.com/pryv/lib-js/blob/master/LICENSE)
4
+ */
5
+ /* global describe, it, expect */
6
+
7
+ const Messages = require('../src/Auth/LoginMessages');
8
+
9
+ describe('[MSGX] LoginMessages', function () {
10
+ it('[MSGA] returns English messages by default', function () {
11
+ const msgs = Messages('en');
12
+ expect(msgs.LOADING).to.equal('...');
13
+ expect(msgs.ERROR).to.equal('Error');
14
+ expect(msgs.LOGIN).to.equal('Signin');
15
+ expect(msgs.SIGNOUT_CONFIRM).to.equal('Logout?');
16
+ });
17
+
18
+ it('[MSGB] returns French messages when available', function () {
19
+ const msgs = Messages('fr');
20
+ expect(msgs.ERROR).to.equal('Erreur');
21
+ expect(msgs.LOGIN).to.equal('Login');
22
+ expect(msgs.SIGNOUT_CONFIRM).to.equal('Se déconnecter ?');
23
+ });
24
+
25
+ it('[MSGC] falls back to English for unavailable language', function () {
26
+ const msgs = Messages('de');
27
+ expect(msgs.LOADING).to.equal('...');
28
+ expect(msgs.ERROR).to.equal('Error');
29
+ });
30
+
31
+ it('[MSGD] uses custom definitions when provided', function () {
32
+ const customDefs = {
33
+ LOADING: { en: 'Loading...', fr: 'Chargement...' },
34
+ CUSTOM: { en: 'Custom Message', fr: 'Message personnalisé' }
35
+ };
36
+ const msgs = Messages('en', customDefs);
37
+ expect(msgs.LOADING).to.equal('Loading...');
38
+ expect(msgs.CUSTOM).to.equal('Custom Message');
39
+ });
40
+
41
+ it('[MSGE] custom definitions fall back to English', function () {
42
+ const customDefs = {
43
+ TEST: { en: 'English only' }
44
+ };
45
+ const msgs = Messages('fr', customDefs);
46
+ expect(msgs.TEST).to.equal('English only');
47
+ });
48
+ });
@@ -0,0 +1,40 @@
1
+ /**
2
+ * @license
3
+ * [BSD-3-Clause](https://github.com/pryv/lib-js/blob/master/LICENSE)
4
+ */
5
+ /* global describe, it, expect */
6
+
7
+ const PryvError = require('../src/lib/PryvError');
8
+
9
+ describe('[PERX] PryvError', function () {
10
+ it('[PERA] creates error with message', function () {
11
+ const error = new PryvError('Test error message');
12
+ expect(error.message).to.equal('Test error message');
13
+ expect(error.name).to.equal('PryvError');
14
+ expect(error).to.be.instanceOf(Error);
15
+ expect(error).to.be.instanceOf(PryvError);
16
+ });
17
+
18
+ it('[PERB] includes innerObject when provided', function () {
19
+ const innerError = new Error('Inner error');
20
+ const error = new PryvError('Outer message', innerError);
21
+ expect(error.innerObject).to.equal(innerError);
22
+ });
23
+
24
+ it('[PERC] accepts object as innerObject', function () {
25
+ const innerObj = { code: 'ERR_001', details: 'some details' };
26
+ const error = new PryvError('Error with object', innerObj);
27
+ expect(error.innerObject).to.deep.equal(innerObj);
28
+ });
29
+
30
+ it('[PERD] has proper stack trace', function () {
31
+ const error = new PryvError('Stack test');
32
+ expect(error.stack).to.exist;
33
+ expect(error.stack).to.include('PryvError');
34
+ });
35
+
36
+ it('[PERE] innerObject is undefined when not provided', function () {
37
+ const error = new PryvError('No inner');
38
+ expect(error.innerObject).to.be.undefined;
39
+ });
40
+ });