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();