1// Copyright 2013 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.
4
5GEN('#include "chrome/browser/ui/webui/identity_internals_ui_browsertest.h"');
6
7/**
8 * Test C++ fixture for downloads WebUI testing.
9 * @constructor
10 * @extends {testing.Test}
11 */
12function IdentityInternalsUIBrowserTest() {}
13
14/**
15 * Base fixture for Downloads WebUI testing.
16 * @extends {testing.Test}
17 * @constructor
18 */
19function BaseIdentityInternalsWebUITest() {}
20
21BaseIdentityInternalsWebUITest.prototype = {
22  __proto__: testing.Test.prototype,
23
24  /**
25   * Browse to the downloads page & call our preLoad().
26   */
27  browsePreload: 'chrome://identity-internals',
28
29  /** @override */
30  typedefCppFixture: 'IdentityInternalsUIBrowserTest',
31
32  /**
33   * Gets all of the token entries on the page.
34   * @return {!NodeList} Elements displaying token information.
35   */
36  getTokens: function() {
37    return document.querySelectorAll('#token-list > div');
38  },
39
40  /**
41   * Gets the expiration time displayed on the page for a given entry.
42   * @param {Element} tokenEntry Display element holding token information.
43   * @return {Date} Expiration date of the token.
44   */
45  getExpirationTime: function(tokenEntry) {
46    // Full-date format has 'at' between date and time in en-US, but
47    // ECMAScript's Date.parse cannot grok it.
48    return Date.parse(tokenEntry.querySelector('.expiration-time')
49        .innerText.replace(' at ', ' '));
50  },
51
52  /**
53   * Gets the extension id displayed on the page for a given entry.
54   * @param {Element} tokenEntry Display element holding token information.
55   * @return {string} Extension Id of the token.
56   */
57  getExtensionId: function(tokenEntry) {
58    return tokenEntry.querySelector('.extension-id').innerText;
59  },
60
61  /**
62   * Gets the extension name displayed on the page for a given entry.
63   * @param {Element} tokenEntry Display element holding token information.
64   * @return {string} Extension Name of the token.
65   */
66  getExtensionName: function(tokenEntry) {
67    return tokenEntry.querySelector('.extension-name').innerText;
68  },
69
70  /**
71   * Gets the revoke button of the token entry.
72   * @param {Element} tokenEntry Diplsy element holding token information.
73   * @return {HTMLButtonElement} Revoke button belonging related to the token.
74   */
75  getRevokeButton: function(tokenEntry) {
76    return tokenEntry.querySelector('.revoke-button');
77  },
78
79  /**
80   * Gets the token ID displayed on the page for a given entry.
81   * @param {Element} tokenEntry Display element holding token information.
82   * @return {string} Token ID of the token.
83   */
84  getAccessToken: function(tokenEntry) {
85    return tokenEntry.querySelector('.access-token').innerText;
86  },
87
88  /**
89   * Gets the token status displayed on the page for a given entry.
90   * @param {Element} tokenEntry Display element holding token information.
91   * @return {string} Token status of the token.
92   */
93  getTokenStatus: function(tokenEntry) {
94    return tokenEntry.querySelector('.token-status').innerText;
95  },
96
97  /**
98   * Gets the token scopes displayed on the page for a given entry.
99   * @param {Element} tokenEntry Display element holding token information.
100   * @return {string[]} Token scopes of the token.
101   */
102  getScopes: function(tokenEntry) {
103    return tokenEntry.querySelector('.scope-list')
104        .innerHTML.split('<br>');
105  },
106};
107
108// Test verifying chrome://identity-internals Web UI when the token cache is
109// empty.
110TEST_F('BaseIdentityInternalsWebUITest', 'emptyTokenCache', function() {
111  var tokenListEntries = this.getTokens();
112  expectEquals(0, tokenListEntries.length);
113});
114
115/**
116 * Fixture for Identity Internals Web UI testing with a single token in the
117 * Identity API token cache.
118 * @extends {BaseIdentityInternalsWebUITest}
119 * @constructor
120 */
121function IdentityInternalsSingleTokenWebUITest() {}
122
123IdentityInternalsSingleTokenWebUITest.prototype = {
124  __proto__: BaseIdentityInternalsWebUITest.prototype,
125
126  /** @override */
127  testGenPreamble: function() {
128    GEN('  SetupTokenCacheWithStoreApp();');
129  },
130};
131
132// Test for listing a token cache with a single token. It uses a known extension
133// - the Chrome Web Store, in order to check the extension name.
134TEST_F('IdentityInternalsSingleTokenWebUITest', 'getAllTokens', function() {
135  var tokenListEntries = this.getTokens();
136  expectEquals(1, tokenListEntries.length);
137  expectEquals('Web Store', this.getExtensionName(tokenListEntries[0]));
138  expectEquals('ahfgeienlihckogmohjhadlkjgocpleb',
139               this.getExtensionId(tokenListEntries[0]));
140  expectEquals('store_token', this.getAccessToken(tokenListEntries[0]));
141  expectEquals('Token Present', this.getTokenStatus(tokenListEntries[0]));
142  expectLT(this.getExpirationTime(tokenListEntries[0]) - new Date(),
143           3600 * 1000);
144  var scopes = this.getScopes(tokenListEntries[0]);
145  expectEquals(3, scopes.length);
146  expectEquals('store_scope1', scopes[0]);
147  expectEquals('store_scope2', scopes[1]);
148  expectEquals('', scopes[2]);
149});
150
151// Test ensuring the getters on the BaseIdentityInternalsWebUITest work
152// correctly. They are implemented on the child class, because the parent does
153// not have any tokens to display.
154TEST_F('IdentityInternalsSingleTokenWebUITest', 'verifyGetters', function() {
155  var tokenListEntries = document.querySelectorAll('#token-list > div');
156  var actualTokens = this.getTokens();
157  expectEquals(tokenListEntries.length, actualTokens.length);
158  expectEquals(tokenListEntries[0], actualTokens[0]);
159  expectEquals(this.getExtensionName(tokenListEntries[0]),
160      tokenListEntries[0].querySelector('.extension-name').innerText);
161  expectEquals(this.getExtensionId(tokenListEntries[0]),
162      tokenListEntries[0].querySelector('.extension-id').innerText);
163  expectEquals(this.getAccessToken(tokenListEntries[0]),
164      tokenListEntries[0].querySelector('.access-token').innerText);
165  expectEquals(this.getTokenStatus(tokenListEntries[0]),
166      tokenListEntries[0].querySelector('.token-status').innerText);
167  // Full-date format has 'at' between date and time in en-US, but
168  // ECMAScript's Date.parse cannot grok it.
169  expectEquals(this.getExpirationTime(tokenListEntries[0]),
170      Date.parse(tokenListEntries[0].querySelector('.expiration-time')
171          .innerText.replace(' at ', ' ')));
172  var scopes = tokenListEntries[0].querySelector('.scope-list')
173      .innerHTML.split('<br>');
174  var actualScopes = this.getScopes(tokenListEntries[0]);
175  expectEquals(scopes.length, actualScopes.length);
176  for (var i = 0; i < scopes.length; i++) {
177    expectEquals(scopes[i], actualScopes[i]);
178  }
179});
180
181/**
182 * Fixture for Identity Internals Web UI testing with multiple tokens in the
183 * Identity API token cache.
184 * @extends {BaseIdentityInternalsWebUITest}
185 * @constructor
186 */
187function IdentityInternalsMultipleTokensWebUITest() {}
188
189IdentityInternalsMultipleTokensWebUITest.prototype = {
190  __proto__: BaseIdentityInternalsWebUITest.prototype,
191
192  /** @override */
193  testGenPreamble: function() {
194    GEN('  SetupTokenCache(2);');
195  },
196};
197
198// Test for listing a token cache with multiple tokens. Names of the extensions
199// are empty, because extensions are faked, and not present in the extension
200// service.
201TEST_F('IdentityInternalsMultipleTokensWebUITest', 'getAllTokens', function() {
202  var tokenListEntries = this.getTokens();
203  expectEquals(2, tokenListEntries.length);
204  expectEquals('', this.getExtensionName(tokenListEntries[0]));
205  expectEquals('extension0',
206               this.getExtensionId(tokenListEntries[0]));
207  expectEquals('token0', this.getAccessToken(tokenListEntries[0]));
208  expectEquals('Token Present', this.getTokenStatus(tokenListEntries[0]));
209  expectLT(this.getExpirationTime(tokenListEntries[0]) - new Date(),
210           3600 * 1000);
211  var scopes = this.getScopes(tokenListEntries[0]);
212  expectEquals(3, scopes.length);
213  expectEquals('scope_1_0', scopes[0]);
214  expectEquals('scope_2_0', scopes[1]);
215  expectEquals('', scopes[2]);
216  expectEquals('', this.getExtensionName(tokenListEntries[1]));
217  expectEquals('extension1',
218               this.getExtensionId(tokenListEntries[1]));
219  expectEquals('token1', this.getAccessToken(tokenListEntries[1]));
220  expectEquals('Token Present', this.getTokenStatus(tokenListEntries[1]));
221  expectLT(this.getExpirationTime(tokenListEntries[1]) - new Date(),
222           3600 * 1000);
223  var scopes = this.getScopes(tokenListEntries[1]);
224  expectEquals(3, scopes.length);
225  expectEquals('scope_1_1', scopes[0]);
226  expectEquals('scope_2_1', scopes[1]);
227  expectEquals('', scopes[2]);
228});
229
230/**
231 * Fixture for asynchronous testing of Identity Internals Web UI with multiple
232 * tokens in Identity API token cache.
233 * @extends {IdentityInternalsMultipleTokensWebUITest}
234 * @constructor
235 */
236function IdentityInternalsWebUITestAsync() {}
237
238IdentityInternalsWebUITestAsync.prototype = {
239  __proto__: IdentityInternalsMultipleTokensWebUITest.prototype,
240
241  /** @override */
242  isAsync: true,
243};
244
245TEST_F('IdentityInternalsWebUITestAsync', 'revokeToken', function() {
246  var tokenListBefore = this.getTokens();
247  expectEquals(2, tokenListBefore.length);
248  var tokenRevokeDone = identity_internals.tokenRevokeDone;
249  identity_internals.tokenRevokeDone = this.continueTest(
250      WhenTestDone.ALWAYS, function(accessTokens) {
251        tokenRevokeDone.call(identity_internals, accessTokens);
252        identity_internals.tokenRevokeDone = tokenRevokeDone;
253        var tokenListAfter = this.getTokens();
254        expectEquals(1, tokenListAfter.length);
255        expectEquals(this.getAccessToken(tokenListBefore[0]),
256                     this.getAccessToken(tokenListAfter[0]));
257      }.bind(this));
258  this.getRevokeButton(tokenListBefore[1]).click();
259});
260
261