Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

exposes test helper form-data and follow FormData specification #155

Open
wants to merge 2 commits into
base: master
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion .travis.yml
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@ language: node_js
node_js:
# we recommend testing addons with the same minimum supported node version as Ember CLI
# so that your addon works for all apps
- "4"
- "8"

sudo: false
dist: trusty
Expand Down
106 changes: 106 additions & 0 deletions test-support/helpers/form-data.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,106 @@
/*
* 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 { isArray } from '@ember/array';

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;
38 changes: 0 additions & 38 deletions tests/helpers/form-data.js

This file was deleted.

65 changes: 65 additions & 0 deletions tests/unit/test-helpers/form-data-test.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,65 @@
import { module, test } from 'qunit';
import { setupTest } from 'ember-qunit';
import TestableFormData from 'dummy/tests/helpers/form-data';
import { isArray } from '@ember/array';
import { warn } from '@ember/debug';

module("test helper | FormData", function(hooks) {
setupTest(hooks);

test('supports empty value', function(assert) {
let formData = new TestableFormData();

assert.strictEqual(formData.get('not-existing'), null, 'get returns null');
assert.ok(isArray(formData.getAll('not-existing')), 'getAll returns an array');
assert.equal(formData.getAll('not-existing').length, 0, 'array returned by getAll is empty');
});

test('supports single value', function(assert) {
let formData = new TestableFormData();
formData.append('foo', 'a');

assert.strictEqual(formData.get('foo'), 'a', 'get returns value');
assert.ok(isArray(formData.getAll('foo')), 'getAll returns an array');
assert.equal(formData.getAll('foo')[0], 'a', 'array returned by getAll contains value');
});

test('supports multiple values', function(assert) {
let formData = new TestableFormData();
formData.append('foo', 'a');
formData.append('foo', 'b');

assert.strictEqual(formData.get('foo'), 'a', 'get returns value which was set as first');
assert.ok(isArray(formData.getAll('foo')), 'getAll returns an array');
assert.equal(formData.getAll('foo')[0], 'a', 'array returned by getAll contains first value');
assert.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([]));

assert.ok(isArray(formData.getAll('foo')), 'getAll returns an array');
assert.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');
assert.expect(0);
return;
}

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');

assert.ok(formData.getAll('foo')[0] instanceof File, 'converts Blob to File object');
assert.equal(formData.getAll('foo')[0].name, 'blob', 'sets name to blob if no name is given');
assert.strictEqual(formData.getAll('foo')[1], fileObject, 'File object does not get changed');
assert.ok(formData.getAll('foo')[2] instanceof File, 'converts Blob to File object');
assert.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
Expand Up @@ -4,8 +4,9 @@ import { computed } from '@ember/object';
import $ from 'jquery';
import Uploader from 'ember-uploader/uploaders/uploader';
import test from 'ember-sinon-qunit/test-support/test';
import TestableFormData from '../helpers/form-data';
import TestableFormData from 'dummy/tests/helpers/form-data';
import { startMirage } from 'dummy/initializers/ember-cli-mirage';
import { isArray } from '@ember/array';

let file;

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

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

let files = formData.getAll('files[]');
assert.ok(isArray(files));
assert.deepEqual(files, [1, 2, 3])
});

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