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 |