Skip to content

Commit

Permalink
exposes test helper form-data and follow FormData specification
Browse files Browse the repository at this point in the history
  • Loading branch information
jelhan committed Jun 23, 2017
1 parent f79b9f3 commit 88aa09f
Show file tree
Hide file tree
Showing 4 changed files with 176 additions and 42 deletions.
108 changes: 108 additions & 0 deletions test-support/helpers/form-data.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,108 @@
/*
* Allows to inject and remove a FormData polyfill which supports get() and
* getAll() methods.
*
* Except for Chrome (>= 50) and Firefox (>= 39) major browser engines implement
* only a very basic subset of FormData specification. Especially current Safari,
* IE, Edge and PhantomJS does not support any methods to retrieve data of a
* FormData object.
* This is a hard limitation in testing. E.g. in an ember-cli-mirage route handler
* you are not able to retrieve values of the request.
*
* Implementation follows FormData specification:
* https://xhr.spec.whatwg.org/#interface-formdata
*/

import Ember from 'ember';

const { isArray, warn } = Ember;

function TestableFormData() {
this._data = {};
}

/*
* Injects FormData polyfill by overriding window.FormData if current browser
* engine does not implement FormData.get method.
* Overriding window.FormData could be forced by passing `true` as first argument.
*/
TestableFormData.inject = function(force) {
if (
window &&
(force || typeof window.FormData.get === 'undefined')
) {
this.OldFormData = window.FormData;
window.FormData = TestableFormData;
}
};

TestableFormData.remove = function() {
if (window && this.OldFormData) {
window.FormData = this.OldFormData;
delete this.OldFormData;
}
};

/*
* FormData.append()
* The append(name, value) and append(name, blobValue, filename) methods, when
* invoked, must run these steps:
* 1. Let value be value if given, and blobValue otherwise.
* 2. Let entry be the result of creating an entry with name, value, and
* filename if given.
* 3. Append entry to context object’s list of entries.
* Note: The reason there is an argument named value as well as blobValue is
* due to a limitation of the editing software used to write the XMLHttpRequest
* Standard.
* https://xhr.spec.whatwg.org/#dom-formdata-append
*/
TestableFormData.prototype.append = function(name, value, filename) {
if (!isArray(this._data[name])) {
this._data[name] = [];
}
/*
* To create an entry for name, value, and optionally a filename, run these steps:
* 3. If value is a Blob object and not a File object, then set value to a
* new File object, representing the same bytes, whose name attribute
* value is "blob".
* 4. If value is (now) a File object and filename is given, then set value
* to a new File object, representing the same bytes, whose name attribute
* value is filename.
* https://xhr.spec.whatwg.org/#create-an-entry
*/
if (
// it's a Blob
value instanceof Blob &&
// but it's not a File yet
!(value instanceof File) &&
// File is supported by current engine
typeof File === 'function'
) {
value = new File([value], filename || 'blob');
}
this._data[name].push(value);
};

/*
* FormData.get()
* The get(name) method, when invoked, must return the value of the first entry
* whose name is name, and null otherwise.
* https://xhr.spec.whatwg.org/#dom-formdata-get
*/
TestableFormData.prototype.get = function(name) {
let values = this._data[name];
return ( isArray(values) && values.length > 0 ) ? values[0] : null;
};

/*
* FormData.getAll()
* The getAll(name) method, when invoked, must return the values of all entries
* whose name is name, in list order, and the empty sequence otherwise.
* https://xhr.spec.whatwg.org/#dom-formdata-getall
*/
TestableFormData.prototype.getAll = function(name) {
let value = this._data[name];
return isArray(value) ? value : [];
};

export default TestableFormData;
37 changes: 0 additions & 37 deletions tests/helpers/form-data.js

This file was deleted.

60 changes: 60 additions & 0 deletions tests/unit/test-helpers/form-data-test.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,60 @@
import Ember from 'ember';
import TestableFormData from 'dummy/tests/helpers/form-data';

const { isArray, warn } = Ember;

module("test helper | FormData");

test('supports empty value', function(assert) {
expect(3);
let formData = new TestableFormData();
strictEqual(formData.get('not-existing'), null, 'get returns null');
ok(isArray(formData.getAll('not-existing')), 'getAll returns an array');
equal(formData.getAll('not-existing').length, 0, 'array returned by getAll is empty');
});

test('supports single value', function(assert) {
expect(3);
let formData = new TestableFormData();
formData.append('foo', 'a');
strictEqual(formData.get('foo'), 'a', 'get returns value');
ok(isArray(formData.getAll('foo')), 'getAll returns an array');
equal(formData.getAll('foo')[0], 'a', 'array returned by getAll contains value');
});

test('supports multiple values', function(assert) {
expect(4);
let formData = new TestableFormData();
formData.append('foo', 'a');
formData.append('foo', 'b');
strictEqual(formData.get('foo'), 'a', 'get returns value which was set as first');
ok(isArray(formData.getAll('foo')), 'getAll returns an array');
equal(formData.getAll('foo')[0], 'a', 'array returned by getAll contains first value');
equal(formData.getAll('foo')[1], 'b', 'array returned by getAll contains second value');
})

test('supports appending Blob', function(assert) {
let formData = new TestableFormData();
formData.append('foo', new Blob([]));
ok(isArray(formData.getAll('foo')), 'getAll returns an array');
ok(formData.getAll('foo')[0] instanceof Blob, 'array returned by getAll contains value');
});

test('supports appending File', function(assert) {
if (typeof File !== 'function') {
warn('Skipping File tests since File not supported by current engine');
expect(0);
return;
}
expect(5);
let formData = new TestableFormData();
let fileObject = new File([], 'untouched');
formData.append('foo', new Blob([]));
formData.append('foo', fileObject);
formData.append('foo', new Blob([]), 'test.jpg');
ok(formData.getAll('foo')[0] instanceof File, 'converts Blob to File object');
equal(formData.getAll('foo')[0].name, 'blob', 'sets name to blob if no name is given');
strictEqual(formData.getAll('foo')[1], fileObject, 'File object does not get changed');
ok(formData.getAll('foo')[2] instanceof File, 'converts Blob to File object');
equal(formData.getAll('foo')[2].name, 'test.jpg', 'supports specifing name');
});
13 changes: 8 additions & 5 deletions tests/unit/uploader-test.js
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
import { Uploader } from 'ember-uploader/uploaders';
import test from 'dummy/tests/ember-sinon-qunit/test';
import startMirage from '../helpers/setup-mirage-for-units';
import TestableFormData from '../helpers/form-data';
import TestableFormData from 'dummy/tests/helpers/form-data';

let file;

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

test("it can upload multiple files", function() {
expect(3);
expect(5);

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

let formData = uploader.createFormData([1,2,3]);
equal(formData.data['files'][0], 1);
equal(formData.data['files'][1], 2);
equal(formData.data['files'][2], 3);
strictEqual(formData.get('files'), null, 'does not set to name without empty brackets');
let files = formData.getAll('files[]');
ok(Ember.isArray(files));
equal(files[0], 1);
equal(files[1], 2);
equal(files[2], 3);
});

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

0 comments on commit 88aa09f

Please sign in to comment.