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 // This file contains various mock objects for the chrome platform to make
6 // unit testing easier.
16 * @extends {ChromeEvent}
18 chromeMocks.Event = function() {
22 /** @param {Function} callback */
23 chromeMocks.Event.prototype.addListener = function(callback) {
24 this.listeners_.push(callback);
27 /** @param {Function} callback */
28 chromeMocks.Event.prototype.removeListener = function(callback) {
29 for (var i = 0; i < this.listeners_.length; i++) {
30 if (this.listeners_[i] === callback) {
31 this.listeners_.splice(i, 1);
38 * @param {...*} var_args
41 chromeMocks.Event.prototype.mock$fire = function(var_args) {
42 var params = Array.prototype.slice.call(arguments);
43 this.listeners_.forEach(
44 /** @param {Function} listener */
46 listener.apply(null, params);
51 chromeMocks.runtime = {};
54 chromeMocks.runtime.Port = function() {
56 this.onMessage = new chromeMocks.Event();
59 this.onDisconnect = new chromeMocks.Event();
64 /** @type {MessageSender} */
68 chromeMocks.runtime.Port.prototype.disconnect = function() {};
71 * @param {Object} message
73 chromeMocks.runtime.Port.prototype.postMessage = function(message) {};
75 /** @type {chromeMocks.Event} */
76 chromeMocks.runtime.onMessage = new chromeMocks.Event();
79 * @param {string?} extensionId
81 * @param {function(*)=} responseCallback
83 chromeMocks.runtime.sendMessage = function(extensionId, message,
87 'The mock only supports sending messages to the same extension.');
88 extensionId = chrome.runtime.id;
89 window.requestAnimationFrame(function() {
90 var message_copy = base.deepCopy(message);
91 chromeMocks.runtime.onMessage.mock$fire(
92 message_copy, {id: extensionId}, responseCallback);
97 * Always returns the same mock port for given application name.
98 * @param {string} application
99 * @return {chromeMocks.runtime.Port}
101 chromeMocks.runtime.connectNative = function(application) {
102 var port = nativePorts[application];
103 if (port === undefined) {
104 port = new chromeMocks.runtime.Port();
105 port.name = application;
106 nativePorts[application] = port;
111 /** @const {Object<string,!chromeMocks.runtime.Port>} */
112 var nativePorts = null;
114 /** @type {string} */
115 chromeMocks.runtime.id = 'extensionId';
117 /** @type {Object} */
118 chromeMocks.runtime.lastError = {
119 /** @type {string|undefined} */
124 // Sample implementation of chrome.StorageArea according to
125 // https://developer.chrome.com/apps/storage#type-StorageArea
127 chromeMocks.StorageArea = function() {
128 /** @type {Object} */
133 * @param {!Object} keys
134 * @return {Array<string>}
136 function getKeys(keys) {
137 if (typeof keys === 'string') {
139 } else if (typeof keys === 'object') {
140 return Object.keys(keys);
146 * @param {!Object} keys
147 * @param {Function} onDone
149 chromeMocks.StorageArea.prototype.get = function(keys, onDone) {
151 onDone(base.deepCopy(this.storage_));
155 var result = (typeof keys === 'object') ? keys : {};
156 getKeys(keys).forEach(
157 /** @param {string} key */
159 if (key in this.storage_) {
160 result[key] = base.deepCopy(this.storage_[key]);
166 /** @param {Object} value */
167 chromeMocks.StorageArea.prototype.set = function(value) {
168 for (var key in value) {
169 this.storage_[key] = base.deepCopy(value[key]);
174 * @param {!Object} keys
176 chromeMocks.StorageArea.prototype.remove = function(keys) {
177 getKeys(keys).forEach(
178 /** @param {string} key */
180 delete this.storage_[key];
184 chromeMocks.StorageArea.prototype.clear = function() {
185 this.storage_ = null;
188 /** @type {Object} */
189 chromeMocks.storage = {};
191 /** @type {chromeMocks.StorageArea} */
192 chromeMocks.storage.local = new chromeMocks.StorageArea();
196 chromeMocks.Identity = function() {
197 /** @private {string|undefined} */
198 this.token_ = undefined;
202 * @param {Object} options
203 * @param {function(string=):void} callback
205 chromeMocks.Identity.prototype.getAuthToken = function(options, callback) {
206 // Append the 'scopes' array, if present, to the dummy token.
207 var token = this.token_;
208 if (token !== undefined && options['scopes'] !== undefined) {
209 token += JSON.stringify(options['scopes']);
211 // Don't use setTimeout because sinon mocks it.
212 window.requestAnimationFrame(callback.bind(null, token));
215 /** @param {string} token */
216 chromeMocks.Identity.prototype.mock$setToken = function(token) {
220 chromeMocks.Identity.prototype.mock$clearToken = function() {
221 this.token_ = undefined;
224 /** @type {chromeMocks.Identity} */
225 chromeMocks.identity;
229 chromeMocks.I18n = function() {};
232 * @param {string} messageName
233 * @param {(string|Array<string>)=} opt_args
236 chromeMocks.I18n.prototype.getMessage = function(messageName, opt_args) {};
241 chromeMocks.I18n.prototype.getUILanguage = function() {};
244 chromeMocks.WindowManager = function() {};
246 chromeMocks.WindowManager.prototype.current = function() {
247 return new chromeMocks.AppWindow();
251 chromeMocks.AppWindow = function() {};
253 var originals_ = null;
256 * Activates a list of Chrome components to mock
258 chromeMocks.activate = function() {
260 throw new Error('chromeMocks.activate() can only be called once.');
265 chromeMocks.i18n = new chromeMocks.I18n();
266 chromeMocks.identity = new chromeMocks.Identity();
268 ['identity', 'i18n', 'runtime', 'storage'].forEach(
269 function(/** string */ component) {
270 if (!chromeMocks[component]) {
271 throw new Error('No mocks defined for chrome.' + component);
273 originals_[component] = chrome[component];
274 chrome[component] = chromeMocks[component];
277 chrome.app['window'] = new chromeMocks.WindowManager();
280 chromeMocks.restore = function() {
282 throw new Error('You must call activate() before restore().');
284 for (var components in originals_) {
285 chrome[components] = originals_[components];