| OLD | NEW |
| 1 // Copyright 2014 The Chromium Authors. All rights reserved. | 1 // Copyright 2014 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 | 6 * @fileoverview |
| 7 * @suppress {checkTypes} By default, JSCompile is not run on test files. | 7 * @suppress {checkTypes} By default, JSCompile is not run on test files. |
| 8 * However, you can modify |remoting_webapp_files.gypi| locally to include | 8 * However, you can modify |remoting_webapp_files.gypi| locally to include |
| 9 * the test in the package to expedite local development. This suppress | 9 * the test in the package to expedite local development. This suppress |
| 10 * is here so that JSCompile won't complain. | 10 * is here so that JSCompile won't complain. |
| 11 * | 11 * |
| 12 * Provides basic functionality for JavaScript based browser test. | 12 * Provides basic functionality for JavaScript based browser test. |
| 13 * | 13 * |
| 14 * To define a browser test, create a class under the browserTest namespace. | 14 * To define a browser test, create a class under the browserTest namespace. |
| 15 * You can pass arbitrary object literals to the browser test from the C++ test | 15 * You can pass arbitrary object literals to the browser test from the C++ test |
| 16 * harness as the test data. Each browser test class should implement the run | 16 * harness as the test data. Each browser test class should implement the run |
| 17 * method. | 17 * method. |
| 18 * For example: | 18 * For example: |
| 19 * | 19 * |
| 20 * browserTest.My_Test = function(myObjectLiteral) {}; | 20 * browserTest.My_Test = function() {}; |
| 21 * browserTest.My_Test.prototype.run() = function() { ... }; | 21 * browserTest.My_Test.prototype.run(myObjectLiteral) = function() { ... }; |
| 22 * | 22 * |
| 23 * The browser test is async in nature. It will keep running until | 23 * The browser test is async in nature. It will keep running until |
| 24 * browserTest.fail("My error message.") or browserTest.pass() is called. | 24 * browserTest.fail("My error message.") or browserTest.pass() is called. |
| 25 * | 25 * |
| 26 * For example: | 26 * For example: |
| 27 * | 27 * |
| 28 * browserTest.My_Test.prototype.run() = function() { | 28 * browserTest.My_Test.prototype.run(myObjectLiteral) = function() { |
| 29 * window.setTimeout(function() { | 29 * window.setTimeout(function() { |
| 30 * if (doSomething()) { | 30 * if (doSomething(myObjectLiteral)) { |
| 31 * browserTest.pass(); | 31 * browserTest.pass(); |
| 32 * } else { | 32 * } else { |
| 33 * browserTest.fail('My error message.'); | 33 * browserTest.fail('My error message.'); |
| 34 * } | 34 * } |
| 35 * }, 1000); | 35 * }, 1000); |
| 36 * }; | 36 * }; |
| 37 * | 37 * |
| 38 * You will then invoke the test in C++ by calling: | 38 * You will then invoke the test in C++ by calling: |
| 39 * | 39 * |
| 40 * RunJavaScriptTest(web_content, "My_Test", "{" | 40 * RunJavaScriptTest(web_content, "My_Test", "{" |
| 41 * "pin: 123123" | 41 * "pin: '123123'" |
| 42 * "}"); | 42 * "}"); |
| 43 */ | 43 */ |
| 44 | 44 |
| 45 'use strict'; | 45 'use strict'; |
| 46 | 46 |
| 47 var browserTest = {}; | 47 var browserTest = {}; |
| 48 | 48 |
| 49 browserTest.init = function() { | 49 browserTest.init = function() { |
| 50 // The domAutomationController is used to communicate progress back to the | 50 // The domAutomationController is used to communicate progress back to the |
| 51 // C++ calling code. It will only exist if chrome is run with the flag | 51 // C++ calling code. It will only exist if chrome is run with the flag |
| 52 // --dom-automation. It is stubbed out here so that browser test can be run | 52 // --dom-automation. It is stubbed out here so that browser test can be run |
| 53 // under the regular app. | 53 // under the regular app. |
| 54 browserTest.automationController_ = window.domAutomationController || { | 54 browserTest.automationController_ = window.domAutomationController || { |
| 55 send: function(json) { | 55 send: function(json) { |
| 56 var result = JSON.parse(json); | 56 var result = JSON.parse(json); |
| 57 if (result.succeeded) { | 57 if (result.succeeded) { |
| 58 console.log('Test Passed.'); | 58 console.log('Test Passed.'); |
| 59 } else { | 59 } else { |
| 60 console.error(result.error_message); | 60 console.error('Test Failed.\n' + |
| 61 result.error_message + '\n' + result.stack_trace); |
| 61 } | 62 } |
| 62 } | 63 } |
| 63 }; | 64 }; |
| 64 }; | 65 }; |
| 65 | 66 |
| 66 browserTest.assert = function(expr, message) { | 67 browserTest.expect = function(expr, message) { |
| 67 if (!expr) { | 68 if (!expr) { |
| 68 message = (message) ? '<' + message + '>' : ''; | 69 message = (message) ? '<' + message + '>' : ''; |
| 69 browserTest.fail('Assertion failed.' + message); | 70 browserTest.fail('Expectation failed.' + message); |
| 70 } | 71 } |
| 71 }; | 72 }; |
| 72 | 73 |
| 73 browserTest.fail = function(error_message, opt_stack_trace) { | 74 browserTest.fail = function(error) { |
| 74 var stack_trace = opt_stack_trace || base.debug.callstack(); | 75 var error_message = error; |
| 76 var stack_trace = base.debug.callstack(); |
| 77 |
| 78 if (error instanceof Error) { |
| 79 error_message = error.toString(); |
| 80 stack_trace = error.stack; |
| 81 } |
| 75 | 82 |
| 76 // To run browserTest locally: | 83 // To run browserTest locally: |
| 77 // 1. Go to |remoting_webapp_files| and look for | 84 // 1. Go to |remoting_webapp_files| and look for |
| 78 // |remoting_webapp_js_browser_test_files| and uncomment it | 85 // |remoting_webapp_js_browser_test_files| and uncomment it |
| 79 // 2. gclient runhooks | 86 // 2. gclient runhooks |
| 80 // 3. rebuild the webapp | 87 // 3. rebuild the webapp |
| 81 // 4. Run it in the console browserTest.runTest(browserTest.MyTest, {}); | 88 // 4. Run it in the console browserTest.runTest(browserTest.MyTest, {}); |
| 82 // 5. The line below will trap the test in the debugger in case of | 89 // 5. The line below will trap the test in the debugger in case of |
| 83 // failure. | 90 // failure. |
| 84 debugger; | 91 debugger; |
| 85 | 92 |
| 86 browserTest.automationController_.send(JSON.stringify({ | 93 browserTest.automationController_.send(JSON.stringify({ |
| 87 succeeded: false, | 94 succeeded: false, |
| 88 error_message: error_message, | 95 error_message: error_message, |
| 89 stack_trace: stack_trace | 96 stack_trace: stack_trace |
| 90 })); | 97 })); |
| 91 }; | 98 }; |
| 92 | 99 |
| 93 browserTest.pass = function() { | 100 browserTest.pass = function() { |
| 94 browserTest.automationController_.send(JSON.stringify({ | 101 browserTest.automationController_.send(JSON.stringify({ |
| 95 succeeded: true, | 102 succeeded: true, |
| 96 error_message: '', | 103 error_message: '', |
| 97 stack_trace: '' | 104 stack_trace: '' |
| 98 })); | 105 })); |
| 99 }; | 106 }; |
| 100 | 107 |
| 101 browserTest.clickOnControl = function(id) { | 108 browserTest.clickOnControl = function(id) { |
| 102 var element = document.getElementById(id); | 109 var element = document.getElementById(id); |
| 103 browserTest.assert(element); | 110 browserTest.expect(element); |
| 104 element.click(); | 111 element.click(); |
| 105 }; | 112 }; |
| 106 | 113 |
| 107 /** @enum {number} */ | 114 /** @enum {number} */ |
| 108 browserTest.Timeout = { | 115 browserTest.Timeout = { |
| 109 NONE: -1, | 116 NONE: -1, |
| 110 DEFAULT: 5000 | 117 DEFAULT: 5000 |
| 111 }; | 118 }; |
| 112 | 119 |
| 113 browserTest.waitForUIMode = function(expectedMode, callback, opt_timeout) { | 120 browserTest.onUIMode = function(expectedMode, opt_timeout) { |
| 114 var uiModeChanged = remoting.testEvents.Names.uiModeChanged; | 121 if (expectedMode == remoting.currentMode) { |
| 115 var timerId = null; | 122 // If the current mode is the same as the expected mode, return a fulfilled |
| 116 | 123 // promise. For some reason, if we fulfill the promise in the same |
| 117 if (opt_timeout === undefined) { | 124 // callstack, V8 will assert at V8RecursionScope.h(66) with |
| 118 opt_timeout = browserTest.Timeout.DEFAULT; | 125 // ASSERT(!ScriptForbiddenScope::isScriptForbidden()). |
| 126 // To avoid the assert, execute the callback in a different callstack. |
| 127 return base.Promise.sleep(0); |
| 119 } | 128 } |
| 120 | 129 |
| 121 function onTimeout() { | 130 return new Promise (function(fulfill, reject) { |
| 122 remoting.testEvents.removeEventListener(uiModeChanged, onUIModeChanged); | 131 var uiModeChanged = remoting.testEvents.Names.uiModeChanged; |
| 123 browserTest.fail('Timeout waiting for ' + expectedMode); | 132 var timerId = null; |
| 124 } | |
| 125 | 133 |
| 126 function onUIModeChanged (mode) { | 134 if (opt_timeout === undefined) { |
| 127 if (mode == expectedMode) { | 135 opt_timeout = browserTest.Timeout.DEFAULT; |
| 136 } |
| 137 |
| 138 function onTimeout() { |
| 128 remoting.testEvents.removeEventListener(uiModeChanged, onUIModeChanged); | 139 remoting.testEvents.removeEventListener(uiModeChanged, onUIModeChanged); |
| 129 window.clearTimeout(timerId); | 140 reject('Timeout waiting for ' + expectedMode); |
| 130 timerId = null; | 141 } |
| 131 try { | 142 |
| 132 callback(); | 143 function onUIModeChanged(mode) { |
| 133 } catch (e) { | 144 if (mode == expectedMode) { |
| 134 browserTest.fail(e.toString(), e.stack); | 145 remoting.testEvents.removeEventListener(uiModeChanged, onUIModeChanged); |
| 146 window.clearTimeout(timerId); |
| 147 timerId = null; |
| 148 fulfill(); |
| 135 } | 149 } |
| 136 } | 150 } |
| 137 } | |
| 138 | 151 |
| 139 if (opt_timeout != browserTest.Timeout.NONE) { | 152 if (opt_timeout != browserTest.Timeout.NONE) { |
| 140 timerId = window.setTimeout(onTimeout.bind(window, timerId), opt_timeout); | 153 timerId = window.setTimeout(onTimeout, opt_timeout); |
| 141 } | 154 } |
| 142 remoting.testEvents.addEventListener(uiModeChanged, onUIModeChanged); | 155 remoting.testEvents.addEventListener(uiModeChanged, onUIModeChanged); |
| 156 }); |
| 157 }; |
| 158 |
| 159 browserTest.expectMe2MeError = function(errorTag) { |
| 160 var AppMode = remoting.AppMode; |
| 161 var Timeout = browserTest.Timeout; |
| 162 |
| 163 var onConnected = browserTest.onUIMode(AppMode.IN_SESSION, Timeout.None); |
| 164 var onFailure = browserTest.onUIMode(AppMode.CLIENT_CONNECT_FAILED_ME2ME); |
| 165 |
| 166 onConnected = onConnected.then(function() { |
| 167 return Promise.reject( |
| 168 'Expected the Me2Me connection to fail.'); |
| 169 }); |
| 170 |
| 171 onFailure = onFailure.then(function() { |
| 172 var errorDiv = document.getElementById('connect-error-message'); |
| 173 var actual = errorDiv.innerText; |
| 174 var expected = l10n.getTranslationOrError(errorTag); |
| 175 |
| 176 browserTest.clickOnControl('client-finished-me2me-button'); |
| 177 |
| 178 if (actual != expected) { |
| 179 return Promise.reject('Unexpected failure. actual:' + actual + |
| 180 ' expected:' + expected); |
| 181 } |
| 182 }); |
| 183 |
| 184 return Promise.race([onConnected, onFailure]); |
| 185 }; |
| 186 |
| 187 browserTest.expectMe2MeConnected = function() { |
| 188 var AppMode = remoting.AppMode; |
| 189 // Timeout if the session is not connected within 30 seconds. |
| 190 var SESSION_CONNECTION_TIMEOUT = 30000; |
| 191 var onConnected = browserTest.onUIMode(AppMode.IN_SESSION, |
| 192 SESSION_CONNECTION_TIMEOUT); |
| 193 var onFailure = browserTest.onUIMode(AppMode.CLIENT_CONNECT_FAILED_ME2ME, |
| 194 browserTest.Timeout.NONE); |
| 195 onFailure = onFailure.then(function() { |
| 196 var errorDiv = document.getElementById('connect-error-message'); |
| 197 var errorMsg = errorDiv.innerText; |
| 198 return Promise.reject('Unexpected error - ' + errorMsg); |
| 199 }); |
| 200 return Promise.race([onConnected, onFailure]); |
| 143 }; | 201 }; |
| 144 | 202 |
| 145 browserTest.runTest = function(testClass, data) { | 203 browserTest.runTest = function(testClass, data) { |
| 146 try { | 204 try { |
| 147 var test = new testClass(data); | 205 var test = new testClass(); |
| 148 browserTest.assert(typeof test.run == 'function'); | 206 browserTest.expect(typeof test.run == 'function'); |
| 149 test.run(); | 207 test.run(data); |
| 150 } catch (e) { | 208 } catch (e) { |
| 151 browserTest.fail(e.toString(), e.stack); | 209 browserTest.fail(e); |
| 152 } | 210 } |
| 153 }; | 211 }; |
| 154 | 212 |
| 155 browserTest.init(); | 213 browserTest.init(); |
| OLD | NEW |