1// Copyright (c) 2011 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// Stub out the `chrome.proxy`, `chrome.i18n`, and `chrome.extension` APIs 6chrome = chrome || { 7 proxy: { 8 settings: { 9 get: function() {}, 10 clear: function() {}, 11 set: function() {} 12 } 13 }, 14 i18n: { 15 getMessage: function(x) { return x; } 16 }, 17 extension: { 18 sendRequest: function() {}, 19 isAllowedIncognitoAccess: function(funk) { 20 funk(true); 21 } 22 } 23}; 24 25var fixture = document.getElementById('fixture'); 26var baselineHTML = fixture.innerHTML; 27var groupIDs = [ProxyFormController.ProxyTypes.DIRECT, 28 ProxyFormController.ProxyTypes.SYSTEM, 29 ProxyFormController.ProxyTypes.PAC, 30 ProxyFormController.ProxyTypes.FIXED]; 31 32var mockFunctionFactory = function(returnValue, logging) { 33 var called = []; 34 returnValue = returnValue || null; 35 36 var funky = function() { 37 called.push(arguments); 38 if (arguments[1] && typeof(arguments[1]) === 'function') { 39 var funk = arguments[1]; 40 funk(returnValue); 41 } 42 return returnValue; 43 }; 44 funky.getCallList = function() { return called; }; 45 funky.getValue = function() { return returnValue; }; 46 return funky; 47}; 48 49var proxyform = new Test.Unit.Runner({ 50 setup: function() { 51 fixture.innerHTML = baselineHTML; 52 this.controller_ = new ProxyFormController('proxyForm'); 53 this.clickEvent_ = document.createEvent('MouseEvents'); 54 this.clickEvent_.initMouseEvent('click', true, true, window, 55 0, 0, 0, 0, 0, false, false, false, false, 0, null); 56 // Reset mock functions. 57 chrome.proxy = { 58 settings: { 59 get: mockFunctionFactory({ 60 value: {mode: 'system' }, 61 levelOfControl: 'controllable_by_this_extension' }), 62 clear: mockFunctionFactory({ 63 value: {mode: 'system' }, 64 levelOfControl: 'controllable_by_this_extension' }), 65 set: mockFunctionFactory({ 66 value: {mode: 'system' }, 67 levelOfControl: 'controllable_by_this_extension' }) 68 } 69 }; 70 }, 71 72 teardown: function() { 73 fixture.removeChild(fixture.childNodes[0]); 74 delete(this.controller_); 75 }, 76 77 // Clicking on various bits of the interface should set correct classes, 78 // and select correct radio buttons. 79 testActivationClicks: function() { 80 var self = this; 81 var i; 82 groupIDs.forEach(function(id) { 83 var group = document.getElementById(id); 84 var all = group.querySelectorAll('*'); 85 for (i = 0; i < all.length; i++) { 86 group.classList.remove('active'); 87 all[i].dispatchEvent(self.clickEvent_); 88 self.assert(group.classList.contains('active')); 89 } 90 }); 91 }, 92 93 // Elements inside an active group should not be disabled, and vice versa 94 testDisabledElements: function() { 95 var self = this; 96 var i, j; 97 groupIDs.forEach(function(id) { 98 var group = document.getElementById(id); 99 var all = group.querySelectorAll('*'); 100 // First, check that activating a group enables its form elements 101 for (i = 0; i < all.length; i++) { 102 group.classList.remove('active'); 103 var inputs = group.querySelectorAll('input:not([type="radio"]),select'); 104 for (j = 0; j < inputs.length; j++) { 105 inputs[j].setAttribute('disabled', 'disabled'); 106 } 107 all[i].dispatchEvent(self.clickEvent_); 108 for (j = 0; j < inputs.length; j++) { 109 self.assert(!inputs[j].hasAttribute('disabled')); 110 } 111 } 112 }); 113 }, 114 115 // Clicking the "Use single proxy" checkbox should set the correct 116 // classes on the form. 117 testSingleProxyToggle: function() { 118 var group = document.getElementById( 119 ProxyFormController.ProxyTypes.FIXED); 120 var checkbox = document.getElementById('singleProxyForEverything'); 121 var section = checkbox.parentNode.parentNode; 122 // Checkbox only works in active group, `testActivationClicks` tests 123 // the inactive click behavior. 124 group.classList.add('active'); 125 126 checkbox.checked = false; 127 checkbox.dispatchEvent(this.clickEvent_); 128 this.assert(section.classList.contains('single')); 129 checkbox.dispatchEvent(this.clickEvent_); 130 this.assert(!section.classList.contains('single')); 131 }, 132 133 // On instantiation, ProxyFormController should read the current state 134 // from `chrome.proxy.settings.get`, and react accordingly. 135 // Let's see if that happens with the next four sets of assertions. 136 testSetupFormSystem: function() { 137 chrome.proxy.settings.get = mockFunctionFactory({ 138 value: {mode: 'system'}, 139 levelOfControl: 'controllable_by_this_extension' 140 }); 141 142 fixture.innerHTML = baselineHTML; 143 this.controller_ = new ProxyFormController('proxyForm'); 144 // Wait for async calls to fire 145 this.wait(100, function() { 146 this.assertEqual( 147 6, 148 chrome.proxy.settings.get.getCallList().length); 149 this.assert( 150 document.getElementById(ProxyFormController.ProxyTypes.SYSTEM) 151 .classList.contains('active')); 152 }); 153 }, 154 155 testSetupFormDirect: function() { 156 chrome.proxy.settings.get = 157 mockFunctionFactory({value: {mode: 'direct'}, 158 levelOfControl: 'controllable_by_this_extension'}, true); 159 160 fixture.innerHTML = baselineHTML; 161 this.controller_ = new ProxyFormController('proxyForm'); 162 // Wait for async calls to fire 163 this.wait(100, function() { 164 this.assertEqual( 165 2, 166 chrome.proxy.settings.get.getCallList().length); 167 this.assert( 168 document.getElementById(ProxyFormController.ProxyTypes.DIRECT) 169 .classList.contains('active')); 170 }); 171 }, 172 173 testSetupFormPac: function() { 174 chrome.proxy.settings.get = 175 mockFunctionFactory({value: {mode: 'pac_script' }, 176 levelOfControl: 'controllable_by_this_extension'}); 177 178 fixture.innerHTML = baselineHTML; 179 this.controller_ = new ProxyFormController('proxyForm'); 180 // Wait for async calls to fire 181 this.wait(100, function() { 182 this.assertEqual( 183 2, 184 chrome.proxy.settings.get.getCallList().length); 185 this.assert( 186 document.getElementById(ProxyFormController.ProxyTypes.PAC) 187 .classList.contains('active')); 188 }); 189 }, 190 191 testSetupFormFixed: function() { 192 chrome.proxy.settings.get = 193 mockFunctionFactory({value: {mode: 'fixed_servers' }, 194 levelOfControl: 'controllable_by_this_extension'}); 195 196 fixture.innerHTML = baselineHTML; 197 this.controller_ = new ProxyFormController('proxyForm'); 198 // Wait for async calls to fire 199 this.wait(100, function() { 200 this.assertEqual( 201 2, 202 chrome.proxy.settings.get.getCallList().length); 203 this.assert( 204 document.getElementById(ProxyFormController.ProxyTypes.FIXED) 205 .classList.contains('active')); 206 }); 207 }, 208 209 // Test that `recalcFormValues_` correctly sets DOM field values when 210 // given a `ProxyConfig` structure 211 testRecalcFormValuesGroups: function() { 212 // Test `AUTO` normalization to `PAC` 213 this.controller_.recalcFormValues_({ 214 mode: ProxyFormController.ProxyTypes.AUTO, 215 rules: {}, 216 pacScript: '' 217 }); 218 this.assert( 219 document.getElementById(ProxyFormController.ProxyTypes.PAC) 220 .classList.contains('active')); 221 222 // DIRECT 223 this.controller_.recalcFormValues_({ 224 mode: ProxyFormController.ProxyTypes.DIRECT, 225 rules: {}, 226 pacScript: '' 227 }); 228 this.assert( 229 document.getElementById(ProxyFormController.ProxyTypes.DIRECT) 230 .classList.contains('active')); 231 232 // FIXED 233 this.controller_.recalcFormValues_({ 234 mode: ProxyFormController.ProxyTypes.FIXED, 235 rules: {}, 236 pacScript: '' 237 }); 238 this.assert( 239 document.getElementById(ProxyFormController.ProxyTypes.FIXED) 240 .classList.contains('active')); 241 242 // PAC 243 this.controller_.recalcFormValues_({ 244 mode: ProxyFormController.ProxyTypes.PAC, 245 rules: {}, 246 pacScript: '' 247 }); 248 this.assert( 249 document.getElementById(ProxyFormController.ProxyTypes.PAC) 250 .classList.contains('active')); 251 252 // SYSTEM 253 this.controller_.recalcFormValues_({ 254 mode: ProxyFormController.ProxyTypes.SYSTEM, 255 rules: {}, 256 pacScript: '' 257 }); 258 this.assert( 259 document.getElementById(ProxyFormController.ProxyTypes.SYSTEM) 260 .classList.contains('active')); 261 }, 262 263 testRecalcFormValuesFixedSingle: function() { 264 this.controller_.recalcFormValues_({ 265 mode: ProxyFormController.ProxyTypes.FIXED, 266 rules: { 267 singleProxy: { 268 scheme: 'socks5', 269 host: 'singleproxy.example.com', 270 port: '1234' 271 } 272 } 273 }); 274 var single = this.controller_.singleProxy; 275 this.assertEqual('socks5', single.scheme); 276 this.assertEqual('singleproxy.example.com', single.host); 277 this.assertEqual(1234, single.port); 278 }, 279 280 testRecalcFormValuesPacScript: function() { 281 this.controller_.recalcFormValues_({ 282 mode: ProxyFormController.ProxyTypes.PAC, 283 rules: {}, 284 pacScript: {url: 'http://example.com/this/is/a/pac.script'} 285 }); 286 this.assertEqual( 287 'http://example.com/this/is/a/pac.script', 288 document.getElementById('autoconfigURL').value); 289 }, 290 291 testRecalcFormValuesSingle: function() { 292 this.controller_.recalcFormValues_({ 293 mode: ProxyFormController.ProxyTypes.FIXED, 294 rules: { 295 singleProxy: { 296 scheme: 'https', 297 host: 'example.com', 298 port: 80 299 } 300 } 301 }); 302 // Single! 303 this.assert( 304 document.querySelector('#' + ProxyFormController.ProxyTypes.FIXED + 305 ' > section').classList.contains('single')); 306 307 var single = this.controller_.singleProxy; 308 this.assertEqual('https', single.scheme); 309 this.assertEqual('example.com', single.host); 310 this.assertEqual(80, single.port); 311 }, 312 313 testRecalcFormValuesMultiple: function() { 314 this.controller_.recalcFormValues_({ 315 mode: ProxyFormController.ProxyTypes.FIXED, 316 rules: { 317 proxyForHttp: { 318 scheme: 'http', 319 host: 'http.example.com', 320 port: 1 321 }, 322 proxyForHttps: { 323 scheme: 'https', 324 host: 'https.example.com', 325 port: 2 326 }, 327 proxyForFtp: { 328 scheme: 'socks4', 329 host: 'socks4.example.com', 330 port: 3 331 }, 332 fallbackProxy: { 333 scheme: 'socks5', 334 host: 'socks5.example.com', 335 port: 4 336 } 337 } 338 }); 339 // Not Single! 340 this.assert( 341 !document.querySelector('#' + ProxyFormController.ProxyTypes.FIXED 342 + ' > section').classList.contains('single')); 343 var server = this.controller_.singleProxy; 344 this.assertNull(server); 345 346 server = this.controller_.httpProxy; 347 this.assertEqual('http', server.scheme); 348 this.assertEqual('http.example.com', server.host); 349 this.assertEqual(1, server.port); 350 351 server = this.controller_.httpsProxy; 352 this.assertEqual('https', server.scheme); 353 this.assertEqual('https.example.com', server.host); 354 this.assertEqual(2, server.port); 355 356 server = this.controller_.ftpProxy; 357 this.assertEqual('socks4', server.scheme); 358 this.assertEqual('socks4.example.com', server.host); 359 this.assertEqual(3, server.port); 360 361 server = this.controller_.fallbackProxy; 362 this.assertEqual('socks5', server.scheme); 363 this.assertEqual('socks5.example.com', server.host); 364 this.assertEqual(4, server.port); 365 }, 366 367 testBypassList: function() { 368 this.controller_.bypassList = ['1.example.com', 369 '2.example.com', 370 '3.example.com']; 371 this.assertEnumEqual( 372 document.getElementById('bypassList').value, 373 '1.example.com, 2.example.com, 3.example.com'); 374 this.assertEnumEqual( 375 this.controller_.bypassList, 376 ['1.example.com', '2.example.com', '3.example.com']); 377 }, 378 379 // Test that "system" rules are correctly generated 380 testProxyRulesGenerationSystem: function() { 381 this.controller_.changeActive_( 382 document.getElementById(ProxyFormController.ProxyTypes.SYSTEM)); 383 384 this.assertHashEqual( 385 {mode: 'system'}, 386 this.controller_.generateProxyConfig_()); 387 }, 388 389 // Test that "direct" rules are correctly generated 390 testProxyRulesGenerationDirect: function() { 391 this.controller_.changeActive_( 392 document.getElementById(ProxyFormController.ProxyTypes.DIRECT)); 393 394 this.assertHashEqual( 395 {mode: 'direct'}, 396 this.controller_.generateProxyConfig_()); 397 }, 398 399 // Test that auto detection rules are correctly generated when "automatic" 400 // is selected, and no PAC file URL is given 401 testProxyRulesGenerationAuto: function() { 402 this.controller_.changeActive_( 403 document.getElementById(ProxyFormController.ProxyTypes.PAC)); 404 405 this.assertHashEqual( 406 {mode: 'auto_detect'}, 407 this.controller_.generateProxyConfig_()); 408 }, 409 410 // Test that PAC URL rules are correctly generated when "automatic" 411 // is selected, and a PAC file URL is given 412 testProxyRulesGenerationPacURL: function() { 413 this.controller_.changeActive_( 414 document.getElementById(ProxyFormController.ProxyTypes.PAC)); 415 this.controller_.pacURL = 'http://example.com/pac.pac'; 416 var result = this.controller_.generateProxyConfig_(); 417 this.assertEqual('pac_script', result.mode); 418 this.assertEqual('http://example.com/pac.pac', result.pacScript.url); 419 }, 420 421 // Manual PAC definitions 422 testProxyRulesGenerationPacData: function() { 423 var pacData = 'function FindProxyForURL(url,host) { return "DIRECT"; }'; 424 this.controller_.changeActive_( 425 document.getElementById(ProxyFormController.ProxyTypes.PAC)); 426 this.controller_.manualPac = pacData; 427 var result = this.controller_.generateProxyConfig_(); 428 this.assertEqual('pac_script', result.mode); 429 this.assertEqual(pacData, result.pacScript.data); 430 }, 431 432 // PAC URLs override manual PAC definitions 433 testProxyRulesGenerationPacURLOverridesData: function() { 434 this.controller_.changeActive_( 435 document.getElementById(ProxyFormController.ProxyTypes.PAC)); 436 this.controller_.pacURL = 'http://example.com/pac.pac'; 437 this.controller_.manualPac = 438 'function FindProxyForURL(url,host) { return "DIRECT"; }'; 439 var result = this.controller_.generateProxyConfig_(); 440 this.assertEqual('pac_script', result.mode); 441 this.assertEqual('http://example.com/pac.pac', result.pacScript.url); 442 }, 443 444 // Test that fixed, manual servers are correctly transformed into a 445 // `ProxyRules` structure. 446 testProxyRulesGenerationSingle: function() { 447 this.controller_.changeActive_( 448 document.getElementById(ProxyFormController.ProxyTypes.FIXED)); 449 450 this.controller_.singleProxy = { 451 scheme: 'http', 452 host: 'example.com', 453 port: '80' 454 }; 455 456 var result = this.controller_.generateProxyConfig_(); 457 this.assertEqual('fixed_servers', result.mode); 458 this.assertEqual('http', result.rules.singleProxy.scheme); 459 this.assertEqual('example.com', result.rules.singleProxy.host); 460 this.assertEqual(80, result.rules.singleProxy.port); 461 this.assertEqual(undefined, result.rules.proxyForHttp); 462 this.assertEqual(undefined, result.rules.proxyForHttps); 463 this.assertEqual(undefined, result.rules.proxyForFtp); 464 this.assertEqual(undefined, result.rules.fallbackProxy); 465 }, 466 467 // Test that proxy configuration rules are correctly generated 468 // for separate manually entered servers. 469 testProxyRulesGenerationSeparate: function() { 470 this.controller_.changeActive_( 471 document.getElementById(ProxyFormController.ProxyTypes.FIXED)); 472 473 this.controller_.singleProxy = false; 474 this.controller_.httpProxy = { 475 scheme: 'http', 476 host: 'http.example.com', 477 port: 80 478 }; 479 this.controller_.httpsProxy = { 480 scheme: 'https', 481 host: 'https.example.com', 482 port: 443 483 }; 484 this.controller_.ftpProxy = { 485 scheme: 'socks4', 486 host: 'ftp.example.com', 487 port: 80 488 }; 489 this.controller_.fallbackProxy = { 490 scheme: 'socks5', 491 host: 'fallback.example.com', 492 port: 80 493 }; 494 495 var result = this.controller_.generateProxyConfig_(); 496 this.assertEqual('fixed_servers', result.mode); 497 this.assertEqual(undefined, result.rules.singleProxy); 498 this.assertEqual('http', result.rules.proxyForHttp.scheme); 499 this.assertEqual('http.example.com', result.rules.proxyForHttp.host); 500 this.assertEqual('80', result.rules.proxyForHttp.port); 501 this.assertEqual('https', result.rules.proxyForHttps.scheme); 502 this.assertEqual('https.example.com', result.rules.proxyForHttps.host); 503 this.assertEqual('443', result.rules.proxyForHttps.port); 504 this.assertEqual('socks4', result.rules.proxyForFtp.scheme); 505 this.assertEqual('ftp.example.com', result.rules.proxyForFtp.host); 506 this.assertEqual('80', result.rules.proxyForFtp.port); 507 this.assertEqual('socks5', result.rules.fallbackProxy.scheme); 508 this.assertEqual('fallback.example.com', result.rules.fallbackProxy.host); 509 this.assertEqual('80', result.rules.fallbackProxy.port); 510 } 511}, { testLog: 'proxyformcontrollerlog' }); 512 513var c = new ProxyFormController('proxyForm'); 514