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
;
16 binding
.registerCustomHook(function(api
) {
17 var chromeTest
= api
.compiledApi
;
18 var apiFunctions
= api
.apiFunctions
;
20 chromeTest
.tests
= chromeTest
.tests
|| [];
22 var currentTest
= null;
26 var failureException
= 'chrome.test.failure';
28 // Helper function to get around the fact that function names in javascript
29 // are read-only, and you can't assign one to anonymous functions.
30 function testName(test
) {
31 return test
? (test
.name
|| test
.generatedName
) : "(no test)";
35 // Use setTimeout here to allow previous test contexts to be
36 // eligible for garbage collection.
37 setTimeout(chromeTest
.runNextTest
, 0);
40 function allTestsDone() {
41 if (testsFailed
== 0) {
42 chromeTest
.notifyPass();
44 chromeTest
.notifyFail('Failed ' + testsFailed
+ ' of ' +
45 testCount
+ ' tests');
48 // Try to get the script to stop running immediately.
49 // This isn't an error, just an attempt at saying "done".
53 var pendingCallbacks
= 0;
55 apiFunctions
.setHandleRequest('callbackAdded', function() {
61 var redundantPrefix
= 'Error\n';
63 'Callback has already been run. ' +
65 $String
.slice(called
, redundantPrefix
.length
) + '\n' +
67 $String
.slice(new Error().stack
, redundantPrefix
.length
));
69 called
= new Error().stack
;
72 if (pendingCallbacks
== 0) {
78 apiFunctions
.setHandleRequest('runNextTest', function() {
79 // There may have been callbacks which were interrupted by failure
83 lastTest
= currentTest
;
84 currentTest
= chromeTest
.tests
.shift();
92 chromeTest
.log("( RUN ) " + testName(currentTest
));
95 if (e
!== failureException
)
96 chromeTest
.fail('uncaught exception: ' + e
);
100 apiFunctions
.setHandleRequest('fail', function(message
) {
101 chromeTest
.log("( FAILED ) " + testName(currentTest
));
104 Error
.captureStackTrace(stack
, chromeTest
.fail
);
107 message
= "FAIL (no message)";
109 message
+= "\n" + stack
.stack
;
110 console
.log("[FAIL] " + testName(currentTest
) + ": " + message
);
114 // Interrupt the rest of the test.
115 throw failureException
;
118 apiFunctions
.setHandleRequest('succeed', function() {
119 console
.log("[SUCCESS] " + testName(currentTest
));
120 chromeTest
.log("( SUCCESS )");
124 apiFunctions
.setHandleRequest('assertTrue', function(test
, message
) {
125 chromeTest
.assertBool(test
, true, message
);
128 apiFunctions
.setHandleRequest('assertFalse', function(test
, message
) {
129 chromeTest
.assertBool(test
, false, message
);
132 apiFunctions
.setHandleRequest('assertBool',
133 function(test
, expected
, message
) {
134 if (test
!== expected
) {
135 if (typeof(test
) == "string") {
137 message
= test
+ "\n" + message
;
141 chromeTest
.fail(message
);
145 apiFunctions
.setHandleRequest('checkDeepEq', function(expected
, actual
) {
146 if ((expected
=== null) != (actual
=== null))
149 if (expected
=== actual
)
152 if (typeof(expected
) !== typeof(actual
))
155 for (var p
in actual
) {
156 if ($Object
.hasOwnProperty(actual
, p
) &&
157 !$Object
.hasOwnProperty(expected
, p
)) {
161 for (var p
in expected
) {
162 if ($Object
.hasOwnProperty(expected
, p
) &&
163 !$Object
.hasOwnProperty(actual
, p
)) {
168 for (var p
in expected
) {
170 switch (typeof(expected
[p
])) {
172 eq
= chromeTest
.checkDeepEq(expected
[p
], actual
[p
]);
175 eq
= (typeof(actual
[p
]) != 'undefined' &&
176 expected
[p
].toString() == actual
[p
].toString());
179 eq
= (expected
[p
] == actual
[p
] &&
180 typeof(expected
[p
]) == typeof(actual
[p
]));
189 apiFunctions
.setHandleRequest('assertEq',
190 function(expected
, actual
, message
) {
191 var error_msg
= "API Test Error in " + testName(currentTest
);
193 error_msg
+= ": " + message
;
194 if (typeof(expected
) == 'object') {
195 if (!chromeTest
.checkDeepEq(expected
, actual
)) {
196 // Note: these JSON.stringify calls may fail in tests that explicitly
197 // override JSON.stringfy, so surround in try-catch.
199 error_msg
+= "\nActual: " + JSON
.stringify(actual
) +
200 "\nExpected: " + JSON
.stringify(expected
);
202 chromeTest
.fail(error_msg
);
206 if (expected
!= actual
) {
207 chromeTest
.fail(error_msg
+
208 "\nActual: " + actual
+ "\nExpected: " + expected
);
210 if (typeof(expected
) != typeof(actual
)) {
211 chromeTest
.fail(error_msg
+
212 " (type mismatch)\nActual Type: " + typeof(actual
) +
213 "\nExpected Type:" + typeof(expected
));
217 apiFunctions
.setHandleRequest('assertNoLastError', function() {
218 if (chrome
.runtime
.lastError
!= undefined) {
219 chromeTest
.fail("lastError.message == " +
220 chrome
.runtime
.lastError
.message
);
224 apiFunctions
.setHandleRequest('assertLastError', function(expectedError
) {
225 chromeTest
.assertEq(typeof(expectedError
), 'string');
226 chromeTest
.assertTrue(chrome
.runtime
.lastError
!= undefined,
227 "No lastError, but expected " + expectedError
);
228 chromeTest
.assertEq(expectedError
, chrome
.runtime
.lastError
.message
);
231 apiFunctions
.setHandleRequest('assertThrows',
232 function(fn
, self
, args
, message
) {
233 assertTrue(typeof fn
== 'function');
235 fn
.apply(self
, args
);
236 chromeTest
.fail('Did not throw error: ' + fn
);
238 if (message
!== undefined)
239 chromeTest
.assertEq(message
, e
.message
);
243 function safeFunctionApply(func
, args
) {
246 $Function
.apply(func
, null, args
);
248 var msg
= "uncaught exception " + e
;
249 chromeTest
.fail(msg
);
253 // Wrapper for generating test functions, that takes care of calling
254 // assertNoLastError() and (optionally) succeed() for you.
255 apiFunctions
.setHandleRequest('callback', function(func
, expectedError
) {
257 chromeTest
.assertEq(typeof(func
), 'function');
259 var callbackCompleted
= chromeTest
.callbackAdded();
262 if (expectedError
== null) {
263 chromeTest
.assertNoLastError();
265 chromeTest
.assertLastError(expectedError
);
269 safeFunctionApply(func
, arguments
);
276 apiFunctions
.setHandleRequest('listenOnce', function(event
, func
) {
277 var callbackCompleted
= chromeTest
.callbackAdded();
278 var listener = function() {
279 event
.removeListener(listener
);
280 safeFunctionApply(func
, arguments
);
283 event
.addListener(listener
);
286 apiFunctions
.setHandleRequest('listenForever', function(event
, func
) {
287 var callbackCompleted
= chromeTest
.callbackAdded();
289 var listener = function() {
290 safeFunctionApply(func
, arguments
);
293 var done = function() {
294 event
.removeListener(listener
);
298 event
.addListener(listener
);
302 apiFunctions
.setHandleRequest('callbackPass', function(func
) {
303 return chromeTest
.callback(func
);
306 apiFunctions
.setHandleRequest('callbackFail', function(expectedError
, func
) {
307 return chromeTest
.callback(func
, expectedError
);
310 apiFunctions
.setHandleRequest('runTests', function(tests
) {
311 chromeTest
.tests
= tests
;
312 testCount
= chromeTest
.tests
.length
;
313 chromeTest
.runNextTest();
316 apiFunctions
.setHandleRequest('getApiDefinitions', function() {
317 return GetExtensionAPIDefinitionsForTest();
320 apiFunctions
.setHandleRequest('getApiFeatures', function() {
321 return GetAPIFeatures();
325 exports
.binding
= binding
.generate();