Chromium Code Reviews| OLD | NEW |
|---|---|
| (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; | |
| OLD | NEW |