Chromium Code Reviews

Side by Side Diff: chrome/test/data/webui/bluetooth_internals_browsertest.js

Issue 2428773005: bluetooth: Basic browser tests for chrome://bluetooth-internals. (Closed)
Patch Set: Clean up Created 4 years, 1 month ago
Use n/p to move between diff chunks; N/P to move between comments.
Jump to:
View unified diff |
« no previous file with comments | « chrome/test/BUILD.gn ('k') | no next file » | no next file with comments »
Toggle Intra-line Diffs ('i') | Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
OLDNEW
(Empty)
1 // Copyright 2016 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
5 /**
6 * @fileoverview Tests for chrome://bluetooth-internals
7 */
8
9 /** @const {string} Path to source root. */
10 var ROOT_PATH = '../../../../';
11
12 /**
13 * Test fixture for BluetoothInternals WebUI testing.
14 * @constructor
15 * @extends testing.Test
16 */
17 function BluetoothInternalsTest() {
18 this.adapterFactory = null;
19 this.setupResolver = new PromiseResolver();
20 }
21
22 BluetoothInternalsTest.prototype = {
23 __proto__: testing.Test.prototype,
24
25 /** @override */
26 browsePreload: 'chrome://bluetooth-internals',
27
28 /** @override */
29 isAsync: true,
30
31 /** @override */
32 runAccessibilityChecks: false,
33
34 /** @override */
35 extraLibraries: [
36 ROOT_PATH + 'third_party/mocha/mocha.js',
37 ROOT_PATH + 'chrome/test/data/webui/mocha_adapter.js',
38 ROOT_PATH + 'ui/webui/resources/js/promise_resolver.js',
39 ROOT_PATH + 'ui/webui/resources/js/cr.js',
40 ROOT_PATH + 'chrome/test/data/webui/settings/test_browser_proxy.js',
41 ],
42
43 preLoad: function() {
44 /**
45 * TODO(crbug.com/652361): Move to shared location.
46 * Helper to convert callback-based define() API to a promise-based API.
47 * @param {!Array<string>} moduleNames
48 * @return {!Promise}
49 */
dpapad 2016/11/02 00:03:00 How many copies of this function do we currently h
mbrunson 2016/11/02 22:47:21 Done. https://codereview.chromium.org/2428773005/
50 function importModules(moduleNames) {
51 return new Promise(function(resolve, reject) {
52 define(moduleNames, function(var_args) {
53 resolve(Array.prototype.slice.call(arguments, 0));
54 });
55 });
56 }
57
58 // A function that is called from chrome://bluetooth-internals to allow this
59 // test to replace the real Mojo browser proxy with a fake one, before any
60 // other code runs.
61 window.setupFn = function() {
62 return importModules([
63 'content/public/renderer/frame_interfaces',
64 'device/bluetooth/public/interfaces/adapter.mojom',
65 'device/bluetooth/public/interfaces/device.mojom',
66 'mojo/public/js/bindings',
67 'mojo/public/js/connection',
68 ])
69 .then(function(
70 [frameInterfaces, adapter, device, bindings, connection]) {
71 /**
72 * A test adapter factory proxy for the chrome://bluetooth-internals
73 * page.
74 *
75 * @constructor
76 * @extends {TestBrowserProxyBase}
77 */
78 var TestAdapterFactoryProxy = function() {
79 settings.TestBrowserProxy.call(this, [
80 'getAdapter',
81 ]);
82
83 this.adapter = new TestAdapter();
84 };
85 TestAdapterFactoryProxy.prototype = {
86 __proto__: settings.TestBrowserProxy.prototype,
87 getAdapter: function() {
88 this.methodCalled('getAdapter');
89
90 // Create message pipe bound to TestAdapter.
91 return Promise.resolve({
92 adapter: connection.bindStubDerivedImpl(this.adapter),
dpapad 2016/11/02 00:03:00 Assuming this needs to be done every time getAdapt
mbrunson 2016/11/02 22:47:23 Done.
93 });
94 }
95 };
96
97 /**
98 * A test adapter for the chrome://bluetooth-internals page.
99 * Must be used to create message pipe handle from test code.
100 *
101 * @constructor
102 * @extends {adapter.Adapter.stubClass}
103 */
104 var TestAdapter = function() {
dpapad 2016/11/02 00:03:00 Can you merge TestAdapterProxy class into TestAdap
mbrunson 2016/11/02 22:47:22 connection.js documentation [1] says the stub pass
105 this.proxy = new TestAdapterProxy();
106 };
dpapad 2016/11/02 00:03:00 \n
mbrunson 2016/11/02 22:47:24 Done.
107 TestAdapter.prototype = {
108 __proto__: adapter.Adapter.stubClass.prototype,
109 getInfo: function() { return this.proxy.getInfo(); },
110 getDevices: function() { return this.proxy.getDevices(); },
111 setClient: function(client) { return this.proxy.setClient(client); }
112 };
113
114 /**
115 * A test adapter proxy for the chrome://bluetooth-internals page.
116 *
117 * @constructor
118 * @extends {TestBrowserProxyBase}
119 */
120 var TestAdapterProxy = function() {
121 settings.TestBrowserProxy.call(this, [
122 'getInfo',
123 'getDevices',
124 'setClient',
125 ]);
126
127 this.client = null;
128
129 this.adapterInfo_ = null;
130 this.devices_ = [];
131 };
132 TestAdapterProxy.prototype = {
133 __proto__: settings.TestBrowserProxy.prototype,
134 getInfo: function() {
135 this.methodCalled('getInfo');
136 return Promise.resolve({ info: this.adapterInfo_ });
137 },
138 getDevices: function() {
139 this.methodCalled('getDevices');
140 return Promise.resolve({ devices: this.devices_ });
141 },
142 setClient: function(client) {
143 this.methodCalled('setClient', client);
144 this.client = connection.bindHandleToProxy(client,
145 adapter.AdapterClient);
146 },
147 setTestAdapter: function(adapterInfo) {
148 this.adapterInfo_ = adapterInfo;
149 },
150 setTestDevices: function(devices) {
151 this.devices_ = devices;
152 }
153 };
154
155
156 frameInterfaces.addInterfaceOverrideForTesting(
157 adapter.AdapterFactory.name,
158 function(handle) {
159 var stub = connection.bindHandleToStub(
160 handle, adapter.AdapterFactory);
161 this.adapterFactory = new TestAdapterFactoryProxy();
162 bindings.StubBindings(stub).delegate = this.adapterFactory;
163
164 this.setupResolver.resolve();
165 }.bind(this));
166
167 }.bind(this));
168 }.bind(this);
169 },
170 };
171
172 TEST_F('BluetoothInternalsTest', 'Startup_BluetoothInternals', function() {
173
dpapad 2016/11/02 00:03:00 Nit: No need for blank line at the start of functi
mbrunson 2016/11/02 22:47:24 Done.
174 var fakeAdapterInfo = {
175 address: '02:1C:7E:6A:11:5A',
176 discoverable: false,
177 discovering: false,
178 initialized: true,
179 name: 'computer.example.com-0',
180 powered: true,
181 present: true,
182 };
183
184 var fakeDeviceInfo1 = {
185 address: "AA:AA:84:96:92:84",
186 name: "AAA",
187 name_for_display: "AAA",
188 rssi: {value: -40},
189 services: []
190 };
191
192 var fakeDeviceInfo2 = {
193 address: "BB:BB:84:96:92:84",
194 name: "BBB",
195 name_for_display: "BBB",
196 rssi: null,
197 services: []
198 };
199
200 var fakeDeviceInfo3 = {
201 address: "CC:CC:84:96:92:84",
202 name: "CCC",
203 name_for_display: "CCC",
204 };
205
206 var adapterFactory = null;
207
208 // Before tests are run, make sure setup completes.
209 var setupPromise = this.setupResolver.promise.then(function() {
210 adapterFactory = this.adapterFactory;
211 }.bind(this));
212
213
214 suite('BluetoothInternalsUITest', function() {
215 var EXPECTED_DEVICES = 2;
216
217 suiteSetup(function() {
218 return setupPromise.then(function() {
219 adapterFactory.adapter.proxy.setTestDevices([
220 fakeDeviceInfo1,
221 fakeDeviceInfo2
222 ]);
223 adapterFactory.adapter.proxy.setTestAdapter(fakeAdapterInfo);
224
225 return Promise.all([
226 adapterFactory.whenCalled('getAdapter'),
227 adapterFactory.adapter.proxy.whenCalled('getInfo'),
228 adapterFactory.adapter.proxy.whenCalled('getDevices'),
229 ]);
230 });
231 });
232
233 setup(function() {
234 var devices = new device_collection.DeviceCollection([]);
235 adapterClient.devices = devices;
236 deviceTable.setDevices(devices);
237 adapterClient.deviceAdded(fakeDeviceInfo1);
238 adapterClient.deviceAdded(fakeDeviceInfo2);
239 });
240
241 teardown(function() {
242 adapterFactory.reset();
243 });
244
245 /**
246 * Updates device info and verifies the contents of the device table.
247 * @param {!device_collection.DeviceInfo} deviceInfo
248 */
249 function changeDevice(deviceInfo) {
250 var deviceRow = document.querySelector('#' + escapeDeviceAddress(
251 deviceInfo.address));
252 var nameForDisplayColumn = deviceRow.children[0];
253 var addressColumn = deviceRow.children[1];
254 var rssiColumn = deviceRow.children[2];
255 var servicesColumn = deviceRow.children[3];
256
257 expectTrue(!!nameForDisplayColumn);
258 expectTrue(!!addressColumn);
259 expectTrue(!!rssiColumn);
260 expectTrue(!!servicesColumn);
261
262 adapterClient.deviceChanged(deviceInfo);
263
264 expectEquals(deviceInfo.name_for_display,
265 nameForDisplayColumn.textContent);
266 expectEquals(deviceInfo.address, addressColumn.textContent);
267
268 expectEquals(String(deviceInfo.rssi.value), rssiColumn.textContent);
269
270 if (deviceInfo.services) {
271 expectEquals(String(deviceInfo.services.length),
272 servicesColumn.textContent);
273 } else {
274 expectEquals('Unknown',
275 servicesColumn.textContent);
dpapad 2016/11/02 00:03:00 Fits in previous line?
mbrunson 2016/11/02 22:47:21 Done.
276 }
277 }
278
279 /**
280 * Escapes colons in a device address for CSS formatting.
281 * @param {!string} address
282 */
283 function escapeDeviceAddress(address) {
284 return address.replace(/:/g, '\\:');
285 }
286
287 /**
288 * Expects whether device is removed or not.
289 * @param {!boolean} expectRemoved
290 */
291 function expectDeviceRemoved(expectRemoved) {
292 var removedRow = document.querySelector('#' + escapeDeviceAddress(
293 newDeviceInfo.address));
294
295 if (expectRemoved) expectTrue(removedRow.classList.contains('removed'));
296 else expectFalse(removedRow.classList.contains('removed'));
dpapad 2016/11/02 00:03:00 expectEquals(expectRemoved, !removedRow.classList.
mbrunson 2016/11/02 22:47:24 The WebUI browser_tests best practices [1] says to
dpapad 2016/11/02 23:19:14 Ok. The reality is that expect*() functions make W
297 }
298
299 /**
300 * Tests whether a device is added successfully and not duplicated.
301 */
302 test('DeviceAdded', function() {
303 var devices = document.querySelectorAll('#device-table tbody tr');
304 expectEquals(EXPECTED_DEVICES, devices.length);
305
306 adapterClient.deviceAdded(fakeDeviceInfo3);
307
308 // Same device shouldn't appear twice.
309 adapterClient.deviceAdded(fakeDeviceInfo3);
310
311 devices = document.querySelectorAll('#device-table tbody tr');
312 expectEquals(EXPECTED_DEVICES + 1, devices.length);
313 });
314
315 /**
316 * Tests whether a device is marked properly as removed.
317 */
318 test('DeviceSetToRemoved', function() {
319 var devices = document.querySelectorAll('#device-table tbody tr');
320 expectEquals(EXPECTED_DEVICES, devices.length);
321 adapterClient.deviceRemoved(fakeDeviceInfo2);
322
323 // The number of rows shouldn't change.
324 devices = document.querySelectorAll('#device-table tbody tr');
325 expectEquals(EXPECTED_DEVICES, devices.length);
326
327 expectDeviceRemoved(true);
328 });
329
330 /**
331 * Tests whether a changed device updates the device table properly.
332 */
333 test('DeviceChanged', function() {
334 var devices = document.querySelectorAll('#device-table tbody tr');
335 expectEquals(EXPECTED_DEVICES, devices.length);
336
337 var newDeviceInfo = Object.assign({}, fakeDeviceInfo1);
338 newDeviceInfo.name_for_display = 'DDDD';
339 newDeviceInfo.rssi = { value: -20 };
340 newDeviceInfo.services = ['service1', 'service2', 'service3'];
341
342 changeDevice(newDeviceInfo);
343 });
344
345 /**
346 * Tests the entire device cycle: added -> updated -> removed -> re-added.
347 */
348 test('DeviceUpdateCycle', function() {
349 var devices = document.querySelectorAll('#device-table tbody tr');
350 expectEquals(EXPECTED_DEVICES, devices.length);
351
352 adapterClient.deviceAdded(fakeDeviceInfo3);
353
354 var newDeviceInfo = Object.assign({}, fakeDeviceInfo3);
355 newDeviceInfo.name_for_display = 'DDDD';
356 newDeviceInfo.rssi = { value: -20 };
357 newDeviceInfo.services = ['service1', 'service2', 'service3'];
358
359 changeDevice(newDeviceInfo);
360 changeDevice(fakeDeviceInfo3);
361
362 adapterClient.deviceRemoved(fakeDeviceInfo3);
363 expectDeviceRemoved(true);
364
365 adapterClient.deviceAdded(fakeDeviceInfo3);
366 expectDeviceRemoved(false);
367 });
368 });
369
370 // Run all registered tests.
371 mocha.run();
372 });
OLDNEW
« no previous file with comments | « chrome/test/BUILD.gn ('k') | no next file » | no next file with comments »

Powered by Google App Engine