@webex/webex-core 2.59.8 → 2.60.0-next.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 (113) hide show
  1. package/dist/config.js +1 -2
  2. package/dist/config.js.map +1 -1
  3. package/dist/credentials-config.js +1 -2
  4. package/dist/credentials-config.js.map +1 -1
  5. package/dist/index.js +2 -2
  6. package/dist/index.js.map +1 -1
  7. package/dist/interceptors/auth.js +4 -3
  8. package/dist/interceptors/auth.js.map +1 -1
  9. package/dist/interceptors/default-options.js +4 -3
  10. package/dist/interceptors/default-options.js.map +1 -1
  11. package/dist/interceptors/embargo.js +4 -3
  12. package/dist/interceptors/embargo.js.map +1 -1
  13. package/dist/interceptors/network-timing.js +4 -3
  14. package/dist/interceptors/network-timing.js.map +1 -1
  15. package/dist/interceptors/payload-transformer.js +4 -3
  16. package/dist/interceptors/payload-transformer.js.map +1 -1
  17. package/dist/interceptors/rate-limit.js +4 -3
  18. package/dist/interceptors/rate-limit.js.map +1 -1
  19. package/dist/interceptors/redirect.js +7 -6
  20. package/dist/interceptors/redirect.js.map +1 -1
  21. package/dist/interceptors/request-event.js +9 -8
  22. package/dist/interceptors/request-event.js.map +1 -1
  23. package/dist/interceptors/request-logger.js +12 -15
  24. package/dist/interceptors/request-logger.js.map +1 -1
  25. package/dist/interceptors/request-timing.js +4 -3
  26. package/dist/interceptors/request-timing.js.map +1 -1
  27. package/dist/interceptors/response-logger.js +10 -10
  28. package/dist/interceptors/response-logger.js.map +1 -1
  29. package/dist/interceptors/user-agent.js +8 -7
  30. package/dist/interceptors/user-agent.js.map +1 -1
  31. package/dist/interceptors/webex-tracking-id.js +4 -3
  32. package/dist/interceptors/webex-tracking-id.js.map +1 -1
  33. package/dist/interceptors/webex-user-agent.js +9 -8
  34. package/dist/interceptors/webex-user-agent.js.map +1 -1
  35. package/dist/lib/batcher.js +8 -5
  36. package/dist/lib/batcher.js.map +1 -1
  37. package/dist/lib/constants.js +13 -0
  38. package/dist/lib/constants.js.map +1 -0
  39. package/dist/lib/credentials/credentials.js +73 -35
  40. package/dist/lib/credentials/credentials.js.map +1 -1
  41. package/dist/lib/credentials/grant-errors.js +5 -5
  42. package/dist/lib/credentials/grant-errors.js.map +1 -1
  43. package/dist/lib/credentials/scope.js +21 -2
  44. package/dist/lib/credentials/scope.js.map +1 -1
  45. package/dist/lib/credentials/token-collection.js +1 -2
  46. package/dist/lib/credentials/token-collection.js.map +1 -1
  47. package/dist/lib/credentials/token.js +11 -10
  48. package/dist/lib/credentials/token.js.map +1 -1
  49. package/dist/lib/page.js +1 -2
  50. package/dist/lib/page.js.map +1 -1
  51. package/dist/lib/services/constants.js +3 -6
  52. package/dist/lib/services/constants.js.map +1 -1
  53. package/dist/lib/services/index.js +2 -2
  54. package/dist/lib/services/index.js.map +1 -1
  55. package/dist/lib/services/interceptors/server-error.js +4 -3
  56. package/dist/lib/services/interceptors/server-error.js.map +1 -1
  57. package/dist/lib/services/interceptors/service.js +8 -5
  58. package/dist/lib/services/interceptors/service.js.map +1 -1
  59. package/dist/lib/services/metrics.js +1 -2
  60. package/dist/lib/services/metrics.js.map +1 -1
  61. package/dist/lib/services/service-catalog.js +5 -5
  62. package/dist/lib/services/service-catalog.js.map +1 -1
  63. package/dist/lib/services/service-fed-ramp.js +1 -2
  64. package/dist/lib/services/service-fed-ramp.js.map +1 -1
  65. package/dist/lib/services/service-host.js +1 -2
  66. package/dist/lib/services/service-host.js.map +1 -1
  67. package/dist/lib/services/service-registry.js +3 -4
  68. package/dist/lib/services/service-registry.js.map +1 -1
  69. package/dist/lib/services/service-state.js +1 -2
  70. package/dist/lib/services/service-state.js.map +1 -1
  71. package/dist/lib/services/service-url.js +1 -2
  72. package/dist/lib/services/service-url.js.map +1 -1
  73. package/dist/lib/services/services.js +8 -11
  74. package/dist/lib/services/services.js.map +1 -1
  75. package/dist/lib/stateless-webex-plugin.js +1 -2
  76. package/dist/lib/stateless-webex-plugin.js.map +1 -1
  77. package/dist/lib/storage/decorators.js +18 -16
  78. package/dist/lib/storage/decorators.js.map +1 -1
  79. package/dist/lib/storage/errors.js +5 -5
  80. package/dist/lib/storage/errors.js.map +1 -1
  81. package/dist/lib/storage/make-webex-plugin-store.js +8 -10
  82. package/dist/lib/storage/make-webex-plugin-store.js.map +1 -1
  83. package/dist/lib/storage/make-webex-store.js.map +1 -1
  84. package/dist/lib/storage/memory-store-adapter.js +1 -2
  85. package/dist/lib/storage/memory-store-adapter.js.map +1 -1
  86. package/dist/lib/webex-core-plugin-mixin.js +13 -14
  87. package/dist/lib/webex-core-plugin-mixin.js.map +1 -1
  88. package/dist/lib/webex-http-error.js +4 -3
  89. package/dist/lib/webex-http-error.js.map +1 -1
  90. package/dist/lib/webex-internal-core-plugin-mixin.js +13 -14
  91. package/dist/lib/webex-internal-core-plugin-mixin.js.map +1 -1
  92. package/dist/lib/webex-plugin.js +5 -8
  93. package/dist/lib/webex-plugin.js.map +1 -1
  94. package/dist/plugins/logger.js +2 -3
  95. package/dist/plugins/logger.js.map +1 -1
  96. package/dist/webex-core.js +37 -38
  97. package/dist/webex-core.js.map +1 -1
  98. package/dist/webex-internal-core.js +1 -2
  99. package/dist/webex-internal-core.js.map +1 -1
  100. package/package.json +21 -20
  101. package/src/lib/constants.js +6 -0
  102. package/src/lib/credentials/credentials.js +82 -40
  103. package/src/lib/credentials/scope.js +19 -2
  104. package/src/lib/services/interceptors/service.js +2 -2
  105. package/src/lib/services/service-catalog.js +3 -1
  106. package/src/lib/services/services.js +2 -2
  107. package/src/webex-core.js +13 -1
  108. package/test/unit/spec/credentials/credentials.js +169 -13
  109. package/test/unit/spec/credentials/scope.js +55 -0
  110. package/test/unit/spec/interceptors/auth.js +3 -0
  111. package/test/unit/spec/interceptors/webex-user-agent.js +6 -6
  112. package/test/unit/spec/services/interceptors/service.js +9 -3
  113. package/test/unit/spec/webex-core.js +12 -0
package/src/webex-core.js CHANGED
@@ -6,7 +6,12 @@ import {EventEmitter} from 'events';
6
6
  import util from 'util';
7
7
 
8
8
  import {proxyEvents, retry, transferEvents} from '@webex/common';
9
- import {HttpStatusInterceptor, defaults as requestDefaults} from '@webex/http-core';
9
+ import {
10
+ HttpStatusInterceptor,
11
+ defaults as requestDefaults,
12
+ protoprepareFetchOptions as prepareFetchOptions,
13
+ setTimingsAndFetch as _setTimingsAndFetch,
14
+ } from '@webex/http-core';
10
15
  import {defaultsDeep, get, isFunction, isString, last, merge, omit, set, unset} from 'lodash';
11
16
  import AmpState from 'ampersand-state';
12
17
  import uuid from 'uuid';
@@ -402,6 +407,13 @@ const WebexCore = AmpState.extend({
402
407
  interceptors: ints,
403
408
  });
404
409
 
410
+ this.prepareFetchOptions = prepareFetchOptions({
411
+ json: true,
412
+ interceptors: ints,
413
+ });
414
+
415
+ this.setTimingsAndFetch = _setTimingsAndFetch;
416
+
405
417
  let sessionId = `${get(this, 'config.trackingIdPrefix', 'webex-js-sdk')}_${get(
406
418
  this,
407
419
  'config.trackingIdBase',
@@ -11,6 +11,7 @@ import {inBrowser} from '@webex/common';
11
11
  import FakeTimers from '@sinonjs/fake-timers';
12
12
  import {skipInBrowser} from '@webex/test-helper-mocha';
13
13
  import Logger from '@webex/plugin-logger';
14
+ import Metrics, {config} from '@webex/internal-plugin-metrics';
14
15
 
15
16
  /* eslint camelcase: [0] */
16
17
 
@@ -59,6 +60,35 @@ describe('webex-core', () => {
59
60
  });
60
61
  });
61
62
 
63
+ describe('#isUnverifiedGuest', () => {
64
+ let credentials;
65
+ let webex;
66
+ beforeEach(() => {
67
+ //generate the webex instance
68
+ webex = new MockWebex();
69
+ credentials = new Credentials(undefined, {parent: webex});
70
+ });
71
+
72
+ it('should have #isUnverifiedGuest', () => {
73
+ assert.exists(credentials.isUnverifiedGuest);
74
+ });
75
+
76
+ it('should get the user status and return as a boolean', () => {
77
+ credentials.set('supertoken', 'AT');
78
+ assert.isFalse(credentials.isUnverifiedGuest);
79
+ });
80
+
81
+ it('should get guest user ', () => {
82
+ credentials.set('supertoken', 'eyJhbGciOiJSUzI1NiJ9.eyJ1c2VyX3R5cGUiOiJndWVzdCJ9');
83
+ assert.isTrue(credentials.isUnverifiedGuest);
84
+ });
85
+
86
+ it('should get login user ', () => {
87
+ credentials.set('supertoken', 'dGhpc2lzbm90YXJlYWx1c2VydG9rZW4=');
88
+ assert.isFalse(credentials.isUnverifiedGuest);
89
+ });
90
+ });
91
+
62
92
  describe('#canAuthorize', () => {
63
93
  it('indicates if the current state has enough information to populate an auth header, even if a token refresh or token downscope is required', () => {
64
94
  const webex = new MockWebex();
@@ -417,7 +447,11 @@ describe('webex-core', () => {
417
447
  });
418
448
 
419
449
  it('schedules a refreshTimer', () => {
420
- const webex = new MockWebex();
450
+ const webex = new MockWebex({
451
+ children: {
452
+ metrics: Metrics,
453
+ },
454
+ });
421
455
  const supertoken = makeToken(webex, {
422
456
  access_token: 'ST',
423
457
  refresh_token: 'RT',
@@ -430,6 +464,7 @@ describe('webex-core', () => {
430
464
  });
431
465
 
432
466
  sinon.stub(supertoken, 'refresh').returns(Promise.resolve(supertoken2));
467
+ sinon.stub(webex.internal.metrics, 'submitClientMetrics').callsFake(() => {});
433
468
  const credentials = new Credentials(supertoken, {parent: webex});
434
469
 
435
470
  webex.trigger('change:config');
@@ -464,7 +499,19 @@ describe('webex-core', () => {
464
499
  });
465
500
 
466
501
  describe('#getUserToken()', () => {
467
- // it('resolves with the supertoken if the supertoken matches the requested scopes');
502
+ it('resolves with the supertoken if the supertoken matches the requested scopes', () => {
503
+ const webex = new MockWebex();
504
+ const credentials = new Credentials(undefined, {parent: webex});
505
+
506
+ webex.trigger('change:config');
507
+ const st = makeToken(webex, {access_token: 'ST', scope: 'scope1'});
508
+
509
+ credentials.set({
510
+ supertoken: st,
511
+ });
512
+
513
+ return credentials.getUserToken('scope1').then((result) => assert.deepEqual(result, st));
514
+ });
468
515
 
469
516
  it('resolves with the token identified by the specified scopes', () => {
470
517
  const webex = new MockWebex();
@@ -492,6 +539,25 @@ describe('webex-core', () => {
492
539
  ]);
493
540
  });
494
541
 
542
+ it('uses the supertoken.scope instead of the config.scope for downscope', () => {
543
+ const webex = new MockWebex();
544
+ const credentials = new Credentials(undefined, {parent: webex});
545
+
546
+ webex.trigger('change:config');
547
+ const st = makeToken(webex, {access_token: 'ST', scope: 'scope1 spark:kms'});
548
+
549
+ credentials.set({
550
+ supertoken: st,
551
+ scope: 'invalidScope scope1',
552
+ });
553
+
554
+ sinon.stub(credentials, 'downscope').returns(Promise.resolve());
555
+
556
+ return credentials.getUserToken().then(() => {
557
+ assert.calledWith(credentials.downscope, 'scope1');
558
+ });
559
+ });
560
+
495
561
  describe('when no matching token is found', () => {
496
562
  it('downscopes the supertoken', () => {
497
563
  const webex = new MockWebex();
@@ -529,13 +595,13 @@ describe('webex-core', () => {
529
595
  it('resolves with a token containing all but the kms scopes', () => {
530
596
  const webex = new MockWebex();
531
597
 
532
- webex.config.credentials.scope = 'scope1 spark:kms';
533
598
  const credentials = new Credentials(undefined, {parent: webex});
534
599
 
535
600
  webex.trigger('change:config');
536
601
 
537
602
  credentials.supertoken = makeToken(webex, {
538
603
  access_token: 'ST',
604
+ scope: 'scope1 spark:kms',
539
605
  });
540
606
 
541
607
  // const t2 = makeToken(webex, {
@@ -562,9 +628,11 @@ describe('webex-core', () => {
562
628
  const webex = new MockWebex({
563
629
  children: {
564
630
  logger: Logger,
631
+ metrics: Metrics,
565
632
  },
566
633
  });
567
634
 
635
+ webex.config.metrics = config.metrics;
568
636
  webex.config.credentials.scope = 'scope1 spark:kms';
569
637
  const credentials = new Credentials(undefined, {parent: webex});
570
638
 
@@ -574,9 +642,11 @@ describe('webex-core', () => {
574
642
  access_token: 'ST',
575
643
  });
576
644
 
577
- sinon
578
- .stub(credentials.supertoken, 'downscope')
579
- .returns(Promise.reject(new Error('downscope failed')));
645
+ const failReason = 'downscope failed';
646
+ sinon.stub(credentials.supertoken, 'downscope').returns(Promise.reject(failReason));
647
+
648
+ sinon.stub(credentials.logger, 'warn').callsFake(() => {});
649
+ sinon.stub(webex.internal.metrics, 'submitClientMetrics').callsFake(() => {});
580
650
 
581
651
  const t1 = makeToken(webex, {
582
652
  access_token: 'AT1',
@@ -587,14 +657,27 @@ describe('webex-core', () => {
587
657
  userTokens: [t1],
588
658
  });
589
659
 
590
- return credentials
591
- .getUserToken('scope2')
592
- .then((t) => assert.equal(t.access_token, credentials.supertoken.access_token));
660
+ return credentials.getUserToken('scope2').then((t) => {
661
+ assert.equal(t.access_token, credentials.supertoken.access_token);
662
+ assert.calledWith(
663
+ credentials.logger.warn,
664
+ 'credentials: failed to downscope supertoken to "scope2"'
665
+ );
666
+ assert.calledWith(
667
+ webex.internal.metrics.submitClientMetrics,
668
+ 'JS_SDK_CREDENTIALS_DOWNSCOPE_FAILED',
669
+ {fields: {failReason, requestedScope: 'scope2'}}
670
+ );
671
+ });
593
672
  });
594
673
  });
595
674
 
596
675
  it('is blocked while a token refresh is inflight', () => {
597
- const webex = new MockWebex();
676
+ const webex = new MockWebex({
677
+ children: {
678
+ metrics: Metrics,
679
+ },
680
+ });
598
681
 
599
682
  webex.config.credentials.scope = 'scope1 spark:kms';
600
683
  const credentials = new Credentials(undefined, {parent: webex});
@@ -620,6 +703,7 @@ describe('webex-core', () => {
620
703
  const at2 = makeToken(webex, {access_token: 'ST2ATD'});
621
704
 
622
705
  sinon.stub(supertoken2, 'downscope').returns(Promise.resolve(at2));
706
+ sinon.stub(webex.internal.metrics, 'submitClientMetrics').callsFake(() => {});
623
707
 
624
708
  return Promise.all([
625
709
  credentials.refresh(),
@@ -751,18 +835,24 @@ describe('webex-core', () => {
751
835
 
752
836
  describe('#refresh()', () => {
753
837
  it('refreshes and downscopes the supertoken, and revokes previous tokens', () => {
754
- const webex = new MockWebex();
838
+ const webex = new MockWebex({
839
+ children: {
840
+ metrics: Metrics,
841
+ },
842
+ });
755
843
  const credentials = new Credentials(undefined, {parent: webex});
756
844
 
757
845
  webex.trigger('change:config');
758
846
  const st = makeToken(webex, {
759
847
  access_token: 'ST',
760
848
  refresh_token: 'RT',
849
+ scope: 'scope1 scope2',
761
850
  });
762
851
 
763
852
  const st2 = makeToken(webex, {
764
853
  access_token: 'ST2',
765
854
  refresh_token: 'RT2',
855
+ scope: 'scope1 scope2',
766
856
  });
767
857
 
768
858
  const t1 = makeToken(webex, {
@@ -779,6 +869,7 @@ describe('webex-core', () => {
779
869
  sinon.stub(st, 'refresh').returns(Promise.resolve(st2));
780
870
  sinon.stub(t1, 'revoke').returns(Promise.resolve());
781
871
  sinon.spy(credentials, 'scheduleRefresh');
872
+ sinon.stub(webex.internal.metrics, 'submitClientMetrics').callsFake(() => {});
782
873
 
783
874
  credentials.set({
784
875
  supertoken: st,
@@ -798,7 +889,11 @@ describe('webex-core', () => {
798
889
  });
799
890
 
800
891
  it('refreshes and downscopes the supertoken even if revocation of previous token fails', () => {
801
- const webex = new MockWebex();
892
+ const webex = new MockWebex({
893
+ children: {
894
+ metrics: Metrics,
895
+ },
896
+ });
802
897
  const credentials = new Credentials(undefined, {parent: webex});
803
898
 
804
899
  webex.trigger('change:config');
@@ -810,6 +905,7 @@ describe('webex-core', () => {
810
905
  const st2 = makeToken(webex, {
811
906
  access_token: 'ST2',
812
907
  refresh_token: 'RT2',
908
+ scope: 'scope1 scope2',
813
909
  });
814
910
 
815
911
  const t1 = makeToken(webex, {
@@ -826,6 +922,7 @@ describe('webex-core', () => {
826
922
  sinon.stub(st, 'refresh').returns(Promise.resolve(st2));
827
923
  sinon.stub(t1, 'revoke').returns(Promise.reject());
828
924
  sinon.spy(credentials, 'scheduleRefresh');
925
+ sinon.stub(webex.internal.metrics, 'submitClientMetrics').callsFake(() => {});
829
926
 
830
927
  credentials.set({
831
928
  supertoken: st,
@@ -848,6 +945,7 @@ describe('webex-core', () => {
848
945
  const webex = new MockWebex({
849
946
  children: {
850
947
  logger: Logger,
948
+ metrics: Metrics,
851
949
  },
852
950
  });
853
951
  const credentials = new Credentials(undefined, {parent: webex});
@@ -856,9 +954,11 @@ describe('webex-core', () => {
856
954
  const st = makeToken(webex, {
857
955
  access_token: 'ST',
858
956
  refresh_token: 'RT',
957
+ scope: '',
859
958
  });
860
959
 
861
960
  sinon.stub(st, 'refresh').returns(Promise.resolve(makeToken(webex, {access_token: 'ST2'})));
961
+ sinon.stub(webex.internal.metrics, 'submitClientMetrics').callsFake(() => {});
862
962
 
863
963
  const t1 = makeToken(webex, {
864
964
  access_token: 'AT1',
@@ -874,7 +974,7 @@ describe('webex-core', () => {
874
974
  });
875
975
 
876
976
  it('allows #getUserToken() to be revoked, but #getUserToken() promises will not resolve until the suport token has been refreshed', () => {
877
- const webex = new MockWebex();
977
+ const webex = new MockWebex({children: {metrics: Metrics}});
878
978
  const credentials = new Credentials(undefined, {parent: webex});
879
979
 
880
980
  webex.trigger('change:config');
@@ -900,6 +1000,7 @@ describe('webex-core', () => {
900
1000
 
901
1001
  sinon.stub(st1, 'refresh').returns(Promise.resolve(st2));
902
1002
  sinon.stub(st2, 'downscope').returns(Promise.resolve(t2));
1003
+ sinon.stub(webex.internal.metrics, 'submitClientMetrics').callsFake(() => {});
903
1004
 
904
1005
  credentials.set({
905
1006
  supertoken: st1,
@@ -956,6 +1057,61 @@ describe('webex-core', () => {
956
1057
  assert.calledWith(triggerSpy, sinon.match('client:InvalidRequestError'));
957
1058
  });
958
1059
  });
1060
+
1061
+ it('exclude invalid scopes from user token, log and call metrics when fetched supertoken scope mismatch with the configured scope', () => {
1062
+ const webex = new MockWebex({
1063
+ children: {
1064
+ logger: Logger,
1065
+ metrics: Metrics,
1066
+ },
1067
+ });
1068
+ const credentials = new Credentials(undefined, {parent: webex});
1069
+
1070
+ webex.trigger('change:config');
1071
+ const st = makeToken(webex, {
1072
+ access_token: 'ST',
1073
+ refresh_token: 'RT',
1074
+ });
1075
+
1076
+ const st2 = makeToken(webex, {
1077
+ access_token: 'ST2',
1078
+ refresh_token: 'RT2',
1079
+ scope: 'scope1',
1080
+ });
1081
+
1082
+ const userToken = makeToken(webex, {
1083
+ access_token: 'AT1',
1084
+ scope: 'scope1 invalidScope1',
1085
+ });
1086
+
1087
+ credentials.set({
1088
+ supertoken: st,
1089
+ userTokens: [userToken],
1090
+ });
1091
+ const invalidScopes = 'invalidScope1 invalidScope2';
1092
+ credentials.config.scope = `scope1 ${invalidScopes}`;
1093
+
1094
+ sinon.stub(st2, 'downscope').returns(Promise.resolve());
1095
+ sinon.stub(st, 'refresh').returns(Promise.resolve(st2));
1096
+ sinon.spy(credentials, 'downscope');
1097
+ sinon.spy(credentials, 'scheduleRefresh');
1098
+
1099
+ sinon.stub(credentials.logger, 'warn').callsFake(() => {});
1100
+ sinon.stub(webex.internal.metrics, 'submitClientMetrics').callsFake(() => {});
1101
+
1102
+ return credentials.refresh().then(() => {
1103
+ assert.calledWith(
1104
+ credentials.logger.warn,
1105
+ `credentials: "${invalidScopes}" scope(s) are invalid because not listed in the supertoken, they will be excluded from user token requests.`
1106
+ );
1107
+ assert.calledWith(
1108
+ webex.internal.metrics.submitClientMetrics,
1109
+ 'JS_SDK_CREDENTIALS_TOKEN_REFRESH_SCOPE_MISMATCH',
1110
+ {fields: {invalidScopes}}
1111
+ );
1112
+ assert.calledWith(credentials.downscope, 'scope1');
1113
+ });
1114
+ });
959
1115
  });
960
1116
 
961
1117
  describe('#scheduleRefresh()', () => {
@@ -0,0 +1,55 @@
1
+ import {assert} from '@webex/test-helper-chai';
2
+ import {sortScope, filterScope, diffScopes} from '@webex/webex-core/src/lib/credentials/scope';
3
+
4
+ describe('webex-core', () => {
5
+ describe('scope utils', () => {
6
+ describe('sortScope', () => {
7
+ it('should sort scopes alphabetically', () => {
8
+ assert.equal(sortScope(undefined), '');
9
+ assert.equal(sortScope(''), '');
10
+ assert.equal(sortScope('a'), 'a');
11
+ assert.equal(sortScope('b c a'), 'a b c');
12
+ });
13
+ });
14
+
15
+ describe('filterScope', () => {
16
+ it('should filter out one scope from the original scope and sort the result', () => {
17
+ assert.equal(filterScope('a', undefined), '');
18
+ assert.equal(filterScope('a', ''), '');
19
+ assert.equal(filterScope('a', 'a'), '');
20
+ assert.equal(filterScope('a', 'a b c'), 'b c');
21
+ assert.equal(filterScope('c', 'a c b'), 'a b');
22
+ });
23
+
24
+ it('should filter out a list of scopes from the original scope and sort the result', () => {
25
+ assert.equal(filterScope([], 'a'), 'a');
26
+ assert.equal(filterScope(['a', 'b'], undefined), '');
27
+ assert.equal(filterScope(['a', 'b'], ''), '');
28
+ assert.equal(filterScope(['a', 'b'], 'a'), '');
29
+ assert.equal(filterScope(['a', 'b'], 'a b c'), 'c');
30
+ assert.equal(filterScope(['a', 'd'], 'a c a b'), 'b c');
31
+ });
32
+ });
33
+
34
+ describe('diffScopes', () => {
35
+ it('should return an empty string, if all items in the first scope are contained in the second scope', () => {
36
+ assert.deepEqual(diffScopes(undefined, undefined), '');
37
+ assert.deepEqual(diffScopes(undefined, ''), '');
38
+ assert.deepEqual(diffScopes('', undefined), '');
39
+ assert.deepEqual(diffScopes('', ''), '');
40
+ assert.deepEqual(diffScopes('a', 'a'), '');
41
+ assert.deepEqual(diffScopes('a b c', 'a b c'), '');
42
+ assert.deepEqual(diffScopes(undefined, 'a b c'), '');
43
+ assert.deepEqual(diffScopes('a b c', 'a b c d'), '');
44
+ });
45
+
46
+ it('should return a string containing all items in the first scope that are not in the second scope', () => {
47
+ assert.deepEqual(diffScopes('a', undefined), 'a');
48
+ assert.deepEqual(diffScopes('a', 'b'), 'a');
49
+ assert.deepEqual(diffScopes('a b c', 'a b'), 'c');
50
+ assert.deepEqual(diffScopes('a b c d', 'a b c'), 'd');
51
+ assert.deepEqual(diffScopes('a b c', undefined), 'a b c');
52
+ });
53
+ });
54
+ });
55
+ });
@@ -12,6 +12,7 @@ import Logger from '@webex/plugin-logger';
12
12
  import MockWebex from '@webex/test-helper-mock-webex';
13
13
  import {AuthInterceptor, config, Credentials, WebexHttpError, Token} from '@webex/webex-core';
14
14
  import {cloneDeep, merge} from 'lodash';
15
+ import Metrics from '@webex/internal-plugin-metrics';
15
16
 
16
17
  const {assert} = chai;
17
18
 
@@ -28,6 +29,7 @@ describe('webex-core', () => {
28
29
  children: {
29
30
  credentials: Credentials,
30
31
  logger: Logger,
32
+ metrics: Metrics,
31
33
  },
32
34
  config: merge(cloneDeep(config), {credentials: {client_secret: 'fake'}}),
33
35
  });
@@ -41,6 +43,7 @@ describe('webex-core', () => {
41
43
  );
42
44
 
43
45
  interceptor = Reflect.apply(AuthInterceptor.create, webex, []);
46
+ sinon.stub(webex.internal.metrics, 'submitClientMetrics').callsFake(() => {});
44
47
  });
45
48
 
46
49
  describe('#onRequest()', () => {
@@ -27,7 +27,7 @@ describe('webex-core', () => {
27
27
  assert.property(options.headers, 'spark-user-agent');
28
28
  assert.equal(
29
29
  options.headers['spark-user-agent'],
30
- `webex-js-sdk/${pkg.version} (${typeof window === 'undefined' ? 'node' : 'web'})`
30
+ `webex-js-sdk/development (${typeof window === 'undefined' ? 'node' : 'web'})`
31
31
  );
32
32
  });
33
33
 
@@ -47,7 +47,7 @@ describe('webex-core', () => {
47
47
  assert.property(options.headers, 'spark-user-agent');
48
48
  assert.equal(
49
49
  options.headers['spark-user-agent'],
50
- `webex-js-sdk/${pkg.version} (${typeof window === 'undefined' ? 'node' : 'web'})`
50
+ `webex-js-sdk/development (${typeof window === 'undefined' ? 'node' : 'web'})`
51
51
  );
52
52
  });
53
53
 
@@ -74,7 +74,7 @@ describe('webex-core', () => {
74
74
  assert.property(options.headers, 'spark-user-agent');
75
75
  assert.equal(
76
76
  options.headers['spark-user-agent'],
77
- `webex-js-sdk/${pkg.version} (${
77
+ `webex-js-sdk/development (${
78
78
  typeof window === 'undefined' ? 'node' : 'web'
79
79
  }) sample/1.0.0`
80
80
  );
@@ -104,7 +104,7 @@ describe('webex-core', () => {
104
104
  assert.property(options.headers, 'spark-user-agent');
105
105
  assert.equal(
106
106
  options.headers['spark-user-agent'],
107
- `webex-js-sdk/${pkg.version} (${
107
+ `webex-js-sdk/development (${
108
108
  typeof window === 'undefined' ? 'node' : 'web'
109
109
  }) sample/1.0.0 custom-label/1.0.0`
110
110
  );
@@ -128,7 +128,7 @@ describe('webex-core', () => {
128
128
  assert.property(options.headers, 'spark-user-agent');
129
129
  assert.equal(
130
130
  options.headers['spark-user-agent'],
131
- `webex/${pkg.version} (${typeof window === 'undefined' ? 'node' : 'web'})`
131
+ `webex/development (${typeof window === 'undefined' ? 'node' : 'web'})`
132
132
  );
133
133
  });
134
134
 
@@ -149,7 +149,7 @@ describe('webex-core', () => {
149
149
  assert.property(options.headers, 'spark-user-agent');
150
150
  assert.equal(
151
151
  options.headers['spark-user-agent'],
152
- `webex/${pkg.version} (${typeof window === 'undefined' ? 'node' : 'web'})`
152
+ `webex/development (${typeof window === 'undefined' ? 'node' : 'web'})`
153
153
  );
154
154
  });
155
155
  });
@@ -5,6 +5,7 @@ import chai from 'chai';
5
5
  import chaiAsPromised from 'chai-as-promised';
6
6
  import sinon from 'sinon';
7
7
  import {ServiceInterceptor} from '@webex/webex-core';
8
+ import CONFIG from '../../../../../src/config';
8
9
 
9
10
  const {assert} = chai;
10
11
 
@@ -26,6 +27,7 @@ describe('webex-core', () => {
26
27
  service: 'example',
27
28
  serviceUrl: 'https://www.example-service.com/',
28
29
  uri: 'https://www.example-uri.com/',
30
+ waitForServiceTimeout: 11,
29
31
  };
30
32
 
31
33
  options = {};
@@ -110,6 +112,7 @@ describe('webex-core', () => {
110
112
 
111
113
  options.service = fixture.service;
112
114
  options.resource = fixture.resource;
115
+ options.timeout = fixture.waitForServiceTimeout;
113
116
  });
114
117
 
115
118
  it('should normalize the options', () =>
@@ -119,9 +122,12 @@ describe('webex-core', () => {
119
122
  interceptor.onRequest(options).then(() => assert.called(interceptor.validateOptions)));
120
123
 
121
124
  it('should attempt to collect the service url', () =>
122
- interceptor
123
- .onRequest(options)
124
- .then(() => assert.calledWith(waitForService, {name: options.service})));
125
+ interceptor.onRequest(options).then(
126
+ assert.calledWith(waitForService, {
127
+ name: options.service,
128
+ timeout: options.waitForServiceTimeout,
129
+ })
130
+ ));
125
131
 
126
132
  describe('when the service url was collected successfully', () => {
127
133
  it('should attempt to generate the full uri', () =>
@@ -54,6 +54,18 @@ describe('Webex', () => {
54
54
  });
55
55
  });
56
56
 
57
+ describe('#request', () => {
58
+ it('exists', () => {
59
+ assert.property(webex, 'request');
60
+ });
61
+ });
62
+
63
+ describe('#prepareFetchOptions', () => {
64
+ it('exists', () => {
65
+ assert.property(webex, 'prepareFetchOptions');
66
+ });
67
+ });
68
+
57
69
  describe('#initialize()', () => {
58
70
  it('initializes without arguments', () => {
59
71
  let webex;