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.
13 /** @type {sinon.FakeXhrCtrl} */
16 /** @type {sinon.FakeXhr} */
20 beforeEach: function() {
22 fakeXhrCtrl
= sinon
.useFakeXMLHttpRequest();
23 fakeXhrCtrl
.onCreate
=
24 function(/** sinon.FakeXhr */ xhr
) {
27 remoting
.identity
= new remoting
.Identity();
28 chromeMocks
.identity
.mock
$setToken('my_token');
30 afterEach: function() {
31 remoting
.identity
= null;
32 fakeXhrCtrl
.restore();
36 QUnit
.test('urlencodeParamHash', function(assert
) {
38 remoting
.Xhr
.urlencodeParamHash({}),
41 remoting
.Xhr
.urlencodeParamHash({'key': 'value'}),
44 remoting
.Xhr
.urlencodeParamHash({'key /?=&': 'value /?=&'}),
45 'key%20%2F%3F%3D%26=value%20%2F%3F%3D%26');
47 remoting
.Xhr
.urlencodeParamHash({'k1': 'v1', 'k2': 'v2'}),
52 // Test for what happens when the parameters are specified
56 QUnit
.test('invalid *content parameters', function(assert
) {
57 assert
.throws(function() {
60 url
: 'http://foo.com',
66 assert
.throws(function() {
69 url
: 'http://foo.com',
75 assert
.throws(function() {
78 url
: 'http://foo.com',
86 QUnit
.test('invalid URL parameters', function(assert
) {
87 assert
.throws(function() {
90 url
: 'http://foo.com?',
95 assert
.throws(function() {
98 url
: 'http://foo.com#',
104 QUnit
.test('invalid auth parameters', function(assert
) {
105 assert
.throws(function() {
108 url
: 'http://foo.com',
117 assert
.throws(function() {
120 url
: 'http://foo.com',
128 assert
.throws(function() {
131 url
: 'http://foo.com',
139 QUnit
.test('invalid auth parameters', function(assert
) {
140 assert
.throws(function() {
143 url
: 'http://foo.com',
152 assert
.throws(function() {
155 url
: 'http://foo.com',
163 assert
.throws(function() {
166 url
: 'http://foo.com',
175 QUnit
.test('unexpected parameters', function(assert
) {
176 assert
.throws(function() {
179 url
: 'http://foo.com',
180 xyzzy
: 'not a real parameter'
189 QUnit
.test('successful GET', function(assert
) {
190 var promise
= new remoting
.Xhr({
192 url
: 'http://foo.com'
193 }).start().then(function(response
) {
194 assert
.ok(!response
.isError());
195 assert
.equal(response
.status
, 200);
196 assert
.equal(response
.getText(), 'body');
198 assert
.equal(fakeXhr
.method
, 'GET');
199 assert
.equal(fakeXhr
.url
, 'http://foo.com');
200 assert
.equal(fakeXhr
.withCredentials
, false);
201 assert
.equal(fakeXhr
.requestBody
, null);
202 assert
.ok(!('Content-type' in fakeXhr
.requestHeaders
));
203 fakeXhr
.respond(200, {}, 'body');
208 // Tests for the effect of acceptJson.
211 QUnit
.test('acceptJson required', function(assert
) {
212 var promise
= new remoting
.Xhr({
214 url
: 'http://foo.com'
215 }).start().then(function(response
) {
216 assert
.throws(response
.getJson
);
218 fakeXhr
.respond(200, {}, '{}');
222 QUnit
.test('JSON response', function(assert
) {
226 var responseText
= JSON
.stringify(responseJson
);
227 var promise
= new remoting
.Xhr({
229 url
: 'http://foo.com',
231 }).start().then(function(response
) {
232 // Calling getText is still OK even when a JSON response is
237 // Check that getJson works as advertised.
241 // Calling getJson multiple times doesn't re-parse the response.
246 fakeXhr
.respond(200, {}, responseText
);
251 // Tests for various parameters that modify the HTTP request.
254 QUnit
.test('GET with param string', function(assert
) {
257 url
: 'http://foo.com',
258 urlParams
: 'the_param_string'
260 assert
.equal(fakeXhr
.url
, 'http://foo.com?the_param_string');
263 QUnit
.test('GET with param object', function(assert
) {
266 url
: 'http://foo.com',
267 urlParams
: {'a': 'b', 'c': 'd'}
269 assert
.equal(fakeXhr
.url
, 'http://foo.com?a=b&c=d');
272 QUnit
.test('GET with headers', function(assert
) {
275 url
: 'http://foo.com',
276 headers
: {'Header1': 'headerValue1', 'Header2': 'headerValue2'}
279 fakeXhr
.requestHeaders
['Header1'],
282 fakeXhr
.requestHeaders
['Header2'],
287 QUnit
.test('GET with credentials', function(assert
) {
290 url
: 'http://foo.com',
291 withCredentials
: true
293 assert
.equal(fakeXhr
.withCredentials
, true);
297 // Checking that typical POST requests work.
300 QUnit
.test('POST with text content', function(assert
) {
301 var done
= assert
.async();
303 var promise
= new remoting
.Xhr({
305 url
: 'http://foo.com',
306 textContent
: 'the_content_string'
307 }).start().then(function(response
) {
308 assert
.equal(response
.status
, 200);
309 assert
.equal(response
.getText(), 'body');
312 assert
.equal(fakeXhr
.method
, 'POST');
313 assert
.equal(fakeXhr
.url
, 'http://foo.com');
314 assert
.equal(fakeXhr
.withCredentials
, false);
315 assert
.equal(fakeXhr
.requestBody
, 'the_content_string');
316 assert
.equal(fakeXhr
.requestHeaders
['Content-type'],
317 'text/plain; charset=UTF-8');
318 fakeXhr
.respond(200, {}, 'body');
322 QUnit
.test('POST with form content', function(assert
) {
325 url
: 'http://foo.com',
326 formContent
: {'a': 'b', 'c': 'd'}
328 assert
.equal(fakeXhr
.requestBody
, 'a=b&c=d');
330 fakeXhr
.requestHeaders
['Content-type'],
331 'application/x-www-form-urlencoded; charset=UTF-8');
335 // Tests for authentication-related options.
338 QUnit
.test('GET with auth token', function(assert
) {
341 url
: 'http://foo.com',
342 oauthToken
: 'my_token'
344 assert
.equal(fakeXhr
.requestHeaders
['Authorization'],
348 QUnit
.test('GET with useIdentity', function(assert
) {
349 var xhr
= new remoting
.Xhr({
351 url
: 'http://foo.com',
356 var done
= assert
.async();
357 fakeXhr
.addEventListener('loadstart', function() {
358 assert
.equal(fakeXhr
.requestHeaders
['Authorization'],
367 QUnit
.test('GET with error response', function(assert
) {
368 var promise
= new remoting
.Xhr({
370 url
: 'http://foo.com'
371 }).start().then(function(response
) {
372 assert
.ok(response
.isError());
373 assert
.equal(response
.status
, 500);
374 assert
.equal(response
.getText(), 'body');
376 fakeXhr
.respond(500, {}, 'body');
380 QUnit
.test('204 is not an error', function(assert
) {
381 var promise
= new remoting
.Xhr({
383 url
: 'http://foo.com'
384 }).start().then(function(response
) {
385 assert
.ok(!response
.isError());
386 assert
.equal(response
.status
, 204);
387 assert
.equal(response
.getText(), '');
389 fakeXhr
.respond(204, {}, null);
393 QUnit
.test('GET with non-HTTP response', function(assert
) {
394 var promise
= new remoting
.Xhr({
396 url
: 'http://foo.com'
397 }).start().then(function(response
) {
398 assert
.ok(response
.isError());
400 fakeXhr
.respond(0, {}, null);
404 QUnit
.module('AutoRetryXhr', {
405 beforeEach: function() {
407 fakeXhrCtrl
= sinon
.useFakeXMLHttpRequest();
408 fakeXhrCtrl
.onCreate = function(/** sinon.FakeXhr */ xhr
) {
412 afterEach: function() {
413 fakeXhrCtrl
.restore();
418 * A class allows you to specify a sequence of canned responses, to be returned
419 * in order in response to XHRs.
421 * @param {Array<Array>} cannedResponses
424 var CannedXhrResponder = function(cannedResponses
) {
426 this.mockXhr_
= sinon
.useFakeXMLHttpRequest();
427 this.cannedResponses_
= cannedResponses
;
428 this.mockXhr_
.onCreate
= this.onCreate_
.bind(this);
432 CannedXhrResponder
.prototype.onCreate_ = function(/** sinon.FakeXhr */ xhr
) {
434 var response
= that
.cannedResponses_
.shift();
435 Promise
.resolve().then(function() {
436 xhr
.respond
.apply(xhr
, response
);
440 CannedXhrResponder
.prototype.dispose = function() {
441 this.mockXhr_
.restore();
444 QUnit
.test('retries on status code equals 0',
446 * 'this' is not defined for jscompile, so it can't figure out the type of
448 * @suppress {reportUnknownTypes|checkVars|checkTypes}
451 this.clock
.restore();
452 fakeXhrCtrl
.restore();
453 var responder
= new CannedXhrResponder([
458 var promise
= new remoting
.AutoRetryXhr({
460 url
: 'http://foo.com'
461 }).start().then(function(response
) {
462 assert
.ok(!response
.isError());
464 throw new Error('Expect retry to succeed.');
469 QUnit
.test('respects opt_maxRetryAttempts',
471 * 'this' is not defined for jscompile, so it can't figure out the type of
473 * @suppress {reportUnknownTypes|checkVars|checkTypes}
476 this.clock
.restore();
477 fakeXhrCtrl
.restore();
478 var responder
= new CannedXhrResponder([
484 var promise
= new remoting
.AutoRetryXhr({
486 url
: 'http://foo.com'
487 }, 2).start().then(function(response
) {
488 throw new Error('Expect retry to fail.');
495 QUnit
.test('does not retry when offline', function(assert
) {
496 var isOnlineStub
= sinon
.stub(base
, 'isOnline');
497 isOnlineStub
.returns(false);
499 var promise
= new remoting
.AutoRetryXhr({
501 url
: 'http://foo.com'
502 }).start().then(function(response
) {
503 assert
.ok(false, 'Expect failure');
504 }).catch(function(/** remoting.Error */ error
) {
505 assert
.equal(error
.getTag(), remoting
.Error
.Tag
.NETWORK_FAILURE
);
507 isOnlineStub
.restore();
511 QUnit
.test('resolves with successful responses', function(assert
) {
512 var promise
= new remoting
.AutoRetryXhr({
514 url
: 'http://foo.com'
515 }).start().then(function(response
) {
516 assert
.ok(!response
.isError());
517 assert
.equal(response
.getText(), 'body');
519 fakeXhr
.respond(200, {}, 'body');
523 QUnit
.test('rejects with failed responses', function(assert
) {
524 var promise
= new remoting
.AutoRetryXhr({
526 url
: 'http://foo.com'
527 }).start().then(function(response
) {
528 assert
.ok(response
.isError());
529 assert
.equal(response
.getText(), 'failure');
531 fakeXhr
.respond(500, {}, 'failure');