Merge Chromium + Blink git repositories
[chromium-blink-merge.git] / remoting / webapp / base / js / identity_unittest.js
blob55ce092eafe601708162a8a0e5931bd6d36ff4b1
1 // Copyright 2015 The Chromium Authors. All rights reserved.
2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file.
5 (function() {
7 'use strict';
9 /** @type {MockConsent} */
10 var consentDialog = null;
11 /** @type {sinon.Spy | Function} */
12 var promptForConsent = null;
13 /** @type {sinon.Spy | Function} */
14 var getAuthToken = null;
15 /** @type {remoting.Identity} */
16 var identity = null;
18 /**
19  * @param {QUnit.Assert} assert
20  * @constructor
21  * @implements {remoting.Identity.ConsentDialog}
22  */
23 var MockConsent = function(assert) {
24   /** @type {boolean} */
25   this.grantConsent = true;
26   /** @private {QUnit.Assert} */
27   this.assert_ = assert;
30 MockConsent.prototype.show = function() {
31   // The consent dialog should only be shown if a previous call to getAuthToken
32   // with {interactive: false} failed, and it should occur before any call with
33   // {interactive: true}.
34   this.assert_.ok(getAuthToken.calledOnce);
35   this.assert_.ok(getAuthToken.calledWith(
36       {'interactive': false, scopes: undefined}));
37   getAuthToken.reset();
39   if (this.grantConsent) {
40     chromeMocks.identity.mock$setToken('token');
41   }
42   return Promise.resolve();
45 QUnit.module('Identity', {
46   beforeEach: function(/** QUnit.Assert*/ assert) {
47     chromeMocks.identity.mock$clearToken();
48     consentDialog = new MockConsent(assert);
49     promptForConsent = sinon.spy(consentDialog, 'show');
50     identity = new remoting.Identity(consentDialog);
51     getAuthToken = sinon.spy(chromeMocks.identity, 'getAuthToken');
52   },
53   afterEach: function() {
54     getAuthToken.restore();
55   }
56 });
58 QUnit.test('consent is requested only on first invocation', function(assert) {
59   assert.ok(!promptForConsent.called);
60   return identity.getToken().then(
61       function(/** string */ token) {
62         assert.ok(promptForConsent.called);
63         assert.ok(getAuthToken.calledOnce);
64         assert.ok(getAuthToken.calledWith(
65             {'interactive': true, 'scopes': undefined}));
67         // Request another token.
68         promptForConsent.reset();
69         getAuthToken.reset();
70         return identity.getToken();
72       }).then(function(/** string */ token) {
73         assert.ok(!promptForConsent.called);
74         assert.ok(getAuthToken.calledOnce);
75         assert.ok(getAuthToken.calledWith({
76           'interactive': true, 'scopes': undefined}));
77         assert.equal(token, 'token');
78       });
79 });
81 QUnit.test('requesting an explicit scope works', function(assert) {
82   assert.ok(!promptForConsent.called);
83   return identity.getToken().then(
84       function() {
85         // Request a token with an explicit scope.
86         promptForConsent.reset();
87         getAuthToken.reset();
88         return identity.getToken(['scope']);
90       }).then(function(/** string */ token) {
91         assert.ok(!promptForConsent.called);
92         assert.ok(getAuthToken.calledOnce);
93         assert.ok(getAuthToken.calledWith({
94           'interactive': true, 'scopes': ['scope']}));
95         assert.equal(token, 'token["scope"]');
96       });
97 });
99 QUnit.test('multiple concurrent outstanding requests are handled correctly',
100            function(assert) {
101   assert.ok(!promptForConsent.called);
102   return identity.getToken().then(
103       function() {
104         // Request a token with an explicit scope and another without.
105         promptForConsent.reset();
106         getAuthToken.reset();
107         var withScope = identity.getToken(['scope']);
108         var withoutScope = identity.getToken();
109         return Promise.all([withScope, withoutScope]);
111       }).then(function(/** Array<string> */ tokens) {
112         assert.ok(!promptForConsent.called);
113         assert.ok(getAuthToken.calledTwice);
114         assert.ok(getAuthToken.calledWith({
115           'interactive': true, 'scopes': ['scope']}));
116         assert.ok(getAuthToken.calledWith({
117           'interactive': true, 'scopes': undefined}));
118         assert.equal(tokens.length, 2);
119         assert.equal(tokens[0], 'token["scope"]');
120         assert.equal(tokens[1], 'token');
121       });
124 QUnit.test('cancellations are reported correctly', function(assert) {
125   consentDialog.grantConsent = false;
126   chromeMocks.runtime.lastError.message = 'The user did not approve access.';
127   return identity.getToken().then(
128       function(/** string */ token) {
129         assert.ok(false, 'expected getToken() to fail');
130       }).catch(function(/** remoting.Error */ error) {
131         assert.equal(error.getTag(), remoting.Error.Tag.CANCELLED);
132       });
136 QUnit.test('other errors are reported correctly', function(assert) {
137   consentDialog.grantConsent = false;
138   chromeMocks.runtime.lastError.message = '<some other error message>';
139   return identity.getToken().then(
140       function(/** string */ token) {
141         assert.ok(false, 'expected getToken() to fail');
142       }).catch(function(/** remoting.Error */ error) {
143         assert.equal(error.getTag(), remoting.Error.Tag.NOT_AUTHENTICATED);
144       });
147 }());