OLD | NEW |
1 // Copyright 2016 The Chromium Authors. All rights reserved. | 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 | 2 // Use of this source code is governed by a BSD-style license that can be |
3 // found in the LICENSE file. | 3 // found in the LICENSE file. |
4 | 4 |
5 /** | 5 /** |
6 * @fileoverview Tests for chrome://bluetooth-internals | 6 * @fileoverview Tests for chrome://bluetooth-internals |
7 */ | 7 */ |
8 | 8 |
9 /** @const {string} Path to source root. */ | 9 /** @const {string} Path to source root. */ |
10 var ROOT_PATH = '../../../../'; | 10 var ROOT_PATH = '../../../../'; |
(...skipping 35 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
46 // test to replace the real Mojo browser proxy with a fake one, before any | 46 // test to replace the real Mojo browser proxy with a fake one, before any |
47 // other code runs. | 47 // other code runs. |
48 window.setupFn = function() { | 48 window.setupFn = function() { |
49 return importModules([ | 49 return importModules([ |
50 'content/public/renderer/frame_interfaces', | 50 'content/public/renderer/frame_interfaces', |
51 'device/bluetooth/public/interfaces/adapter.mojom', | 51 'device/bluetooth/public/interfaces/adapter.mojom', |
52 'device/bluetooth/public/interfaces/device.mojom', | 52 'device/bluetooth/public/interfaces/device.mojom', |
53 'mojo/public/js/bindings', | 53 'mojo/public/js/bindings', |
54 ]).then(function([frameInterfaces, adapter, device, bindings]) { | 54 ]).then(function([frameInterfaces, adapter, device, bindings]) { |
55 /** | 55 /** |
56 * A test adapter factory proxy for the chrome://bluetooth-internals | 56 * A test adapter factory proxy for the chrome://bluetooth-internals |
57 * page. | 57 * page. |
58 * | 58 * |
59 * @constructor | 59 * @constructor |
60 * @extends {TestBrowserProxyBase} | 60 * @extends {TestBrowserProxyBase} |
61 */ | 61 */ |
62 var TestAdapterFactoryProxy = function() { | 62 var TestAdapterFactoryProxy = function() { |
63 settings.TestBrowserProxy.call(this, [ | 63 settings.TestBrowserProxy.call(this, [ |
64 'getAdapter', | 64 'getAdapter', |
65 ]); | 65 ]); |
66 | 66 |
67 this.binding = new bindings.Binding(adapter.AdapterFactory, this); | 67 this.binding = new bindings.Binding(adapter.AdapterFactory, this); |
68 this.adapter = new TestAdapterProxy(); | 68 this.adapter = new TestAdapterProxy(); |
69 this.adapterBinding_ = new bindings.Binding(adapter.Adapter, | 69 this.adapterBinding_ = new bindings.Binding(adapter.Adapter, |
70 this.adapter); | 70 this.adapter); |
71 }; | 71 }; |
72 | 72 |
73 TestAdapterFactoryProxy.prototype = { | 73 TestAdapterFactoryProxy.prototype = { |
74 __proto__: settings.TestBrowserProxy.prototype, | 74 __proto__: settings.TestBrowserProxy.prototype, |
75 getAdapter: function() { | 75 getAdapter: function() { |
76 this.methodCalled('getAdapter'); | 76 this.methodCalled('getAdapter'); |
77 | 77 |
78 // Create message pipe bound to TestAdapter. | 78 // Create message pipe bound to TestAdapter. |
79 return Promise.resolve({ | 79 return Promise.resolve({ |
80 adapter: this.adapterBinding_.createInterfacePtrAndBind(), | 80 adapter: this.adapterBinding_.createInterfacePtrAndBind(), |
81 }); | 81 }); |
82 } | 82 } |
83 }; | 83 }; |
84 | 84 |
85 /** | 85 /** |
86 * A test adapter proxy for the chrome://bluetooth-internals page. | 86 * A test adapter proxy for the chrome://bluetooth-internals page. |
87 * | 87 * @constructor |
88 * @constructor | 88 * @extends {TestBrowserProxyBase} |
89 * @extends {TestBrowserProxyBase} | 89 */ |
90 */ | |
91 var TestAdapterProxy = function() { | 90 var TestAdapterProxy = function() { |
92 settings.TestBrowserProxy.call(this, [ | 91 settings.TestBrowserProxy.call(this, [ |
93 'getInfo', | 92 'getInfo', |
94 'getDevices', | 93 'getDevices', |
95 'setClient', | 94 'setClient', |
96 ]); | 95 ]); |
97 | 96 |
| 97 this.deviceProxyMap = new Map(); |
98 this.adapterInfo_ = null; | 98 this.adapterInfo_ = null; |
99 this.devices_ = []; | 99 this.devices_ = []; |
| 100 this.connectResult_ = adapter.AdapterInfo.SUCCESS; |
100 }; | 101 }; |
101 | 102 |
102 TestAdapterProxy.prototype = { | 103 TestAdapterProxy.prototype = { |
103 __proto__: settings.TestBrowserProxy.prototype, | 104 __proto__: settings.TestBrowserProxy.prototype, |
104 | 105 |
| 106 connectToDevice: function(address) { |
| 107 assert(this.deviceProxyMap.has(address), 'Device does not exist'); |
| 108 |
| 109 return Promise.resolve({ |
| 110 result: this.connectResult_, |
| 111 device: this.deviceProxyMap.get( |
| 112 address).binding.createInterfacePtrAndBind(), |
| 113 }); |
| 114 }, |
| 115 |
105 getInfo: function() { | 116 getInfo: function() { |
106 this.methodCalled('getInfo'); | 117 this.methodCalled('getInfo'); |
107 return Promise.resolve({info: this.adapterInfo_}); | 118 return Promise.resolve({info: this.adapterInfo_}); |
108 }, | 119 }, |
109 | 120 |
110 getDevices: function() { | 121 getDevices: function() { |
111 this.methodCalled('getDevices'); | 122 this.methodCalled('getDevices'); |
112 return Promise.resolve({devices: this.devices_}); | 123 return Promise.resolve({devices: this.devices_}); |
113 }, | 124 }, |
114 | 125 |
115 setClient: function(client) { | 126 setClient: function(client) { |
116 this.methodCalled('setClient', client); | 127 this.methodCalled('setClient', client); |
117 }, | 128 }, |
118 | 129 |
119 setTestAdapter: function(adapterInfo) { | 130 setTestAdapter: function(adapterInfo) { |
120 this.adapterInfo_ = adapterInfo; | 131 this.adapterInfo_ = adapterInfo; |
121 }, | 132 }, |
122 | 133 |
| 134 setTestConnectResult: function(connectResult) { |
| 135 this.connectResult_ = connectResult; |
| 136 }, |
| 137 |
123 setTestDevices: function(devices) { | 138 setTestDevices: function(devices) { |
124 this.devices_ = devices; | 139 this.devices_ = devices; |
125 } | 140 this.devices_.forEach(function(device) { |
| 141 this.deviceProxyMap.set( |
| 142 device.address, new TestDeviceProxy(device)); |
| 143 }, this); |
| 144 }, |
126 }; | 145 }; |
127 | 146 |
| 147 /** |
| 148 * A test Device proxy for the chrome://bluetooth-internals |
| 149 * page. Proxies are generated by a TestAdapterProxy which provides |
| 150 * the DeviceInfo. |
| 151 * @constructor |
| 152 * @extends {TestBrowserProxyBase} |
| 153 * @param {!device.DeviceInfo} info |
| 154 */ |
| 155 var TestDeviceProxy = function(info) { |
| 156 settings.TestBrowserProxy.call(this, [ |
| 157 'getInfo', |
| 158 'getServices', |
| 159 ]); |
| 160 |
| 161 this.binding = new bindings.Binding(device.Device, this); |
| 162 this.info_ = info; |
| 163 this.services_ = []; |
| 164 } |
| 165 |
| 166 TestDeviceProxy.prototype = { |
| 167 __proto__: settings.TestBrowserProxy.prototype, |
| 168 |
| 169 disconnect: function() { |
| 170 this.binding.close(); |
| 171 }, |
| 172 |
| 173 getInfo: function() { |
| 174 this.methodCalled('getInfo'); |
| 175 return Promise.resolve({info: this.info_}); |
| 176 }, |
| 177 |
| 178 getServices: function() { |
| 179 this.methodCalled('getServices'); |
| 180 return Promise.resolve({services: this.services_}); |
| 181 }, |
| 182 |
| 183 setTestServices: function(services) { |
| 184 this.services_ = services; |
| 185 }, |
| 186 } |
| 187 |
128 frameInterfaces.addInterfaceOverrideForTesting( | 188 frameInterfaces.addInterfaceOverrideForTesting( |
129 adapter.AdapterFactory.name, function(handle) { | 189 adapter.AdapterFactory.name, function(handle) { |
130 this.adapterFactory = new TestAdapterFactoryProxy(); | 190 this.adapterFactory = new TestAdapterFactoryProxy(); |
131 this.adapterFactory.binding.bind(handle); | 191 this.adapterFactory.binding.bind(handle); |
132 | 192 |
133 this.adapterFactory.adapter.setTestDevices([ | 193 this.adapterFactory.adapter.setTestDevices([ |
134 this.fakeDeviceInfo1(), | 194 this.fakeDeviceInfo1(), |
135 this.fakeDeviceInfo2(), | 195 this.fakeDeviceInfo2(), |
136 ]); | 196 ]); |
137 this.adapterFactory.adapter.setTestAdapter( | 197 this.adapterFactory.adapter.setTestAdapter( |
138 this.fakeAdapterInfo()); | 198 this.fakeAdapterInfo()); |
139 | 199 |
| 200 this.adapterFactory.adapter.deviceProxyMap.forEach( |
| 201 function(deviceProxy) { |
| 202 deviceProxy.setTestServices([ |
| 203 this.fakeServiceInfo1(), |
| 204 this.fakeServiceInfo2(), |
| 205 ]) |
| 206 }, this); |
| 207 |
140 this.setupResolver.resolve(); | 208 this.setupResolver.resolve(); |
141 }.bind(this)); | 209 }.bind(this)); |
142 | 210 |
143 }.bind(this)); | 211 }.bind(this)); |
144 }.bind(this); | 212 }.bind(this); |
145 }, | 213 }, |
146 | 214 |
147 /** | 215 /** |
148 * Returns a copy of fake adapter info object. | 216 * Returns a copy of fake adapter info object. |
149 * @return {!Object} | 217 * @return {!Object} |
(...skipping 43 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
193 * rssi and services properties. | 261 * rssi and services properties. |
194 * @return {!Object} | 262 * @return {!Object} |
195 */ | 263 */ |
196 fakeDeviceInfo3: function() { | 264 fakeDeviceInfo3: function() { |
197 return { | 265 return { |
198 address: "CC:CC:84:96:92:84", | 266 address: "CC:CC:84:96:92:84", |
199 name: "CCC", | 267 name: "CCC", |
200 name_for_display: "CCC", | 268 name_for_display: "CCC", |
201 }; | 269 }; |
202 }, | 270 }, |
| 271 |
| 272 /** |
| 273 * Returns a copy of fake service info object (variant 1). |
| 274 * @return {!Object} |
| 275 */ |
| 276 fakeServiceInfo1: function() { |
| 277 return { |
| 278 uuid: '00002a05-0000-1000-8000-00805f9b34fb', |
| 279 is_primary: true, |
| 280 } |
| 281 }, |
| 282 |
| 283 /** |
| 284 * Returns a copy of fake service info object (variant 2). |
| 285 * @return {!Object} |
| 286 */ |
| 287 fakeServiceInfo2: function() { |
| 288 return { |
| 289 uuid: '0000180d-0000-1000-8000-00805f9b34fb', |
| 290 is_primary: true, |
| 291 } |
| 292 }, |
203 }; | 293 }; |
204 | 294 |
205 TEST_F('BluetoothInternalsTest', 'Startup_BluetoothInternals', function() { | 295 TEST_F('BluetoothInternalsTest', 'Startup_BluetoothInternals', function() { |
206 /** @const */ var PageManager = cr.ui.pageManager.PageManager; | 296 /** @const */ var PageManager = cr.ui.pageManager.PageManager; |
207 | 297 |
208 var adapterFactory = null; | 298 var adapterFactory = null; |
209 var adapterFieldSet = null; | 299 var adapterFieldSet = null; |
210 var deviceTable = null; | 300 var deviceTable = null; |
211 var sidebarNode = null; | 301 var sidebarNode = null; |
| 302 var pageNames = ['adapter', 'devices']; |
212 | 303 |
213 var fakeAdapterInfo = this.fakeAdapterInfo; | 304 var fakeAdapterInfo = this.fakeAdapterInfo; |
214 var fakeDeviceInfo1 = this.fakeDeviceInfo1; | 305 var fakeDeviceInfo1 = this.fakeDeviceInfo1; |
215 var fakeDeviceInfo2 = this.fakeDeviceInfo2; | 306 var fakeDeviceInfo2 = this.fakeDeviceInfo2; |
216 var fakeDeviceInfo3 = this.fakeDeviceInfo3; | 307 var fakeDeviceInfo3 = this.fakeDeviceInfo3; |
| 308 var fakeServiceInfo1 = this.fakeServiceInfo1; |
| 309 var fakeServiceInfo2 = this.fakeServiceInfo2; |
217 | 310 |
218 // Before tests are run, make sure setup completes. | 311 // Before tests are run, make sure setup completes. |
219 var setupPromise = this.setupResolver.promise.then(function() { | 312 var setupPromise = this.setupResolver.promise.then(function() { |
220 adapterFactory = this.adapterFactory; | 313 adapterFactory = this.adapterFactory; |
221 }.bind(this)); | 314 }.bind(this)); |
222 | 315 |
223 suite('BluetoothInternalsUITest', function() { | 316 suite('BluetoothInternalsUITest', function() { |
224 var EXPECTED_DEVICES = 2; | 317 var EXPECTED_DEVICES = 2; |
225 | 318 |
226 suiteSetup(function() { | 319 suiteSetup(function() { |
227 return setupPromise.then(function() { | 320 return setupPromise.then(function() { |
228 return Promise.all([ | 321 return Promise.all([ |
229 adapterFactory.whenCalled('getAdapter'), | 322 adapterFactory.whenCalled('getAdapter'), |
230 adapterFactory.adapter.whenCalled('getInfo'), | 323 adapterFactory.adapter.whenCalled('getInfo'), |
231 adapterFactory.adapter.whenCalled('getDevices'), | 324 adapterFactory.adapter.whenCalled('getDevices'), |
232 adapterFactory.adapter.whenCalled('setClient'), | 325 adapterFactory.adapter.whenCalled('setClient'), |
233 ]); | 326 ]); |
234 }); | 327 }); |
235 }); | 328 }); |
236 | 329 |
237 setup(function() { | 330 setup(function() { |
238 adapterFieldSet = document.querySelector('#adapter fieldset'); | 331 adapterFieldSet = document.querySelector('#adapter fieldset'); |
239 deviceTable = document.querySelector('#devices table'); | 332 deviceTable = document.querySelector('#devices table'); |
240 sidebarNode = document.querySelector('#sidebar'); | 333 sidebarNode = document.querySelector('#sidebar'); |
241 devices.splice(0, devices.length); | 334 devices.splice(0, devices.length); |
242 adapterBroker.adapterClient_.deviceAdded(fakeDeviceInfo1()); | 335 adapterBroker.adapterClient_.deviceAdded(fakeDeviceInfo1()); |
243 adapterBroker.adapterClient_.deviceAdded(fakeDeviceInfo2()); | 336 adapterBroker.adapterClient_.deviceAdded(fakeDeviceInfo2()); |
| 337 |
244 }); | 338 }); |
245 | 339 |
246 teardown(function() { | 340 teardown(function() { |
247 adapterFactory.reset(); | 341 adapterFactory.reset(); |
248 sidebarObj.close(); | 342 sidebarObj.close(); |
249 snackbar.Snackbar.dismiss(true); | 343 snackbar.Snackbar.dismiss(true); |
| 344 |
| 345 adapterFactory.adapter.deviceProxyMap.forEach(function(deviceProxy) { |
| 346 deviceProxy.reset(); |
| 347 }); |
| 348 |
250 PageManager.registeredPages['adapter'].setAdapterInfo(fakeAdapterInfo()); | 349 PageManager.registeredPages['adapter'].setAdapterInfo(fakeAdapterInfo()); |
| 350 |
| 351 for (var pageName in PageManager.registeredPages) { |
| 352 var page = PageManager.registeredPages[pageName]; |
| 353 |
| 354 if (pageNames.indexOf(pageName) < 0) { |
| 355 page.pageDiv.parentNode.removeChild(page.pageDiv); |
| 356 PageManager.unregister(page); |
| 357 } |
| 358 } |
251 }); | 359 }); |
252 | 360 |
253 /** | 361 /** |
254 * Updates device info and verifies the contents of the device table. | 362 * Updates device info and verifies the contents of the device table. |
255 * @param {!device_collection.DeviceInfo} deviceInfo | 363 * @param {!device_collection.DeviceInfo} deviceInfo |
256 */ | 364 */ |
257 function changeDevice(deviceInfo) { | 365 function changeDevice(deviceInfo) { |
258 var deviceRow = deviceTable.querySelector('#' + escapeDeviceAddress( | 366 var deviceRow = deviceTable.querySelector('#' + escapeDeviceAddress( |
259 deviceInfo.address)); | 367 deviceInfo.address)); |
260 var nameForDisplayColumn = deviceRow.children[0]; | 368 var nameForDisplayColumn = deviceRow.children[0]; |
(...skipping 149 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
410 newDeviceInfo3.rssi = {value: -17}; | 518 newDeviceInfo3.rssi = {value: -17}; |
411 adapterBroker.adapterClient_.deviceChanged(newDeviceInfo3); | 519 adapterBroker.adapterClient_.deviceChanged(newDeviceInfo3); |
412 expectEquals('-17', rssiColumn.textContent); | 520 expectEquals('-17', rssiColumn.textContent); |
413 }); | 521 }); |
414 | 522 |
415 /* Sidebar Tests */ | 523 /* Sidebar Tests */ |
416 test('Sidebar_Setup', function() { | 524 test('Sidebar_Setup', function() { |
417 var sidebarItems = Array.from( | 525 var sidebarItems = Array.from( |
418 sidebarNode.querySelectorAll('.sidebar-content li')); | 526 sidebarNode.querySelectorAll('.sidebar-content li')); |
419 | 527 |
420 ['adapter', 'devices'].forEach(function(pageName) { | 528 pageNames.forEach(function(pageName) { |
421 expectTrue(sidebarItems.some(function(item) { | 529 expectTrue(sidebarItems.some(function(item) { |
422 return item.dataset.pageName === pageName; | 530 return item.dataset.pageName === pageName; |
423 })); | 531 })); |
424 }); | 532 }); |
425 }); | 533 }); |
426 | 534 |
427 test('Sidebar_DefaultState', function() { | 535 test('Sidebar_DefaultState', function() { |
428 // Sidebar should be closed by default. | 536 // Sidebar should be closed by default. |
429 expectFalse(sidebarNode.classList.contains('open')); | 537 expectFalse(sidebarNode.classList.contains('open')); |
430 }); | 538 }); |
(...skipping 162 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
593 checkAdapterFieldSet(adapterInfo); | 701 checkAdapterFieldSet(adapterInfo); |
594 adapterBroker.adapterClient_.presentChanged(adapterInfo.present); | 702 adapterBroker.adapterClient_.presentChanged(adapterInfo.present); |
595 checkAdapterFieldSet(adapterInfo); | 703 checkAdapterFieldSet(adapterInfo); |
596 | 704 |
597 adapterInfo.discovering = !adapterInfo.discovering; | 705 adapterInfo.discovering = !adapterInfo.discovering; |
598 adapterBroker.adapterClient_.discoveringChanged(adapterInfo.discovering); | 706 adapterBroker.adapterClient_.discoveringChanged(adapterInfo.discovering); |
599 checkAdapterFieldSet(adapterInfo); | 707 checkAdapterFieldSet(adapterInfo); |
600 adapterBroker.adapterClient_.discoveringChanged(adapterInfo.discovering); | 708 adapterBroker.adapterClient_.discoveringChanged(adapterInfo.discovering); |
601 checkAdapterFieldSet(adapterInfo); | 709 checkAdapterFieldSet(adapterInfo); |
602 }); | 710 }); |
| 711 |
| 712 /** Device Details Page Tests */ |
| 713 |
| 714 /** |
| 715 * Checks DeviceDetailsPage status fieldset. |
| 716 * @param {!HTMLElement} detailsPage |
| 717 * @param {!Object} deviceInfo |
| 718 */ |
| 719 function checkDeviceDetailsFieldSet(detailsPage, deviceInfo) { |
| 720 [ |
| 721 'name', |
| 722 'address', |
| 723 'is_gatt_connected', |
| 724 'rssi.value', |
| 725 'services.length', |
| 726 ].forEach(function(propName){ |
| 727 var valueCell = detailsPage.querySelector( |
| 728 'fieldset [data-field="' + propName + '"]'); |
| 729 |
| 730 var parts = propName.split('.'); |
| 731 var value = deviceInfo; |
| 732 |
| 733 while (value != null && parts.length > 0) { |
| 734 var part = parts.shift(); |
| 735 value = value[part]; |
| 736 } |
| 737 |
| 738 if (propName == 'is_gatt_connected') |
| 739 value = value ? 'Connected' : 'Not Connected'; |
| 740 |
| 741 if (typeof(value) === 'boolean') { |
| 742 expectEquals(value, valueCell.classList.contains('checked')); |
| 743 } else if (typeof(value) === 'string') { |
| 744 expectEquals(value, valueCell.textContent); |
| 745 } else { |
| 746 assert('boolean or string type expected but got ' + typeof(value)); |
| 747 } |
| 748 }); |
| 749 } |
| 750 |
| 751 test('DeviceDetailsPage_NewDelete', function() { |
| 752 var device = devices.item(0); |
| 753 |
| 754 var deviceInspectLink = $(device.address).querySelector( |
| 755 '[is="action-link"]'); |
| 756 |
| 757 var deviceDetailsPageId = 'devices/' + device.address.toLowerCase(); |
| 758 |
| 759 deviceInspectLink.click(); |
| 760 expectEquals("#" + deviceDetailsPageId, window.location.hash); |
| 761 |
| 762 var detailsPage = $(deviceDetailsPageId); |
| 763 assertTrue(!!detailsPage); |
| 764 |
| 765 return adapterFactory.adapter.deviceProxyMap.get( |
| 766 device.address).whenCalled('getServices').then(function() { |
| 767 // At this point, the device details page should be fully loaded. |
| 768 checkDeviceDetailsFieldSet(detailsPage, device); |
| 769 |
| 770 detailsPage.querySelector('.forget').click(); |
| 771 expectEquals('#devices', window.location.hash); |
| 772 detailsPage = $(deviceDetailsPageId); |
| 773 expectFalse(!!detailsPage); |
| 774 }); |
| 775 }); |
| 776 |
| 777 test('DeviceDetailsPage_NewDelete_FromDevicesPage', function() { |
| 778 var device = devices.item(0); |
| 779 var deviceDetailsPageId = 'devices/' + device.address.toLowerCase(); |
| 780 |
| 781 var deviceLinks = $(device.address).querySelectorAll( |
| 782 '[is="action-link"]'); |
| 783 |
| 784 // First link is 'Inspect'. |
| 785 deviceLinks[0].click(); |
| 786 expectEquals("#" + deviceDetailsPageId, window.location.hash); |
| 787 |
| 788 var detailsPage = $(deviceDetailsPageId); |
| 789 assertTrue(!!detailsPage); |
| 790 |
| 791 return adapterFactory.adapter.deviceProxyMap.get( |
| 792 device.address).whenCalled('getServices').then(function() { |
| 793 checkDeviceDetailsFieldSet(detailsPage, device); |
| 794 |
| 795 // Second link is 'Forget'. |
| 796 deviceLinks[1].click(); |
| 797 expectEquals('#devices', window.location.hash); |
| 798 detailsPage = $(deviceDetailsPageId); |
| 799 expectFalse(!!detailsPage); |
| 800 }); |
| 801 }); |
603 }); | 802 }); |
604 | 803 |
605 // Run all registered tests. | 804 // Run all registered tests. |
606 mocha.run(); | 805 mocha.run(); |
607 }); | 806 }); |
OLD | NEW |