| 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 |