Skip to content

Commit 88aa09f

Browse files
committed
exposes test helper form-data and follow FormData specification
1 parent f79b9f3 commit 88aa09f

File tree

4 files changed

+176
-42
lines changed

4 files changed

+176
-42
lines changed

test-support/helpers/form-data.js

Lines changed: 108 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,108 @@
1+
/*
2+
* Allows to inject and remove a FormData polyfill which supports get() and
3+
* getAll() methods.
4+
*
5+
* Except for Chrome (>= 50) and Firefox (>= 39) major browser engines implement
6+
* only a very basic subset of FormData specification. Especially current Safari,
7+
* IE, Edge and PhantomJS does not support any methods to retrieve data of a
8+
* FormData object.
9+
* This is a hard limitation in testing. E.g. in an ember-cli-mirage route handler
10+
* you are not able to retrieve values of the request.
11+
*
12+
* Implementation follows FormData specification:
13+
* https://xhr.spec.whatwg.org/#interface-formdata
14+
*/
15+
16+
import Ember from 'ember';
17+
18+
const { isArray, warn } = Ember;
19+
20+
function TestableFormData() {
21+
this._data = {};
22+
}
23+
24+
/*
25+
* Injects FormData polyfill by overriding window.FormData if current browser
26+
* engine does not implement FormData.get method.
27+
* Overriding window.FormData could be forced by passing `true` as first argument.
28+
*/
29+
TestableFormData.inject = function(force) {
30+
if (
31+
window &&
32+
(force || typeof window.FormData.get === 'undefined')
33+
) {
34+
this.OldFormData = window.FormData;
35+
window.FormData = TestableFormData;
36+
}
37+
};
38+
39+
TestableFormData.remove = function() {
40+
if (window && this.OldFormData) {
41+
window.FormData = this.OldFormData;
42+
delete this.OldFormData;
43+
}
44+
};
45+
46+
/*
47+
* FormData.append()
48+
* The append(name, value) and append(name, blobValue, filename) methods, when
49+
* invoked, must run these steps:
50+
* 1. Let value be value if given, and blobValue otherwise.
51+
* 2. Let entry be the result of creating an entry with name, value, and
52+
* filename if given.
53+
* 3. Append entry to context object’s list of entries.
54+
* Note: The reason there is an argument named value as well as blobValue is
55+
* due to a limitation of the editing software used to write the XMLHttpRequest
56+
* Standard.
57+
* https://xhr.spec.whatwg.org/#dom-formdata-append
58+
*/
59+
TestableFormData.prototype.append = function(name, value, filename) {
60+
if (!isArray(this._data[name])) {
61+
this._data[name] = [];
62+
}
63+
/*
64+
* To create an entry for name, value, and optionally a filename, run these steps:
65+
* 3. If value is a Blob object and not a File object, then set value to a
66+
* new File object, representing the same bytes, whose name attribute
67+
* value is "blob".
68+
* 4. If value is (now) a File object and filename is given, then set value
69+
* to a new File object, representing the same bytes, whose name attribute
70+
* value is filename.
71+
* https://xhr.spec.whatwg.org/#create-an-entry
72+
*/
73+
if (
74+
// it's a Blob
75+
value instanceof Blob &&
76+
// but it's not a File yet
77+
!(value instanceof File) &&
78+
// File is supported by current engine
79+
typeof File === 'function'
80+
) {
81+
value = new File([value], filename || 'blob');
82+
}
83+
this._data[name].push(value);
84+
};
85+
86+
/*
87+
* FormData.get()
88+
* The get(name) method, when invoked, must return the value of the first entry
89+
* whose name is name, and null otherwise.
90+
* https://xhr.spec.whatwg.org/#dom-formdata-get
91+
*/
92+
TestableFormData.prototype.get = function(name) {
93+
let values = this._data[name];
94+
return ( isArray(values) && values.length > 0 ) ? values[0] : null;
95+
};
96+
97+
/*
98+
* FormData.getAll()
99+
* The getAll(name) method, when invoked, must return the values of all entries
100+
* whose name is name, in list order, and the empty sequence otherwise.
101+
* https://xhr.spec.whatwg.org/#dom-formdata-getall
102+
*/
103+
TestableFormData.prototype.getAll = function(name) {
104+
let value = this._data[name];
105+
return isArray(value) ? value : [];
106+
};
107+
108+
export default TestableFormData;

tests/helpers/form-data.js

Lines changed: 0 additions & 37 deletions
This file was deleted.
Lines changed: 60 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,60 @@
1+
import Ember from 'ember';
2+
import TestableFormData from 'dummy/tests/helpers/form-data';
3+
4+
const { isArray, warn } = Ember;
5+
6+
module("test helper | FormData");
7+
8+
test('supports empty value', function(assert) {
9+
expect(3);
10+
let formData = new TestableFormData();
11+
strictEqual(formData.get('not-existing'), null, 'get returns null');
12+
ok(isArray(formData.getAll('not-existing')), 'getAll returns an array');
13+
equal(formData.getAll('not-existing').length, 0, 'array returned by getAll is empty');
14+
});
15+
16+
test('supports single value', function(assert) {
17+
expect(3);
18+
let formData = new TestableFormData();
19+
formData.append('foo', 'a');
20+
strictEqual(formData.get('foo'), 'a', 'get returns value');
21+
ok(isArray(formData.getAll('foo')), 'getAll returns an array');
22+
equal(formData.getAll('foo')[0], 'a', 'array returned by getAll contains value');
23+
});
24+
25+
test('supports multiple values', function(assert) {
26+
expect(4);
27+
let formData = new TestableFormData();
28+
formData.append('foo', 'a');
29+
formData.append('foo', 'b');
30+
strictEqual(formData.get('foo'), 'a', 'get returns value which was set as first');
31+
ok(isArray(formData.getAll('foo')), 'getAll returns an array');
32+
equal(formData.getAll('foo')[0], 'a', 'array returned by getAll contains first value');
33+
equal(formData.getAll('foo')[1], 'b', 'array returned by getAll contains second value');
34+
})
35+
36+
test('supports appending Blob', function(assert) {
37+
let formData = new TestableFormData();
38+
formData.append('foo', new Blob([]));
39+
ok(isArray(formData.getAll('foo')), 'getAll returns an array');
40+
ok(formData.getAll('foo')[0] instanceof Blob, 'array returned by getAll contains value');
41+
});
42+
43+
test('supports appending File', function(assert) {
44+
if (typeof File !== 'function') {
45+
warn('Skipping File tests since File not supported by current engine');
46+
expect(0);
47+
return;
48+
}
49+
expect(5);
50+
let formData = new TestableFormData();
51+
let fileObject = new File([], 'untouched');
52+
formData.append('foo', new Blob([]));
53+
formData.append('foo', fileObject);
54+
formData.append('foo', new Blob([]), 'test.jpg');
55+
ok(formData.getAll('foo')[0] instanceof File, 'converts Blob to File object');
56+
equal(formData.getAll('foo')[0].name, 'blob', 'sets name to blob if no name is given');
57+
strictEqual(formData.getAll('foo')[1], fileObject, 'File object does not get changed');
58+
ok(formData.getAll('foo')[2] instanceof File, 'converts Blob to File object');
59+
equal(formData.getAll('foo')[2].name, 'test.jpg', 'supports specifing name');
60+
});

tests/unit/uploader-test.js

Lines changed: 8 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
import { Uploader } from 'ember-uploader/uploaders';
22
import test from 'dummy/tests/ember-sinon-qunit/test';
33
import startMirage from '../helpers/setup-mirage-for-units';
4-
import TestableFormData from '../helpers/form-data';
4+
import TestableFormData from 'dummy/tests/helpers/form-data';
55

66
let file;
77

@@ -65,16 +65,19 @@ test("has an ajax request of type 'PUT'", function() {
6565
});
6666

6767
test("it can upload multiple files", function() {
68-
expect(3);
68+
expect(5);
6969

7070
let uploader = Uploader.extend({
7171
paramName: 'files'
7272
}).create();
7373

7474
let formData = uploader.createFormData([1,2,3]);
75-
equal(formData.data['files'][0], 1);
76-
equal(formData.data['files'][1], 2);
77-
equal(formData.data['files'][2], 3);
75+
strictEqual(formData.get('files'), null, 'does not set to name without empty brackets');
76+
let files = formData.getAll('files[]');
77+
ok(Ember.isArray(files));
78+
equal(files[0], 1);
79+
equal(files[1], 2);
80+
equal(files[2], 3);
7881
});
7982

8083
test("uploads to the given url", function() {

0 commit comments

Comments
 (0)