Skip to content

Commit 8e43e7d

Browse files
committed
exposes test helper form-data and follow FormData specification
1 parent dd3f31a commit 8e43e7d

File tree

4 files changed

+179
-43
lines changed

4 files changed

+179
-43
lines changed

test-support/helpers/form-data.js

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

tests/helpers/form-data.js

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

tests/unit/uploader-test.js

Lines changed: 8 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -4,8 +4,9 @@ import { computed } from '@ember/object';
44
import $ from 'jquery';
55
import Uploader from 'ember-uploader/uploaders/uploader';
66
import test from 'ember-sinon-qunit/test-support/test';
7-
import TestableFormData from '../helpers/form-data';
7+
import TestableFormData from 'dummy/tests/helpers/form-data';
88
import { startMirage } from 'dummy/initializers/ember-cli-mirage';
9+
import { isArray } from '@ember/array';
910

1011
let file;
1112

@@ -77,11 +78,13 @@ module('EmberUploader.Uploader', function(hooks) {
7778
let uploader = Uploader.extend({
7879
paramName: 'files'
7980
}).create();
81+
let formData = uploader.createFormData([1, 2, 3]);
8082

81-
let formData = uploader.createFormData([1,2,3]);
82-
assert.equal(formData.data['files'][0], 1);
83-
assert.equal(formData.data['files'][1], 2);
84-
assert.equal(formData.data['files'][2], 3);
83+
assert.strictEqual(formData.get('files'), null, 'does not set to name without empty brackets');
84+
85+
let files = formData.getAll('files[]');
86+
assert.ok(isArray(files));
87+
assert.deepEqual(files, [1, 2, 3])
8588
});
8689

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

0 commit comments

Comments
 (0)