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');