OLD | NEW |
1 // Copyright (c) 2012 The Chromium Authors. All rights reserved. | 1 // Copyright (c) 2012 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 // extension_apitest.js | 5 // extension_apitest.js |
6 // mini-framework for ExtensionApiTest browser tests | 6 // mini-framework for ExtensionApiTest browser tests |
7 | 7 |
8 chrome.test = chrome.test || {}; | 8 var bindings = new (require('schema_binding_generator').Bindings)('test'); |
9 | 9 |
10 chrome.test.tests = chrome.test.tests || []; | 10 var chrome = requireNative('chrome').GetChrome(); |
| 11 |
| 12 bindings.registerCustomHook(function(api) { |
| 13 chrome_test = api.compiledApi; |
| 14 |
| 15 chrome_test.tests = chrome_test.tests || []; |
11 | 16 |
12 var currentTest = null; | 17 var currentTest = null; |
13 var lastTest = null; | 18 var lastTest = null; |
14 var testsFailed = 0; | 19 var testsFailed = 0; |
15 var testCount = 1; | 20 var testCount = 1; |
16 var failureException = 'chrome.test.failure'; | 21 var failureException = 'chrome.test.failure'; |
17 | 22 |
18 // Helper function to get around the fact that function names in javascript | 23 // Helper function to get around the fact that function names in javascript |
19 // are read-only, and you can't assign one to anonymous functions. | 24 // are read-only, and you can't assign one to anonymous functions. |
20 function testName(test) { | 25 function testName(test) { |
21 return test ? (test.name || test.generatedName) : "(no test)"; | 26 return test ? (test.name || test.generatedName) : "(no test)"; |
22 } | 27 } |
23 | 28 |
24 function testDone() { | 29 function testDone() { |
25 // Use setTimeout here to allow previous test contexts to be | 30 // Use setTimeout here to allow previous test contexts to be |
26 // eligible for garbage collection. | 31 // eligible for garbage collection. |
27 setTimeout(chrome.test.runNextTest, 0); | 32 setTimeout(chrome_test.runNextTest, 0); |
28 } | 33 } |
29 | 34 |
30 function allTestsDone() { | 35 function allTestsDone() { |
31 if (testsFailed == 0) { | 36 if (testsFailed == 0) { |
32 chrome.test.notifyPass(); | 37 chrome_test.notifyPass(); |
33 } else { | 38 } else { |
34 chrome.test.notifyFail('Failed ' + testsFailed + ' of ' + | 39 chrome_test.notifyFail('Failed ' + testsFailed + ' of ' + |
35 testCount + ' tests'); | 40 testCount + ' tests'); |
36 } | 41 } |
37 | 42 |
38 // Try to get the script to stop running immediately. | 43 // Try to get the script to stop running immediately. |
39 // This isn't an error, just an attempt at saying "done". | 44 // This isn't an error, just an attempt at saying "done". |
40 throw "completed"; | 45 throw "completed"; |
41 } | 46 } |
42 | 47 |
43 var pendingCallbacks = 0; | 48 var pendingCallbacks = 0; |
44 | 49 |
45 chrome.test.callbackAdded = function() { | 50 chrome_test.callbackAdded = function() { |
46 pendingCallbacks++; | 51 pendingCallbacks++; |
47 | 52 |
48 return function() { | 53 return function() { |
49 pendingCallbacks--; | 54 pendingCallbacks--; |
50 if (pendingCallbacks == 0) { | 55 if (pendingCallbacks == 0) { |
51 chrome.test.succeed(); | 56 chrome_test.succeed(); |
52 } | 57 } |
53 }; | 58 }; |
54 }; | 59 }; |
55 | 60 |
56 chrome.test.runNextTest = function() { | 61 chrome_test.runNextTest = function() { |
57 // There may have been callbacks which were interrupted by failure | 62 // There may have been callbacks which were interrupted by failure |
58 // exceptions. | 63 // exceptions. |
59 pendingCallbacks = 0; | 64 pendingCallbacks = 0; |
60 | 65 |
61 lastTest = currentTest; | 66 lastTest = currentTest; |
62 currentTest = chrome.test.tests.shift(); | 67 currentTest = chrome_test.tests.shift(); |
63 | 68 |
64 if (!currentTest) { | 69 if (!currentTest) { |
65 allTestsDone(); | 70 allTestsDone(); |
66 return; | 71 return; |
67 } | 72 } |
68 | 73 |
69 try { | 74 try { |
70 chrome.test.log("( RUN ) " + testName(currentTest)); | 75 chrome_test.log("( RUN ) " + testName(currentTest)); |
71 currentTest.call(); | 76 currentTest.call(); |
72 } catch (e) { | 77 } catch (e) { |
73 if (e !== failureException) | 78 if (e !== failureException) |
74 chrome.test.fail('uncaught exception: ' + e); | 79 chrome_test.fail('uncaught exception: ' + e); |
75 } | 80 } |
76 }; | 81 }; |
77 | 82 |
78 chrome.test.fail = function(message) { | 83 chrome_test.fail = function(message) { |
79 chrome.test.log("( FAILED ) " + testName(currentTest)); | 84 chrome_test.log("( FAILED ) " + testName(currentTest)); |
80 | 85 |
81 var stack = {}; | 86 var stack = {}; |
82 Error.captureStackTrace(stack, chrome.test.fail); | 87 Error.captureStackTrace(stack, chrome_test.fail); |
83 | 88 |
84 if (!message) | 89 if (!message) |
85 message = "FAIL (no message)"; | 90 message = "FAIL (no message)"; |
86 | 91 |
87 message += "\n" + stack.stack; | 92 message += "\n" + stack.stack; |
88 console.log("[FAIL] " + testName(currentTest) + ": " + message); | 93 console.log("[FAIL] " + testName(currentTest) + ": " + message); |
89 testsFailed++; | 94 testsFailed++; |
90 testDone(); | 95 testDone(); |
91 | 96 |
92 // Interrupt the rest of the test. | 97 // Interrupt the rest of the test. |
93 throw failureException; | 98 throw failureException; |
94 }; | 99 }; |
95 | 100 |
96 chrome.test.succeed = function() { | 101 chrome_test.succeed = function() { |
97 console.log("[SUCCESS] " + testName(currentTest)); | 102 console.log("[SUCCESS] " + testName(currentTest)); |
98 chrome.test.log("( SUCCESS )"); | 103 chrome_test.log("( SUCCESS )"); |
99 testDone(); | 104 testDone(); |
100 }; | 105 }; |
101 | 106 |
102 chrome.test.assertTrue = function(test, message) { | 107 chrome_test.assertTrue = function(test, message) { |
103 chrome.test.assertBool(test, true, message); | 108 chrome_test.assertBool(test, true, message); |
104 }; | 109 }; |
105 | 110 |
106 chrome.test.assertFalse = function(test, message) { | 111 chrome_test.assertFalse = function(test, message) { |
107 chrome.test.assertBool(test, false, message); | 112 chrome_test.assertBool(test, false, message); |
108 }; | 113 }; |
109 | 114 |
110 chrome.test.assertBool = function(test, expected, message) { | 115 chrome_test.assertBool = function(test, expected, message) { |
111 if (test !== expected) { | 116 if (test !== expected) { |
112 if (typeof(test) == "string") { | 117 if (typeof(test) == "string") { |
113 if (message) | 118 if (message) |
114 message = test + "\n" + message; | 119 message = test + "\n" + message; |
115 else | 120 else |
116 message = test; | 121 message = test; |
117 } | 122 } |
118 chrome.test.fail(message); | 123 chrome_test.fail(message); |
119 } | 124 } |
120 }; | 125 }; |
121 | 126 |
122 chrome.test.checkDeepEq = function (expected, actual) { | 127 chrome_test.checkDeepEq = function (expected, actual) { |
123 if ((expected === null) != (actual === null)) | 128 if ((expected === null) != (actual === null)) |
124 return false; | 129 return false; |
125 | 130 |
126 if (expected === actual) | 131 if (expected === actual) |
127 return true; | 132 return true; |
128 | 133 |
129 if (typeof(expected) !== typeof(actual)) | 134 if (typeof(expected) !== typeof(actual)) |
130 return false; | 135 return false; |
131 | 136 |
132 for (var p in actual) { | 137 for (var p in actual) { |
133 if (actual.hasOwnProperty(p) && !expected.hasOwnProperty(p)) | 138 if (actual.hasOwnProperty(p) && !expected.hasOwnProperty(p)) |
134 return false; | 139 return false; |
135 } | 140 } |
136 for (var p in expected) { | 141 for (var p in expected) { |
137 if (expected.hasOwnProperty(p) && !actual.hasOwnProperty(p)) | 142 if (expected.hasOwnProperty(p) && !actual.hasOwnProperty(p)) |
138 return false; | 143 return false; |
139 } | 144 } |
140 | 145 |
141 for (var p in expected) { | 146 for (var p in expected) { |
142 var eq = true; | 147 var eq = true; |
143 switch (typeof(expected[p])) { | 148 switch (typeof(expected[p])) { |
144 case 'object': | 149 case 'object': |
145 eq = chrome.test.checkDeepEq(expected[p], actual[p]); | 150 eq = chrome_test.checkDeepEq(expected[p], actual[p]); |
146 break; | 151 break; |
147 case 'function': | 152 case 'function': |
148 eq = (typeof(actual[p]) != 'undefined' && | 153 eq = (typeof(actual[p]) != 'undefined' && |
149 expected[p].toString() == actual[p].toString()); | 154 expected[p].toString() == actual[p].toString()); |
150 break; | 155 break; |
151 default: | 156 default: |
152 eq = (expected[p] == actual[p] && | 157 eq = (expected[p] == actual[p] && |
153 typeof(expected[p]) == typeof(actual[p])); | 158 typeof(expected[p]) == typeof(actual[p])); |
154 break; | 159 break; |
155 } | 160 } |
156 if (!eq) | 161 if (!eq) |
157 return false; | 162 return false; |
158 } | 163 } |
159 return true; | 164 return true; |
160 }; | 165 }; |
161 | 166 |
162 chrome.test.assertEq = function(expected, actual, message) { | 167 chrome_test.assertEq = function(expected, actual, message) { |
163 var error_msg = "API Test Error in " + testName(currentTest); | 168 var error_msg = "API Test Error in " + testName(currentTest); |
164 if (message) | 169 if (message) |
165 error_msg += ": " + message; | 170 error_msg += ": " + message; |
166 if (typeof(expected) == 'object') { | 171 if (typeof(expected) == 'object') { |
167 if (!chrome.test.checkDeepEq(expected, actual)) { | 172 if (!chrome_test.checkDeepEq(expected, actual)) { |
168 chrome.test.fail(error_msg + | 173 chrome_test.fail(error_msg + |
169 "\nActual: " + JSON.stringify(actual) + | 174 "\nActual: " + JSON.stringify(actual) + |
170 "\nExpected: " + JSON.stringify(expected)); | 175 "\nExpected: " + JSON.stringify(expected)); |
171 } | 176 } |
172 return; | 177 return; |
173 } | 178 } |
174 if (expected != actual) { | 179 if (expected != actual) { |
175 chrome.test.fail(error_msg + | 180 chrome_test.fail(error_msg + |
176 "\nActual: " + actual + "\nExpected: " + expected); | 181 "\nActual: " + actual + "\nExpected: " + expected); |
177 } | 182 } |
178 if (typeof(expected) != typeof(actual)) { | 183 if (typeof(expected) != typeof(actual)) { |
179 chrome.test.fail(error_msg + | 184 chrome_test.fail(error_msg + |
180 " (type mismatch)\nActual Type: " + typeof(actual) + | 185 " (type mismatch)\nActual Type: " + typeof(actual) + |
181 "\nExpected Type:" + typeof(expected)); | 186 "\nExpected Type:" + typeof(expected)); |
182 } | 187 } |
183 }; | 188 }; |
184 | 189 |
185 chrome.test.assertNoLastError = function() { | 190 chrome_test.assertNoLastError = function() { |
186 if (chrome.runtime.lastError != undefined) { | 191 if (chrome.runtime.lastError != undefined) { |
187 chrome.test.fail("lastError.message == " + | 192 chrome_test.fail("lastError.message == " + |
188 chrome.runtime.lastError.message); | 193 chrome.runtime.lastError.message); |
189 } | 194 } |
190 }; | 195 }; |
191 | 196 |
192 chrome.test.assertLastError = function(expectedError) { | 197 chrome_test.assertLastError = function(expectedError) { |
193 chrome.test.assertEq(typeof(expectedError), 'string'); | 198 chrome_test.assertEq(typeof(expectedError), 'string'); |
194 chrome.test.assertTrue(chrome.runtime.lastError != undefined, | 199 chrome_test.assertTrue(chrome.runtime.lastError != undefined, |
195 "No lastError, but expected " + expectedError); | 200 "No lastError, but expected " + expectedError); |
196 chrome.test.assertEq(expectedError, chrome.runtime.lastError.message); | 201 chrome_test.assertEq(expectedError, chrome.runtime.lastError.message); |
197 } | 202 } |
198 | 203 |
199 function safeFunctionApply(func, arguments) { | 204 function safeFunctionApply(func, arguments) { |
200 try { | 205 try { |
201 if (func) | 206 if (func) |
202 func.apply(null, arguments); | 207 func.apply(null, arguments); |
203 } catch (e) { | 208 } catch (e) { |
204 var msg = "uncaught exception " + e; | 209 var msg = "uncaught exception " + e; |
205 chrome.test.fail(msg); | 210 chrome_test.fail(msg); |
206 } | 211 } |
207 }; | 212 }; |
208 | 213 |
209 // Wrapper for generating test functions, that takes care of calling | 214 // Wrapper for generating test functions, that takes care of calling |
210 // assertNoLastError() and (optionally) succeed() for you. | 215 // assertNoLastError() and (optionally) succeed() for you. |
211 chrome.test.callback = function(func, expectedError) { | 216 chrome_test.callback = function(func, expectedError) { |
212 if (func) { | 217 if (func) { |
213 chrome.test.assertEq(typeof(func), 'function'); | 218 chrome_test.assertEq(typeof(func), 'function'); |
214 } | 219 } |
215 var callbackCompleted = chrome.test.callbackAdded(); | 220 var callbackCompleted = chrome_test.callbackAdded(); |
216 | 221 |
217 return function() { | 222 return function() { |
218 if (expectedError == null) { | 223 if (expectedError == null) { |
219 chrome.test.assertNoLastError(); | 224 chrome_test.assertNoLastError(); |
220 } else { | 225 } else { |
221 chrome.test.assertLastError(expectedError); | 226 chrome_test.assertLastError(expectedError); |
222 } | 227 } |
223 | 228 |
224 if (func) { | 229 if (func) { |
225 safeFunctionApply(func, arguments); | 230 safeFunctionApply(func, arguments); |
226 } | 231 } |
227 | 232 |
228 callbackCompleted(); | 233 callbackCompleted(); |
229 }; | 234 }; |
230 }; | 235 }; |
231 | 236 |
232 chrome.test.listenOnce = function(event, func) { | 237 chrome_test.listenOnce = function(event, func) { |
233 var callbackCompleted = chrome.test.callbackAdded(); | 238 var callbackCompleted = chrome_test.callbackAdded(); |
234 var listener = function() { | 239 var listener = function() { |
235 event.removeListener(listener); | 240 event.removeListener(listener); |
236 safeFunctionApply(func, arguments); | 241 safeFunctionApply(func, arguments); |
237 callbackCompleted(); | 242 callbackCompleted(); |
238 }; | 243 }; |
239 event.addListener(listener); | 244 event.addListener(listener); |
240 }; | 245 }; |
241 | 246 |
242 chrome.test.listenForever = function(event, func) { | 247 chrome_test.listenForever = function(event, func) { |
243 var callbackCompleted = chrome.test.callbackAdded(); | 248 var callbackCompleted = chrome_test.callbackAdded(); |
244 | 249 |
245 var listener = function() { | 250 var listener = function() { |
246 safeFunctionApply(func, arguments); | 251 safeFunctionApply(func, arguments); |
247 }; | 252 }; |
248 | 253 |
249 var done = function() { | 254 var done = function() { |
250 event.removeListener(listener); | 255 event.removeListener(listener); |
251 callbackCompleted(); | 256 callbackCompleted(); |
252 }; | 257 }; |
253 | 258 |
254 event.addListener(listener); | 259 event.addListener(listener); |
255 return done; | 260 return done; |
256 }; | 261 }; |
257 | 262 |
258 chrome.test.callbackPass = function(func) { | 263 chrome_test.callbackPass = function(func) { |
259 return chrome.test.callback(func); | 264 return chrome_test.callback(func); |
260 }; | 265 }; |
261 | 266 |
262 chrome.test.callbackFail = function(expectedError, func) { | 267 chrome_test.callbackFail = function(expectedError, func) { |
263 return chrome.test.callback(func, expectedError); | 268 return chrome_test.callback(func, expectedError); |
264 }; | 269 }; |
265 | 270 |
266 chrome.test.runTests = function(tests) { | 271 chrome_test.runTests = function(tests) { |
267 chrome.test.tests = tests; | 272 chrome_test.tests = tests; |
268 testCount = chrome.test.tests.length; | 273 testCount = chrome_test.tests.length; |
269 chrome.test.runNextTest(); | 274 chrome_test.runNextTest(); |
270 }; | 275 }; |
| 276 }); |
| 277 |
| 278 exports.bindings = bindings.generate(); |
OLD | NEW |