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
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 chrome
= requireNative('chrome').GetChrome();
11 var GetExtensionAPIDefinitionsForTest
=
12 requireNative('apiDefinitions').GetExtensionAPIDefinitionsForTest
;
13 var GetAvailability
= requireNative('v8_context').GetAvailability
;
14 var GetAPIFeatures
= requireNative('test_features').GetAPIFeatures
;
15 var userGestures
= requireNative('user_gestures');
17 binding
.registerCustomHook(function(api
) {
18 var chromeTest
= api
.compiledApi
;
19 var apiFunctions
= api
.apiFunctions
;
21 chromeTest
.tests
= chromeTest
.tests
|| [];
23 var currentTest
= null;
27 var failureException
= 'chrome.test.failure';
29 // Helper function to get around the fact that function names in javascript
30 // are read-only, and you can't assign one to anonymous functions.
31 function testName(test
) {
32 return test
? (test
.name
|| test
.generatedName
) : "(no test)";
36 // Use setTimeout here to allow previous test contexts to be
37 // eligible for garbage collection.
38 setTimeout(chromeTest
.runNextTest
, 0);
41 function allTestsDone() {
42 if (testsFailed
== 0) {
43 chromeTest
.notifyPass();
45 chromeTest
.notifyFail('Failed ' + testsFailed
+ ' of ' +
46 testCount
+ ' tests');
49 // Try to get the script to stop running immediately.
50 // This isn't an error, just an attempt at saying "done".
54 var pendingCallbacks
= 0;
56 apiFunctions
.setHandleRequest('callbackAdded', function() {
62 var redundantPrefix
= 'Error\n';
64 'Callback has already been run. ' +
66 $String
.slice(called
, redundantPrefix
.length
) + '\n' +
68 $String
.slice(new Error().stack
, redundantPrefix
.length
));
70 called
= new Error().stack
;
73 if (pendingCallbacks
== 0) {
79 apiFunctions
.setHandleRequest('runNextTest', function() {
80 // There may have been callbacks which were interrupted by failure
84 lastTest
= currentTest
;
85 currentTest
= chromeTest
.tests
.shift();
93 chromeTest
.log("( RUN ) " + testName(currentTest
));
96 if (e
!== failureException
)
97 chromeTest
.fail('uncaught exception: ' + e
);
101 apiFunctions
.setHandleRequest('fail', function(message
) {
102 chromeTest
.log("( FAILED ) " + testName(currentTest
));
105 Error
.captureStackTrace(stack
, chromeTest
.fail
);
108 message
= "FAIL (no message)";
110 message
+= "\n" + stack
.stack
;
111 console
.log("[FAIL] " + testName(currentTest
) + ": " + message
);
115 // Interrupt the rest of the test.
116 throw failureException
;
119 apiFunctions
.setHandleRequest('succeed', function() {
120 console
.log("[SUCCESS] " + testName(currentTest
));
121 chromeTest
.log("( SUCCESS )");
125 apiFunctions
.setHandleRequest('assertTrue', function(test
, message
) {
126 chromeTest
.assertBool(test
, true, message
);
129 apiFunctions
.setHandleRequest('assertFalse', function(test
, message
) {
130 chromeTest
.assertBool(test
, false, message
);
133 apiFunctions
.setHandleRequest('assertBool',
134 function(test
, expected
, message
) {
135 if (test
!== expected
) {
136 if (typeof(test
) == "string") {
138 message
= test
+ "\n" + message
;
142 chromeTest
.fail(message
);
146 apiFunctions
.setHandleRequest('checkDeepEq', function(expected
, actual
) {
147 if ((expected
=== null) != (actual
=== null))
150 if (expected
=== actual
)
153 if (typeof(expected
) !== typeof(actual
))
156 for (var p
in actual
) {
157 if ($Object
.hasOwnProperty(actual
, p
) &&
158 !$Object
.hasOwnProperty(expected
, p
)) {
162 for (var p
in expected
) {
163 if ($Object
.hasOwnProperty(expected
, p
) &&
164 !$Object
.hasOwnProperty(actual
, p
)) {
169 for (var p
in expected
) {
171 switch (typeof(expected
[p
])) {
173 eq
= chromeTest
.checkDeepEq(expected
[p
], actual
[p
]);
176 eq
= (typeof(actual
[p
]) != 'undefined' &&
177 expected
[p
].toString() == actual
[p
].toString());
180 eq
= (expected
[p
] == actual
[p
] &&
181 typeof(expected
[p
]) == typeof(actual
[p
]));
190 apiFunctions
.setHandleRequest('assertEq',
191 function(expected
, actual
, message
) {
192 var error_msg
= "API Test Error in " + testName(currentTest
);
194 error_msg
+= ": " + message
;
195 if (typeof(expected
) == 'object') {
196 if (!chromeTest
.checkDeepEq(expected
, actual
)) {
197 // Note: these JSON.stringify calls may fail in tests that explicitly
198 // override JSON.stringfy, so surround in try-catch.
200 error_msg
+= "\nActual: " + JSON
.stringify(actual
) +
201 "\nExpected: " + JSON
.stringify(expected
);
203 chromeTest
.fail(error_msg
);
207 if (expected
!= actual
) {
208 chromeTest
.fail(error_msg
+
209 "\nActual: " + actual
+ "\nExpected: " + expected
);
211 if (typeof(expected
) != typeof(actual
)) {
212 chromeTest
.fail(error_msg
+
213 " (type mismatch)\nActual Type: " + typeof(actual
) +
214 "\nExpected Type:" + typeof(expected
));
218 apiFunctions
.setHandleRequest('assertNoLastError', function() {
219 if (chrome
.runtime
.lastError
!= undefined) {
220 chromeTest
.fail("lastError.message == " +
221 chrome
.runtime
.lastError
.message
);
225 apiFunctions
.setHandleRequest('assertLastError', function(expectedError
) {
226 chromeTest
.assertEq(typeof(expectedError
), 'string');
227 chromeTest
.assertTrue(chrome
.runtime
.lastError
!= undefined,
228 "No lastError, but expected " + expectedError
);
229 chromeTest
.assertEq(expectedError
, chrome
.runtime
.lastError
.message
);
232 apiFunctions
.setHandleRequest('assertThrows',
233 function(fn
, self
, args
, message
) {
234 chromeTest
.assertTrue(typeof fn
== 'function');
236 fn
.apply(self
, args
);
237 chromeTest
.fail('Did not throw error: ' + fn
);
239 if (e
!= failureException
&& message
!== undefined) {
240 if (message
instanceof RegExp
) {
241 chromeTest
.assertTrue(message
.test(e
.message
),
242 e
.message
+ ' should match ' + message
)
244 chromeTest
.assertEq(message
, e
.message
);
250 function safeFunctionApply(func
, args
) {
253 $Function
.apply(func
, null, args
);
255 var msg
= "uncaught exception " + e
;
256 chromeTest
.fail(msg
);
260 // Wrapper for generating test functions, that takes care of calling
261 // assertNoLastError() and (optionally) succeed() for you.
262 apiFunctions
.setHandleRequest('callback', function(func
, expectedError
) {
264 chromeTest
.assertEq(typeof(func
), 'function');
266 var callbackCompleted
= chromeTest
.callbackAdded();
269 if (expectedError
== null) {
270 chromeTest
.assertNoLastError();
272 chromeTest
.assertLastError(expectedError
);
276 safeFunctionApply(func
, arguments
);
283 apiFunctions
.setHandleRequest('listenOnce', function(event
, func
) {
284 var callbackCompleted
= chromeTest
.callbackAdded();
285 var listener = function() {
286 event
.removeListener(listener
);
287 safeFunctionApply(func
, arguments
);
290 event
.addListener(listener
);
293 apiFunctions
.setHandleRequest('listenForever', function(event
, func
) {
294 var callbackCompleted
= chromeTest
.callbackAdded();
296 var listener = function() {
297 safeFunctionApply(func
, arguments
);
300 var done = function() {
301 event
.removeListener(listener
);
305 event
.addListener(listener
);
309 apiFunctions
.setHandleRequest('callbackPass', function(func
) {
310 return chromeTest
.callback(func
);
313 apiFunctions
.setHandleRequest('callbackFail', function(expectedError
, func
) {
314 return chromeTest
.callback(func
, expectedError
);
317 apiFunctions
.setHandleRequest('runTests', function(tests
) {
318 chromeTest
.tests
= tests
;
319 testCount
= chromeTest
.tests
.length
;
320 chromeTest
.runNextTest();
323 apiFunctions
.setHandleRequest('getApiDefinitions', function() {
324 return GetExtensionAPIDefinitionsForTest();
327 apiFunctions
.setHandleRequest('getApiFeatures', function() {
328 return GetAPIFeatures();
331 apiFunctions
.setHandleRequest('isProcessingUserGesture', function() {
332 return userGestures
.IsProcessingUserGesture();
335 apiFunctions
.setHandleRequest('runWithUserGesture', function(callback
) {
336 chromeTest
.assertEq(typeof(callback
), 'function');
337 return userGestures
.RunWithUserGesture(callback
);
340 apiFunctions
.setHandleRequest('runWithoutUserGesture', function(callback
) {
341 chromeTest
.assertEq(typeof(callback
), 'function');
342 return userGestures
.RunWithoutUserGesture(callback
);
346 exports
.binding
= binding
.generate();