Skip to content

Commit 3677bb1

Browse files
committed
testing two open PRs together
1 parent 1c3a8d5 commit 3677bb1

File tree

4 files changed

+170
-106
lines changed

4 files changed

+170
-106
lines changed

addon/mixins/adapter-fetch.js

Lines changed: 19 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -38,7 +38,25 @@ export default Mixin.create({
3838
if (adapterHeaders) {
3939
options.headers = assign(options.headers || {}, adapterHeaders);
4040
}
41-
return mungOptionsForFetch(options);
41+
42+
const mungedOptions = mungOptionsForFetch(options);
43+
44+
// Mimics the default behavior in Ember Data's `ajaxOptions`, namely to set the
45+
// 'Content-Type' header to application/json if it is not a GET request and it has a body.
46+
if (
47+
mungedOptions.method !== 'GET' &&
48+
mungedOptions.body &&
49+
(mungedOptions.headers === undefined ||
50+
!(
51+
mungedOptions.headers['Content-Type'] ||
52+
mungedOptions.headers['content-type']
53+
))
54+
) {
55+
mungedOptions.headers = mungedOptions.headers || {};
56+
mungedOptions.headers['Content-Type'] = 'application/json; charset=utf-8';
57+
}
58+
59+
return mungedOptions;
4260
},
4361

4462
/**

addon/utils/mung-options-for-fetch.js

Lines changed: 9 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -12,7 +12,7 @@ export default function mungOptionsForFetch(_options) {
1212
}, _options);
1313

1414
// Default to 'GET' in case `type` is not passed in (mimics jQuery.ajax).
15-
options.method = options.method || options.type || 'GET';
15+
options.method = (options.method || options.type || 'GET').toUpperCase();
1616

1717
if (options.data) {
1818
// GET and HEAD requests can't have a `body`
@@ -24,19 +24,17 @@ export default function mungOptionsForFetch(_options) {
2424
options.url += `${queryParamDelimiter}${serializeQueryParams(options.data)}`;
2525
}
2626
} else {
27-
// NOTE: a request's body cannot be an object, so we stringify it if it is.
27+
// NOTE: a request's body cannot be a POJO, so we stringify it if it is.
2828
// JSON.stringify removes keys with values of `undefined` (mimics jQuery.ajax).
29-
// If the data is already a string, we assume it's already been stringified.
30-
options.body = typeof options.data !== 'string' ? JSON.stringify(options.data) : options.data;
29+
// If the data is not a POJO (it's a String, FormData, etc), we just set it.
30+
// If the data is a string, we assume it's a stringified object.
31+
if (Object.prototype.toString.call(options.data) === '[object Object]') {
32+
options.body = JSON.stringify(options.data);
33+
} else {
34+
options.body = options.data;
35+
}
3136
}
3237
}
3338

34-
// Mimics the default behavior in Ember Data's `ajaxOptions`, namely to set the
35-
// 'Content-Type' header to application/json if it is not a GET request and it has a body.
36-
if (options.method !== 'GET' && options.body && (options.headers === undefined || !(options.headers['Content-Type'] || options.headers['content-type']))) {
37-
options.headers = options.headers || {};
38-
options.headers['Content-Type'] = 'application/json; charset=utf-8';
39-
}
40-
4139
return options;
4240
}

tests/unit/mixins/adapter-fetch-test.js

Lines changed: 114 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -62,6 +62,120 @@ module('Unit | Mixin | adapter-fetch', function(hooks) {
6262
);
6363
});
6464

65+
test('mixin adds a default "Content-Type" header if none is present', function(assert) {
66+
assert.expect(2);
67+
const optionsNoHeaders = {
68+
url: 'https://emberjs.com',
69+
type: 'POST',
70+
data: { a: 1 }
71+
};
72+
const optionsHeadersWithoutContentType = {
73+
url: 'https://emberjs.com',
74+
type: 'POST',
75+
headers: {
76+
'X-foo': 'bar'
77+
},
78+
data: { a: 1 }
79+
};
80+
let options = this.JSONAPIAdapter.ajaxOptions(optionsNoHeaders.url, optionsNoHeaders.type, optionsNoHeaders);
81+
assert.deepEqual(
82+
options.headers,
83+
{
84+
'Content-Type': 'application/json; charset=utf-8',
85+
'custom-header': 'foo',
86+
},
87+
"POST call's options without a headers object now has a headers object which has a content-type header"
88+
);
89+
90+
options = this.JSONAPIAdapter.ajaxOptions(
91+
optionsHeadersWithoutContentType.url,
92+
optionsHeadersWithoutContentType.type,
93+
optionsHeadersWithoutContentType
94+
);
95+
assert.deepEqual(
96+
options.headers,
97+
{
98+
'Content-Type': 'application/json; charset=utf-8',
99+
'X-foo': 'bar',
100+
'custom-header': 'foo',
101+
},
102+
"POST call's options with a headers object now has a content-type header"
103+
);
104+
});
105+
106+
test('mixin does not add a "Content-Type" header if it is a GET request', function(assert) {
107+
assert.expect(1);
108+
const getOptions = {
109+
url: 'https://emberjs.com',
110+
type: 'GET',
111+
headers: {
112+
foo: 'bar'
113+
}
114+
};
115+
116+
let options = this.JSONAPIAdapter.ajaxOptions(getOptions.url, getOptions.type, getOptions);
117+
assert.deepEqual(
118+
options.headers,
119+
{
120+
foo: 'bar',
121+
'custom-header': 'foo',
122+
},
123+
"GET call's options has no added content-type header"
124+
);
125+
});
126+
127+
test('mixin does not add a "Content-Type" header if a POST request has no body', function(assert) {
128+
assert.expect(1);
129+
const postNoDataOptions = {
130+
url: 'https://emberjs.com',
131+
type: 'GET',
132+
headers: {
133+
foo: 'bar',
134+
'custom-header': 'foo',
135+
}
136+
};
137+
138+
let options = this.JSONAPIAdapter.ajaxOptions(
139+
postNoDataOptions.url,
140+
postNoDataOptions.type,
141+
postNoDataOptions
142+
);
143+
assert.deepEqual(
144+
options.headers,
145+
{
146+
foo: 'bar',
147+
'custom-header': 'foo',
148+
},
149+
'POST call with no body has no added content-type header'
150+
);
151+
});
152+
153+
test('mixin respects the "Content-Type" header if present', function(assert) {
154+
assert.expect(1);
155+
const optionsHeadersWithContentType = {
156+
url: 'https://emberjs.com',
157+
type: 'POST',
158+
headers: {
159+
'Content-Type': 'application/special-type'
160+
},
161+
data: { a: 1 }
162+
};
163+
164+
let options = this.JSONAPIAdapter.ajaxOptions(
165+
optionsHeadersWithContentType.url,
166+
optionsHeadersWithContentType.type,
167+
optionsHeadersWithContentType
168+
);
169+
assert.deepEqual(
170+
options.headers,
171+
{
172+
'Content-Type': 'application/special-type',
173+
'custom-header': 'foo',
174+
},
175+
"POST call's options has the original content-type header"
176+
);
177+
});
178+
65179
test('parseFetchResponseForError is able to be overwritten to mutate the error payload that gets passed along', function(assert) {
66180
assert.expect(1);
67181

tests/unit/utils/mung-options-for-fetch-test.js

Lines changed: 28 additions & 94 deletions
Original file line numberDiff line numberDiff line change
@@ -53,9 +53,6 @@ module('Unit | mungOptionsForFetch', function() {
5353
url: 'https://emberjs.com',
5454
method: 'POST',
5555
type: 'POST',
56-
headers: {
57-
'Content-Type': 'application/json; charset=utf-8'
58-
},
5956
body: '{"a":1}',
6057
data: {
6158
a: 1
@@ -65,111 +62,34 @@ module('Unit | mungOptionsForFetch', function() {
6562
);
6663
});
6764

68-
test('mungOptionsForFetch adds a default "Content-Type" header if none is present', function(assert) {
69-
assert.expect(2);
70-
const optionsNoHeaders = {
71-
url: 'https://emberjs.com',
72-
type: 'POST',
73-
data: { a: 1 }
74-
};
75-
const optionsHeadersWithoutContentType = {
76-
url: 'https://emberjs.com',
77-
type: 'POST',
78-
headers: {
79-
'X-foo': 'bar'
80-
},
81-
data: { a: 1 }
82-
};
83-
let options = mungOptionsForFetch(optionsNoHeaders);
84-
assert.deepEqual(
85-
options.headers,
86-
{
87-
'Content-Type': 'application/json; charset=utf-8'
88-
},
89-
"POST call's options without a headers object now has a headers object which has a content-type header"
90-
);
91-
92-
options = mungOptionsForFetch(optionsHeadersWithoutContentType);
93-
assert.deepEqual(
94-
options.headers,
95-
{
96-
'Content-Type': 'application/json; charset=utf-8',
97-
'X-foo': 'bar'
98-
},
99-
"POST call's options with a headers object now has a content-type header"
100-
);
101-
});
102-
103-
test('mungOptionsForFetch does not add a "Content-Type" header if it is a GET request', function(assert) {
65+
test('mungOptionsForFetch sets the method to "GET" if `type` is not provided', function(assert) {
10466
assert.expect(1);
10567
const getOptions = {
10668
url: 'https://emberjs.com',
107-
type: 'GET',
108-
headers: {
109-
foo: 'bar'
110-
}
111-
};
112-
113-
let options = mungOptionsForFetch(getOptions);
114-
assert.deepEqual(
115-
options.headers,
116-
{
117-
foo: 'bar'
118-
},
119-
"GET call's options has no added content-type header"
120-
);
121-
});
122-
123-
test('mungOptionsForFetch does not add a "Content-Type" header if a POST request has no body', function(assert) {
124-
assert.expect(1);
125-
const PostNoDataOptions = {
126-
url: 'https://emberjs.com',
127-
type: 'GET',
128-
headers: {
129-
foo: 'bar'
130-
}
69+
type: undefined
13170
};
13271

133-
let options = mungOptionsForFetch(PostNoDataOptions);
134-
assert.deepEqual(
135-
options.headers,
136-
{
137-
foo: 'bar'
138-
},
139-
'POST call with no body has no added content-type header'
140-
);
72+
const options = mungOptionsForFetch(getOptions);
73+
assert.equal(options.method, 'GET');
14174
});
14275

143-
test('mungOptionsForFetch respects the "Content-Type" header if present', function(assert) {
144-
assert.expect(1);
145-
const optionsHeadersWithContentType = {
76+
test('mungOptionsForFetch sets the method to an uppercase string', function(assert) {
77+
assert.expect(2);
78+
const getOptions = {
14679
url: 'https://emberjs.com',
147-
type: 'POST',
148-
headers: {
149-
'Content-Type': 'application/special-type'
150-
},
151-
data: { a: 1 }
80+
type: 'get',
15281
};
15382

154-
let options = mungOptionsForFetch(optionsHeadersWithContentType);
155-
assert.deepEqual(
156-
options.headers,
157-
{
158-
'Content-Type': 'application/special-type'
159-
},
160-
"POST call's options has the original content-type header"
161-
);
162-
});
83+
let options = mungOptionsForFetch(getOptions);
84+
assert.equal(options.method, 'GET');
16385

164-
test('mungOptionsForFetch sets the method to "GET" if `type` is not provided', function(assert) {
165-
assert.expect(1);
166-
const getOptions = {
86+
const postOptions = {
16787
url: 'https://emberjs.com',
168-
type: undefined
88+
method: 'post',
16989
};
17090

171-
const options = mungOptionsForFetch(getOptions);
172-
assert.equal(options.method, 'GET');
91+
options = mungOptionsForFetch(postOptions);
92+
assert.equal(options.method, 'POST');
17393
});
17494

17595
test('mungOptionsForFetch adds string query params to the url correctly', function(assert) {
@@ -340,4 +260,18 @@ module('Unit | mungOptionsForFetch', function() {
340260
const postOptions = mungOptionsForFetch(postData);
341261
assert.equal(postOptions.body, '{}', "'options.body' is an empty object");
342262
});
263+
264+
test("mungOptionsForFetch sets the request body correctly when 'data' is FormData", function(assert) {
265+
assert.expect(1);
266+
267+
const formData = new FormData()
268+
const postData = {
269+
url: 'https://emberjs.com',
270+
type: 'POST',
271+
data: formData,
272+
};
273+
274+
const postOptions = mungOptionsForFetch(postData);
275+
assert.equal(postOptions.body, formData, "'options.body' is the FormData passed in");
276+
});
343277
});

0 commit comments

Comments
 (0)