Unregister from GCM when the only GCM app is removed
[chromium-blink-merge.git] / chrome / test / data / webui / test_api.js
blobabd27ae3826b49aeef251ea653209b42d13ba840
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 /**
6  * @fileoverview Library providing basic test framework functionality.
7  */
9 /**
10  * Namespace for |Test|.
11  * @type {Object}
12  */
13 var testing = {};
14 (function(exports) {
15   /**
16    * Holds the original version of the |chrome| object.
17    */
18   var originalChrome = null;
20   /**
21    * Hold the currentTestCase across between preLoad and run.
22    * @type {TestCase}
23    */
24   var currentTestCase = null;
26   /**
27    * The string representation of the currently running test function.
28    * @type {?string}
29    */
30   var currentTestFunction = null;
32   /**
33    * The arguments of the currently running test.
34    * @type {Array}
35    */
36   var currentTestArguments = [];
38  /**
39    * This class will be exported as testing.Test, and is provided to hold the
40    * fixture's configuration and callback methods for the various phases of
41    * invoking a test. It is called "Test" rather than TestFixture to roughly
42    * mimic the gtest's class names.
43    * @constructor
44    */
45   function Test() {};
47   Test.prototype = {
48     /**
49      * The name of the test.
50      */
51     name: null,
53     /**
54      * When set to a string value representing a url, generate BrowsePreload
55      * call, which will browse to the url and call fixture.preLoad of the
56      * currentTestCase.
57      * @type {string}
58      */
59     browsePreload: null,
61     /**
62      * When set to a string value representing an html page in the test
63      * directory, generate BrowsePrintPreload call, which will browse to a url
64      * representing the file, cause print, and call fixture.preLoad of the
65      * currentTestCase.
66      * @type {string}
67      */
68     browsePrintPreload: null,
70     /**
71      * When set to a function, will be called in the context of the test
72      * generation inside the function, after AddLibrary calls and before
73      * generated C++.
74      * @type {function(string,string)}
75      */
76     testGenPreamble: null,
78     /**
79      * When set to a function, will be called in the context of the test
80      * generation inside the function, and after any generated C++.
81      * @type {function(string,string)}
82      */
83     testGenPostamble: null,
85     /**
86      * When set to a non-null string, auto-generate typedef before generating
87      * TEST*: {@code typedef typedefCppFixture testFixture}.
88      * @type {string}
89      */
90     typedefCppFixture: 'WebUIBrowserTest',
92     /**
93      * This should be initialized by the test fixture and can be referenced
94      * during the test run. It holds any mocked handler methods.
95      * @type {?Mock4JS.Mock}
96      */
97     mockHandler: null,
99     /**
100      * This should be initialized by the test fixture and can be referenced
101      * during the test run. It holds any mocked global functions.
102      * @type {?Mock4JS.Mock}
103      */
104     mockGlobals: null,
106     /**
107      * Value is passed through call to C++ RunJavascriptF to invoke this test.
108      * @type {boolean}
109      */
110     isAsync: false,
112     /**
113      * True when the test is expected to fail for testing the test framework.
114      * @type {boolean}
115      */
116     testShouldFail: false,
118     /**
119      * Extra libraries to add before loading this test file.
120      * @type {Array.<string>}
121      */
122     extraLibraries: [],
124     /**
125      * Extra libraries to add before loading this test file.
126      * This list is in the form of Closure library style object
127      * names.  To support this, a closure deps.js file must
128      * be specified when generating the test C++ source.
129      * The specified libraries will be included with their transitive
130      * dependencies according to the deps file.
131      * @type {Array.<string>}
132      */
133     closureModuleDeps: [],
135     /**
136      * Whether to run the accessibility checks.
137      * @type {boolean}
138      */
139     runAccessibilityChecks: true,
141     /**
142      * Configuration for the accessibility audit.
143      * @type {axs.AuditConfiguration}
144      */
145     accessibilityAuditConfig_: null,
147     /**
148      * Returns the configuration for the accessibility audit, creating it
149      * on-demand.
150      * @return {axs.AuditConfiguration}
151      */
152     get accessibilityAuditConfig() {
153       if (!this.accessibilityAuditConfig_) {
154         this.accessibilityAuditConfig_ = new axs.AuditConfiguration();
156         this.accessibilityAuditConfig_.showUnsupportedRulesWarning = false;
158         this.accessibilityAuditConfig_.auditRulesToIgnore = [
159             // The "elements with meaningful background image" accessibility
160             // audit (AX_IMAGE_01) does not apply, since Chrome doesn't
161             // disable background images in high-contrast mode like some
162             // browsers do.
163             "elementsWithMeaningfulBackgroundImage",
165             // Most WebUI pages are inside an IFrame, so the "web page should
166             // have a title that describes topic or purpose" test (AX_TITLE_01)
167             // generally does not apply.
168             "pageWithoutTitle",
170             // TODO(aboxhall): re-enable when crbug.com/267035 is fixed.
171             // Until then it's just noise.
172             "lowContrastElements",
173         ];
174       }
175       return this.accessibilityAuditConfig_;
176     },
178     /**
179      * Whether to treat accessibility issues (errors or warnings) as test
180      * failures. If true, any accessibility issues will cause the test to fail.
181      * If false, accessibility issues will cause a console.warn.
182      * Off by default to begin with; as we add the ability to suppress false
183      * positives, we will transition this to true.
184      * @type {boolean}
185      */
186     accessibilityIssuesAreErrors: false,
188     /**
189      * Holds any accessibility results found during the accessibility audit.
190      * @type {Array.<Object>}
191      */
192     a11yResults_: [],
194     /**
195      * Gets the list of accessibility errors found during the accessibility
196      * audit. Only for use in testing.
197      * @return {Array.<Object>}
198      */
199     getAccessibilityResults: function() {
200       return this.a11yResults_;
201     },
203     /**
204      * Run accessibility checks after this test completes.
205      */
206     enableAccessibilityChecks: function() {
207       this.runAccessibilityChecks = true;
208     },
210     /**
211      * Don't run accessibility checks after this test completes.
212      */
213     disableAccessibilityChecks: function() {
214       this.runAccessibilityChecks = false;
215     },
217     /**
218      * Create a new class to handle |messageNames|, assign it to
219      * |this.mockHandler|, register its messages and return it.
220      * @return {Mock} Mock handler class assigned to |this.mockHandler|.
221      */
222     makeAndRegisterMockHandler: function(messageNames) {
223       var MockClass = makeMockClass(messageNames);
224       this.mockHandler = mock(MockClass);
225       registerMockMessageCallbacks(this.mockHandler, MockClass);
226       return this.mockHandler;
227     },
229     /**
230      * Create a new class to handle |functionNames|, assign it to
231      * |this.mockGlobals|, register its global overrides, and return it.
232      * @return {Mock} Mock handler class assigned to |this.mockGlobals|.
233      * @see registerMockGlobals
234      */
235     makeAndRegisterMockGlobals: function(functionNames) {
236       var MockClass = makeMockClass(functionNames);
237       this.mockGlobals = mock(MockClass);
238       registerMockGlobals(this.mockGlobals, MockClass);
239       return this.mockGlobals;
240     },
242     /**
243       * Create a container of mocked standalone functions to handle
244       * '.'-separated |apiNames|, assign it to |this.mockApis|, register its API
245       * overrides and return it.
246       * @return {Mock} Mock handler class.
247       * @see makeMockFunctions
248       * @see registerMockApis
249       */
250     makeAndRegisterMockApis: function (apiNames) {
251       var apiMockNames = apiNames.map(function(name) {
252         return name.replace(/\./g, '_');
253       });
255       this.mockApis = makeMockFunctions(apiMockNames);
256       registerMockApis(this.mockApis);
257       return this.mockApis;
258     },
260     /**
261       * Create a container of mocked standalone functions to handle
262       * |functionNames|, assign it to |this.mockLocalFunctions| and return it.
263       * @param {!Array.<string>} functionNames
264       * @return {Mock} Mock handler class.
265       * @see makeMockFunctions
266       */
267     makeMockLocalFunctions: function(functionNames) {
268       this.mockLocalFunctions = makeMockFunctions(functionNames);
269       return this.mockLocalFunctions;
270     },
272     /**
273      * Override this method to perform initialization during preload (such as
274      * creating mocks and registering handlers).
275      * @type {Function}
276      */
277     preLoad: function() {},
279     /**
280      * Override this method to perform tasks before running your test.
281      * @type {Function}
282      */
283     setUp: function() {
284       // These should be ignored in many of the web UI tests.
285       // user-image-stream and supervised-user-creation-image-stream are
286       // streaming video elements used for capturing a user image so they won't
287       // have captions and should be ignored everywhere.
288       this.accessibilityAuditConfig.ignoreSelectors('videoWithoutCaptions',
289                                                     '.user-image-stream');
290       this.accessibilityAuditConfig.ignoreSelectors(
291           'videoWithoutCaptions', '.supervised-user-creation-image-stream');
292     },
294     /**
295      * Override this method to perform tasks after running your test. If you
296      * create a mock class, you must call Mock4JS.verifyAllMocks() in this
297      * phase.
298      * @type {Function}
299      */
300     tearDown: function() {
301       Mock4JS.verifyAllMocks();
302     },
304     /**
305      * Called to run the body from the perspective of this fixture.
306      * @type {Function}
307      */
308     runTest: function(testBody) {
309       testBody.call(this);
310     },
312     /**
313      * Called to run the accessibility audit from the perspective of this
314      * fixture.
315      */
316     runAccessibilityAudit: function() {
317       if (!this.runAccessibilityChecks || typeof document === 'undefined')
318         return;
320       var auditConfig = this.accessibilityAuditConfig;
321       if (!runAccessibilityAudit(this.a11yResults_, auditConfig)) {
322         var report = accessibilityAuditReport(this.a11yResults_);
323         if (this.accessibilityIssuesAreErrors)
324           throw new Error(report);
325         else
326           console.warn(report);
327       }
328     },
330     /**
331      * Create a closure function for continuing the test at a later time. May be
332      * used as a listener function.
333      * @param {WhenTestDone} whenTestDone Call testDone() at the appropriate
334      *     time.
335      * @param {Function} completion The function to call to complete the test.
336      * @param {...*} var_args Arguments to pass when calling completionAction.
337      * @return {function(): void} Return a function, bound to this test fixture,
338      *     which continues the test.
339      */
340     continueTest: function(whenTestDone, completion) {
341       var savedArgs = new SaveMockArguments();
342       var completionAction = new CallFunctionAction(
343           this, savedArgs, completion,
344           Array.prototype.slice.call(arguments, 2));
345       if (whenTestDone === WhenTestDone.DEFAULT)
346         whenTestDone = WhenTestDone.ASSERT;
347       var runAll = new RunAllAction(
348           true, whenTestDone, [completionAction]);
349       return function() {
350         savedArgs.arguments = Array.prototype.slice.call(arguments);
351         runAll.invoke();
352       };
353     },
355     /**
356      * Call this during setUp to defer the call to runTest() until later. The
357      * caller must call the returned function at some point to run the test.
358      * @type {Function}
359      * @param {WhenTestDone} whenTestDone Call testDone() at the appropriate
360      *     time.
361      * @param {...*} var_args Arguments to pass when running the
362      *     |currentTestCase|.
363      * @return {function(): void} A function which will run the current body of
364      *     the currentTestCase.
365      */
366     deferRunTest: function(whenTestDone) {
367       if (whenTestDone === WhenTestDone.DEFAULT)
368         whenTestDone = WhenTestDone.ALWAYS;
370       return currentTestCase.deferRunTest.apply(
371           currentTestCase, [whenTestDone].concat(
372               Array.prototype.slice.call(arguments, 1)));
373     },
374   };
376   /**
377    * This class is not exported and is available to hold the state of the
378    * |currentTestCase| throughout preload and test run.
379    * @param {string} name The name of the test case.
380    * @param {Test} fixture The fixture object for this test case.
381    * @param {Function} body The code to run for the test.
382    * @constructor
383    */
384   function TestCase(name, fixture, body) {
385     this.name = name;
386     this.fixture = fixture;
387     this.body = body;
388   }
390   TestCase.prototype = {
391     /**
392      * The name of this test.
393      * @type {string}
394      */
395     name: null,
397     /**
398      * The test fixture to set |this| to when running the test |body|.
399      * @type {testing.Test}
400      */
401     fixture: null,
403     /**
404      * The test body to execute in runTest().
405      * @type {Function}
406      */
407     body: null,
409     /**
410      * True when the test fixture will run the test later.
411      * @type {boolean}
412      * @private
413      */
414     deferred_: false,
416     /**
417      * Called at preload time, proxies to the fixture.
418      * @type {Function}
419      */
420     preLoad: function(name) {
421       if (this.fixture)
422         this.fixture.preLoad();
423     },
425     /**
426      * Called before a test runs.
427      */
428     setUp: function() {
429       if (this.fixture)
430         this.fixture.setUp();
431     },
433     /**
434      * Called before a test is torn down (by testDone()).
435      */
436     tearDown: function() {
437       if (this.fixture)
438         this.fixture.tearDown();
439     },
441     /**
442      * Called to run this test's body.
443      */
444     runTest: function() {
445       if (this.body && this.fixture)
446         this.fixture.runTest(this.body);
447     },
449     /**
450      * Called after a test is run (in testDone) to test accessibility.
451      */
452     runAccessibilityAudit: function() {
453       if (this.fixture)
454         this.fixture.runAccessibilityAudit();
455     },
457     /**
458      * Runs this test case with |this| set to the |fixture|.
459      *
460      * Note: Tests created with TEST_F may depend upon |this| being set to an
461      * instance of this.fixture. The current implementation of TEST creates a
462      * dummy constructor, but tests created with TEST should not rely on |this|
463      * being set.
464      * @type {Function}
465      */
466     run: function() {
467       try {
468         this.setUp();
469       } catch(e) {
470         // Mock4JSException doesn't inherit from Error, so fall back on
471         // toString().
472         console.error(e.stack || e.toString());
473       }
475       if (!this.deferred_)
476         this.runTest();
478       // tearDown called by testDone().
479     },
481     /**
482      * Cause this TestCase to be deferred (don't call runTest()) until the
483      * returned function is called.
484      * @type {Function}
485      * @param {WhenTestDone} whenTestDone Call testDone() at the appropriate
486      *     time.
487      * @param {...*} var_args Arguments to pass when running the
488      *     |currentTestCase|.
489      * @return {function(): void} A function thatwill run this TestCase when
490      *     called.
491      */
492     deferRunTest: function(whenTestDone) {
493       this.deferred_ = true;
494       var savedArgs = new SaveMockArguments();
495       var completionAction = new CallFunctionAction(
496           this, savedArgs, this.runTest,
497           Array.prototype.slice.call(arguments, 1));
498       var runAll = new RunAllAction(
499           true, whenTestDone, [completionAction]);
500       return function() {
501         savedArgs.arguments = Array.prototype.slice.call(arguments);
502         runAll.invoke();
503       };
504     },
506   };
508   /**
509    * Registry of javascript-defined callbacks for {@code chrome.send}.
510    * @type {Object}
511    */
512   var sendCallbacks = {};
514   /**
515    * Registers the message, object and callback for {@code chrome.send}
516    * @param {string} name The name of the message to route to this |callback|.
517    * @param {Object} messageHandler Pass as |this| when calling the |callback|.
518    * @param {function(...)} callback Called by {@code chrome.send}.
519    * @see sendCallbacks
520    */
521   function registerMessageCallback(name, messageHandler, callback) {
522     sendCallbacks[name] = [messageHandler, callback];
523   }
525   /**
526    * Register all methods of {@code mockClass.prototype} with messages of the
527    * same name as the method, using the proxy of the |mockObject| as the
528    * |messageHandler| when registering.
529    * @param {Mock4JS.Mock} mockObject The mock to register callbacks against.
530    * @param {function(new:Object)} mockClAss Constructor for the mocked class.
531    * @see registerMessageCallback
532    * @see overrideChrome
533    */
534   function registerMockMessageCallbacks(mockObject, mockClass) {
535     if (!deferGlobalOverrides && !originalChrome)
536       overrideChrome();
537     var mockProxy = mockObject.proxy();
538     for (var func in mockClass.prototype) {
539       if (typeof mockClass.prototype[func] === 'function') {
540         registerMessageCallback(func, mockProxy, mockProxy[func]);
541       }
542     }
543   }
545   /**
546    * Holds the mapping of name -> global override information.
547    * @type {Object}
548    */
549   var globalOverrides = {};
551   /**
552    * When preloading JavaScript libraries, this is true until the
553    * DOMContentLoaded event has been received as globals cannot be overridden
554    * until the page has loaded its JavaScript.
555    * @type {boolean}
556    */
557   var deferGlobalOverrides = false;
559   /**
560    * Override the global function |funcName| with its registered mock. This
561    * should not be called twice for the same |funcName|.
562    * @param {string} funcName The name of the global function to override.
563    */
564   function overrideGlobal(funcName) {
565     assertNotEquals(undefined, this[funcName]);
566     var globalOverride = globalOverrides[funcName];
567     assertNotEquals(undefined, globalOverride);
568     assertEquals(undefined, globalOverride.original);
569     globalOverride.original = this[funcName];
570     this[funcName] = globalOverride.callback.bind(globalOverride.object);
571   }
573   /**
574    * Registers the global function name, object and callback.
575    * @param {string} name The name of the message to route to this |callback|.
576    * @param {Object} object Pass as |this| when calling the |callback|.
577    * @param {function(...)} callback Called by {@code chrome.send}.
578    * @see overrideGlobal
579    */
580   function registerMockGlobal(name, object, callback) {
581     assertEquals(undefined, globalOverrides[name]);
582     globalOverrides[name] = {
583       object: object,
584       callback: callback,
585     };
587     if (!deferGlobalOverrides)
588       overrideGlobal(name);
589   }
591   /**
592    * Registers the mock API call and its function.
593    * @param {string} name The '_'-separated name of the API call.
594    * @param {function(...)} theFunction Mock function for this API call.
595    */
596   function registerMockApi(name, theFunction) {
597     var path = name.split('_');
599     var namespace = this;
600     for(var i = 0; i < path.length - 1; i++) {
601       var fieldName = path[i];
602       if(!namespace[fieldName])
603         namespace[fieldName] = {};
605       namespace = namespace[fieldName];
606     }
608     var fieldName = path[path.length-1];
609     namespace[fieldName] = theFunction;
610   }
612   /**
613    * Empty function for use in making mocks.
614    * @const
615    */
616   function emptyFunction() {}
618   /**
619    * Make a mock from the supplied |methodNames| array.
620    * @param {Array.<string>} methodNames Array of names of methods to mock.
621    * @return {Function} Constructor with prototype filled in with methods
622    *     matching |methodNames|.
623    */
624   function makeMockClass(methodNames) {
625     function MockConstructor() {}
626     for(var i = 0; i < methodNames.length; i++)
627       MockConstructor.prototype[methodNames[i]] = emptyFunction;
628     return MockConstructor;
629   }
631   /**
632     * Create a new class to handle |functionNames|, add method 'functions()'
633     * that returns a container of standalone functions based on the mock class
634     * members, and return it.
635     * @return {Mock} Mock handler class.
636     */
637   function makeMockFunctions(functionNames) {
638     var MockClass = makeMockClass(functionNames);
639     var mockFunctions = mock(MockClass);
640     var mockProxy = mockFunctions.proxy();
642     mockFunctions.functions_ = {};
644     for (var func in MockClass.prototype) {
645       if (typeof MockClass.prototype[func] === 'function')
646         mockFunctions.functions_[func] = mockProxy[func].bind(mockProxy);
647     }
649     mockFunctions.functions = function () {
650       return this.functions_;
651     };
653     return mockFunctions;
654   }
656   /**
657    * Register all methods of {@code mockClass.prototype} as overrides to global
658    * functions of the same name as the method, using the proxy of the
659    * |mockObject| to handle the functions.
660    * @param {Mock4JS.Mock} mockObject The mock to register callbacks against.
661    * @param {function(new:Object)} mockClass Constructor for the mocked class.
662    * @see registerMockGlobal
663    */
664   function registerMockGlobals(mockObject, mockClass) {
665     var mockProxy = mockObject.proxy();
666     for (var func in mockClass.prototype) {
667       if (typeof mockClass.prototype[func] === 'function')
668         registerMockGlobal(func, mockProxy, mockProxy[func]);
669     }
670   }
672   /**
673    * Register all functions in |mockObject.functions()| as global API calls.
674    * @param {Mock4JS.Mock} mockObject The mock to register callbacks against.
675    * @see registerMockApi
676    */
677   function registerMockApis(mockObject) {
678     var functions = mockObject.functions();
679     for (var func in functions) {
680       if (typeof functions[func] === 'function')
681         registerMockApi(func, functions[func]);
682     }
683   }
685   /**
686    * Overrides {@code chrome.send} for routing messages to javascript
687    * functions. Also falls back to sending with the original chrome object.
688    * @param {string} messageName The message to route.
689    */
690   function send(messageName) {
691     var callback = sendCallbacks[messageName];
692     if (callback != undefined)
693       callback[1].apply(callback[0], Array.prototype.slice.call(arguments, 1));
694     else
695       this.__proto__.send.apply(this.__proto__, arguments);
696   }
698   /**
699    * Provides a mechanism for assert* and expect* methods to fetch the signature
700    * of their caller. Assert* methods should |registerCall| and expect* methods
701    * should set |isExpect| and |expectName| properties to indicate that the
702    * interesting caller is one more level up the stack.
703    */
704   function CallHelper() {
705     this.__proto__ = CallHelper.prototype;
706   }
708   CallHelper.prototype = {
709     /**
710      * Holds the mapping of (callerCallerString, callerName) -> count of times
711      * called.
712      * @type {Object.<string, Object.<string, number>>}
713      */
714     counts_: {},
716     /**
717      * This information about the caller is needed from most of the following
718      * routines.
719      * @param {Function} caller the caller of the assert* routine.
720      * @return {{callerName: string, callercallerString: string}} stackInfo
721      * @private
722      */
723     getCallerInfo_: function(caller) {
724       var callerName = caller.name;
725       var callerCaller = caller.caller;
726       if (callerCaller['isExpect']) {
727         callerName = callerCaller.expectName;
728         callerCaller = callerCaller.caller;
729       }
730       var callerCallerString = callerCaller.toString();
731       return {
732         callerName: callerName,
733         callerCallerString: callerCallerString,
734       };
735     },
737     /**
738      * Register a call to an assertion class.
739      */
740     registerCall: function() {
741       var stackInfo = this.getCallerInfo_(arguments.callee.caller);
742       if (!(stackInfo.callerCallerString in this.counts_))
743         this.counts_[stackInfo.callerCallerString] = {};
744       if (!(stackInfo.callerName in this.counts_[stackInfo.callerCallerString]))
745         this.counts_[stackInfo.callerCallerString][stackInfo.callerName] = 0;
746       ++this.counts_[stackInfo.callerCallerString][stackInfo.callerName];
747     },
749     /**
750      * Get the call signature of this instance of the caller's call to this
751      * function.
752      * @param {Function} caller The caller of the assert* routine.
753      * @return {String} Call signature.
754      * @private
755      */
756     getCall_: function(caller) {
757       var stackInfo = this.getCallerInfo_(caller);
758       var count =
759           this.counts_[stackInfo.callerCallerString][stackInfo.callerName];
761       // Allow pattern to match multiple lines for text wrapping.
762       var callerRegExp =
763           new RegExp(stackInfo.callerName + '\\((.|\\n|\\r)*?\\);', 'g');
765       // Find all matches allowing wrap around such as when a helper function
766       // calls assert/expect calls and that helper function is called multiple
767       // times.
768       var matches = stackInfo.callerCallerString.match(callerRegExp);
769       var match = matches[(count - 1) % matches.length];
771       // Chop off the trailing ';'.
772       return match.substring(0, match.length-1);
773     },
775     /**
776      * Returns the text of the call signature and any |message|.
777      * @param {string=} message Addtional message text from caller.
778      */
779     getCallMessage: function(message) {
780       var callMessage = this.getCall_(arguments.callee.caller);
781       if (message)
782         callMessage += ': ' + message;
783       return callMessage;
784     },
785   };
787   /**
788    * Help register calls for better error reporting.
789    * @type {CallHelper}
790    */
791   var helper = new CallHelper();
793   /**
794    * true when testDone has been called.
795    * @type {boolean}
796    */
797   var testIsDone = false;
799   /**
800    * Holds the errors, if any, caught by expects so that the test case can
801    * fail. Cleared when results are reported from runTest() or testDone().
802    * @type {Array.<Error>}
803    */
804   var errors = [];
806   /**
807    * URL to dummy WebUI page for testing framework.
808    * @type {string}
809    */
810   var DUMMY_URL = 'chrome://DummyURL';
812   /**
813    * Resets test state by clearing |errors| and |testIsDone| flags.
814    */
815   function resetTestState() {
816     errors.splice(0, errors.length);
817     testIsDone = false;
818   }
820   /**
821    * Notifies the running browser test of the test results. Clears |errors|.
822    * @param {Array.<boolean, string>=} result When passed, this is used for the
823    *     testResult message.
824    */
825   function testDone(result) {
826     if (!testIsDone) {
827       testIsDone = true;
828       if (currentTestCase) {
829         var ok = true;
830         ok = createExpect(currentTestCase.runAccessibilityAudit.bind(
831             currentTestCase)).call(null) && ok;
832         ok = createExpect(currentTestCase.tearDown.bind(
833             currentTestCase)).call(null) && ok;
835         if (!ok && result)
836           result = [false, errorsToMessage(errors, result[1])];
838         currentTestCase = null;
839       }
840       if (!result)
841         result = testResult();
842       if (chrome.send) {
843         // For WebUI tests.
844         chrome.send('testResult', result);
845       } else if (window.domAutomationController.send) {
846         // For extension tests.
847         valueResult = { 'result': result[0], message: result[1] };
848         window.domAutomationController.send(JSON.stringify(valueResult));
849       }
850       errors.splice(0, errors.length);
851     } else {
852       console.warn('testIsDone already');
853     }
854   }
856   /**
857    * Converts each Error in |errors| to a suitable message, adding them to
858    * |message|, and returns the message string.
859    * @param {Array.<Error>} errors Array of errors to add to |message|.
860    * @param {string?} message When supplied, error messages are appended to it.
861    * @return {string} |message| + messages of all |errors|.
862    */
863   function errorsToMessage(errors, message) {
864     for (var i = 0; i < errors.length; ++i) {
865       var errorMessage = errors[i].stack || errors[i].message;
866       if (message)
867         message += '\n';
869       message += 'Failed: ' + currentTestFunction + '(' +
870           currentTestArguments.map(JSON.stringify) +
871           ')\n' + errorMessage;
872     }
873     return message;
874   }
876   /**
877    * Returns [success, message] & clears |errors|.
878    * @param {boolean} errorsOk When true, errors are ok.
879    * @return {Array.<boolean, string>}
880    */
881   function testResult(errorsOk) {
882     var result = [true, ''];
883     if (errors.length)
884       result = [!!errorsOk, errorsToMessage(errors)];
886     return result;
887   }
889   // Asserts.
890   // Use the following assertions to verify a condition within a test.
891   // If assertion fails, throw an Error with information pertinent to the test.
893   /**
894    * When |test| !== true, aborts the current test.
895    * @param {boolean} test The predicate to check against |expected|.
896    * @param {string=} message The message to include in the Error thrown.
897    * @throws {Error} upon failure.
898    */
899   function assertTrue(test, message) {
900     helper.registerCall();
901     if (test !== true)
902       throw new Error(
903           'Test Error ' + helper.getCallMessage(message) + ': ' + test);
904   }
906   /**
907    * When |test| !== false, aborts the current test.
908    * @param {boolean} test The predicate to check against |expected|.
909    * @param {string=} message The message to include in the Error thrown.
910    * @throws {Error} upon failure.
911    */
912   function assertFalse(test, message) {
913     helper.registerCall();
914     if (test !== false)
915       throw new Error(
916           'Test Error ' + helper.getCallMessage(message) + ': ' + test);
917   }
919   /**
920    * When |val1| < |val2|, aborts the current test.
921    * @param {number} val1 The number expected to be >= |val2|.
922    * @param {number} val2 The number expected to be < |val1|.
923    * @param {string=} message The message to include in the Error thrown.
924    */
925   function assertGE(val1, val2, message) {
926     helper.registerCall();
927     if (val1 < val2) {
928       throw new Error(
929           'Test Error ' + helper.getCallMessage(message) + val1 + '<' + val2);
930     }
931   }
933   /**
934    * When |val1| <= |val2|, aborts the current test.
935    * @param {number} val1 The number expected to be > |val2|.
936    * @param {number} val2 The number expected to be <= |val1|.
937    * @param {string=} message The message to include in the Error thrown.
938    */
939   function assertGT(val1, val2, message) {
940     helper.registerCall();
941     if (val1 <= val2) {
942       throw new Error(
943           'Test Error ' + helper.getCallMessage(message) + val1 + '<=' + val2);
944     }
945   }
947   /**
948    * When |expected| !== |actual|, aborts the current test.
949    * @param {*} expected The expected value of |actual|.
950    * @param {*} actual The predicate to check against |expected|.
951    * @param {string=} message The message to include in the Error thrown.
952    * @throws {Error} upon failure.
953    */
954   function assertEquals(expected, actual, message) {
955     helper.registerCall();
956     if (expected != actual) {
957       throw new Error(
958           'Test Error ' + helper.getCallMessage(message) +
959           '\nActual: ' + actual + '\nExpected: ' + expected);
960     }
961     if (typeof expected !== typeof actual) {
962       throw new Error(
963           'Test Error (type mismatch) ' + helper.getCallMessage(message) +
964           '\nActual Type: ' + typeof actual +
965           '\nExpected Type:' + typeof expected);
966     }
967   }
969   /**
970    * When |val1| > |val2|, aborts the current test.
971    * @param {number} val1 The number expected to be <= |val2|.
972    * @param {number} val2 The number expected to be > |val1|.
973    * @param {string=} message The message to include in the Error thrown.
974    */
975   function assertLE(val1, val2, message) {
976     helper.registerCall();
977     if (val1 > val2) {
978       throw new Error(
979           'Test Error ' + helper.getCallMessage(message) + val1 + '>' + val2);
980     }
981   }
983   /**
984    * When |val1| >= |val2|, aborts the current test.
985    * @param {number} val1 The number expected to be < |val2|.
986    * @param {number} val2 The number expected to be >= |val1|.
987    * @param {string=} message The message to include in the Error thrown.
988    */
989   function assertLT(val1, val2, message) {
990     helper.registerCall();
991     if (val1 >= val2) {
992       throw new Error(
993           'Test Error ' + helper.getCallMessage(message) + val1 + '>=' + val2);
994     }
995   }
997   /**
998    * When |notExpected| === |actual|, aborts the current test.
999    * @param {*} notExpected The expected value of |actual|.
1000    * @param {*} actual The predicate to check against |notExpected|.
1001    * @param {string=} message The message to include in the Error thrown.
1002    * @throws {Error} upon failure.
1003    */
1004   function assertNotEquals(notExpected, actual, message) {
1005     helper.registerCall();
1006     if (notExpected === actual) {
1007       throw new Error(
1008           'Test Error ' + helper.getCallMessage(message) +
1009           '\nActual: ' + actual + '\nnotExpected: ' + notExpected);
1010     }
1011   }
1013   /**
1014    * Always aborts the current test.
1015    * @param {string=} message The message to include in the Error thrown.
1016    * @throws {Error} always.
1017    */
1018   function assertNotReached(message) {
1019     helper.registerCall();
1020     throw new Error(helper.getCallMessage(message));
1021   }
1023   /**
1024    * Run an accessibility audit on the current page state.
1025    * @type {Function}
1026    * @param {Array} a11yResults
1027    * @param {axs.AuditConfigutarion=} opt_config
1028    * @return {boolean} Whether there were any errors or warnings
1029    * @private
1030    */
1031   function runAccessibilityAudit(a11yResults, opt_config) {
1032     var auditResults = axs.Audit.run(opt_config);
1033     for (var i = 0; i < auditResults.length; i++) {
1034       var auditResult = auditResults[i];
1035       if (auditResult.result == axs.constants.AuditResult.FAIL) {
1036         var auditRule = auditResult.rule;
1037         // TODO(aboxhall): more useful error messages (sadly non-trivial)
1038         a11yResults.push(auditResult);
1039       }
1040     }
1041     // TODO(aboxhall): have strict (no errors or warnings) vs non-strict
1042     // (warnings ok)
1043     // TODO(aboxhall): some kind of info logging for warnings only??
1044     return (a11yResults.length == 0);
1045   }
1047   /**
1048    * Concatenates the accessibility error messages for each result in
1049    * |a11yResults| and
1050    * |a11yWarnings| in to an accessibility report, appends it to the given
1051    * |message| and returns the resulting message string.
1052    * @param {Array.<string>} a11yResults The list of accessibility results
1053    * @return {string} |message| + accessibility report.
1054    */
1055   function accessibilityAuditReport(a11yResults, message) {
1056     message = message ? message + '\n\n' : '\n';
1057     message += 'Accessibility issues found on ' + window.location.href + '\n';
1058     message += axs.Audit.createReport(a11yResults);
1059     return message;
1060   }
1062   /**
1063    * Asserts that the current page state passes the accessibility audit.
1064    * @param {Array=} opt_results Array to fill with results, if desired.
1065    */
1066   function assertAccessibilityOk(opt_results) {
1067     helper.registerCall();
1068     var a11yResults = opt_results || [];
1069     var auditConfig = currentTestCase.fixture.accessibilityAuditConfig;
1070     if (!runAccessibilityAudit(a11yResults, auditConfig))
1071       throw new Error(accessibilityAuditReport(a11yResults));
1072   }
1074   /**
1075    * Creates a function based upon a function that thows an exception on
1076    * failure. The new function stuffs any errors into the |errors| array for
1077    * checking by runTest. This allows tests to continue running other checks,
1078    * while failing the overall test if any errors occurrred.
1079    * @param {Function} assertFunc The function which may throw an Error.
1080    * @return {function(...*):bool} A function that applies its arguments to
1081    *     |assertFunc| and returns true if |assertFunc| passes.
1082    * @see errors
1083    * @see runTestFunction
1084    */
1085   function createExpect(assertFunc) {
1086     var expectFunc = function() {
1087       try {
1088         assertFunc.apply(null, arguments);
1089       } catch (e) {
1090         errors.push(e);
1091         return false;
1092       }
1093       return true;
1094     };
1095     expectFunc.isExpect = true;
1096     expectFunc.expectName = assertFunc.name.replace(/^assert/, 'expect');
1097     return expectFunc;
1098   }
1100   /**
1101    * This is the starting point for tests run by WebUIBrowserTest.  If an error
1102    * occurs, it reports a failure and a message created by joining individual
1103    * error messages. This supports sync tests and async tests by calling
1104    * testDone() when |isAsync| is not true, relying on async tests to call
1105    * testDone() when they complete.
1106    * @param {boolean} isAsync When false, call testDone() with the test result
1107    *     otherwise only when assertions are caught.
1108    * @param {string} testFunction The function name to call.
1109    * @param {Array} testArguments The arguments to call |testFunction| with.
1110    * @return {boolean} true always to signal successful execution (but not
1111    *     necessarily successful results) of this test.
1112    * @see errors
1113    * @see runTestFunction
1114    */
1115   function runTest(isAsync, testFunction, testArguments) {
1116     // Avoid eval() if at all possible, since it will not work on pages
1117     // that have enabled content-security-policy.
1118     var testBody = this[testFunction];    // global object -- not a method.
1119     var testName = testFunction;
1121     // Depending on how we were called, |this| might not resolve to the global
1122     // context.
1123     if (testName == 'RUN_TEST_F' && testBody === undefined)
1124       testBody = RUN_TEST_F;
1126     if (typeof testBody === "undefined") {
1127       testBody = eval(testFunction);
1128       testName = testBody.toString();
1129     }
1130     if (testBody != RUN_TEST_F) {
1131       console.log('Running test ' + testName);
1132     }
1134     // Async allow expect errors, but not assert errors.
1135     var result = runTestFunction(testFunction, testBody, testArguments,
1136                                  isAsync);
1137     if (!isAsync || !result[0])
1138       testDone(result);
1139     return true;
1140   }
1142   /**
1143    * This is the guts of WebUIBrowserTest. It runs the test surrounded by an
1144    * expect to catch Errors. If |errors| is non-empty, it reports a failure and
1145    * a message by joining |errors|. Consumers can use this to use assert/expect
1146    * functions asynchronously, but are then responsible for reporting errors to
1147    * the browser themselves through testDone().
1148    * @param {string} testFunction The function name to report on failure.
1149    * @param {Function} testBody The function to call.
1150    * @param {Array} testArguments The arguments to call |testBody| with.
1151    * @param {boolean} onlyAssertFails When true, only assertions cause failing
1152    *     testResult.
1153    * @return {Array.<boolean, string>} [test-succeeded, message-if-failed]
1154    * @see createExpect
1155    * @see testResult
1156    */
1157   function runTestFunction(testFunction, testBody, testArguments,
1158                            onlyAssertFails) {
1159     currentTestFunction = testFunction;
1160     currentTestArguments = testArguments;
1161     var ok = createExpect(testBody).apply(null, testArguments);
1162     return testResult(onlyAssertFails && ok);
1163   }
1165   /**
1166    * Creates a new test case for the given |testFixture| and |testName|. Assumes
1167    * |testFixture| describes a globally available subclass of type Test.
1168    * @param {string} testFixture The fixture for this test case.
1169    * @param {string} testName The name for this test case.
1170    * @return {TestCase} A newly created TestCase.
1171    */
1172   function createTestCase(testFixture, testName) {
1173     var fixtureConstructor = this[testFixture];
1174     var testBody = fixtureConstructor.testCaseBodies[testName];
1175     var fixture = new fixtureConstructor();
1176     fixture.name = testFixture;
1177     return new TestCase(testName, fixture, testBody);
1178   }
1180   /**
1181    * Overrides the |chrome| object to enable mocking calls to chrome.send().
1182    */
1183   function overrideChrome() {
1184     if (originalChrome) {
1185       console.error('chrome object already overridden');
1186       return;
1187     }
1189     originalChrome = chrome;
1190     chrome = {
1191       __proto__: originalChrome,
1192       send: send,
1193       originalSend: originalChrome.send.bind(originalChrome),
1194     };
1195   }
1197   /**
1198    * Used by WebUIBrowserTest to preload the javascript libraries at the
1199    * appropriate time for javascript injection into the current page. This
1200    * creates a test case and calls its preLoad for any early initialization such
1201    * as registering handlers before the page's javascript runs it's OnLoad
1202    * method. This is called before the page is loaded, so the |chrome| object is
1203    * not yet bound and this DOMContentLoaded listener will be called first to
1204    * override |chrome| in order to route messages registered in |sendCallbacks|.
1205    * @param {string} testFixture The test fixture name.
1206    * @param {string} testName The test name.
1207    * @see sendCallbacks
1208    */
1209   function preloadJavascriptLibraries(testFixture, testName) {
1210     deferGlobalOverrides = true;
1212     // The document seems to change from the point of preloading to the point of
1213     // events (and doesn't fire), whereas the window does not. Listening to the
1214     // capture phase allows this event to fire first.
1215     window.addEventListener('DOMContentLoaded', function() {
1216       overrideChrome();
1218       // Override globals at load time so they will be defined.
1219       assertTrue(deferGlobalOverrides);
1220       deferGlobalOverrides = false;
1221       for (var funcName in globalOverrides)
1222         overrideGlobal(funcName);
1223     }, true);
1224     currentTestCase = createTestCase(testFixture, testName);
1225     currentTestCase.preLoad();
1226   }
1228   /**
1229    * During generation phase, this outputs; do nothing at runtime.
1230    */
1231   function GEN() {}
1233   /**
1234    * During generation phase, this outputs; do nothing at runtime.
1235    */
1236   function GEN_INCLUDE() {}
1238   /**
1239    * At runtime, register the testName with a test fixture. Since this method
1240    * doesn't have a test fixture, create a dummy fixture to hold its |name|
1241    * and |testCaseBodies|.
1242    * @param {string} testCaseName The name of the test case.
1243    * @param {string} testName The name of the test function.
1244    * @param {Function} testBody The body to execute when running this test.
1245    */
1246   function TEST(testCaseName, testName, testBody) {
1247     var fixtureConstructor = this[testCaseName];
1248     if (fixtureConstructor === undefined) {
1249       fixtureConstructor = function() {};
1250       this[testCaseName] = fixtureConstructor;
1251       fixtureConstructor.prototype = {
1252         __proto__: Test.prototype,
1253         name: testCaseName,
1254       };
1255       fixtureConstructor.testCaseBodies = {};
1256     }
1257     fixtureConstructor.testCaseBodies[testName] = testBody;
1258   }
1260   /**
1261    * At runtime, register the testName with its fixture. Stuff the |name| into
1262    * the |testFixture|'s prototype, if needed, and the |testCaseBodies| into its
1263    * constructor.
1264    * @param {string} testFixture The name of the test fixture class.
1265    * @param {string} testName The name of the test function.
1266    * @param {Function} testBody The body to execute when running this test.
1267    */
1268   function TEST_F(testFixture, testName, testBody) {
1269     var fixtureConstructor = this[testFixture];
1270     if (!fixtureConstructor.prototype.name)
1271       fixtureConstructor.prototype.name = testFixture;
1272     if (fixtureConstructor['testCaseBodies'] === undefined)
1273       fixtureConstructor.testCaseBodies = {};
1274     fixtureConstructor.testCaseBodies[testName] = testBody;
1275   }
1277   /**
1278    * RunJavascriptTestF uses this as the |testFunction| when invoking
1279    * runTest. If |currentTestCase| is non-null at this point, verify that
1280    * |testFixture| and |testName| agree with the preloaded values. Create
1281    * |currentTestCase|, if needed, run it, and clear the |currentTestCase|.
1282    * @param {string} testFixture The name of the test fixture class.
1283    * @param {string} testName The name of the test function.
1284    * @see preloadJavascriptLibraries
1285    * @see runTest
1286    */
1287   function RUN_TEST_F(testFixture, testName) {
1288     if (!currentTestCase)
1289       currentTestCase = createTestCase(testFixture, testName);
1290     assertEquals(currentTestCase.name, testName);
1291     assertEquals(currentTestCase.fixture.name, testFixture);
1292     console.log('Running TestCase ' + testFixture + '.' + testName);
1293     currentTestCase.run();
1294   }
1296   /**
1297    * This Mock4JS matcher object pushes each |actualArgument| parameter to
1298    * match() calls onto |args|.
1299    * @param {Array} args The array to push |actualArgument| onto.
1300    * @param {Object} realMatcher The real matcher check arguments with.
1301    * @constructor
1302    * @extends {realMatcher}
1303    */
1304   function SaveMockArgumentMatcher(args, realMatcher) {
1305     this.arguments_ = args;
1306     this.realMatcher_ = realMatcher;
1307   }
1309   SaveMockArgumentMatcher.prototype = {
1310     /**
1311      * Holds the arguments to push each |actualArgument| onto.
1312      * @type {Array}
1313      * @private
1314      */
1315     arguments_: null,
1317     /**
1318      * The real Mock4JS matcher object to check arguments with.
1319      * @type {Object}
1320      */
1321     realMatcher_: null,
1323     /**
1324      * Pushes |actualArgument| onto |arguments_| and call |realMatcher_|. Clears
1325      * |arguments_| on non-match.
1326      * @param {*} actualArgument The argument to match and save.
1327      * @return {boolean} Result of calling the |realMatcher|.
1328      */
1329     argumentMatches: function(actualArgument) {
1330       this.arguments_.push(actualArgument);
1331       var match = this.realMatcher_.argumentMatches(actualArgument);
1332       if (!match)
1333         this.arguments_.splice(0, this.arguments_.length);
1335       return match;
1336     },
1338     /**
1339      * Proxy to |realMatcher_| for description.
1340      * @return {string} Description of this Mock4JS matcher.
1341      */
1342     describe: function() {
1343       return this.realMatcher_.describe();
1344     },
1345   };
1347   /**
1348    * Actions invoked by Mock4JS's "will()" syntax do not receive arguments from
1349    * the mocked method. This class works with SaveMockArgumentMatcher to save
1350    * arguments so that the invoked Action can pass arguments through to the
1351    * invoked function.
1352    * @param {!Object} realMatcher The real matcher to perform matching with.
1353    * @constructor
1354    */
1355   function SaveMockArguments() {
1356     this.arguments = [];
1357   }
1359   SaveMockArguments.prototype = {
1360     /**
1361      * Wraps the |realMatcher| with an object which will push its argument onto
1362      * |arguments| and call realMatcher.
1363      * @param {Object} realMatcher A Mock4JS matcher object for this argument.
1364      * @return {SaveMockArgumentMatcher} A new matcher which will push its
1365      *     argument onto |arguments|.
1366      */
1367     match: function(realMatcher) {
1368       return new SaveMockArgumentMatcher(this.arguments, realMatcher);
1369     },
1371     /**
1372      * Remember the argument passed to this stub invocation.
1373      * @type {Array}
1374      */
1375     arguments: null,
1376   };
1378   /**
1379    * CallFunctionAction is provided to allow mocks to have side effects.
1380    * @param {Object} obj The object to set |this| to when calling |func_|.
1381    * @param {?SaveMockArguments} savedArgs when non-null, saved arguments are
1382    *     passed to |func|.
1383    * @param {Function} func The function to call.
1384    * @param {Array=} args Any arguments to pass to func.
1385    * @constructor
1386    */
1387   function CallFunctionAction(obj, savedArgs, func, args) {
1388     this.obj_ = obj;
1389     this.savedArgs_ = savedArgs;
1390     this.func_ = func;
1391     this.args_ = args ? args : [];
1392   }
1394   CallFunctionAction.prototype = {
1395     /**
1396      * Set |this| to |obj_| when calling |func_|.
1397      * @type {?Object}
1398      */
1399     obj_: null,
1401     /**
1402      * The SaveMockArguments to hold arguments when invoking |func_|.
1403      * @type {?SaveMockArguments}
1404      * @private
1405      */
1406     savedArgs_: null,
1408     /**
1409      * The function to call when invoked.
1410      * @type {!Function}
1411      * @private
1412      */
1413     func_: null,
1415     /**
1416      * Arguments to pass to |func_| when invoked.
1417      * @type {!Array}
1418      */
1419     args_: null,
1421     /**
1422      * Accessor for |func_|.
1423      * @return {Function} The function to invoke.
1424      */
1425     get func() {
1426       return this.func_;
1427     },
1429     /**
1430      * Called by Mock4JS when using .will() to specify actions for stubs() or
1431      * expects(). Clears |savedArgs_| so it can be reused.
1432      * @return The results of calling |func_| with the concatenation of
1433      *     |savedArgs_| and |args_|.
1434      */
1435     invoke: function() {
1436       var prependArgs = [];
1437       if (this.savedArgs_) {
1438         prependArgs = this.savedArgs_.arguments.splice(
1439             0, this.savedArgs_.arguments.length);
1440       }
1441       return this.func.apply(this.obj_, prependArgs.concat(this.args_));
1442     },
1444     /**
1445      * Describe this action to Mock4JS.
1446      * @return {string} A description of this action.
1447      */
1448     describe: function() {
1449       return 'calls the given function with saved arguments and ' + this.args_;
1450     }
1451   };
1453   /**
1454    * Syntactic sugar for use with will() on a Mock4JS.Mock.
1455    * @param {Function} func The function to call when the method is invoked.
1456    * @param {...*} var_args Arguments to pass when calling func.
1457    * @return {CallFunctionAction} Action for use in will.
1458    */
1459   function callFunction(func) {
1460     return new CallFunctionAction(
1461         null, null, func, Array.prototype.slice.call(arguments, 1));
1462   }
1464   /**
1465    * Syntactic sugar for use with will() on a Mock4JS.Mock.
1466    * @param {SaveMockArguments} savedArgs Arguments saved with this object
1467    *     are passed to |func|.
1468    * @param {Function} func The function to call when the method is invoked.
1469    * @param {...*} var_args Arguments to pass when calling func.
1470    * @return {CallFunctionAction} Action for use in will.
1471    */
1472   function callFunctionWithSavedArgs(savedArgs, func) {
1473     return new CallFunctionAction(
1474         null, savedArgs, func, Array.prototype.slice.call(arguments, 2));
1475   }
1477   /**
1478    * CallGlobalAction as a subclass of CallFunctionAction looks up the original
1479    * global object in |globalOverrides| using |funcName| as the key. This allows
1480    * tests, which need to wait until a global function to be called in order to
1481    * start the test to run the original function. When used with runAllActions
1482    * or runAllActionsAsync, Mock4JS expectations may call start or continue the
1483    * test after calling the original function.
1484    * @param {?SaveMockArguments} savedArgs when non-null, saved arguments are
1485    *     passed to the global function |funcName|.
1486    * @param {string} funcName The name of the global function to call.
1487    * @param {Array} args Any arguments to pass to func.
1488    * @constructor
1489    * @extends {CallFunctionAction}
1490    * @see globalOverrides
1491    */
1492   function CallGlobalAction(savedArgs, funcName, args) {
1493     CallFunctionAction.call(this, null, savedArgs, funcName, args);
1494   }
1496   CallGlobalAction.prototype = {
1497     __proto__: CallFunctionAction.prototype,
1499     /**
1500      * Fetch and return the original global function to call.
1501      * @return {Function} The global function to invoke.
1502      * @override
1503      */
1504     get func() {
1505       var func = globalOverrides[this.func_].original;
1506       assertNotEquals(undefined, func);
1507       return func;
1508     },
1509   };
1511   /**
1512    * Syntactic sugar for use with will() on a Mock4JS.Mock.
1513    * @param {SaveMockArguments} savedArgs Arguments saved with this object
1514    *     are passed to the global function |funcName|.
1515    * @param {string} funcName The name of a registered mock global function to
1516    *     call when the method is invoked.
1517    * @param {...*} var_args Arguments to pass when calling func.
1518    * @return {CallGlobalAction} Action for use in Mock4JS will().
1519    */
1520   function callGlobalWithSavedArgs(savedArgs, funcName) {
1521     return new CallGlobalAction(
1522         savedArgs, funcName, Array.prototype.slice.call(arguments, 2));
1523   }
1525   /**
1526    * When to call testDone().
1527    * @enum {number}
1528    */
1529   var WhenTestDone = {
1530     /**
1531      * Default for the method called.
1532      */
1533     DEFAULT: -1,
1535     /**
1536      * Never call testDone().
1537      */
1538     NEVER: 0,
1540     /**
1541      * Call testDone() on assert failure.
1542      */
1543     ASSERT: 1,
1545     /**
1546      * Call testDone() if there are any assert or expect failures.
1547      */
1548     EXPECT: 2,
1550     /**
1551      * Always call testDone().
1552      */
1553     ALWAYS: 3,
1554   };
1556   /**
1557    * Runs all |actions|.
1558    * @param {boolean} isAsync When true, call testDone() on Errors.
1559    * @param {WhenTestDone} whenTestDone Call testDone() at the appropriate
1560    *     time.
1561    * @param {Array.<Object>} actions Actions to run.
1562    * @constructor
1563    */
1564   function RunAllAction(isAsync, whenTestDone, actions) {
1565     this.isAsync_ = isAsync;
1566     this.whenTestDone_ = whenTestDone;
1567     this.actions_ = actions;
1568   }
1570   RunAllAction.prototype = {
1571     /**
1572      * When true, call testDone() on Errors.
1573      * @type {boolean}
1574      * @private
1575      */
1576     isAsync_: false,
1578     /**
1579      * Call testDone() at appropriate time.
1580      * @type {WhenTestDone}
1581      * @private
1582      * @see WhenTestDone
1583      */
1584     whenTestDone_: WhenTestDone.ASSERT,
1586     /**
1587      * Holds the actions to execute when invoked.
1588      * @type {Array}
1589      * @private
1590      */
1591     actions_: null,
1593     /**
1594      * Runs all |actions_|, returning the last one. When running in sync mode,
1595      * throws any exceptions to be caught by runTest() or
1596      * runTestFunction(). Call testDone() according to |whenTestDone_| setting.
1597      */
1598     invoke: function() {
1599       try {
1600         var result;
1601         for(var i = 0; i < this.actions_.length; ++i)
1602           result = this.actions_[i].invoke();
1604         if ((this.whenTestDone_ == WhenTestDone.EXPECT && errors.length) ||
1605             this.whenTestDone_ == WhenTestDone.ALWAYS)
1606           testDone();
1608         return result;
1609       } catch (e) {
1610         if (!(e instanceof Error))
1611           e = new Error(e.toString());
1613         if (!this.isAsync_)
1614           throw e;
1616         errors.push(e);
1617         if (this.whenTestDone_ != WhenTestDone.NEVER)
1618           testDone();
1619       }
1620     },
1622     /**
1623      * Describe this action to Mock4JS.
1624      * @return {string} A description of this action.
1625      */
1626     describe: function() {
1627       return 'Calls all actions: ' + this.actions_;
1628     },
1629   };
1631   /**
1632    * Syntactic sugar for use with will() on a Mock4JS.Mock.
1633    * @param {...Object} var_actions Actions to run.
1634    * @return {RunAllAction} Action for use in will.
1635    */
1636   function runAllActions() {
1637     return new RunAllAction(false, WhenTestDone.NEVER,
1638                             Array.prototype.slice.call(arguments));
1639   }
1641   /**
1642    * Syntactic sugar for use with will() on a Mock4JS.Mock.
1643    * @param {WhenTestDone} whenTestDone Call testDone() at the appropriate
1644    *     time.
1645    * @param {...Object} var_actions Actions to run.
1646    * @return {RunAllAction} Action for use in will.
1647    */
1648   function runAllActionsAsync(whenTestDone) {
1649     return new RunAllAction(true, whenTestDone,
1650                             Array.prototype.slice.call(arguments, 1));
1651   }
1653   /**
1654    * Syntactic sugar for use with will() on a Mock4JS.Mock.
1655    * Creates an action for will() that invokes a callback that the tested code
1656    * passes to a mocked function.
1657    * @param {SaveMockArguments} savedArgs Arguments that will contain the
1658    *     callback once the mocked function is called.
1659    * @param {number} callbackParameter Index of the callback parameter in
1660    *     |savedArgs|.
1661    * @param {...Object} var_args Arguments to pass to the callback.
1662    * @return {CallFunctionAction} Action for use in will().
1663    */
1664   function invokeCallback(savedArgs, callbackParameter, var_args) {
1665     var callbackArguments = Array.prototype.slice.call(arguments, 2);
1666     return callFunction(function() {
1667       savedArgs.arguments[callbackParameter].apply(null, callbackArguments);
1669       // Mock4JS does not clear the saved args after invocation.
1670       // To allow reuse of the same SaveMockArguments for multiple
1671       // invocations with similar arguments, clear them here.
1672       savedArgs.arguments.splice(0, savedArgs.arguments.length);
1673     });
1674   }
1676   /**
1677    * Mock4JS matcher object that matches the actual argument and the expected
1678    * value iff their JSON represenations are same.
1679    * @param {Object} expectedValue
1680    * @constructor
1681    */
1682   function MatchJSON(expectedValue) {
1683     this.expectedValue_ = expectedValue;
1684   }
1686   MatchJSON.prototype = {
1687     /**
1688      * Checks that JSON represenation of the actual and expected arguments are
1689      * same.
1690      * @param {Object} actualArgument The argument to match.
1691      * @return {boolean} Result of the comparison.
1692      */
1693     argumentMatches: function(actualArgument) {
1694       return JSON.stringify(this.expectedValue_) ===
1695           JSON.stringify(actualArgument);
1696     },
1698     /**
1699      * Describes the matcher.
1700      * @return {string} Description of this Mock4JS matcher.
1701      */
1702     describe: function() {
1703       return 'eqJSON(' + JSON.stringify(this.expectedValue_) + ')';
1704     },
1705   };
1707   /**
1708    * Builds a MatchJSON argument matcher for a given expected value.
1709    * @param {Object} expectedValue
1710    * @return {MatchJSON} Resulting Mock4JS matcher.
1711    */
1712   function eqJSON(expectedValue) {
1713     return new MatchJSON(expectedValue);
1714   }
1716   /**
1717    * Mock4JS matcher object that matches the actual argument and the expected
1718    * value iff the the string representation of the actual argument is equal to
1719    * the expected value.
1720    * @param {string} expectedValue
1721    * @constructor
1722    */
1723   function MatchToString(expectedValue) {
1724     this.expectedValue_ = expectedValue;
1725   }
1727   MatchToString.prototype = {
1728     /**
1729      * Checks that the the string representation of the actual argument matches
1730      * the expected value.
1731      * @param {*} actualArgument The argument to match.
1732      * @return {boolean} Result of the comparison.
1733      */
1734     argumentMatches: function(actualArgument) {
1735       return this.expectedValue_ === String(actualArgument);
1736     },
1738     /**
1739      * Describes the matcher.
1740      * @return {string} Description of this Mock4JS matcher.
1741      */
1742     describe: function() {
1743       return 'eqToString("' + this.expectedValue_ + '")';
1744     },
1745   };
1747   /**
1748    * Builds a MatchToString argument matcher for a given expected value.
1749    * @param {Object} expectedValue
1750    * @return {MatchToString} Resulting Mock4JS matcher.
1751    */
1752   function eqToString(expectedValue) {
1753     return new MatchToString(expectedValue);
1754   }
1756   // Exports.
1757   testing.Test = Test;
1758   exports.testDone = testDone;
1759   exports.assertTrue = assertTrue;
1760   exports.assertFalse = assertFalse;
1761   exports.assertGE = assertGE;
1762   exports.assertGT = assertGT;
1763   exports.assertEquals = assertEquals;
1764   exports.assertLE = assertLE;
1765   exports.assertLT = assertLT;
1766   exports.assertNotEquals = assertNotEquals;
1767   exports.assertNotReached = assertNotReached;
1768   exports.assertAccessibilityOk = assertAccessibilityOk;
1769   exports.callFunction = callFunction;
1770   exports.callFunctionWithSavedArgs = callFunctionWithSavedArgs;
1771   exports.callGlobalWithSavedArgs = callGlobalWithSavedArgs;
1772   exports.eqJSON = eqJSON;
1773   exports.eqToString = eqToString;
1774   exports.expectTrue = createExpect(assertTrue);
1775   exports.expectFalse = createExpect(assertFalse);
1776   exports.expectGE = createExpect(assertGE);
1777   exports.expectGT = createExpect(assertGT);
1778   exports.expectEquals = createExpect(assertEquals);
1779   exports.expectLE = createExpect(assertLE);
1780   exports.expectLT = createExpect(assertLT);
1781   exports.expectNotEquals = createExpect(assertNotEquals);
1782   exports.expectNotReached = createExpect(assertNotReached);
1783   exports.expectAccessibilityOk = createExpect(assertAccessibilityOk);
1784   exports.invokeCallback = invokeCallback;
1785   exports.preloadJavascriptLibraries = preloadJavascriptLibraries;
1786   exports.registerMessageCallback = registerMessageCallback;
1787   exports.registerMockGlobals = registerMockGlobals;
1788   exports.registerMockMessageCallbacks = registerMockMessageCallbacks;
1789   exports.resetTestState = resetTestState;
1790   exports.runAccessibilityAudit = runAccessibilityAudit;
1791   exports.runAllActions = runAllActions;
1792   exports.runAllActionsAsync = runAllActionsAsync;
1793   exports.runTest = runTest;
1794   exports.runTestFunction = runTestFunction;
1795   exports.SaveMockArguments = SaveMockArguments;
1796   exports.DUMMY_URL = DUMMY_URL;
1797   exports.TEST = TEST;
1798   exports.TEST_F = TEST_F;
1799   exports.RUNTIME_TEST_F = TEST_F;
1800   exports.GEN = GEN;
1801   exports.GEN_INCLUDE = GEN_INCLUDE;
1802   exports.WhenTestDone = WhenTestDone;
1804   // Import the Mock4JS helpers.
1805   Mock4JS.addMockSupport(exports);
1806 })(this);