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
40 * @suppress {reportUnknownTypes}
42 chromeMocks.Event.prototype.mock$fire = function(var_args) {
43 var params = Array.prototype.slice.call(arguments);
44 this.listeners_.forEach(
45 /** @param {Function} listener */
47 listener.apply(null, params);
52 chromeMocks.runtime = {};
55 chromeMocks.runtime.Port = function() {
57 this.onMessage = new chromeMocks.Event();
60 this.onDisconnect = new chromeMocks.Event();
65 /** @type {MessageSender} */
69 chromeMocks.runtime.Port.prototype.disconnect = function() {};
72 * @param {Object} message
74 chromeMocks.runtime.Port.prototype.postMessage = function(message) {};
76 /** @type {chromeMocks.Event} */
77 chromeMocks.runtime.onMessage = new chromeMocks.Event();
80 /** @type {chromeMocks.Event} */
81 chromeMocks.runtime.onSuspend = new chromeMocks.Event();
84 * @param {string?} extensionId
86 * @param {function(*)=} responseCallback
88 chromeMocks.runtime.sendMessage = function(extensionId, message,
92 'The mock only supports sending messages to the same extension.');
93 extensionId = chrome.runtime.id;
94 Promise.resolve().then(function() {
95 var message_copy = base.deepCopy(message);
96 chromeMocks.runtime.onMessage.mock$fire(
97 message_copy, {id: extensionId}, responseCallback);
102 * Always returns the same mock port for given application name.
103 * @param {string} application
104 * @return {chromeMocks.runtime.Port}
106 chromeMocks.runtime.connectNative = function(application) {
107 var port = nativePorts[application];
108 if (port === undefined) {
109 port = new chromeMocks.runtime.Port();
110 port.name = application;
111 nativePorts[application] = port;
116 /** @const {Object<!chromeMocks.runtime.Port>} */
117 var nativePorts = null;
119 /** @type {string} */
120 chromeMocks.runtime.id = 'extensionId';
122 /** @type {Object} */
123 chromeMocks.runtime.lastError = {
124 /** @type {string|undefined} */
128 chromeMocks.runtime.getManifest = function() {
137 // Sample implementation of chrome.StorageArea according to
138 // https://developer.chrome.com/apps/storage#type-StorageArea
141 * @extends {StorageArea}
143 chromeMocks.StorageArea = function() {
144 /** @type {!Object} */
149 * @param {Object|string} keys
150 * @return {Array<string>}
152 function getKeys(keys) {
153 if (typeof keys === 'string') {
155 } else if (typeof keys === 'object') {
156 var objectKeys = /** @type {!Object} */ (keys);
157 return Object.keys(objectKeys);
162 chromeMocks.StorageArea.prototype.get = function(keys, onDone) {
164 // No keys are specified, returns the entire storage.
165 var storageCopy = base.deepCopy(this.storage_);
166 onDone(/** @type {Object} */ (storageCopy));
170 var result = (typeof keys === 'object') ? keys : {};
171 getKeys(keys).forEach(
172 /** @param {string} key */
174 if (key in this.storage_) {
175 result[key] = base.deepCopy(this.storage_[key]);
181 chromeMocks.StorageArea.prototype.set = function(value, opt_onDone) {
182 for (var key in value) {
183 this.storage_[key] = base.deepCopy(value[key]);
190 chromeMocks.StorageArea.prototype.remove = function(keys, opt_onDone) {
191 getKeys(keys).forEach(
192 /** @param {string} key */
194 delete this.storage_[key];
201 /** @return {!Object} */
202 chromeMocks.StorageArea.prototype.mock$getStorage = function() {
203 return this.storage_;
206 chromeMocks.StorageArea.prototype.clear = function() {
210 /** @type {Object} */
211 chromeMocks.storage = {};
213 /** @type {chromeMocks.StorageArea} */
214 chromeMocks.storage.local = new chromeMocks.StorageArea();
218 chromeMocks.Identity = function() {
219 /** @private {string|undefined} */
220 this.token_ = undefined;
224 * @param {Object} options
225 * @param {function(string=):void} callback
227 chromeMocks.Identity.prototype.getAuthToken = function(options, callback) {
228 // Append the 'scopes' array, if present, to the dummy token.
229 var token = this.token_;
230 if (token !== undefined && options['scopes'] !== undefined) {
231 token += JSON.stringify(options['scopes']);
233 // Don't use setTimeout because sinon mocks it.
234 Promise.resolve().then(callback.bind(null, token));
237 /** @param {string} token */
238 chromeMocks.Identity.prototype.mock$setToken = function(token) {
242 chromeMocks.Identity.prototype.mock$clearToken = function() {
243 this.token_ = undefined;
246 /** @type {chromeMocks.Identity} */
247 chromeMocks.identity;
250 chromeMocks.MetricsPrivate = function() {};
252 chromeMocks.MetricsPrivate.prototype.recordValue = function() {};
254 /** @type {chromeMocks.MetricsPrivate} */
255 chromeMocks.metricsPrivate;
258 chromeMocks.I18n = function() {};
261 * @param {string} messageName
262 * @param {(string|Array<string>)=} opt_args
265 chromeMocks.I18n.prototype.getMessage = function(messageName, opt_args) {};
270 chromeMocks.I18n.prototype.getUILanguage = function() {};
273 chromeMocks.WindowManager = function() {
274 this.current_ = new chromeMocks.AppWindow();
277 chromeMocks.WindowManager.prototype.current = function() {
278 return this.current_;
282 chromeMocks.AppWindow = function() {};
284 var originals_ = null;
287 * Activates a list of Chrome components to mock
289 chromeMocks.activate = function() {
291 throw new Error('chromeMocks.activate() can only be called once.');
296 chromeMocks.i18n = new chromeMocks.I18n();
297 chromeMocks.identity = new chromeMocks.Identity();
298 chromeMocks.metricsPrivate = new chromeMocks.MetricsPrivate();
300 ['identity', 'i18n', 'runtime', 'storage', 'metricsPrivate'].forEach(
301 function(/** string */ component) {
302 if (!chromeMocks[component]) {
303 throw new Error('No mocks defined for chrome.' + component);
305 originals_[component] = chrome[component];
306 chrome[component] = chromeMocks[component];
309 chrome.app['window'] = new chromeMocks.WindowManager();
312 chromeMocks.restore = function() {
314 throw new Error('You must call activate() before restore().');
316 for (var components in originals_) {
317 chrome[components] = originals_[components];