1 // Copyright 2013 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 // Common test utilities.
8 * Allows console.log output.
10 var showConsoleLogOutput
= false;
13 * Conditionally allow console.log output based off of showConsoleLogOutput.
15 console
.log = function() {
16 var originalConsoleLog
= console
.log
;
18 if (showConsoleLogOutput
) {
19 originalConsoleLog
.apply(console
, arguments
);
24 function emptyMock() {}
26 // Container for event handlers added by mocked 'addListener' functions.
27 var mockEventHandlers
= {};
30 * Mocks 'addListener' function of an API event. The mocked function will keep
32 * @param {Object} topLevelContainer Top-level container of the original
33 * function. Can be either 'chrome' or 'instrumented'.
34 * @param {string} eventIdentifier Event identifier, such as
35 * 'runtime.onSuspend'.
37 function mockChromeEvent(topLevelContainer
, eventIdentifier
) {
38 var eventIdentifierParts
= eventIdentifier
.split('.');
39 var eventName
= eventIdentifierParts
.pop();
40 var originalMethodContainer
= topLevelContainer
;
41 var mockEventContainer
= mockEventHandlers
;
42 eventIdentifierParts
.forEach(function(fragment
) {
43 originalMethodContainer
=
44 originalMethodContainer
[fragment
] =
45 originalMethodContainer
[fragment
] || {};
47 mockEventContainer
[fragment
] =
48 mockEventContainer
[fragment
] || {};
51 mockEventContainer
[eventName
] = [];
52 originalMethodContainer
[eventName
] = {
53 addListener: function(callback
) {
54 mockEventContainer
[eventName
].push(callback
);
60 * Gets the array of event handlers added by a mocked 'addListener' function.
61 * @param {string} eventIdentifier Event identifier, such as
62 * 'runtime.onSuspend'.
63 * @return {Array<Function>} Array of handlers.
65 function getMockHandlerContainer(eventIdentifier
) {
66 var eventIdentifierParts
= eventIdentifier
.split('.');
67 var mockEventContainer
= mockEventHandlers
;
68 eventIdentifierParts
.forEach(function(fragment
) {
69 mockEventContainer
= mockEventContainer
[fragment
];
72 return mockEventContainer
;
77 * The JS test harness expects all calls to complete synchronously.
78 * As a result, we can't use built-in JS promises since they run asynchronously.
79 * Instead of mocking all possible calls to promises, a skeleton
80 * implementation is provided to get the tests to pass.
82 * This functionality and logic originates from ECMAScript 6's spec of promises.
84 var Promise = function() {
85 function PromisePrototypeObject(asyncTask
) {
86 function isThenable(value
) {
87 return (typeof value
=== 'object') && isCallable(value
.then
);
90 function isCallable(value
) {
91 return typeof value
=== 'function';
94 function callResolveRejectFunc(func
) {
96 var funcResolved
= false;
98 function(resolveResult
) {
99 funcResult
= resolveResult
;
102 function(rejectResult
) {
103 funcResult
= rejectResult
;
104 funcResolved
= false;
106 return { result
: funcResult
, resolved
: funcResolved
};
109 function then(onResolve
, onReject
) {
110 var resolutionHandler
=
111 isCallable(onResolve
) ? onResolve : function() { return result
; };
112 var rejectionHandler
=
113 isCallable(onReject
) ? onReject : function() { return result
; };
115 resolved
? resolutionHandler(result
) : rejectionHandler(result
);
116 var promiseResolved
= resolved
;
117 if (isThenable(handlerResult
)) {
118 var resolveReject
= callResolveRejectFunc(handlerResult
.then
);
119 handlerResult
= resolveReject
.result
;
120 promiseResolved
= resolveReject
.resolved
;
123 if (promiseResolved
) {
124 return Promise
.resolve(handlerResult
);
126 return Promise
.reject(handlerResult
);
130 // Promises use the function name "catch" to call back error handlers.
131 // We can't use "catch" since function or variable names cannot use the word
133 function catchFunc(onRejected
) {
134 return this.then(undefined, onRejected
);
137 var resolveReject
= callResolveRejectFunc(asyncTask
);
138 var result
= resolveReject
.result
;
139 var resolved
= resolveReject
.resolved
;
141 if (isThenable(result
)) {
142 var thenResolveReject
= callResolveRejectFunc(result
.then
);
143 result
= thenResolveReject
.result
;
144 resolved
= thenResolveReject
.resolved
;
147 return {then
: then
, catch: catchFunc
, isPromise
: true};
150 function all(arrayOfPromises
) {
152 for (i
= 0; i
< arrayOfPromises
.length
; i
++) {
153 if (arrayOfPromises
[i
].isPromise
) {
154 arrayOfPromises
[i
].then(function(result
) {
158 results
[i
] = arrayOfPromises
[i
];
161 var promise
= new PromisePrototypeObject(function(resolve
) {
167 function resolve(value
) {
168 var promise
= new PromisePrototypeObject(function(resolve
) {
174 function reject(value
) {
175 var promise
= new PromisePrototypeObject(function(resolve
, reject
) {
181 PromisePrototypeObject
.all
= all
;
182 PromisePrototypeObject
.resolve
= resolve
;
183 PromisePrototypeObject
.reject
= reject
;
184 return PromisePrototypeObject
;
188 * Sets up the test to expect a Chrome Local Storage call.
189 * @param {Object} fixture Mock JS Test Object.
190 * @param {Object} defaultObject Storage request default object.
191 * @param {Object} result Storage result.
192 * @param {boolean=} opt_AllowRejection Allow Promise Rejection
194 function expectChromeLocalStorageGet(
195 fixture
, defaultObject
, result
, opt_AllowRejection
) {
196 if (opt_AllowRejection
=== undefined) {
197 fixture
.mockApis
.expects(once()).
198 fillFromChromeLocalStorage(eqJSON(defaultObject
)).
199 will(returnValue(Promise
.resolve(result
)));
201 fixture
.mockApis
.expects(once()).
202 fillFromChromeLocalStorage(eqJSON(defaultObject
), opt_AllowRejection
).
203 will(returnValue(Promise
.resolve(result
)));