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
3 // found in the LICENSE file.
5 // test_custom_bindings.js
6 // mini-framework for ExtensionApiTest browser tests
8 var binding = require('binding').Binding.create('test');
10 var environmentSpecificBindings = require('test_environment_specific_bindings');
11 var GetExtensionAPIDefinitionsForTest =
12 requireNative('apiDefinitions').GetExtensionAPIDefinitionsForTest;
13 var GetAPIFeatures = requireNative('test_features').GetAPIFeatures;
14 var natives = requireNative('test_native_handler');
15 var uncaughtExceptionHandler = require('uncaught_exception_handler');
16 var userGestures = requireNative('user_gestures');
18 var RunWithNativesEnabled = requireNative('v8_context').RunWithNativesEnabled;
19 var GetModuleSystem = requireNative('v8_context').GetModuleSystem;
21 binding.registerCustomHook(function(api) {
22 var chromeTest = api.compiledApi;
23 var apiFunctions = api.apiFunctions;
25 chromeTest.tests = chromeTest.tests || [];
27 var currentTest = null;
31 var failureException = 'chrome.test.failure';
33 // Helper function to get around the fact that function names in javascript
34 // are read-only, and you can't assign one to anonymous functions.
35 function testName(test) {
36 return test ? (test.name || test.generatedName) : "(no test)";
40 environmentSpecificBindings.testDone(chromeTest.runNextTest);
43 function allTestsDone() {
44 if (testsFailed == 0) {
45 chromeTest.notifyPass();
47 chromeTest.notifyFail('Failed ' + testsFailed + ' of ' +
48 testCount + ' tests');
52 var pendingCallbacks = 0;
54 apiFunctions.setHandleRequest('callbackAdded', function() {
60 var redundantPrefix = 'Error\n';
62 'Callback has already been run. ' +
64 $String.slice(called, redundantPrefix.length) + '\n' +
66 $String.slice(new Error().stack, redundantPrefix.length));
68 called = new Error().stack;
71 if (pendingCallbacks == 0) {
77 apiFunctions.setHandleRequest('runNextTest', function() {
78 // There may have been callbacks which were interrupted by failure
82 lastTest = currentTest;
83 currentTest = chromeTest.tests.shift();
91 chromeTest.log("( RUN ) " + testName(currentTest));
92 uncaughtExceptionHandler.setHandler(function(message, e) {
93 if (e !== failureException)
94 chromeTest.fail('uncaught exception: ' + message);
98 uncaughtExceptionHandler.handle(e.message, e);
102 apiFunctions.setHandleRequest('fail', function(message) {
103 chromeTest.log("( FAILED ) " + testName(currentTest));
106 Error.captureStackTrace(stack, chromeTest.fail);
109 message = "FAIL (no message)";
111 message += "\n" + stack.stack;
112 console.log("[FAIL] " + testName(currentTest) + ": " + message);
116 // Interrupt the rest of the test.
117 throw failureException;
120 apiFunctions.setHandleRequest('succeed', function() {
121 console.log("[SUCCESS] " + testName(currentTest));
122 chromeTest.log("( SUCCESS )");
126 apiFunctions.setHandleRequest('runWithNativesEnabled', function(callback) {
127 RunWithNativesEnabled(callback);
130 apiFunctions.setHandleRequest('getModuleSystem', function(context) {
131 return GetModuleSystem(context);
134 apiFunctions.setHandleRequest('assertTrue', function(test, message) {
135 chromeTest.assertBool(test, true, message);
138 apiFunctions.setHandleRequest('assertFalse', function(test, message) {
139 chromeTest.assertBool(test, false, message);
142 apiFunctions.setHandleRequest('assertBool',
143 function(test, expected, message) {
144 if (test !== expected) {
145 if (typeof(test) == "string") {
147 message = test + "\n" + message;
151 chromeTest.fail(message);
155 apiFunctions.setHandleRequest('checkDeepEq', function(expected, actual) {
156 if ((expected === null) != (actual === null))
159 if (expected === actual)
162 if (typeof(expected) !== typeof(actual))
165 for (var p in actual) {
166 if ($Object.hasOwnProperty(actual, p) &&
167 !$Object.hasOwnProperty(expected, p)) {
171 for (var p in expected) {
172 if ($Object.hasOwnProperty(expected, p) &&
173 !$Object.hasOwnProperty(actual, p)) {
178 for (var p in expected) {
180 switch (typeof(expected[p])) {
182 eq = chromeTest.checkDeepEq(expected[p], actual[p]);
185 eq = (typeof(actual[p]) != 'undefined' &&
186 expected[p].toString() == actual[p].toString());
189 eq = (expected[p] == actual[p] &&
190 typeof(expected[p]) == typeof(actual[p]));
199 apiFunctions.setHandleRequest('assertEq',
200 function(expected, actual, message) {
201 var error_msg = "API Test Error in " + testName(currentTest);
203 error_msg += ": " + message;
204 if (typeof(expected) == 'object') {
205 if (!chromeTest.checkDeepEq(expected, actual)) {
206 error_msg += "\nActual: " + $JSON.stringify(actual) +
207 "\nExpected: " + $JSON.stringify(expected);
208 chromeTest.fail(error_msg);
212 if (expected != actual) {
213 chromeTest.fail(error_msg +
214 "\nActual: " + actual + "\nExpected: " + expected);
216 if (typeof(expected) != typeof(actual)) {
217 chromeTest.fail(error_msg +
218 " (type mismatch)\nActual Type: " + typeof(actual) +
219 "\nExpected Type:" + typeof(expected));
223 apiFunctions.setHandleRequest('assertNoLastError', function() {
224 if (chrome.runtime.lastError != undefined) {
225 chromeTest.fail("lastError.message == " +
226 chrome.runtime.lastError.message);
230 apiFunctions.setHandleRequest('assertLastError', function(expectedError) {
231 chromeTest.assertEq(typeof(expectedError), 'string');
232 chromeTest.assertTrue(chrome.runtime.lastError != undefined,
233 "No lastError, but expected " + expectedError);
234 chromeTest.assertEq(expectedError, chrome.runtime.lastError.message);
237 apiFunctions.setHandleRequest('assertThrows',
238 function(fn, self, args, message) {
239 chromeTest.assertTrue(typeof fn == 'function');
241 fn.apply(self, args);
242 chromeTest.fail('Did not throw error: ' + fn);
244 if (e != failureException && message !== undefined) {
245 if (message instanceof RegExp) {
246 chromeTest.assertTrue(message.test(e.message),
247 e.message + ' should match ' + message)
249 chromeTest.assertEq(message, e.message);
255 function safeFunctionApply(func, args) {
258 return $Function.apply(func, undefined, args);
260 var msg = "uncaught exception " + e;
261 chromeTest.fail(msg);
265 // Wrapper for generating test functions, that takes care of calling
266 // assertNoLastError() and (optionally) succeed() for you.
267 apiFunctions.setHandleRequest('callback', function(func, expectedError) {
269 chromeTest.assertEq(typeof(func), 'function');
271 var callbackCompleted = chromeTest.callbackAdded();
274 if (expectedError == null) {
275 chromeTest.assertNoLastError();
277 chromeTest.assertLastError(expectedError);
282 result = safeFunctionApply(func, arguments);
290 apiFunctions.setHandleRequest('listenOnce', function(event, func) {
291 var callbackCompleted = chromeTest.callbackAdded();
292 var listener = function() {
293 event.removeListener(listener);
294 safeFunctionApply(func, arguments);
297 event.addListener(listener);
300 apiFunctions.setHandleRequest('listenForever', function(event, func) {
301 var callbackCompleted = chromeTest.callbackAdded();
303 var listener = function() {
304 safeFunctionApply(func, arguments);
307 var done = function() {
308 event.removeListener(listener);
312 event.addListener(listener);
316 apiFunctions.setHandleRequest('callbackPass', function(func) {
317 return chromeTest.callback(func);
320 apiFunctions.setHandleRequest('callbackFail', function(expectedError, func) {
321 return chromeTest.callback(func, expectedError);
324 apiFunctions.setHandleRequest('runTests', function(tests) {
325 chromeTest.tests = tests;
326 testCount = chromeTest.tests.length;
327 chromeTest.runNextTest();
330 apiFunctions.setHandleRequest('getApiDefinitions', function() {
331 return GetExtensionAPIDefinitionsForTest();
334 apiFunctions.setHandleRequest('getApiFeatures', function() {
335 return GetAPIFeatures();
338 apiFunctions.setHandleRequest('isProcessingUserGesture', function() {
339 return userGestures.IsProcessingUserGesture();
342 apiFunctions.setHandleRequest('runWithUserGesture', function(callback) {
343 chromeTest.assertEq(typeof(callback), 'function');
344 return userGestures.RunWithUserGesture(callback);
347 apiFunctions.setHandleRequest('runWithoutUserGesture', function(callback) {
348 chromeTest.assertEq(typeof(callback), 'function');
349 return userGestures.RunWithoutUserGesture(callback);
352 apiFunctions.setHandleRequest('setExceptionHandler', function(callback) {
353 chromeTest.assertEq(typeof(callback), 'function');
354 uncaughtExceptionHandler.setHandler(callback);
357 apiFunctions.setHandleRequest('getWakeEventPage', function() {
358 return natives.GetWakeEventPage();
361 environmentSpecificBindings.registerHooks(api);
364 exports.binding = binding.generate();