From 1f6119cff1e7075548dfe9bbfb36c24c86c7c77f Mon Sep 17 00:00:00 2001 From: vvakame Date: Tue, 22 Mar 2016 01:18:45 +0900 Subject: [PATCH] feat(ajax): add FormData support in AjaxObservable and add percent encoding for parameter key in body FormData spec https://xhr.spec.whatwg.org/#interface-formdata add some tests for ajax request body. --- spec/observables/dom/ajax-spec.ts | 95 ++++++++++++++++++++++++++++ src/observable/dom/AjaxObservable.ts | 4 +- 2 files changed, 98 insertions(+), 1 deletion(-) diff --git a/spec/observables/dom/ajax-spec.ts b/spec/observables/dom/ajax-spec.ts index d30f81c796..207b81a101 100644 --- a/spec/observables/dom/ajax-spec.ts +++ b/spec/observables/dom/ajax-spec.ts @@ -268,6 +268,101 @@ describe('Observable.ajax', () => { }); }); + describe('ajax request body', () => { + let rFormData: FormData; + + beforeEach(() => { + rFormData = root.FormData; + root.FormData = root.FormData || class {}; + }); + + afterEach(() => { + root.FormData = rFormData; + }); + + it('can take string body', () => { + const obj = { + url: '/flibbertyJibbet', + method: '', + body: 'foobar' + }; + + Rx.Observable.ajax(obj).subscribe(); + + expect(MockXMLHttpRequest.mostRecent.url).toBe('/flibbertyJibbet'); + expect(MockXMLHttpRequest.mostRecent.data).toBe('foobar'); + }); + + it('can take FormData body', () => { + const body = new root.FormData(); + const obj = { + url: '/flibbertyJibbet', + method: '', + body: body + }; + + Rx.Observable.ajax(obj).subscribe(); + + expect(MockXMLHttpRequest.mostRecent.url).toBe('/flibbertyJibbet'); + expect(MockXMLHttpRequest.mostRecent.data).toBe(body); + }); + + it('should not fail when FormData is undefined', () => { + root.FormData = void 0; + + const obj = { + url: '/flibbertyJibbet', + method: '', + headers: { + 'Content-Type': 'application/x-www-form-urlencoded' + }, + body: { '🌟': '🚀' } + }; + + Rx.Observable.ajax(obj).subscribe(); + + expect(MockXMLHttpRequest.mostRecent.url).toBe('/flibbertyJibbet'); + }); + + it('should send by form-urlencoded format', () => { + const body = { + '🌟': '🚀' + }; + const obj = { + url: '/flibbertyJibbet', + method: '', + headers: { + 'Content-Type': 'application/x-www-form-urlencoded' + }, + body: body + }; + + Rx.Observable.ajax(obj).subscribe(); + + expect(MockXMLHttpRequest.mostRecent.url).toBe('/flibbertyJibbet'); + expect(MockXMLHttpRequest.mostRecent.data).toBe('%F0%9F%8C%9F=%F0%9F%9A%80'); + }); + + it('should send by JSON', () => { + const body = { + '🌟': '🚀' + }; + const obj = { + url: '/flibbertyJibbet', + method: '', + headers: { + 'Content-Type': 'application/json' + }, + body: body + }; + + Rx.Observable.ajax(obj).subscribe(); + + expect(MockXMLHttpRequest.mostRecent.url).toBe('/flibbertyJibbet'); + expect(MockXMLHttpRequest.mostRecent.data).toBe('{"🌟":"🚀"}'); + }); + }); + describe('ajax.get', () => { it('should succeed on 200', () => { const expected = { foo: 'bar' }; diff --git a/src/observable/dom/AjaxObservable.ts b/src/observable/dom/AjaxObservable.ts index ea4c4020a0..94bd5cc073 100644 --- a/src/observable/dom/AjaxObservable.ts +++ b/src/observable/dom/AjaxObservable.ts @@ -245,6 +245,8 @@ export class AjaxSubscriber extends Subscriber { private serializeBody(body: any, contentType: string) { if (!body || typeof body === 'string') { return body; + } else if (root.FormData && body instanceof root.FormData) { + return body; } const splitIndex = contentType.indexOf(';'); @@ -254,7 +256,7 @@ export class AjaxSubscriber extends Subscriber { switch (contentType) { case 'application/x-www-form-urlencoded': - return Object.keys(body).map(key => `${key}=${encodeURI(body[key])}`).join('&'); + return Object.keys(body).map(key => `${encodeURI(key)}=${encodeURI(body[key])}`).join('&'); case 'application/json': return JSON.stringify(body); }