Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(74)

Side by Side Diff: remoting/webapp/crd/js/mock_xhr.js

Issue 1055313002: Added mock_xhr module w/ unit tests. (Closed) Base URL: https://chromium.googlesource.com/chromium/src.git@master
Patch Set: Created 5 years, 8 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch
OLDNEW
(Empty)
1 // Copyright (c) 2015 The Chromium Authors. All rights reserved.
John Williams 2015/04/02 23:57:06 The main file for this CL. Needs more docs, I kno
Jamie 2015/04/03 01:45:57 No (c) needed
Jamie 2015/04/03 01:45:57 Doesn't sinon already support mocking out XMLHttpR
John Williams 2015/04/04 01:40:26 Because it's a test file, or because we're phasing
John Williams 2015/04/04 01:40:26 Done.
Jamie 2015/04/06 19:24:03 It's not needed for any new files (for the past ye
2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file.
4
5 /**
6 * @fileoverview
7 * A mock version of remoting.Xhr.
8 */
9
10 (function() {
11 'use strict';
12
13 /**
14 * @constructor
15 * @param {remoting.Xhr.Params} params
Jamie 2015/04/03 01:45:57 Would it make sense to declare this as @extends {X
John Williams 2015/04/04 01:40:26 Doing that causes the compiler to check for privat
Jamie 2015/04/06 19:24:03 Acknowledged.
16 */
17 remoting.MockXhr = function(params) {
18 origXhr['checkParams_'](params);
19
20 /** @const {remoting.Xhr.Params} */
21 this.params = normalizeParams(params);
22
23
Jamie 2015/04/03 01:45:57 Duplicate blank line.
John Williams 2015/04/04 01:40:26 Done.
24 /** @private {base.Deferred<!remoting.Xhr.Response>} */
25 this.deferred_ = null;
26
27 /** @type {remoting.Xhr.Response} */
28 this.response_ = null;
29
30 /** @type {boolean} */
31 this.aborted_ = false;
32 };
33
34 /**
35 * @param {remoting.Xhr.Params} params
36 * @return {remoting.Xhr.Params} The argument with all missing fields
37 * filled in with default values.
38 */
39 var normalizeParams = function(params) {
40 return {
41 method: params.method,
42 url: params.url,
43 urlParams: typeof params.urlParams == 'object' ?
44 base.copyWithoutNullFields(params.urlParams) :
45 params.urlParams,
46 textContent: params.textContent,
47 jsonContent: params.jsonContent,
48 formContent: params.formContent ||
49 base.copyWithoutNullFields(params.formContent),
Jamie 2015/04/03 01:45:57 You're only calling copyWithoutNullFields if its p
John Williams 2015/04/04 01:40:26 Having formContent === undefined is a special case
Jamie 2015/04/06 19:24:03 That's not what this does, I don't think. If param
John Williams 2015/04/06 23:46:13 I changed it to be more explicit about undefined.
50 headers: base.copyWithoutNullFields(params.headers),
51 withCredentials: !!params.withCredentials,
Jamie 2015/04/03 01:45:57 Prefer Boolean(x) to !!x for clarity.
John Williams 2015/04/04 01:40:26 Done.
52 oauthToken: params.oauthToken == null : null params.oauthToken,
Jamie 2015/04/03 01:45:57 This doesn't look right.
John Williams 2015/04/04 01:40:26 Yeah, I was in a hurry to get this CL out before I
53 useIdentity: !!params.useIdentity,
54 acceptJson: !!params.acceptJson
55 };
56 };
57
58 //////////////////////////////////////////////////////////////////////////////
59 //
60 // Mock implementation.
61 //
Jamie 2015/04/03 01:45:57 I don't think we have a big block comment like thi
62
63 /**
64 * @return {void}
65 */
66 remoting.MockXhr.prototype.abort = function() {
67 this.aborted_ = true;
68 };
69
70 /**
71 * @return {!Promise<!remoting.Xhr.Response>}
72 */
73 remoting.MockXhr.prototype.start = function() {
74 runMatchingHandler(this);
75 if (!this.deferred_) {
76 this.deferred_ = new base.Deferred();
77 this.maybeRespond_();
78 }
79 return this.deferred_.promise();
80 };
81
82 //////////////////////////////////////////////////////////////////////////////
83 //
84 // Mock-specific methods.
85 //
86
87 /**
88 * @param {number} status
Jamie 2015/04/03 01:45:57 I think this (and subsequent) methods should be @p
John Williams 2015/04/04 01:40:26 They need to be called by user code (see the unit
89 */
90 remoting.MockXhr.prototype.setEmptyResponse = function(status) {
91 this.setResponse_(new remoting.Xhr.Response(
92 status,
93 'mock status text from setEmptyResponse',
94 null,
95 '',
96 false));
97 };
98
99 /**
100 * @param {number} status
101 * @param {string} body
102 */
103 remoting.MockXhr.prototype.setTextResponse = function(status, body) {
104 this.setResponse_(new remoting.Xhr.Response(
105 status,
106 'mock status text from setTextResponse',
107 null,
108 body || '',
109 false));
110 };
111
112 /**
113 * @param {number} status
114 * @param {*} body
115 */
116 remoting.MockXhr.prototype.setJsonResponse = function(status, body) {
117 if (!this.params.acceptJson) {
118 throw new Error('client does not want JSON response');
119 }
120 this.setResponse_(new remoting.Xhr.Response(
121 status,
122 'mock status text from setJsonResponse',
123 null,
124 JSON.stringify(body),
125 true));
126 };
127
128 /**
129 * @param {!remoting.Xhr.Response} response
130 */
131 remoting.MockXhr.prototype.setResponse_ = function(response) {
Jamie 2015/04/03 01:45:57 I think this (and some other) methods should be @p
John Williams 2015/04/04 01:40:26 Done.
132 base.debug.assert(this.response_ == null);
133 this.response_ = response;
134 this.maybeRespond_();
135 };
136
137 remoting.MockXhr.prototype.maybeRespond_ = function() {
138 if (this.deferred_ && this.response_ && !this.aborted_) {
139 this.deferred_.resolve(this.response_);
140 }
141 };
142
143 /** @type {*} */
Jamie 2015/04/03 01:45:57 Can you be more specific about the type of this?
John Williams 2015/04/04 01:40:26 It's a pretty ugly type, but OK.
Jamie 2015/04/06 19:24:03 Yuck; that is horrible. I was thinking it would be
John Williams 2015/04/06 23:46:13 Done.
144 var origXhr = null;
145
146 /**
147 * @type {!Array<remoting.MockXhr.UrlHandler>}
148 */
149 var handlers = [];
150
151 /**
152 * Registers a handler for a given method and URL. The |urlPattern|
153 * argument may either be a string, which must equal a URL to match
154 * it, or a RegExp, which is matched against URLs with the |test|
Jamie 2015/04/03 01:45:57 I don't think "with the test method" adds any valu
John Williams 2015/04/04 01:40:26 Hmm. You're right. I'm used to there being two met
155 * method.
156 *
157 * Matching handlers are run when a FakeXhr's |start| method is called.
158 *
159 * @param {?string} method The HTTP method to respond to, or null to
160 * response to any method.
Jamie 2015/04/03 01:45:57 s/response/respond/
John Williams 2015/04/04 01:40:26 Done.
161 * @param {?string|!RegExp} urlPattern The URL or pattern to respond
162 * to, or null to match any URL.
163 * @param {function(!remoting.MockXhr):void} proc The function to call
Jamie 2015/04/03 01:45:57 |callback| would be a more conventional name for t
John Williams 2015/04/04 01:40:26 Done.
164 * when a matching XHR is started.
165 * @param {boolean=} opt_reuse If true, the response can be used for
166 * multiple requests.
167 */
168 remoting.MockXhr.setResponseFor = function(
169 method, urlPattern, proc, opt_reuse) {
170 handlers.push({
171 method: method,
172 urlPattern: urlPattern,
173 proc: proc,
174 reuse: !!opt_reuse
175 });
176 };
177
178 /**
179 * Calls |setResponseFor| to add a 200 response with text content.
Jamie 2015/04/03 01:45:57 s/200/204/ s/with text content/(no content)/ I wo
John Williams 2015/04/04 01:40:26 Done. I said "calls |setResponseFor|" because |se
Jamie 2015/04/06 19:24:03 Either copy them, or add a "see setResponseFor" co
John Williams 2015/04/06 23:46:13 Done.
180 *
181 * @param {?string} method
182 * @param {?string|!RegExp} urlPattern
183 * @param {boolean=} opt_reuse
184 */
185 remoting.MockXhr.setEmptyResponseFor = function(method, urlPattern, opt_reuse) {
186 remoting.MockXhr.setResponseFor(
187 method, urlPattern, function(/** remoting.MockXhr */ xhr) {
188 xhr.setEmptyResponse(204);
189 }, opt_reuse);
190 };
191
192 /**
193 * Calls |setResponseFor| to add a 200 response with text content.
194 *
195 * @param {?string} method
196 * @param {?string|!RegExp} urlPattern
197 * @param {string} content
198 * @param {boolean=} opt_reuse
199 */
200 remoting.MockXhr.setTextResponseFor = function(
201 method, urlPattern, content, opt_reuse) {
202 remoting.MockXhr.setResponseFor(
203 method, urlPattern, function(/** remoting.MockXhr */ xhr) {
204 xhr.setTextResponse(200, content);
205 }, opt_reuse);
206 };
207
208 /**
209 * Calls |setResponseFor| to add a 200 response with JSON content.
210 *
211 * @param {?string} method
212 * @param {?string|!RegExp} urlPattern
213 * @param {*} content
214 * @param {boolean=} opt_reuse
215 */
216 remoting.MockXhr.setJsonResponseFor = function(
217 method, urlPattern, content, opt_reuse) {
218 remoting.MockXhr.setResponseFor(
219 method, urlPattern, function(/** remoting.MockXhr */ xhr) {
220 xhr.setJsonResponse(200, content);
221 }, opt_reuse);
222 };
223
224 /**
225 * Runs the most first handler for a given method and URL.
226 * @param {!remoting.MockXhr} xhr
227 */
228 var runMatchingHandler = function(xhr) {
229 for (var i = 0; i < handlers.length; i++) {
230 var handler = handlers[i];
231 if (handler.method == null || handler.method != xhr.params.method) {
232 continue;
233 }
234 if (handler.urlPattern == null) {
235 // Let the handler run.
236 } else if (typeof handler.urlPattern == 'string') {
237 if (xhr.params.url != handler.urlPattern) {
238 continue;
239 }
240 } else {
241 var regexp = /** @type {RegExp} */ (handler.urlPattern);
242 if (!regexp.test(xhr.params.url)) {
243 continue;
244 }
245 }
246 if (!handler.reuse) {
247 handlers.splice(i, 1);
248 }
249 handler.proc(xhr);
250 return;
251 };
252 throw new Error(
253 'No handler registered for ' + xhr.params.method +
254 ' to '+ xhr.params.url);
255 };
256
257 remoting.MockXhr.activate = function() {
258 base.debug.assert(
259 origXhr == null,
260 'Xhr mocking already active');
261 origXhr = remoting.Xhr;
262 remoting.MockXhr.Response = remoting.Xhr.Response;
263 remoting['Xhr'] = remoting.MockXhr;
264 };
265
266 remoting.MockXhr.restore = function() {
267 base.debug.assert(
268 origXhr != null,
269 'Xhr mocking not active');
270 remoting['Xhr'] = origXhr;
271 origXhr = null;
272 handlers = [];
273 };
274
275 })();
276
277 // Can't put put typedefs inside a function :-(
278 /**
279 * @typedef {{
280 * method:?string,
281 * urlPattern:(?string|RegExp),
282 * proc:function(!remoting.MockXhr):void,
283 * reuse:boolean
284 * }}
285 */
286 remoting.MockXhr.UrlHandler;
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698