• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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-form</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="../../paper-checkbox/paper-checkbox.html">
20  <link rel="import" href="../../paper-input/paper-input.html">
21  <link rel="import" href="../../paper-button/paper-button.html">
22  <link rel="import" href="../iron-form.html">
23
24</head>
25<body>
26
27  <dom-module id="x-input-wrapper">
28    <template>
29      <input name="check_wrapped" value="foo"/>
30    </template>
31  </dom-module>
32
33  <test-fixture id="serialization">
34    <template>
35      <div>
36        <iron-form id="native-checkboxes">
37          <form action="/get" method="get">
38            <input type="checkbox" name="check1" checked> <!-- default value is "on" -->
39            <input type="checkbox" name="check1" value="1">
40            <input type="checkbox" name="check1" value="2" checked>
41            <input type="checkbox" name="check2" value="3" checked>
42            <input type="checkbox" name="check3" value="4">
43          </form>
44        </iron-form>
45        <iron-form id="native-radios">
46          <form action="/get" method="get">
47            <input type="radio" name="radio1" checked> <!-- default value is "on" -->
48            <input type="radio" name="radio1" value="1">
49            <input type="radio" name="radio2" value="2" checked>
50            <input type="radio" name="radio2" value="3" checked> <!-- it's a radio group -->
51            <input type="radio" name="radio3" value="4">
52          </form>
53        </iron-form>
54        <iron-form id="native-buttons">
55          <form action="/get" method="get">
56            <input type="reset" name="reset1" value="reset">
57            <input type="submit" name="submit1" value="submit">
58            <button name="button1" value="button">text</button>
59          </form>
60        </iron-form>
61        <iron-form id="native-selects">
62          <form action="/get" method="get">
63            <select name="select1" multiple>
64              <option value="1" selected>A</option>
65              <option value="2" selected>B</option>
66              <option value="3">C</option>
67            </select>
68            <select name="select2">
69              <option value="1" selected>A</option>
70              <option value="2">B</option>
71            </select>
72          </form>
73        </iron-form>
74        <iron-form id="native-inputs">
75          <form action="/get" method="get">
76            <input type="text" name="input1">
77            <input type="text" name="input1" value="foo">
78            <input type="text" name="input1" value="zag">
79            <input type="text" name="input2" value="bar">
80            <input type="password" name="pass1" value="pass">
81            <input type="number" name="number1" value="35">
82            <input name="empty" value="">
83            <input name="empty" value="">
84          </form>
85        </iron-form>
86        <iron-form id="native-inputs-empty">
87          <form action="/get" method="get">
88            <input type="text" name="input1">
89          </form>
90        </iron-form>
91        <iron-form id="custom-checkboxes">
92          <form action="/get" method="get">
93            <paper-checkbox name="check1" checked></paper-checkbox> <!-- default value is "on" -->
94            <paper-checkbox name="check1" value="1"></paper-checkbox>
95            <paper-checkbox name="check1" value="2" checked></paper-checkbox>
96            <paper-checkbox name="check2" value="3" checked></paper-checkbox>
97            <paper-checkbox name="check3" value="4"></paper-checkbox>
98          </form>
99        </iron-form>
100        <iron-form id="custom-inputs">
101          <form action="/get" method="get">
102            <paper-input name="input1" value=""></paper-input>
103            <paper-input name="input1" value="foo"></paper-input>
104            <paper-input name="input1" value="zag"></paper-input>
105            <paper-input name="input2" value="bar"></paper-input>
106            <paper-input type="password" name="pass1" value="pass"></paper-input>
107            <paper-input type="number" name="number1" value="35"></paper-input>
108            <paper-input name="empty" value=""></paper-input>
109            <paper-input name="empty" value=""></paper-input>
110            <x-input-wrapper></x-input-wrapper>
111          </form>
112        </iron-form>
113        <iron-form id="nested-elements">
114          <form action="/get" method="get">
115            <div>
116              <input type="text" name="input1" value="i1">
117            </div>
118            <div>
119              <paper-input name="paper-input1" value="p1"></paper-input>
120            </div>
121            <div>
122              <p>
123                <div>
124                  <input type="text" name="input2" value="i2">
125                  <paper-input name="paper-input2" value="p2"></paper-input>
126                </div>
127              </p>
128            </div>
129          </form>
130        </iron-form>
131        <iron-form id="duplicate-names">
132          <form action="/get" method="get">
133            <input name="input1" value="">
134            <input name="input1" value="foo">
135            <paper-input name="input1" value=""></paper-input>
136            <paper-input name="input1" value="bar"></paper-input>
137            <input name="empty" value="">
138            <input name="empty" value="">
139            <paper-input name="empty" value=""></paper-input>
140            <paper-input name="empty" value=""></paper-input>
141          </form>
142        </iron-form>
143
144      </div>
145    </template>
146  </test-fixture>
147
148  <test-fixture id="validation">
149    <template>
150      <div>
151        <iron-form id="native-required">
152          <form action="/get" method="get">
153            <input required>
154          </form>
155        </iron-form>
156
157        <iron-form id="native-invalid">
158          <form action="/get" method="get">
159            <input pattern="aa" value="b">
160          </form>
161        </iron-form>
162
163        <iron-form id="custom-required">
164          <form action="/get" method="get">
165            <paper-input required></paper-input>
166          </form>
167        </iron-form>
168
169        <iron-form id="custom-invalid">
170          <form action="/get" method="get">
171            <paper-input pattern="aa" value="b"></paper-input>
172          </form>
173        </iron-form>
174
175        <iron-form id="mixed-invalid">
176          <form action="/get" method="get">
177            <input pattern="aa" value="b">
178            <paper-input pattern="aa" value="b"></paper-input>
179          </form>
180        </iron-form>
181      </div>
182    </template>
183  </test-fixture>
184
185  <test-fixture id="submission">
186    <template>
187      <iron-form>
188        <form action="/get" method="get">
189          <input type="checkbox" name="check1" checked>
190          <input type="submit">
191          <input type="button">
192          <paper-button></paper-button>
193        </form>
194      </iron-form>
195    </template>
196  </test-fixture>
197
198  <test-fixture id="resetting">
199    <template>
200      <iron-form>
201        <form action="/get" method="get">
202          <input type="input" name="input1" id="input1" value="input1">
203          <input type="input" name="input2" id="input2">
204          <input type="checkbox" name="check1" id="check1" checked>
205          <input type="checkbox" name="check2" id="check2">
206          <input type="radio" name="radio1" id="radio1" checked>
207          <input type="radio" name="radio2" id="radio2">
208          <paper-checkbox name="papercheck1" id="papercheck1" checked></paper-checkbox>
209          <paper-checkbox name="papercheck2" id="papercheck2"></paper-checkbox>
210          <paper-input name="paper1" id="paper1" value="paper1"></paper-input>
211          <paper-input name="paper2" id="paper2" value=""></paper-input>
212          <input type="reset">
213        </form>
214      </iron-form>
215    </template>
216  </test-fixture>
217
218  <test-fixture id="content-type">
219    <template>
220      <div>
221        <iron-form id="simple-form">
222          <form action="/valid/url" method="post">
223            <paper-input name="paper1" value="value1"></paper-input>
224            <paper-input name="paper2" value="value2"></paper-input>
225          </form>
226        </iron-form>
227        <iron-form id="json-form">
228          <form action="/valid/url" method="post" enctype="application/json">
229            <paper-input name="paper1" value="value1"></paper-input>
230            <paper-input name="paper2" value="value2"></paper-input>
231          </form>
232        </iron-form>
233          <iron-form id="plain-form">
234              <form action="/valid/url" method="post" enctype="text/plain">
235                  <paper-input name="paper1" value="value1"></paper-input>
236                  <paper-input name="paper2" value="value2"></paper-input>
237              </form>
238          </iron-form>
239        </div>
240    </template>
241  </test-fixture>
242
243  <script>
244    suite('serialization', function() {
245      var f;
246      var server;
247
248      suiteSetup(function () {
249        Polymer({is: 'x-input-wrapper'});
250      });
251
252      setup(function() {
253        f = fixture('serialization');
254
255        server = sinon.fakeServer.create();
256        server.respondWith(
257          'GET',
258          /\/get.*/,
259          [
260            200,
261            '{"Content-Type":"application/json"}',
262            '{"success":true}'
263          ]
264        );
265      });
266
267      teardown(function() {
268        server.restore();
269      });
270
271      test('serializes native checkboxes', function(done) {
272        var form = f.querySelector('#native-checkboxes');
273        form.addEventListener('iron-form-response', function(event) {
274          expect(event.detail.url).to.equal('/get?check1=on&check1=2&check2=3');
275          expect(event.detail.response.success).to.be.equal(true);
276          done();
277        });
278
279        // Wait one tick for observeNodes.
280        Polymer.Base.async(function() {
281          form.submit();
282          server.respond();
283        });
284      });
285
286      test('serializes native radio buttons', function(done) {
287        var form = f.querySelector('#native-radios');
288        form.addEventListener('iron-form-response', function(event) {
289          expect(event.detail.url).to.equal('/get?radio1=on&radio2=3');
290          expect(event.detail.response.success).to.be.equal(true);
291          done();
292        });
293
294        // Wait one tick for observeNodes.
295        Polymer.Base.async(function() {
296          form.submit();
297          server.respond();
298        });
299      });
300
301      test('serializes native buttons', function(done) {
302        var form = f.querySelector('#native-buttons');
303        form.addEventListener('iron-form-response', function(event) {
304          expect(event.detail.url).to.equal('/get');
305          expect(event.detail.response.success).to.be.equal(true);
306          done();
307        });
308
309        // Wait one tick for observeNodes.
310        Polymer.Base.async(function() {
311          form.submit();
312          server.respond();
313        });
314      });
315
316      test('serializes native selects', function(done) {
317        var form = f.querySelector('#native-selects');
318        form.addEventListener('iron-form-response', function(event) {
319          expect(event.detail.url).to.equal('/get?select1=1&select1=2&select2=1');
320          expect(event.detail.response.success).to.be.equal(true);
321          done();
322        });
323
324        // Wait one tick for observeNodes.
325        Polymer.Base.async(function() {
326          form.submit();
327          server.respond();
328        });
329      });
330
331      test('serializes native inputs', function(done) {
332        var form = f.querySelector('#native-inputs');
333
334        form.addEventListener('iron-form-response', function(event) {
335          expect(event.detail.url).to.equal('/get?input1=&input1=foo&input1=zag&input2=bar&pass1=pass&number1=35&empty=&empty=');
336          expect(event.detail.response.success).to.be.equal(true);
337          done();
338        });
339
340        // Wait one tick for observeNodes.
341        Polymer.Base.async(function() {
342          form.submit();
343          server.respond();
344        });
345      });
346
347      test('serializes empty native inputs', function(done) {
348        var form = f.querySelector('#native-inputs-empty');
349        form.addEventListener('iron-form-response', function(event) {
350          expect(event.detail.url).to.equal('/get?input1=');
351          expect(event.detail.response.success).to.be.equal(true);
352          done();
353        });
354
355        // Wait one tick for observeNodes.
356        Polymer.Base.async(function() {
357          form.submit();
358          server.respond();
359        });
360      });
361
362      test('serializes custom checkboxes', function(done) {
363        var form = f.querySelector('#custom-checkboxes');
364        form.addEventListener('iron-form-response', function(event) {
365          expect(event.detail.url).to.equal('/get?check1=on&check1=2&check2=3');
366          expect(event.detail.response.success).to.be.equal(true);
367          done();
368        });
369
370        // Wait one tick for observeNodes.
371        Polymer.Base.async(function() {
372          form.submit();
373          server.respond();
374        });
375      });
376
377      test('serializes custom inputs', function(done) {
378        var form = f.querySelector('#custom-inputs');
379        form.addEventListener('iron-form-response', function(event) {
380          expect(event.detail.url).to.equal('/get?input1=&input1=foo&input1=zag&input2=bar&pass1=pass&number1=35&empty=&empty=&check_wrapped=foo');
381          expect(event.detail.response.success).to.be.equal(true);
382          done();
383        });
384
385        // Wait one tick for observeNodes.
386        Polymer.Base.async(function() {
387          form.submit();
388          server.respond();
389        });
390      });
391
392      test('serializes elements deeply nested in divs', function(done) {
393        var form = f.querySelector('#nested-elements');
394        form.addEventListener('iron-form-response', function(event) {
395          expect(event.detail.url).to.equal('/get?input1=i1&paper-input1=p1&input2=i2&paper-input2=p2');
396          expect(event.detail.response.success).to.be.equal(true);
397          done();
398        });
399        // Wait one tick for observeNodes.
400        Polymer.Base.async(function() {
401          form.submit();
402          server.respond();
403        });
404      });
405
406      test('serializes elements with duplicate names', function(done) {
407        var form = f.querySelector('#duplicate-names');
408        form.addEventListener('iron-form-response', function(event) {
409          expect(event.detail.url).to.equal('/get?input1=&input1=foo&input1=&input1=bar&empty=&empty=&empty=&empty=');
410          expect(event.detail.response.success).to.be.equal(true);
411          done();
412        });
413        // Wait one tick for observeNodes.
414        Polymer.Base.async(function() {
415          form.submit();
416          server.respond();
417        });
418      });
419    });
420
421
422    suite('validation', function() {
423      var f;
424      var server;
425
426      setup(function() {
427        f = fixture('validation');
428
429        server = sinon.fakeServer.create();
430        server.respondWith(
431          'GET',
432          /\/get.*/,
433          [
434            200,
435            '{"Content-Type":"application/json"}',
436            '{"success":true}'
437          ]
438        );
439      });
440
441      teardown(function() {
442        server.restore();
443      });
444
445      test('fires iron-form-invalid if it can\'t submit', function(done) {
446        var form = f.querySelector('#mixed-invalid');
447        form.addEventListener('iron-form-invalid', function(event) {
448          expect(form.validate()).to.be.equal(false);
449          done();
450        });
451        // Wait one tick for observeNodes.
452        Polymer.Base.async(function() {
453          expect(form.validate()).to.be.equal(false);
454          form.submit();
455          server.respond();
456        });
457      });
458
459      test('<input required> is validated and does not submit the form', function(done) {
460        var form = f.querySelector('#native-required');
461
462        var responses = 0;
463        form.addEventListener('iron-form-response', function(event) {
464          responses++;
465        });
466
467        // Wait one tick for observeNodes.
468        Polymer.Base.async(function() {
469          expect(form.validate()).to.be.equal(false);
470          form.submit();
471          server.respond();
472        });
473
474        setTimeout(function() {
475          expect(responses).to.be.equal(0);
476          done();
477        },  200);
478      });
479
480      test('invalid <input> but not required is validated and does not submit the form', function(done) {
481        var form = f.querySelector('#native-invalid');
482
483        var responses = 0;
484        form.addEventListener('iron-form-response', function(event) {
485          responses++;
486        });
487
488        // Wait one tick for observeNodes.
489        Polymer.Base.async(function() {
490          expect(form.validate()).to.be.equal(false);
491          form.submit();
492          server.respond();
493        });
494
495        setTimeout(function() {
496          expect(responses).to.be.equal(0);
497          done();
498        },  200);
499      });
500
501      test('<paper-input required> is validated and does not submit the form', function(done) {
502        var form = f.querySelector('#custom-required');
503
504        var responses = 0;
505        form.addEventListener('iron-form-response', function(event) {
506          responses++;
507        });
508
509        // Wait one tick for observeNodes.
510        Polymer.Base.async(function() {
511          form.validate();
512          expect(form.validate()).to.be.equal(false);
513          form.submit();
514          server.respond();
515        });
516
517        setTimeout(function() {
518          expect(responses).to.be.equal(0);
519          done();
520        },  200);
521      });
522
523      test('invalid <paper-input> but not required is validated and does not submit the form', function(done) {
524        var form = f.querySelector('#custom-invalid');
525
526        var responses = 0;
527        form.addEventListener('iron-form-response', function(event) {
528          responses++;
529        });
530
531        // Wait one tick for observeNodes.
532        Polymer.Base.async(function() {
533          expect(form.validate()).to.be.equal(false);
534          form.submit();
535          server.respond();
536        });
537
538        setTimeout(function() {
539          expect(responses).to.be.equal(0);
540          done();
541        },  200);
542      });
543    });
544
545    suite('submission', function() {
546      var form;
547      var server;
548
549      setup(function() {
550        form = fixture('submission');
551
552        server = sinon.fakeServer.create();
553        server.respondWith(
554          'GET',
555          /\/get.*/,
556          [
557            200,
558            '{"Content-Type":"application/json"}',
559            '{"success":true}'
560          ]
561        );
562        server.respondWith(
563          'POST',
564          /\/post.*/,
565          [
566            200,
567            '{"Content-Type":"application/json"}',
568            '{"success":true}'
569          ]
570        );
571        server.respondWith(
572          'GET',
573          /\/error.*/,
574          [
575            404,
576            '{"Content-Type":"application/text"}',
577            '{"success":false}'
578          ]
579        );
580      });
581
582      teardown(function() {
583        server.restore();
584      });
585
586      test('calling submit() on a form with method=get', function(done) {
587        form.addEventListener('iron-form-response', function(event) {
588          expect(event.detail.response.success).to.be.equal(true);
589          done();
590        });
591
592        // Wait one tick for observeNodes.
593        Polymer.Base.async(function() {
594          form.submit();
595          server.respond();
596        });
597      });
598
599      test('calling submit() on a form with method=post', function(done) {
600        form.addEventListener('iron-form-response', function(event) {
601          expect(event.detail.response.success).to.be.equal(true);
602          done();
603        });
604
605        // Wait one tick for observeNodes.
606        Polymer.Base.async(function() {
607          form._form.setAttribute('method', 'POST');
608          form._form.setAttribute('action', '/post');
609          form.submit();
610          server.respond();
611        });
612      });
613
614      test('calling submit() on a form with method unset', function(done) {
615        form.addEventListener('iron-form-response', function(event) {
616          expect(event.detail.response.success).to.be.equal(true);
617          done();
618        });
619
620        // Wait one tick for observeNodes.
621        Polymer.Base.async(function() {
622          form._form.removeAttribute('method');
623          form.submit();
624          server.respond();
625        });
626      });
627
628      test('pressing an <input type=submit> submits the form', function(done) {
629        form.addEventListener('iron-form-response', function(event) {
630          expect(event.detail.response.success).to.be.equal(true);
631          done();
632        });
633
634        // Wait one tick for observeNodes.
635        Polymer.Base.async(function() {
636          form._form.querySelector('input[type=submit]').click();
637          server.respond();
638        });
639      });
640
641      test('pressing an <input type=button> with an event handler submits the form', function(done) {
642        form.addEventListener('iron-form-response', function(event) {
643          expect(event.detail.response.success).to.be.equal(true);
644          done();
645        });
646
647        // Wait one tick for observeNodes.
648        Polymer.Base.async(function() {
649          var button = form._form.querySelector('input[type=button]');
650          button.addEventListener('click', function() {
651            form.submit();
652          });
653          button.click();
654
655          server.respond();
656        });
657      });
658
659      test('pressing a paper-button with an event handler submits the form', function(done) {
660        form.addEventListener('iron-form-response', function(event) {
661          expect(event.detail.response.success).to.be.equal(true);
662          done();
663        });
664
665        // Wait one tick for observeNodes.
666        Polymer.Base.async(function() {
667          var button = form._form.querySelector('paper-button');
668          button.addEventListener('click', function() {
669            form.submit();
670          });
671          button.click();
672
673          server.respond();
674        });
675      });
676
677      test('can modify the request in the presubmit', function(done) {
678        var submitted = false;
679        var presubmitted = false;
680
681        form.addEventListener('iron-form-submit', function() {
682          submitted = true;
683        });
684        form.addEventListener('iron-form-presubmit', function() {
685          presubmitted = true;
686          this.request.params = {batman: true};
687        });
688
689        form.addEventListener('iron-form-response', function(event) {
690          expect(submitted).to.be.equal(true);
691          expect(presubmitted).to.be.equal(true);
692
693          // We have changed the json parameters
694          expect(event.detail.url).to.contain('batman=true');
695
696          var response = event.detail.response;
697          expect(response).to.be.ok;
698          expect(response).to.be.an('object');
699          expect(response.success).to.be.equal(true);
700          done();
701        });
702
703        // Wait one tick for observeNodes.
704        Polymer.Base.async(function() {
705          form.submit();
706          server.respond();
707        });
708      });
709
710      test('can do a custom submission in the presubmit', function(done) {
711        var presubmitted = false;
712        // Since we are not using the normal form submission, these events should
713        // never be called.
714        var formResponseHandler = sinon.spy();
715        form.addEventListener('iron-form-response', formResponseHandler);
716        var formSubmitHandler = sinon.spy();
717        form.addEventListener('iron-form-submit', formSubmitHandler);
718
719        form.addEventListener('iron-form-presubmit', function(event) {
720          presubmitted = true;
721          event.preventDefault();
722          // Your custom submission logic could go here (like using Firebase).
723          // In this case, fire a custom event as a an example.
724          this.fire('custom-form-submit');
725        });
726        form.addEventListener('custom-form-submit', function(event) {
727          expect(presubmitted).to.be.equal(true);
728          expect(formResponseHandler.callCount).to.be.equal(0);
729          expect(formSubmitHandler.callCount).to.be.equal(0);
730          done();
731        });
732        // Wait one tick for observeNodes.
733        Polymer.Base.async(function() {
734          form.submit();
735        });
736      });
737
738      test('can relay errors', function(done) {
739        form.addEventListener('iron-form-error', function(event) {
740          var error = event.detail;
741          expect(error).to.be.ok;
742          expect(error).to.be.an('object');
743          expect(error.error).to.be.ok;
744          done();
745        });
746
747        // Wait one tick for observeNodes.
748        Polymer.Base.async(function() {
749          form._form.setAttribute('action', '/error');
750          form.submit();
751          server.respond();
752        });
753      });
754    });
755
756    suite('resetting', function() {
757      test('can reset a form', function(done) {
758        var form = fixture('resetting');
759
760        // Wait one tick for observeNodes.
761        Polymer.Base.async(function() {
762          var initial = form.serializeForm();
763          expect(JSON.stringify(initial)).to.be.equal('{"input1":"input1","input2":"","check1":"on","radio1":"on","papercheck1":"on","paper1":"paper1","paper2":""}');
764
765          // Modify all the values, flip all the inputs.
766          document.getElementById('input1').value = 'input1++';
767          document.getElementById('input2').value = 'input2++';
768          document.getElementById('check1').checked = false;
769          document.getElementById('check2').checked = true;
770          document.getElementById('radio1').checked = false;
771          document.getElementById('radio2').checked = true;
772          document.getElementById('papercheck1').checked = false;
773          document.getElementById('papercheck2').checked = true;
774          document.getElementById('paper1').value = 'paper1++';
775          document.getElementById('paper2').value = 'paper2++';
776
777          var updated = form.serializeForm();
778          expect(JSON.stringify(updated)).to.not.be.equal(initial);
779          form.reset();
780          var final = form.serializeForm();
781          expect(JSON.stringify(initial)).to.be.equal(JSON.stringify(final));
782          done();
783        });
784      });
785    });
786
787    suite('dynamically created', function() {
788      var server;
789
790      setup(function() {
791        server = sinon.fakeServer.create();
792        server.respondWith(
793          'GET',
794          /\/get.*/,
795          [
796            200,
797            '{"Content-Type":"application/json"}',
798            '{"success":true}'
799          ]
800        );
801      });
802
803      teardown(function() {
804        server.restore();
805      });
806
807      test('submits a form', function(done) {
808        var form = document.createElement('iron-form');
809        // Need to add to the document so observeNodes runs.
810        document.body.appendChild(form);
811
812        var nativeForm = document.createElement('form');
813        nativeForm.action = '/get';
814        nativeForm.method = 'get';
815
816        var input = document.createElement('input');
817        nativeForm.appendChild(input);
818        input.required = true;
819        input.name = 'foo';
820        Polymer.dom(form).appendChild(nativeForm);
821
822        form.addEventListener('iron-form-response', function(event) {
823          expect(event.detail.url).to.equal('/get?foo=bar');
824          expect(event.detail.response.success).to.be.equal(true);
825          document.body.removeChild(form);
826          done();
827        });
828
829        // Wait one tick for observeNodes.
830        Polymer.Base.async(function() {
831          expect(form.validate()).to.be.equal(false);
832          input.value = 'bar';
833          expect(form.validate()).to.be.equal(true);
834          form.submit();
835          server.respond();
836        }, 1);
837      });
838    });
839
840    suite('content type', function() {
841      var server;
842      var f;
843
844      setup(function() {
845        server = sinon.fakeServer.create();
846        f = fixture('content-type');
847      });
848
849      teardown(function() {
850        server.restore();
851      });
852
853      test('submits a form with text/plain', function(done) {
854        var form = f.querySelector('#plain-form');
855
856        server.respondWith(
857          'POST',
858          /\/valid\/url.*/,
859          function (request) {
860            expect(request.requestHeaders).to.deep.equal({
861                "content-type": "text/plain;charset=utf-8",
862                "accept": "application/json"});
863            expect(request.requestBody).to.deep.equal({
864                "paper1": "value1",
865                "paper2": "value2"});
866            done();
867          }
868        );
869
870          // Wait one tick for observeNodes.
871          Polymer.Base.async(function() {
872            form.submit();
873            server.respond();
874          });
875      });
876      test('submits a form with application/json', function(done) {
877          var form = f.querySelector('#json-form');
878
879          server.respondWith(
880            'POST',
881            /\/valid\/url.*/,
882            function (request) {
883              expect(request.requestHeaders).to.deep.equal({
884                  "content-type": "application/json;charset=utf-8",
885                  "accept": "application/json"});
886              expect(request.requestBody).to.equal(
887                  '{"paper1":"value1","paper2":"value2"}');
888              done();
889            }
890          );
891
892          // Wait one tick for observeNodes.
893          Polymer.Base.async(function() {
894            form.submit();
895            server.respond();
896          });
897      });
898        test('submits a form with application/x-www-form-urlencoded', function(done) {
899            var form = f.querySelector('#simple-form');
900
901            server.respondWith(
902                'POST',
903                /\/valid\/url.*/,
904                function (request) {
905                    expect(request.requestHeaders).to.deep.equal({
906                        "content-type": "application/x-www-form-urlencoded;charset=utf-8",
907                        "accept": "application/json"});
908                    expect(request.requestBody).to.equal(
909                        'paper1=value1&paper2=value2');
910                    done();
911                }
912            );
913
914            // Wait one tick for observeNodes.
915            Polymer.Base.async(function() {
916                form.submit();
917                server.respond();
918            });
919        });
920    });
921  </script>
922</body>
923</html>
924