pict-section-login 0.0.1

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.
Files changed (25) hide show
  1. package/example_applications/custom_login/Custom-Login-Application.js +75 -0
  2. package/example_applications/custom_login/html/index.html +110 -0
  3. package/example_applications/custom_login/package.json +27 -0
  4. package/example_applications/harness_app/Harness-App-Application.js +167 -0
  5. package/example_applications/harness_app/Harness-App-Configuration.json +4 -0
  6. package/example_applications/harness_app/html/index.html +90 -0
  7. package/example_applications/harness_app/package.json +28 -0
  8. package/example_applications/harness_app/providers/PictRouter-HarnessApp.json +24 -0
  9. package/example_applications/harness_app/views/PictView-HarnessApp-Books.js +172 -0
  10. package/example_applications/harness_app/views/PictView-HarnessApp-Dashboard.js +158 -0
  11. package/example_applications/harness_app/views/PictView-HarnessApp-Layout.js +86 -0
  12. package/example_applications/harness_app/views/PictView-HarnessApp-Login.js +58 -0
  13. package/example_applications/harness_app/views/PictView-HarnessApp-TopBar.js +157 -0
  14. package/example_applications/harness_app/views/PictView-HarnessApp-Users.js +188 -0
  15. package/example_applications/oauth_login/OAuth-Login-Application.js +78 -0
  16. package/example_applications/oauth_login/html/index.html +57 -0
  17. package/example_applications/oauth_login/package.json +27 -0
  18. package/example_applications/orator_login/Orator-Login-Application.js +61 -0
  19. package/example_applications/orator_login/html/index.html +51 -0
  20. package/example_applications/orator_login/package.json +27 -0
  21. package/package.json +53 -0
  22. package/source/Pict-Section-Login-DefaultConfiguration.js +265 -0
  23. package/source/Pict-Section-Login.js +533 -0
  24. package/test/Browser_Integration_tests.js +588 -0
  25. package/test/Pict-Section-Login_tests.js +593 -0
@@ -0,0 +1,593 @@
1
+ /*
2
+ Unit tests for Pict-Section-Login
3
+ */
4
+
5
+ const libBrowserEnv = require('browser-env');
6
+ libBrowserEnv();
7
+
8
+ const Chai = require('chai');
9
+ const Expect = Chai.expect;
10
+
11
+ const libPict = require('pict');
12
+
13
+ const configureTestPict = (pPict) =>
14
+ {
15
+ let tmpPict = (typeof (pPict) == 'undefined') ? new libPict() : pPict;
16
+ tmpPict.TestData = (
17
+ {
18
+ Reads: [],
19
+ Assignments: [],
20
+ Appends: [],
21
+ Gets: []
22
+ });
23
+ tmpPict.ContentAssignment.customReadFunction = (pAddress, pContentType) =>
24
+ {
25
+ tmpPict.TestData.Reads.push(pAddress);
26
+ tmpPict.log.info(`Mocking a read of type ${pContentType} from Address: ${pAddress}`);
27
+ return '';
28
+ };
29
+ tmpPict.ContentAssignment.customGetElementFunction = (pAddress) =>
30
+ {
31
+ tmpPict.TestData.Gets.push(pAddress);
32
+ tmpPict.log.info(`Mocking a get of Address: ${pAddress}`);
33
+ return '';
34
+ };
35
+ tmpPict.ContentAssignment.customAppendElementFunction = (pAddress, pContent) =>
36
+ {
37
+ tmpPict.TestData.Appends.push(pAddress);
38
+ tmpPict.log.info(`Mocking an append of Address: ${pAddress}`, { Content: pContent });
39
+ return '';
40
+ };
41
+ tmpPict.ContentAssignment.customAssignFunction = (pAddress, pContent) =>
42
+ {
43
+ tmpPict.TestData.Assignments.push(pAddress);
44
+ tmpPict.log.info(`Mocking an assignment of Address: ${pAddress}`, { Content: pContent });
45
+ return '';
46
+ };
47
+
48
+ return tmpPict;
49
+ };
50
+
51
+ const libPictSectionLogin = require('../source/Pict-Section-Login.js');
52
+
53
+ suite
54
+ (
55
+ 'PictSectionLogin',
56
+ () =>
57
+ {
58
+ setup(() => { });
59
+
60
+ suite
61
+ (
62
+ 'Module Exports',
63
+ () =>
64
+ {
65
+ test
66
+ (
67
+ 'Main class should be exported',
68
+ (fDone) =>
69
+ {
70
+ Expect(libPictSectionLogin).to.be.a('function');
71
+ return fDone();
72
+ }
73
+ );
74
+ test
75
+ (
76
+ 'Default configuration should be exported',
77
+ (fDone) =>
78
+ {
79
+ Expect(libPictSectionLogin.default_configuration).to.be.an('object');
80
+ Expect(libPictSectionLogin.default_configuration).to.have.property('DefaultRenderable');
81
+ Expect(libPictSectionLogin.default_configuration).to.have.property('LoginEndpoint');
82
+ Expect(libPictSectionLogin.default_configuration).to.have.property('LogoutEndpoint');
83
+ Expect(libPictSectionLogin.default_configuration).to.have.property('CheckSessionEndpoint');
84
+ Expect(libPictSectionLogin.default_configuration).to.have.property('CSS');
85
+ Expect(libPictSectionLogin.default_configuration).to.have.property('Templates');
86
+ return fDone();
87
+ }
88
+ );
89
+ }
90
+ );
91
+
92
+ suite
93
+ (
94
+ 'Default Configuration',
95
+ () =>
96
+ {
97
+ test
98
+ (
99
+ 'Should have orator-authentication default endpoints',
100
+ (fDone) =>
101
+ {
102
+ let tmpConfig = libPictSectionLogin.default_configuration;
103
+ Expect(tmpConfig.LoginEndpoint).to.equal('/1.0/Authenticate');
104
+ Expect(tmpConfig.LogoutEndpoint).to.equal('/1.0/Deauthenticate');
105
+ Expect(tmpConfig.CheckSessionEndpoint).to.equal('/1.0/CheckSession');
106
+ Expect(tmpConfig.OAuthProvidersEndpoint).to.equal('/1.0/OAuth/Providers');
107
+ Expect(tmpConfig.OAuthBeginEndpoint).to.equal('/1.0/OAuth/Begin');
108
+ return fDone();
109
+ }
110
+ );
111
+ test
112
+ (
113
+ 'Should default to POST login method',
114
+ (fDone) =>
115
+ {
116
+ Expect(libPictSectionLogin.default_configuration.LoginMethod).to.equal('POST');
117
+ return fDone();
118
+ }
119
+ );
120
+ test
121
+ (
122
+ 'Should have CheckSessionOnLoad enabled by default',
123
+ (fDone) =>
124
+ {
125
+ Expect(libPictSectionLogin.default_configuration.CheckSessionOnLoad).to.equal(true);
126
+ return fDone();
127
+ }
128
+ );
129
+ test
130
+ (
131
+ 'Should have ShowOAuthProviders disabled by default',
132
+ (fDone) =>
133
+ {
134
+ Expect(libPictSectionLogin.default_configuration.ShowOAuthProviders).to.equal(false);
135
+ return fDone();
136
+ }
137
+ );
138
+ test
139
+ (
140
+ 'Should have a SessionDataAddress',
141
+ (fDone) =>
142
+ {
143
+ Expect(libPictSectionLogin.default_configuration.SessionDataAddress).to.equal('AppData.Session');
144
+ return fDone();
145
+ }
146
+ );
147
+ test
148
+ (
149
+ 'Should include 5 templates',
150
+ (fDone) =>
151
+ {
152
+ let tmpTemplates = libPictSectionLogin.default_configuration.Templates;
153
+ Expect(tmpTemplates).to.be.an('array');
154
+ Expect(tmpTemplates.length).to.equal(5);
155
+ let tmpHashes = tmpTemplates.map((pT) => pT.Hash);
156
+ Expect(tmpHashes).to.include('Pict-Login-Template-Wrapper');
157
+ Expect(tmpHashes).to.include('Pict-Login-Template-Form');
158
+ Expect(tmpHashes).to.include('Pict-Login-Template-Status');
159
+ Expect(tmpHashes).to.include('Pict-Login-Template-OAuthProviders');
160
+ Expect(tmpHashes).to.include('Pict-Login-Template-Error');
161
+ return fDone();
162
+ }
163
+ );
164
+ test
165
+ (
166
+ 'Should include CSS',
167
+ (fDone) =>
168
+ {
169
+ Expect(libPictSectionLogin.default_configuration.CSS).to.be.a('string');
170
+ Expect(libPictSectionLogin.default_configuration.CSS).to.contain('.pict-login-card');
171
+ Expect(libPictSectionLogin.default_configuration.CSS).to.contain('.pict-login-form');
172
+ Expect(libPictSectionLogin.default_configuration.CSS).to.contain('.pict-login-oauth');
173
+ return fDone();
174
+ }
175
+ );
176
+ }
177
+ );
178
+
179
+ suite
180
+ (
181
+ 'Basic Initialization',
182
+ () =>
183
+ {
184
+ test
185
+ (
186
+ 'Should create a view instance with default options',
187
+ (fDone) =>
188
+ {
189
+ let tmpPict = configureTestPict();
190
+ let tmpView = tmpPict.addView('Pict-View-TestLogin', {}, libPictSectionLogin);
191
+ Expect(tmpView).to.be.an('object');
192
+ Expect(tmpView.authenticated).to.equal(false);
193
+ Expect(tmpView.sessionData).to.equal(null);
194
+ Expect(tmpView.oauthProviders).to.be.an('array').that.is.empty;
195
+ return fDone();
196
+ }
197
+ );
198
+ test
199
+ (
200
+ 'Should create a view with custom endpoints',
201
+ (fDone) =>
202
+ {
203
+ let tmpPict = configureTestPict();
204
+ let tmpView = tmpPict.addView(
205
+ 'Pict-View-TestLogin-Custom',
206
+ {
207
+ LoginEndpoint: '/api/custom-login',
208
+ LogoutEndpoint: '/api/custom-logout',
209
+ CheckSessionEndpoint: '/api/custom-session'
210
+ },
211
+ libPictSectionLogin
212
+ );
213
+ Expect(tmpView.options.LoginEndpoint).to.equal('/api/custom-login');
214
+ Expect(tmpView.options.LogoutEndpoint).to.equal('/api/custom-logout');
215
+ Expect(tmpView.options.CheckSessionEndpoint).to.equal('/api/custom-session');
216
+ return fDone();
217
+ }
218
+ );
219
+ test
220
+ (
221
+ 'Should create a view with GET login method',
222
+ (fDone) =>
223
+ {
224
+ let tmpPict = configureTestPict();
225
+ let tmpView = tmpPict.addView(
226
+ 'Pict-View-TestLogin-GET',
227
+ {
228
+ LoginMethod: 'GET'
229
+ },
230
+ libPictSectionLogin
231
+ );
232
+ Expect(tmpView.options.LoginMethod).to.equal('GET');
233
+ return fDone();
234
+ }
235
+ );
236
+ test
237
+ (
238
+ 'Should create a view with custom session data address',
239
+ (fDone) =>
240
+ {
241
+ let tmpPict = configureTestPict();
242
+ let tmpView = tmpPict.addView(
243
+ 'Pict-View-TestLogin-Address',
244
+ {
245
+ SessionDataAddress: 'AppData.Auth.CurrentSession'
246
+ },
247
+ libPictSectionLogin
248
+ );
249
+ Expect(tmpView.options.SessionDataAddress).to.equal('AppData.Auth.CurrentSession');
250
+ return fDone();
251
+ }
252
+ );
253
+ test
254
+ (
255
+ 'Should create a view with ShowOAuthProviders enabled',
256
+ (fDone) =>
257
+ {
258
+ let tmpPict = configureTestPict();
259
+ let tmpView = tmpPict.addView(
260
+ 'Pict-View-TestLogin-OAuth',
261
+ {
262
+ ShowOAuthProviders: true
263
+ },
264
+ libPictSectionLogin
265
+ );
266
+ Expect(tmpView.options.ShowOAuthProviders).to.equal(true);
267
+ return fDone();
268
+ }
269
+ );
270
+ test
271
+ (
272
+ 'Should create a view with CheckSessionOnLoad disabled',
273
+ (fDone) =>
274
+ {
275
+ let tmpPict = configureTestPict();
276
+ let tmpView = tmpPict.addView(
277
+ 'Pict-View-TestLogin-NoCheck',
278
+ {
279
+ CheckSessionOnLoad: false
280
+ },
281
+ libPictSectionLogin
282
+ );
283
+ Expect(tmpView.options.CheckSessionOnLoad).to.equal(false);
284
+ return fDone();
285
+ }
286
+ );
287
+ }
288
+ );
289
+
290
+ suite
291
+ (
292
+ 'Public API',
293
+ () =>
294
+ {
295
+ test
296
+ (
297
+ 'login should be a function',
298
+ (fDone) =>
299
+ {
300
+ let tmpPict = configureTestPict();
301
+ let tmpView = tmpPict.addView('Pict-View-TestLogin-API1', {}, libPictSectionLogin);
302
+ Expect(tmpView.login).to.be.a('function');
303
+ return fDone();
304
+ }
305
+ );
306
+ test
307
+ (
308
+ 'logout should be a function',
309
+ (fDone) =>
310
+ {
311
+ let tmpPict = configureTestPict();
312
+ let tmpView = tmpPict.addView('Pict-View-TestLogin-API2', {}, libPictSectionLogin);
313
+ Expect(tmpView.logout).to.be.a('function');
314
+ return fDone();
315
+ }
316
+ );
317
+ test
318
+ (
319
+ 'checkSession should be a function',
320
+ (fDone) =>
321
+ {
322
+ let tmpPict = configureTestPict();
323
+ let tmpView = tmpPict.addView('Pict-View-TestLogin-API3', {}, libPictSectionLogin);
324
+ Expect(tmpView.checkSession).to.be.a('function');
325
+ return fDone();
326
+ }
327
+ );
328
+ test
329
+ (
330
+ 'loadOAuthProviders should be a function',
331
+ (fDone) =>
332
+ {
333
+ let tmpPict = configureTestPict();
334
+ let tmpView = tmpPict.addView('Pict-View-TestLogin-API4', {}, libPictSectionLogin);
335
+ Expect(tmpView.loadOAuthProviders).to.be.a('function');
336
+ return fDone();
337
+ }
338
+ );
339
+ }
340
+ );
341
+
342
+ suite
343
+ (
344
+ 'Overridable Hooks',
345
+ () =>
346
+ {
347
+ test
348
+ (
349
+ 'onLoginSuccess should be a function',
350
+ (fDone) =>
351
+ {
352
+ let tmpPict = configureTestPict();
353
+ let tmpView = tmpPict.addView('Pict-View-TestLogin-Hook1', {}, libPictSectionLogin);
354
+ Expect(tmpView.onLoginSuccess).to.be.a('function');
355
+ return fDone();
356
+ }
357
+ );
358
+ test
359
+ (
360
+ 'onLoginFailed should be a function',
361
+ (fDone) =>
362
+ {
363
+ let tmpPict = configureTestPict();
364
+ let tmpView = tmpPict.addView('Pict-View-TestLogin-Hook2', {}, libPictSectionLogin);
365
+ Expect(tmpView.onLoginFailed).to.be.a('function');
366
+ return fDone();
367
+ }
368
+ );
369
+ test
370
+ (
371
+ 'onLogout should be a function',
372
+ (fDone) =>
373
+ {
374
+ let tmpPict = configureTestPict();
375
+ let tmpView = tmpPict.addView('Pict-View-TestLogin-Hook3', {}, libPictSectionLogin);
376
+ Expect(tmpView.onLogout).to.be.a('function');
377
+ return fDone();
378
+ }
379
+ );
380
+ test
381
+ (
382
+ 'onSessionChecked should be a function',
383
+ (fDone) =>
384
+ {
385
+ let tmpPict = configureTestPict();
386
+ let tmpView = tmpPict.addView('Pict-View-TestLogin-Hook4', {}, libPictSectionLogin);
387
+ Expect(tmpView.onSessionChecked).to.be.a('function');
388
+ return fDone();
389
+ }
390
+ );
391
+ test
392
+ (
393
+ 'Hooks should be overridable on the instance',
394
+ (fDone) =>
395
+ {
396
+ let tmpPict = configureTestPict();
397
+ let tmpView = tmpPict.addView('Pict-View-TestLogin-Hook5', {}, libPictSectionLogin);
398
+ let tmpCalled = false;
399
+ tmpView.onLoginSuccess = () => { tmpCalled = true; };
400
+ tmpView.onLoginSuccess({});
401
+ Expect(tmpCalled).to.equal(true);
402
+ return fDone();
403
+ }
404
+ );
405
+ }
406
+ );
407
+
408
+ suite
409
+ (
410
+ 'State Management',
411
+ () =>
412
+ {
413
+ test
414
+ (
415
+ 'Should start with authenticated = false',
416
+ (fDone) =>
417
+ {
418
+ let tmpPict = configureTestPict();
419
+ let tmpView = tmpPict.addView('Pict-View-TestLogin-State1', {}, libPictSectionLogin);
420
+ Expect(tmpView.authenticated).to.equal(false);
421
+ return fDone();
422
+ }
423
+ );
424
+ test
425
+ (
426
+ 'Should start with sessionData = null',
427
+ (fDone) =>
428
+ {
429
+ let tmpPict = configureTestPict();
430
+ let tmpView = tmpPict.addView('Pict-View-TestLogin-State2', {}, libPictSectionLogin);
431
+ Expect(tmpView.sessionData).to.equal(null);
432
+ return fDone();
433
+ }
434
+ );
435
+ test
436
+ (
437
+ 'Should start with empty oauthProviders array',
438
+ (fDone) =>
439
+ {
440
+ let tmpPict = configureTestPict();
441
+ let tmpView = tmpPict.addView('Pict-View-TestLogin-State3', {}, libPictSectionLogin);
442
+ Expect(tmpView.oauthProviders).to.be.an('array').that.is.empty;
443
+ return fDone();
444
+ }
445
+ );
446
+ test
447
+ (
448
+ 'Should start with initialRenderComplete = false',
449
+ (fDone) =>
450
+ {
451
+ let tmpPict = configureTestPict();
452
+ let tmpView = tmpPict.addView('Pict-View-TestLogin-State4', {}, libPictSectionLogin);
453
+ Expect(tmpView.initialRenderComplete).to.equal(false);
454
+ return fDone();
455
+ }
456
+ );
457
+ }
458
+ );
459
+
460
+ suite
461
+ (
462
+ 'Internal Helpers',
463
+ () =>
464
+ {
465
+ test
466
+ (
467
+ '_displayError should be a function',
468
+ (fDone) =>
469
+ {
470
+ let tmpPict = configureTestPict();
471
+ let tmpView = tmpPict.addView('Pict-View-TestLogin-Helper1', {}, libPictSectionLogin);
472
+ Expect(tmpView._displayError).to.be.a('function');
473
+ return fDone();
474
+ }
475
+ );
476
+ test
477
+ (
478
+ '_clearError should be a function',
479
+ (fDone) =>
480
+ {
481
+ let tmpPict = configureTestPict();
482
+ let tmpView = tmpPict.addView('Pict-View-TestLogin-Helper2', {}, libPictSectionLogin);
483
+ Expect(tmpView._clearError).to.be.a('function');
484
+ return fDone();
485
+ }
486
+ );
487
+ test
488
+ (
489
+ '_updateView should be a function',
490
+ (fDone) =>
491
+ {
492
+ let tmpPict = configureTestPict();
493
+ let tmpView = tmpPict.addView('Pict-View-TestLogin-Helper3', {}, libPictSectionLogin);
494
+ Expect(tmpView._updateView).to.be.a('function');
495
+ return fDone();
496
+ }
497
+ );
498
+ test
499
+ (
500
+ '_storeSessionData should be a function',
501
+ (fDone) =>
502
+ {
503
+ let tmpPict = configureTestPict();
504
+ let tmpView = tmpPict.addView('Pict-View-TestLogin-Helper4', {}, libPictSectionLogin);
505
+ Expect(tmpView._storeSessionData).to.be.a('function');
506
+ return fDone();
507
+ }
508
+ );
509
+ test
510
+ (
511
+ '_renderOAuthButtons should be a function',
512
+ (fDone) =>
513
+ {
514
+ let tmpPict = configureTestPict();
515
+ let tmpView = tmpPict.addView('Pict-View-TestLogin-Helper5', {}, libPictSectionLogin);
516
+ Expect(tmpView._renderOAuthButtons).to.be.a('function');
517
+ return fDone();
518
+ }
519
+ );
520
+ test
521
+ (
522
+ '_updateView is called during initial render to populate form',
523
+ (fDone) =>
524
+ {
525
+ let tmpPict = configureTestPict();
526
+ let tmpView = tmpPict.addView('Pict-View-TestLogin-RenderUpdate',
527
+ {
528
+ AutoRender: false,
529
+ CheckSessionOnLoad: false,
530
+ ShowOAuthProviders: false
531
+ },
532
+ libPictSectionLogin);
533
+
534
+ let tmpUpdateViewCalled = false;
535
+ let tmpOriginalUpdateView = tmpView._updateView.bind(tmpView);
536
+ tmpView._updateView = function()
537
+ {
538
+ tmpUpdateViewCalled = true;
539
+ tmpOriginalUpdateView();
540
+ };
541
+
542
+ // Before render, _updateView has not been called
543
+ Expect(tmpUpdateViewCalled).to.equal(false);
544
+ Expect(tmpView.initialRenderComplete).to.equal(false);
545
+
546
+ // Trigger render
547
+ tmpView.render();
548
+
549
+ // After render, _updateView should have been called
550
+ // as part of onAfterInitialRender
551
+ Expect(tmpUpdateViewCalled).to.equal(true);
552
+ Expect(tmpView.initialRenderComplete).to.equal(true);
553
+
554
+ return fDone();
555
+ }
556
+ );
557
+ test
558
+ (
559
+ '_updateView is only called once for initial render (not on subsequent renders)',
560
+ (fDone) =>
561
+ {
562
+ let tmpPict = configureTestPict();
563
+ let tmpView = tmpPict.addView('Pict-View-TestLogin-RenderOnce',
564
+ {
565
+ AutoRender: false,
566
+ CheckSessionOnLoad: false,
567
+ ShowOAuthProviders: false
568
+ },
569
+ libPictSectionLogin);
570
+
571
+ let tmpUpdateViewCallCount = 0;
572
+ let tmpOriginalUpdateView = tmpView._updateView.bind(tmpView);
573
+ tmpView._updateView = function()
574
+ {
575
+ tmpUpdateViewCallCount++;
576
+ tmpOriginalUpdateView();
577
+ };
578
+
579
+ // First render triggers _updateView via onAfterInitialRender
580
+ tmpView.render();
581
+ Expect(tmpUpdateViewCallCount).to.equal(1);
582
+
583
+ // Second render should NOT trigger onAfterInitialRender again
584
+ tmpView.render();
585
+ Expect(tmpUpdateViewCallCount).to.equal(1);
586
+
587
+ return fDone();
588
+ }
589
+ );
590
+ }
591
+ );
592
+ }
593
+ );