1<!doctype html> 2<!-- 3@license 4Copyright (c) 2015 The Polymer Project Authors. All rights reserved. 5This code may only be used under the BSD style license found at http://polymer.github.io/LICENSE.txt 6The complete set of authors may be found at http://polymer.github.io/AUTHORS.txt 7The complete set of contributors may be found at http://polymer.github.io/CONTRIBUTORS.txt 8Code distributed by Google as part of the polymer project is also 9subject to an additional IP rights grant found at http://polymer.github.io/PATENTS.txt 10--> 11<html> 12<head> 13 <title>iron-ajax</title> 14 15 <script src="../../webcomponentsjs/webcomponents-lite.js"></script> 16 <script src="../../web-component-tester/browser.js"></script> 17 18 <link rel="import" href="../../polymer/polymer.html"> 19 <link rel="import" href="../../promise-polyfill/promise-polyfill.html"> 20 <link rel="import" href="../iron-ajax.html"> 21</head> 22<body> 23 <test-fixture id="TrivialGet"> 24 <template> 25 <iron-ajax url="/responds_to_get_with_json"></iron-ajax> 26 </template> 27 </test-fixture> 28 <test-fixture id="ParamsGet"> 29 <template> 30 <iron-ajax url="/responds_to_get_with_json" 31 params='{"a": "a"}'></iron-ajax> 32 </template> 33 </test-fixture> 34 <test-fixture id="AutoGet"> 35 <template> 36 <iron-ajax auto url="/responds_to_get_with_json"></iron-ajax> 37 </template> 38 </test-fixture> 39 <test-fixture id="GetEcho"> 40 <template> 41 <iron-ajax handle-as="json" url="/echoes_request_url"></iron-ajax> 42 </template> 43 </test-fixture> 44 <test-fixture id="TrivialPost"> 45 <template> 46 <iron-ajax method="POST" 47 url="/responds_to_post_with_json"></iron-ajax> 48 </template> 49 </test-fixture> 50 <test-fixture id="DebouncedGet"> 51 <template> 52 <iron-ajax auto 53 url="/responds_to_debounced_get_with_json" 54 debounce-duration="150"></iron-ajax> 55 </template> 56 </test-fixture> 57 <test-fixture id='BlankUrl'> 58 <template> 59 <iron-ajax auto handle-as='text'></iron-ajax> 60 </template> 61 </test-fixture> 62 <test-fixture id="RealPost"> 63 <template> 64 <iron-ajax method="POST" url="http://httpbin.org/post"></iron-ajax> 65 </template> 66 </test-fixture> 67 <test-fixture id="Delay"> 68 <template> 69 <iron-ajax url="http://httpbin.org/delay/1"></iron-ajax> 70 </template> 71 </test-fixture> 72 <test-fixture id="Bubbles"> 73 <template> 74 <iron-ajax url="http://httpbin.org/post" method="POST" bubbles></iron-ajax> 75 <iron-ajax url="/responds_to_get_with_502_error_json" bubbles></iron-ajax> 76 </template> 77 </test-fixture> 78 <script> 79 'use strict'; 80 suite('<iron-ajax>', function() { 81 var responseHeaders = { 82 json: { 'Content-Type': 'application/json' }, 83 plain: { 'Content-Type': 'text/plain' } 84 }; 85 var ajax; 86 var request; 87 var server; 88 89 function timePasses(ms) { 90 return new Promise(function(resolve) { 91 window.setTimeout(function() { 92 resolve(); 93 }, ms); 94 }); 95 } 96 97 setup(function() { 98 server = sinon.fakeServer.create(); 99 server.respondWith( 100 'GET', 101 /\/responds_to_get_with_json.*/, 102 [ 103 200, 104 responseHeaders.json, 105 '{"success":true}' 106 ] 107 ); 108 109 server.respondWith( 110 'POST', 111 '/responds_to_post_with_json', 112 [ 113 200, 114 responseHeaders.json, 115 '{"post_success":true}' 116 ] 117 ); 118 119 server.respondWith( 120 'GET', 121 '/responds_to_get_with_text', 122 [ 123 200, 124 responseHeaders.plain, 125 'Hello World' 126 ] 127 ); 128 129 server.respondWith( 130 'GET', 131 '/responds_to_debounced_get_with_json', 132 [ 133 200, 134 responseHeaders.json, 135 '{"success": "true"}' 136 ] 137 ); 138 139 server.respondWith( 140 'GET', 141 '/responds_to_get_with_502_error_json', 142 [ 143 502, 144 responseHeaders.json, 145 '{"message": "an error has occurred"}' 146 ] 147 ); 148 149 ajax = fixture('TrivialGet'); 150 }); 151 152 teardown(function() { 153 server.restore(); 154 }); 155 156 // Echo requests are responded to individually and on demand, unlike the 157 // others in this file which are responded to with server.respond(), 158 // which responds to all open requests. 159 // We don't use server.respondWith here because there's no way to use it 160 // and only respond to a subset of requests. 161 // This way we can test for delayed and out of order responses and 162 // distinquish them by their responses. 163 function respondToEchoRequest(request) { 164 request.respond(200, responseHeaders.json, JSON.stringify({ 165 url: request.url 166 })); 167 } 168 169 suite('when making simple GET requests for JSON', function() { 170 test('has sane defaults that love you', function() { 171 request = ajax.generateRequest(); 172 173 server.respond(); 174 175 expect(request.response).to.be.ok; 176 expect(request.response).to.be.an('object'); 177 expect(request.response.success).to.be.equal(true); 178 }); 179 180 test('will be asynchronous by default', function() { 181 expect(ajax.toRequestOptions().async).to.be.eql(true); 182 }); 183 }); 184 185 suite('when setting custom headers', function() { 186 test('are present in the request headers', function() { 187 ajax.headers['custom-header'] = 'valid'; 188 var options = ajax.toRequestOptions(); 189 190 expect(options.headers).to.be.ok; 191 expect(options.headers['custom-header']).to.be.an('string'); 192 expect(options.headers.hasOwnProperty('custom-header')).to.be.equal( 193 true); 194 }); 195 196 test('non-objects in headers are not applied', function() { 197 ajax.headers = 'invalid'; 198 var options = ajax.toRequestOptions(); 199 200 expect(Object.keys(options.headers).length).to.be.equal(0); 201 }); 202 }); 203 204 suite('when url isn\'t set yet', function() { 205 test('we don\'t fire any automatic requests', function() { 206 expect(server.requests.length).to.be.equal(0); 207 ajax = fixture('BlankUrl'); 208 209 return timePasses(1).then(function() { 210 // We don't make any requests. 211 expect(server.requests.length).to.be.equal(0); 212 213 // Explicitly asking for the request to fire works. 214 ajax.generateRequest(); 215 expect(server.requests.length).to.be.equal(1); 216 server.requests = []; 217 218 // Explicitly setting url to '' works too. 219 ajax = fixture('BlankUrl'); 220 ajax.url = ''; 221 return timePasses(1); 222 }).then(function() { 223 expect(server.requests.length).to.be.equal(1); 224 }); 225 }); 226 227 test('requestUrl remains empty despite valid queryString', function() { 228 ajax = fixture('BlankUrl'); 229 expect(ajax.url).to.be.equal(undefined); 230 expect(ajax.queryString).to.be.equal(''); 231 expect(ajax.requestUrl).to.be.equal(''); 232 233 ajax.params = {'a':'b', 'c':'d'}; 234 235 expect(ajax.queryString).to.be.equal('a=b&c=d'); 236 expect(ajax.requestUrl).to.be.equal('?a=b&c=d'); 237 }); 238 239 test('generateRequest works with empty URL and valid queryString', function() { 240 ajax = fixture('BlankUrl'); 241 expect(ajax.url).to.be.equal(undefined); 242 243 ajax.generateRequest(); 244 expect(server.requests[0].url).to.be.eql(''); 245 246 ajax.params = {'a':'b', 'c':'d'}; 247 248 ajax.generateRequest(); 249 expect(server.requests[1].url).to.be.eql('?a=b&c=d'); 250 }); 251 }); 252 253 suite('when properties are changed', function() { 254 test('generates simple-request elements that reflect the change', function() { 255 request = ajax.generateRequest(); 256 257 expect(request.xhr.method).to.be.equal('GET'); 258 259 ajax.method = 'POST'; 260 ajax.url = '/responds_to_post_with_json'; 261 262 request = ajax.generateRequest(); 263 264 expect(request.xhr.method).to.be.equal('POST'); 265 }); 266 }); 267 268 suite('when generating a request', function() { 269 test('yields an iron-request instance', function() { 270 var IronRequest = document.createElement('iron-request').constructor; 271 272 expect(ajax.generateRequest()).to.be.instanceOf(IronRequest); 273 }); 274 275 test('correctly adds params to a URL that already has some', function() { 276 ajax.url += '?a=b'; 277 ajax.params = {'c': 'd'}; 278 279 expect(ajax.requestUrl).to.be.equal('/responds_to_get_with_json?a=b&c=d') 280 }) 281 282 test('encodes params properly', function() { 283 ajax.params = {'a b,c': 'd e f'}; 284 285 expect(ajax.queryString).to.be.equal('a%20b%2Cc=d%20e%20f'); 286 }); 287 288 test('encodes array params properly', function() { 289 ajax.params = {'a b': ['c','d e', 'f']}; 290 291 expect(ajax.queryString).to.be.equal('a%20b=c&a%20b=d%20e&a%20b=f'); 292 }); 293 294 test('reflects the loading state in the `loading` property', function() { 295 var request = ajax.generateRequest(); 296 297 expect(ajax.loading).to.be.equal(true); 298 299 server.respond(); 300 301 return request.completes.then(function() { 302 return timePasses(1); 303 }).then(function() { 304 expect(ajax.loading).to.be.equal(false); 305 }); 306 }); 307 308 test('the `iron-ajax-presend` event gets fired', function() { 309 var spy = sinon.spy(); 310 var windowSpy = sinon.spy(); 311 ajax.addEventListener('iron-ajax-presend', spy); 312 window.addEventListener('iron-ajax-presend', windowSpy); 313 314 var request = ajax.generateRequest(); 315 316 server.respond() 317 318 return request.completes.then(function() { 319 expect(spy).to.be.calledOnce; 320 expect(windowSpy).not.to.be.called; 321 }); 322 }); 323 324 test('the loading-changed event gets fired twice', function() { 325 var count = 0; 326 ajax.addEventListener('loading-changed', function() { 327 count++; 328 }); 329 330 var request = ajax.generateRequest(); 331 332 server.respond(); 333 334 return request.completes.then(function() { 335 return timePasses(1); 336 }).then(function() { 337 expect(count).to.be.equal(2); 338 }); 339 }); 340 }); 341 342 suite('when there are multiple requests', function() { 343 var requests; 344 var echoAjax; 345 var promiseAllComplete; 346 347 setup(function() { 348 echoAjax = fixture('GetEcho'); 349 requests = []; 350 351 for (var i = 0; i < 3; ++i) { 352 echoAjax.params = {'order': i + 1}; 353 requests.push(echoAjax.generateRequest()); 354 } 355 var allPromises = requests.map(function(r){return r.completes}); 356 promiseAllComplete = Promise.all(allPromises); 357 }); 358 359 test('holds all requests in the `activeRequests` Array', function() { 360 expect(requests).to.deep.eql(echoAjax.activeRequests); 361 }); 362 363 test('empties `activeRequests` when requests are completed', function() { 364 expect(echoAjax.activeRequests.length).to.be.equal(3); 365 for (var i = 0; i < 3; i++) { 366 respondToEchoRequest(server.requests[i]); 367 } 368 return promiseAllComplete.then(function() { 369 return timePasses(1); 370 }).then(function() { 371 expect(echoAjax.activeRequests.length).to.be.equal(0); 372 }); 373 }); 374 375 test('avoids race conditions with last response', function() { 376 expect(echoAjax.lastResponse).to.be.equal(undefined); 377 378 // Resolving the oldest request doesn't update lastResponse. 379 respondToEchoRequest(server.requests[0]); 380 return requests[0].completes.then(function() { 381 expect(echoAjax.lastResponse).to.be.equal(undefined); 382 383 // Resolving the most recent request does! 384 respondToEchoRequest(server.requests[2]); 385 return requests[2].completes; 386 }).then(function() { 387 expect(echoAjax.lastResponse).to.be.deep.eql( 388 {url: '/echoes_request_url?order=3'}); 389 390 391 // Resolving an out of order stale request after does nothing! 392 respondToEchoRequest(server.requests[1]); 393 return requests[1].completes; 394 }).then(function() { 395 expect(echoAjax.lastResponse).to.be.deep.eql( 396 {url: '/echoes_request_url?order=3'}); 397 }); 398 }); 399 400 test('`loading` is true while the last one is loading', function() { 401 expect(echoAjax.loading).to.be.equal(true); 402 403 respondToEchoRequest(server.requests[0]); 404 return requests[0].completes.then(function() { 405 // We're still loading because requests[2] is the most recently 406 // made request. 407 expect(echoAjax.loading).to.be.equal(true); 408 409 respondToEchoRequest(server.requests[2]); 410 return requests[2].completes; 411 }).then(function() { 412 // Now we're done loading. 413 expect(echoAjax.loading).to.be.eql(false); 414 415 // Resolving an out of order stale request after should have 416 // no effect. 417 respondToEchoRequest(server.requests[1]); 418 return requests[1].completes; 419 }).then(function() { 420 expect(echoAjax.loading).to.be.eql(false); 421 }); 422 }); 423 }); 424 425 suite('when params are changed', function() { 426 test('generates a request that reflects the change', function() { 427 ajax = fixture('ParamsGet'); 428 request = ajax.generateRequest(); 429 430 expect(request.xhr.url).to.be.equal('/responds_to_get_with_json?a=a'); 431 432 ajax.params = {b: 'b'}; 433 request = ajax.generateRequest(); 434 435 expect(request.xhr.url).to.be.equal('/responds_to_get_with_json?b=b'); 436 }); 437 }); 438 439 suite('when `auto` is enabled', function() { 440 setup(function() { 441 ajax = fixture('AutoGet'); 442 }); 443 444 test('automatically generates new requests', function() { 445 return new Promise(function(resolve) { 446 ajax.addEventListener('request', function() { 447 resolve(); 448 }); 449 }); 450 }); 451 452 test('does not send requests if url is not a string', function() { 453 return new Promise(function(resolve, reject) { 454 ajax.addEventListener('request', function() { 455 reject('A request was generated but url is null!'); 456 }); 457 458 ajax.url = null; 459 ajax.handleAs = 'text'; 460 461 Polymer.Base.async(function() { 462 resolve(); 463 }, 1); 464 }); 465 }); 466 467 test('deduplicates multiple changes to a single request', function() { 468 return new Promise(function(resolve, reject) { 469 ajax.addEventListener('request', function() { 470 server.respond(); 471 }); 472 473 ajax.addEventListener('response', function() { 474 try { 475 expect(ajax.activeRequests.length).to.be.eql(1); 476 resolve() 477 } catch (e) { 478 reject(e); 479 } 480 }); 481 482 ajax.handleas = 'text'; 483 ajax.params = { foo: 'bar' }; 484 ajax.headers = { 'X-Foo': 'Bar' }; 485 }); 486 }); 487 488 test('automatically generates new request when a sub-property of params is changed', function(done) { 489 ajax.addEventListener('request', function() { 490 server.respond(); 491 }); 492 493 ajax.params = { foo: 'bar' }; 494 ajax.addEventListener('response', function() { 495 ajax.addEventListener('request', function() { 496 done(); 497 }); 498 499 ajax.set('params.foo', 'xyz'); 500 }); 501 }); 502 }); 503 504 suite('the last response', function() { 505 setup(function() { 506 request = ajax.generateRequest(); 507 server.respond(); 508 }); 509 510 test('is accessible as a readonly property', function() { 511 return request.completes.then(function(request) { 512 expect(ajax.lastResponse).to.be.equal(request.response); 513 }); 514 }); 515 516 517 test('updates with each new response', function() { 518 return request.completes.then(function(request) { 519 520 expect(request.response).to.be.an('object'); 521 expect(ajax.lastResponse).to.be.equal(request.response); 522 523 ajax.handleAs = 'text'; 524 request = ajax.generateRequest(); 525 server.respond(); 526 527 return request.completes; 528 }).then(function(request) { 529 expect(request.response).to.be.a('string'); 530 expect(ajax.lastResponse).to.be.equal(request.response); 531 }); 532 }); 533 }); 534 535 suite('when making POST requests', function() { 536 setup(function() { 537 ajax = fixture('TrivialPost'); 538 }); 539 540 test('POSTs the value of the `body` attribute', function() { 541 var requestBody = JSON.stringify({foo: 'bar'}); 542 543 ajax.body = requestBody; 544 ajax.generateRequest(); 545 546 expect(server.requests[0]).to.be.ok; 547 expect(server.requests[0].requestBody).to.be.equal(requestBody); 548 }); 549 550 test('if `contentType` is set to form encode, the body is encoded',function() { 551 ajax.body = {foo: 'bar\nbip', 'biz bo': 'baz blar'}; 552 ajax.contentType = 'application/x-www-form-urlencoded'; 553 ajax.generateRequest(); 554 555 expect(server.requests[0]).to.be.ok; 556 expect(server.requests[0].requestBody).to.be.equal( 557 'foo=bar%0D%0Abip&biz+bo=baz+blar'); 558 }); 559 560 test('if `contentType` is json, the body is json encoded', function() { 561 var requestObj = {foo: 'bar', baz: [1,2,3]} 562 ajax.body = requestObj; 563 ajax.contentType = 'application/json'; 564 ajax.generateRequest(); 565 566 expect(server.requests[0]).to.be.ok; 567 expect(server.requests[0].requestBody).to.be.equal( 568 JSON.stringify(requestObj)); 569 }); 570 571 suite('the examples in the documentation work', function() { 572 test('json content, body attribute is an object', function() { 573 ajax.setAttribute('body', '{"foo": "bar baz", "x": 1}'); 574 ajax.contentType = 'application/json'; 575 ajax.generateRequest(); 576 577 expect(server.requests[0]).to.be.ok; 578 expect(server.requests[0].requestBody).to.be.equal( 579 '{"foo":"bar baz","x":1}'); 580 }); 581 582 test('form content, body attribute is an object', function() { 583 ajax.setAttribute('body', '{"foo": "bar baz", "x": 1}'); 584 ajax.contentType = 'application/x-www-form-urlencoded'; 585 ajax.generateRequest(); 586 587 expect(server.requests[0]).to.be.ok; 588 expect(server.requests[0].requestBody).to.be.equal( 589 'foo=bar+baz&x=1'); 590 }); 591 }); 592 593 suite('and `contentType` is explicitly set to form encode', function() { 594 test('we encode a custom object', function() { 595 function Foo(bar) { this.bar = bar }; 596 var requestObj = new Foo('baz'); 597 ajax.body = requestObj; 598 ajax.contentType = 'application/x-www-form-urlencoded'; 599 ajax.generateRequest(); 600 601 expect(server.requests[0]).to.be.ok; 602 expect(server.requests[0].requestBody).to.be.equal('bar=baz'); 603 }); 604 }) 605 606 suite('and `contentType` isn\'t set', function() { 607 test('we don\'t try to encode an ArrayBuffer', function() { 608 var requestObj = new ArrayBuffer() 609 ajax.body = requestObj; 610 ajax.generateRequest(); 611 612 expect(server.requests[0]).to.be.ok; 613 // We give the browser the ArrayBuffer directly, without trying 614 // to encode it. 615 expect(server.requests[0].requestBody).to.be.equal(requestObj); 616 }); 617 }) 618 }); 619 620 suite('when debouncing requests', function() { 621 setup(function() { 622 ajax = fixture('DebouncedGet'); 623 }); 624 625 test('only requests a single resource', function() { 626 ajax._requestOptionsChanged(); 627 expect(server.requests[0]).to.be.equal(undefined); 628 ajax._requestOptionsChanged(); 629 return timePasses(200).then(function() { 630 expect(server.requests[0]).to.be.ok; 631 }); 632 }); 633 }); 634 635 suite('when a response handler is bound', function() { 636 var responseHandler; 637 638 setup(function() { 639 responseHandler = sinon.spy(); 640 ajax.addEventListener('response', responseHandler); 641 }); 642 643 test('calls the handler after every response', function() { 644 ajax.generateRequest(); 645 ajax.generateRequest(); 646 647 server.respond(); 648 649 return ajax.lastRequest.completes.then(function() { 650 expect(responseHandler.callCount).to.be.equal(2); 651 }); 652 }); 653 }); 654 655 suite('when the response type is `json`', function() { 656 setup(function() { 657 server.restore(); 658 }); 659 660 test('finds the JSON on any platform', function() { 661 ajax.url = '../bower.json'; 662 request = ajax.generateRequest(); 663 return request.completes.then(function() { 664 expect(ajax.lastResponse).to.be.instanceOf(Object); 665 }); 666 }); 667 }); 668 669 suite('when handleAs parameter is `text`', function() { 670 671 test('response type is string', function() { 672 ajax.url = '/responds_to_get_with_json'; 673 ajax.handleAs = 'text'; 674 675 request = ajax.generateRequest(); 676 var promise = request.completes.then(function() { 677 expect(typeof(ajax.lastResponse)).to.be.equal('string'); 678 }); 679 680 expect(server.requests.length).to.be.equal(1); 681 expect(server.requests[0].requestHeaders['accept']).to.be.equal( 682 'text/plain'); 683 server.respond(); 684 685 return promise; 686 }); 687 688 }); 689 690 suite('when a request fails', function() { 691 test('we give an error with useful details', function() { 692 ajax.url = '/responds_to_get_with_502_error_json'; 693 ajax.handleAs = 'json'; 694 var eventFired = false; 695 ajax.addEventListener('error', function(event) { 696 expect(event.detail.request).to.be.ok; 697 expect(event.detail.error).to.be.ok; 698 eventFired = true; 699 }); 700 var request = ajax.generateRequest(); 701 var promise = request.completes.then(function() { 702 throw new Error('Expected the request to fail!'); 703 }, function(error) { 704 expect(error).to.be.instanceof(Error); 705 expect(request.succeeded).to.be.eq(false); 706 return timePasses(100); 707 }).then(function() { 708 expect(eventFired).to.be.eq(true); 709 expect(ajax.lastError).to.not.be.eq(null); 710 expect(ajax.lastError.status).to.be.eq(502); 711 expect(ajax.lastError.statusText).to.be.eq("Bad Gateway"); 712 expect(ajax.lastError.response).to.be.ok; 713 }); 714 715 server.respond(); 716 717 return promise; 718 }); 719 720 test('with rejectWithRequest the promise chain contains the request and error', function() { 721 ajax.url = '/responds_to_get_with_502_error_json'; 722 ajax.handleAs = 'json'; 723 ajax.rejectWithRequest = true; 724 725 var request = ajax.generateRequest(); 726 var promise = request.completes.then(function() { 727 throw new Error('Expected the request to fail!'); 728 }, function(resp) { 729 expect(resp.error).to.be.instanceof(Error); 730 expect(resp.request).to.deep.equal(request); 731 }); 732 733 server.respond(); 734 735 return promise; 736 }); 737 738 test('we give a useful error even when the domain doesn\'t resolve', function() { 739 ajax.url = 'http://nonexistant.example.com/'; 740 server.restore(); 741 var eventFired = false; 742 ajax.addEventListener('error', function(event) { 743 expect(event.detail.request).to.be.ok; 744 expect(event.detail.error).to.be.ok; 745 eventFired = true; 746 }); 747 var request = ajax.generateRequest(); 748 var promise = request.completes.then(function() { 749 throw new Error('Expected the request to fail!'); 750 }, function(error) { 751 expect(request.succeeded).to.be.eq(false); 752 expect(error).to.not.be.eq(null); 753 return timePasses(100); 754 }).then(function() { 755 expect(eventFired).to.be.eq(true); 756 expect(ajax.lastError).to.not.be.eq(null); 757 }); 758 759 server.respond(); 760 761 return promise; 762 }); 763 }); 764 765 suite('when handleAs parameter is `json`', function() { 766 767 test('response type is string', function() { 768 ajax.url = '/responds_to_get_with_json'; 769 ajax.handleAs = 'json'; 770 771 request = ajax.generateRequest(); 772 var promise = request.completes.then(function() { 773 expect(typeof(ajax.lastResponse)).to.be.equal('object'); 774 }); 775 776 expect(server.requests.length).to.be.equal(1); 777 expect(server.requests[0].requestHeaders['accept']).to.be.equal( 778 'application/json'); 779 780 server.respond(); 781 782 return promise; 783 }); 784 785 }); 786 787 suite('when making a POST over the wire', function() { 788 test('FormData is handled correctly', function() { 789 server.restore(); 790 var requestBody = new FormData(); 791 requestBody.append('a', 'foo'); 792 requestBody.append('b', 'bar'); 793 794 var ajax = fixture('RealPost'); 795 ajax.body = requestBody; 796 return ajax.generateRequest().completes.then(function() { 797 expect(ajax.lastResponse.headers['Content-Type']).to.match( 798 /^multipart\/form-data; boundary=.*$/); 799 800 expect(ajax.lastResponse.form.a).to.be.equal('foo'); 801 expect(ajax.lastResponse.form.b).to.be.equal('bar'); 802 }); 803 }); 804 805 test('json is handled correctly', function() { 806 server.restore(); 807 var ajax = fixture('RealPost'); 808 ajax.body = JSON.stringify({a: 'foo', b: 'bar'}); 809 ajax.contentType = 'application/json'; 810 return ajax.generateRequest().completes.then(function() { 811 expect(ajax.lastResponse.headers['Content-Type']).to.match( 812 /^application\/json(;.*)?$/); 813 expect(ajax.lastResponse.json.a).to.be.equal('foo'); 814 expect(ajax.lastResponse.json.b).to.be.equal('bar'); 815 }); 816 }); 817 818 test('urlencoded data is handled correctly', function() { 819 server.restore(); 820 var ajax = fixture('RealPost'); 821 ajax.body = 'a=foo&b=bar'; 822 return ajax.generateRequest().completes.then(function() { 823 expect(ajax.lastResponse.headers['Content-Type']).to.match( 824 /^application\/x-www-form-urlencoded(;.*)?$/); 825 826 expect(ajax.lastResponse.form.a).to.be.equal('foo'); 827 expect(ajax.lastResponse.form.b).to.be.equal('bar'); 828 }); 829 }); 830 831 test('xml is handled correctly', function() { 832 server.restore(); 833 var ajax = fixture('RealPost'); 834 835 var xmlDoc = document.implementation.createDocument( 836 null, "foo", null); 837 var node = xmlDoc.createElement("bar"); 838 node.setAttribute("name" , "baz"); 839 xmlDoc.documentElement.appendChild(node); 840 ajax.body = xmlDoc; 841 return ajax.generateRequest().completes.then(function() { 842 expect(ajax.lastResponse.headers['Content-Type']).to.match( 843 /^application\/xml(;.*)?$/); 844 expect(ajax.lastResponse.data).to.match( 845 /<foo\s*><bar\s+name="baz"\s*\/><\/foo\s*>/); 846 }); 847 }); 848 }); 849 850 suite('when setting timeout', function() { 851 setup(function() { 852 server.restore(); 853 }); 854 855 test('it is present in the request xhr object', function() { 856 ajax.url = '/responds_to_get_with_json'; 857 ajax.timeout = 5000; // 5 Seconds 858 859 request = ajax.generateRequest(); 860 expect(request.xhr.timeout).to.be.equal(5000); // 5 Seconds 861 }); 862 863 test('it fails once that timeout is reached', function() { 864 var ajax = fixture('Delay'); 865 ajax.timeout = 1; // 1 Millisecond 866 867 request = ajax.generateRequest(); 868 return request.completes.then(function() { 869 throw new Error('Expected the request to throw an error.'); 870 }, function() { 871 expect(request.succeeded).to.be.equal(false); 872 expect(request.xhr.status).to.be.equal(0); 873 expect(request.timedOut).to.be.equal(true); 874 return timePasses(1); 875 }).then(function() { 876 expect(ajax.loading).to.be.equal(false); 877 expect(ajax.lastResponse).to.be.equal(null); 878 expect(ajax.lastError).to.not.be.equal(null); 879 }); 880 }); 881 }); 882 883 suite('when using the bubbles attribute', function() { 884 test('the request and response events should bubble to window', function(done) { 885 server.restore(); 886 var total = 0; 887 function incrementTotal() { 888 total++; 889 if (total === 5) { 890 done(); 891 } 892 } 893 window.addEventListener('iron-ajax-presend', incrementTotal); 894 window.addEventListener('request', incrementTotal); 895 window.addEventListener('iron-ajax-request', incrementTotal); 896 window.addEventListener('response', incrementTotal); 897 window.addEventListener('iron-ajax-response', incrementTotal); 898 var ajax = fixture('Bubbles')[0]; 899 ajax.generateRequest(); 900 server.respond(); 901 }); 902 903 test('the request and error events should bubble to window', function(done) { 904 var total = 0; 905 function incrementTotal() { 906 total++; 907 if (total === 5) { 908 done(); 909 } 910 } 911 window.addEventListener('iron-ajax-presend', incrementTotal); 912 window.addEventListener('request', incrementTotal); 913 window.addEventListener('iron-ajax-request', incrementTotal); 914 // NOTE(cdata): This needs to be capturing because Mocha + Firefox 915 // results in the error event being observed too early by the test 916 // runner and failing the test: 917 window.addEventListener('error', incrementTotal, true); 918 window.addEventListener('iron-ajax-error', incrementTotal); 919 var ajax = fixture('Bubbles')[1]; 920 ajax.generateRequest(); 921 server.respond(); 922 }); 923 }); 924 925 suite('when handling the `iron-ajax-presend` event', function() { 926 setup(function() { 927 server.restore(); 928 }); 929 930 test('ability to cancel request', function() { 931 var requestSpy = sinon.spy(); 932 var promiseSpy = sinon.spy(); 933 934 ajax.addEventListener('iron-ajax-presend', function(e) { 935 e.preventDefault(); 936 }); 937 ajax.addEventListener('iron-ajax-request', requestSpy); 938 939 var request = ajax.generateRequest(); 940 941 return request.completes.catch(function(request) { 942 expect(request.aborted).to.be.true; 943 promiseSpy(); 944 }).then(function() { 945 expect(promiseSpy).to.be.calledOnce; 946 expect(requestSpy).not.to.be.called; 947 }); 948 }); 949 950 test('ability to modify the request options', function(done) { 951 ajax.addEventListener('iron-ajax-presend', function(e) { 952 e.detail.options.url += '/test'; 953 e.detail.options.headers.authToken = 'a.b.c'; 954 }); 955 ajax.addEventListener('iron-ajax-request', function(e) { 956 expect(e.detail.options.url).to.equal('/responds_to_get_with_json/test'); 957 expect(e.detail.options.headers.authToken).to.equal('a.b.c'); 958 done(); 959 }); 960 961 ajax.generateRequest(); 962 }); 963 }); 964 }); 965 </script> 966 967</body> 968</html> 969