Don't show supervised user as "already on this device" while they're being imported.
[chromium-blink-merge.git] / remoting / webapp / crd / js / mock_xhr.js
blob0e96f784d1a6a125ab901cb96694c582ef84ed17
1 // Copyright (c) 2015 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 A mock version of remoting.Xhr.  Compared to
7  * sinon.useMockXhr, this allows unit tests to be written at a higher
8  * level, and it eliminates a fair amount of boilerplate involved in
9  * making the sinon mocks work with asynchronous calls
10  * (cf. gcd_client_unittest.js vs. gcd_client_with_mock_xhr.js for an
11  * example).
12  */
14 (function() {
15 'use strict';
17 /**
18  * @constructor
19  * @param {remoting.Xhr.Params} params
20  */
21 remoting.MockXhr = function(params) {
22   origXhr['checkParams_'](params);
24   /** @const {remoting.Xhr.Params} */
25   this.params = normalizeParams(params);
27   /** @private {base.Deferred<!remoting.Xhr.Response>} */
28   this.deferred_ = null;
30   /** @type {remoting.Xhr.Response} */
31   this.response_ = null;
33   /** @type {boolean} */
34   this.aborted_ = false;
37 /**
38  * Converts constuctor parameters to a normalized form that hides
39  * details of how the constructor is called.
40  * @param {remoting.Xhr.Params} params
41  * @return {remoting.Xhr.Params} The argument with all missing fields
42  *     filled in with default values.
43  */
44 var normalizeParams = function(params) {
45   return {
46     method: params.method,
47     url: params.url,
48     urlParams: typeof params.urlParams == 'object' ?
49         base.copyWithoutNullFields(params.urlParams) :
50         params.urlParams,
51     textContent: params.textContent,
52     jsonContent: params.jsonContent,
53     formContent: params.formContent === undefined ? undefined :
54         base.copyWithoutNullFields(params.formContent),
55     headers: base.copyWithoutNullFields(params.headers),
56     withCredentials: Boolean(params.withCredentials),
57     oauthToken: params.oauthToken,
58     useIdentity: Boolean(params.useIdentity),
59     acceptJson: Boolean(params.acceptJson)
60   };
63 /**
64  * Psuedo-override from remoting.Xhr.
65  * @return {void}
66  */
67 remoting.MockXhr.prototype.abort = function() {
68   this.aborted_ = true;
71 /**
72  * Psuedo-override from remoting.Xhr.
73  * @return {!Promise<!remoting.Xhr.Response>}
74  */
75 remoting.MockXhr.prototype.start = function() {
76   runMatchingHandler(this);
77   if (!this.deferred_) {
78     this.deferred_ = new base.Deferred();
79     this.maybeRespond_();
80   }
81   return this.deferred_.promise();
84 /**
85  * Tells this object to send an empty response to the current or next
86  * request.
87  * @param {number} status The HTTP status code to respond with.
88  */
89 remoting.MockXhr.prototype.setEmptyResponse = function(status) {
90   this.setResponse_(new remoting.Xhr.Response(
91       status,
92       'mock status text from setEmptyResponse',
93       null,
94       '',
95       false));
98 /**
99  * Tells this object to send a text/plain response to the current or
100  * next request.
101  * @param {number} status The HTTP status code to respond with.
102  * @param {string} body The content to respond with.
103  */
104 remoting.MockXhr.prototype.setTextResponse = function(status, body) {
105   this.setResponse_(new remoting.Xhr.Response(
106       status,
107       'mock status text from setTextResponse',
108       null,
109       body || '',
110       false));
114  * Tells this object to send an application/json response to the
115  * current or next request.
116  * @param {number} status The HTTP status code to respond with.
117  * @param {*} body The content to respond with.
118  */
119 remoting.MockXhr.prototype.setJsonResponse = function(status, body) {
120   if (!this.params.acceptJson) {
121     throw new Error('client does not want JSON response');
122   }
123   this.setResponse_(new remoting.Xhr.Response(
124       status,
125       'mock status text from setJsonResponse',
126       null,
127       JSON.stringify(body),
128       true));
132  * Sets the response to be used for the current or next request.
133  * @param {!remoting.Xhr.Response} response
134  * @private
135  */
136 remoting.MockXhr.prototype.setResponse_ = function(response) {
137   base.debug.assert(this.response_ == null);
138   this.response_ = response;
139   this.maybeRespond_();
143  * Sends a response if one is available.
144  * @private
145  */
146 remoting.MockXhr.prototype.maybeRespond_ = function() {
147   if (this.deferred_ && this.response_ && !this.aborted_) {
148     this.deferred_.resolve(this.response_);
149   }
153  * The original value of the remoting.Xhr constructor.  The JSDoc type
154  * is that of the remoting.Xhr constructor function.
155  * @type {?function(this: remoting.Xhr, remoting.Xhr.Params):void}
156  */
157 var origXhr = null;
160  * @type {!Array<remoting.MockXhr.UrlHandler>}
161  */
162 var handlers = [];
165  * Registers a handler for a given method and URL.  The |urlPattern|
166  * argument may either be a string, which must equal a URL to match
167  * it, or a RegExp.
169  * Matching handlers are run when a FakeXhr's |start| method is
170  * called.  The handler should generally call one of
171  * |set{Test,Json,Empty}Response|
173  * @param {?string} method The HTTP method to respond to, or null to
174  *     respond to any method.
175  * @param {?string|!RegExp} urlPattern The URL or pattern to respond
176  *     to, or null to match any URL.
177  * @param {function(!remoting.MockXhr):void} callback The handler
178  *     function to call when a matching XHR is started.
179  * @param {boolean=} opt_reuse If true, the response can be used for
180  *     multiple requests.
181  */
182 remoting.MockXhr.setResponseFor = function(
183     method, urlPattern, callback, opt_reuse) {
184   handlers.push({
185     method: method,
186     urlPattern: urlPattern,
187     callback: callback,
188     reuse: !!opt_reuse
189   });
193  * Installs a response with no content.  See |setResponseFor| for
194  * more details on how the parameters work.
196  * @param {?string} method
197  * @param {?string|!RegExp} urlPattern
198  * @param {number=} opt_status The status code to return.
199  * @param {boolean=} opt_reuse
200  */
201 remoting.MockXhr.setEmptyResponseFor = function(
202     method, urlPattern, opt_status, opt_reuse) {
203   remoting.MockXhr.setResponseFor(
204       method, urlPattern, function(/** remoting.MockXhr */ xhr) {
205         xhr.setEmptyResponse(opt_status === undefined ? 204 : opt_status);
206       }, opt_reuse);
210  * Installs a 200 response with text content.  See |setResponseFor|
211  * for more details on how the parameters work.
213  * @param {?string} method
214  * @param {?string|!RegExp} urlPattern
215  * @param {string} content
216  * @param {boolean=} opt_reuse
217  */
218 remoting.MockXhr.setTextResponseFor = function(
219     method, urlPattern, content, opt_reuse) {
220   remoting.MockXhr.setResponseFor(
221       method, urlPattern, function(/** remoting.MockXhr */ xhr) {
222         xhr.setTextResponse(200, content);
223       }, opt_reuse);
227  * Installs a 200 response with JSON content.  See |setResponseFor|
228  * for more details on how the parameters work.
230  * @param {?string} method
231  * @param {?string|!RegExp} urlPattern
232  * @param {*} content
233  * @param {boolean=} opt_reuse
234  */
235 remoting.MockXhr.setJsonResponseFor = function(
236     method, urlPattern, content, opt_reuse) {
237   remoting.MockXhr.setResponseFor(
238       method, urlPattern, function(/** remoting.MockXhr */ xhr) {
239         xhr.setJsonResponse(200, content);
240       }, opt_reuse);
244  * Runs the most first handler for a given method and URL.
245  * @param {!remoting.MockXhr} xhr
246  */
247 var runMatchingHandler = function(xhr) {
248   for (var i = 0; i < handlers.length; i++) {
249     var handler = handlers[i];
250     if (handler.method == null || handler.method != xhr.params.method) {
251       continue;
252     }
253     if (handler.urlPattern == null) {
254       // Let the handler run.
255     } else if (typeof handler.urlPattern == 'string') {
256       if (xhr.params.url != handler.urlPattern) {
257         continue;
258       }
259     } else {
260       var regexp = /** @type {RegExp} */ (handler.urlPattern);
261       if (!regexp.test(xhr.params.url)) {
262         continue;
263       }
264     }
265     if (!handler.reuse) {
266       handlers.splice(i, 1);
267     }
268     handler.callback(xhr);
269     return;
270   };
271   throw new Error(
272       'No handler registered for ' + xhr.params.method +
273       ' to '+ xhr.params.url);
277  * Activates this mock.
278  */
279 remoting.MockXhr.activate = function() {
280   base.debug.assert(
281       origXhr == null,
282       'Xhr mocking already active');
283   origXhr = remoting.Xhr;
284   remoting.MockXhr.Response = remoting.Xhr.Response;
285   remoting['Xhr'] = remoting.MockXhr;
289  * Restores the original definiton of |remoting.Xhr|.
290  */
291 remoting.MockXhr.restore = function() {
292   base.debug.assert(
293       origXhr != null,
294       'Xhr mocking not active');
295   remoting['Xhr'] = origXhr;
296   origXhr = null;
297   handlers = [];
300 })();
302 // Can't put put typedefs inside a function :-(
304  * @typedef {{
305  *   method:?string,
306  *   urlPattern:(?string|RegExp),
307  *   callback:function(!remoting.MockXhr):void,
308  *   reuse:boolean
309  * }}
310  */
311 remoting.MockXhr.UrlHandler;