dojo
Version:
Dojo core is a powerful, lightweight library that makes common tasks quicker and easier. Animate elements, manipulate the DOM, and query with easy CSS syntax, all without sacrificing performance.
702 lines (607 loc) • 16.5 kB
JavaScript
define([
'intern!object',
'intern/chai!assert',
'../../../request/xhr',
'../../../errors/RequestTimeoutError',
'../../../errors/CancelError',
'dojo/promise/all',
'dojo/query',
'require',
'../../../has'
], function(registerSuite, assert, xhr, RequestTimeoutError, CancelError, all, query, require, has){
var global = this;
var hasFormData = 'FormData' in this && typeof FormData === 'function';
var hasResponseType = typeof XMLHttpRequest !== 'undefined' &&
typeof new XMLHttpRequest().responseType !== 'undefined';
var formData;
function hasFile(){
if (typeof File !== 'undefined') {
try {
new File();
} catch (e) {
// File is not a constructor.
}
}
return false;
}
registerSuite({
name: 'dojo/request/xhr',
'.get': function(){
var promise = xhr.get('/__services/request/xhr', {
preventCache: true,
handleAs: 'json'
});
assert.isFunction(promise.then);
assert.isFunction(promise.cancel);
assert.isObject(promise.response);
assert.isFunction(promise.response.then);
assert.isFunction(promise.response.cancel);
return promise.response.then(function(response){
assert.strictEqual(response.data.method, 'GET');
assert.strictEqual(response.xhr.readyState, 4);
return response;
});
},
'.get 404': function(){
var def = this.async(),
promise = xhr.get(require.toUrl('./xhr_blarg.html'), {
preventCache: true
});
promise.response.then(
def.reject,
def.callback(function(error){
assert.strictEqual(error.response.status, 404);
})
);
},
'.get json with truthy value': function(){
var def = this.async(),
promise = xhr.get(require.toUrl('./support/truthy.json'), {
preventCache: true,
handleAs: 'json'
});
promise.then(
def.callback(function(response){
assert.strictEqual(response, true);
})
);
},
'.get json with falsy value': function(){
var def = this.async(),
promise = xhr.get(require.toUrl('./support/falsy.json'), {
preventCache: true,
handleAs: 'json'
});
promise.then(
def.callback(function(response){
assert.strictEqual(response, false);
})
);
},
'.get with progress': function(){
var def = this.async(),
promise = xhr.get(require.toUrl('./support/truthy.json'), {
handleAs: 'json',
preventCache: true
});
promise.then(def.callback(
function(){
}), function(error){
assert.isTrue(false, error);
}, def.callback(function(event){
assert.strictEqual(event.transferType, 'download');
}));
return def.promise;
},
'.get with query': function(){
var def = this.async(),
promise = xhr.get('/__services/request/xhr?color=blue', {
query: {
foo: ['bar', 'baz'],
thud: 'thonk',
xyzzy: 3
},
handleAs: 'json'
});
promise.response.then(def.callback(function(response){
assert.strictEqual(response.data.method, 'GET');
var query = response.data.query;
assert.ok(query.color && query.foo && query.foo.length && query.thud && query.xyzzy);
assert.strictEqual(query.color, 'blue');
assert.strictEqual(query.foo.length, 2);
assert.strictEqual(query.thud, 'thonk');
assert.strictEqual(query.xyzzy, '3');
assert.strictEqual(response.url, '/__services/request/xhr?color=blue&foo=bar&foo=baz&thud=thonk&xyzzy=3');
}));
},
'.post': function(){
var def = this.async(),
promise = xhr.post('/__services/request/xhr', {
data: {color: 'blue'},
handleAs: 'json'
});
promise.response.then(
def.callback(function(response){
assert.strictEqual(response.data.method, 'POST');
var payload = response.data.payload;
assert.ok(payload && payload.color);
assert.strictEqual(payload.color, 'blue');
}),
def.reject
);
},
'.post ArrayBuffer': function(){
if (has('native-arraybuffer')) {
var def = this.async(),
str = 'foo',
arrbuff = new ArrayBuffer(str.length),
i8array = new Uint8Array(arrbuff);
for (var i = 0; i < str.length; i++) {
i8array[i] = str.charCodeAt(i);
}
var promise = xhr.post('/__services/request/xhr', {
data: arrbuff,
handleAs: 'json',
headers: {
'Content-Type': 'text/plain'
}
});
promise.response.then(
def.callback(function(response){
assert.strictEqual(response.data.method, 'POST');
var payload = response.data.payload;
assert.deepEqual(payload, {'foo': ''});
}),
def.reject
);
} else {
this.skip('ArrayBuffer not available');
}
},
'.post Blob': function(){
if (has('native-blob')) {
var def = this.async(),
str = 'foo',
blob = new Blob([str], {type: 'text/plain'});
var promise = xhr.post('/__services/request/xhr', {
data: blob,
handleAs: 'json',
headers: {
'Content-Type': 'text/plain'
}
});
promise.response.then(
def.callback(function(response){
assert.strictEqual(response.data.method, 'POST');
var payload = response.data.payload;
assert.deepEqual(payload, {'foo': ''});
}),
def.reject
);
} else {
this.skip('Blob not available');
}
},
'.post File': function(){
if (hasFile()) {
var def = this.async(),
str = 'foo',
file = new File([str], 'bar.txt', {type: 'text/plain'});
var promise = xhr.post('/__services/request/xhr', {
data: file,
handleAs: 'json',
headers: {
'Content-Type': 'text/plain'
}
});
promise.response.then(
def.callback(function(response){
assert.strictEqual(response.data.method, 'POST');
var payload = response.data.payload;
assert.deepEqual(payload, {'foo': ''});
}),
def.reject
);
} else {
this.skip('File or File constructor not available');
}
},
'.post File with upload progress': function(){
if (hasFile()) {
var def = this.async(),
str = 'foo',
file = new File([str], 'bar.txt', {type: 'text/plain'});
var promise = xhr.post('/__services/request/xhr', {
data: file,
handleAs: 'json',
uploadProgress: true,
query: {
simulateProgress: true
},
headers: {
'Content-Type': 'text/plain'
}
});
promise.then(null, def.reject, def.callback(function(progressEvent){
assert.isDefined(progressEvent.xhr);
assert.deepEqual(progressEvent.transferType, 'upload');
}));
} else {
this.skip('File or File constructor not available');
}
},
'.post with query': function(){
var def = this.async(),
promise = xhr.post('/__services/request/xhr', {
query: {
foo: ['bar', 'baz'],
thud: 'thonk',
xyzzy: 3
},
data: {color: 'blue'},
handleAs: 'json'
});
promise.then(
def.callback(function(data){
assert.strictEqual(data.method, 'POST');
var query = data.query,
payload = data.payload;
assert.ok(query);
assert.deepEqual(query.foo, ['bar', 'baz']);
assert.strictEqual(query.thud, 'thonk');
assert.strictEqual(query.xyzzy, '3');
assert.ok(payload);
assert.strictEqual(payload.color, 'blue');
}),
def.reject
);
},
'.post string payload': function(){
var def = this.async(),
promise = xhr.post('/__services/request/xhr', {
data: 'foo=bar&color=blue&height=average',
handleAs: 'json'
});
promise.then(
def.callback(function(data){
assert.strictEqual(data.method, 'POST');
var payload = data.payload;
assert.ok(payload);
assert.strictEqual(payload.foo, 'bar');
assert.strictEqual(payload.color, 'blue');
assert.strictEqual(payload.height, 'average');
}),
def.reject
);
},
'.put': function(){
var def = this.async(),
promise = xhr.put('/__services/request/xhr', {
query: {foo: 'bar'},
data: {color: 'blue'},
handleAs: 'json'
});
promise.then(
def.callback(function(data){
assert.strictEqual(data.method, 'PUT');
assert.ok(data.payload);
assert.strictEqual(data.payload.color, 'blue');
assert.ok(data.query);
assert.strictEqual(data.query.foo, 'bar');
}),
def.reject
);
},
'.del': function(){
var def = this.async(),
promise = xhr.del('/__services/request/xhr', {
query: {foo: 'bar'},
handleAs: 'json'
});
promise.then(
def.callback(function(data){
assert.strictEqual(data.method, 'DELETE');
assert.strictEqual(data.query.foo, 'bar');
}),
def.reject
);
},
'timeout': function(){
var def = this.async(),
promise = xhr.get('/__services/request/xhr', {
query: {
delay: '3000'
},
timeout: 1000
});
promise.then(
def.reject,
def.callback(function(error){
assert.instanceOf(error, RequestTimeoutError);
})
);
},
cancel: function(){
var def = this.async(),
promise = xhr.get('/__services/request/xhr', {
query: {
delay: '3000'
}
});
promise.then(
def.reject,
def.callback(function(error){
assert.instanceOf(error, CancelError);
})
);
promise.cancel();
},
sync: function(){
var called = false;
xhr.get('/__services/request/xhr', {
sync: true
}).then(function(){
called = true;
});
assert.ok(called);
},
'cross-domain fails': function(){
var def = this.async();
xhr.get('http://dojotoolkit.org').response.then(
def.reject,
function(){
def.resolve(true);
}
);
},
'has Content-Type with data': function(){
var def = this.async();
xhr.post('/__services/request/xhr', {
data: 'testing',
handleAs: 'json'
}).then(
def.callback(function(response){
assert.equal(response.headers['content-type'], 'application/x-www-form-urlencoded');
}),
def.reject
);
},
'no Content-Type with no data': function(){
var def = this.async();
xhr.get('/__services/request/xhr', {
handleAs: 'json'
}).then(
def.callback(function(response){
assert.isUndefined(response.headers['content-type']);
}),
def.reject
);
},
headers: function(){
var def = this.async();
xhr.get('/__services/request/xhr').response.then(
def.callback(function(response){
assert.notEqual(response.getHeader('Content-Type'), null);
}),
def.reject
);
},
'custom Content-Type': function(){
var def = this.async(),
expectedContentType = 'application/x-test-xhr';
function post(headers){
return xhr.post('/__services/request/xhr', {
query: {
'header-test': 'true'
},
headers: headers,
data: 'testing',
handleAs: 'json'
});
}
all({
lowercase: post({
'content-type': expectedContentType
}),
uppercase: post({
'CONTENT-TYPE': expectedContentType
})
}).then(
def.callback(function(results){
assert.match(
results.lowercase.headers['content-type'],
/^application\/x-test-xhr(?:;.*)?$/
);
assert.match(
results.uppercase.headers['content-type'],
/^application\/x-test-xhr(?:;.*)?$/
);
}),
def.reject
);
},
'queryable xml': function(){
var def = this.async();
xhr.get('/__services/request/xhr/xml', {
handleAs: 'xml'
}).then(
def.callback(function(xmlDoc){
var results = query('bar', xmlDoc);
assert.strictEqual(results.length, 2);
}),
def.reject
);
},
'strip fragment': function(){
var def = this.async(),
promise = xhr.get('/__services/request/xhr?color=blue#some-hash', {
handleAs: 'json'
});
promise.response.then(def.callback(function(response){
assert.strictEqual(response.data.method, 'GET');
assert.strictEqual(response.data.url, '/__services/request/xhr?color=blue');
}));
},
'form data': {
setup: function(){
if (!hasFormData) {
return;
}
formData = new FormData();
formData.append('foo', 'bar');
formData.append('baz', 'blah');
},
post: function(){
if (!hasFormData) {
this.skip('No FormData to test');
}
var def = this.async();
xhr.post('/__services/request/xhr/multipart', {
data: formData,
handleAs: 'json'
}).then(
def.callback(function(data){
assert.deepEqual(data, {foo: 'bar', baz: 'blah'});
}),
def.reject
);
},
teardown: function(){
formData = null;
}
},
'response type': {
'Blob': function(){
if (!hasResponseType) {
this.skip('No responseType to test');
}
return xhr.get('/__services/request/xhr/responseTypeGif', {
handleAs: 'blob'
}).then(function(response){
assert.strictEqual(response.constructor, Blob);
});
},
'Blob POST': function(){
if (!hasResponseType) {
this.skip('No responseType to test');
}
return xhr.post('/__services/request/xhr/responseTypeGif', {
handleAs: 'blob'
}).then(function(response){
assert.strictEqual(response.constructor, Blob);
});
},
'ArrayBuffer': function(){
if (has('native-arraybuffer') && hasResponseType) {
return xhr.get('/__services/request/xhr/responseTypeGif', {
handleAs: 'arraybuffer'
}).then(function(response){
assert.strictEqual(response.constructor, ArrayBuffer);
});
} else {
this.skip('No responseType to test');
}
},
'ArrayBuffer POST': function(){
if (has('native-arraybuffer') && hasResponseType) {
return xhr.post('/__services/request/xhr/responseTypeGif', {
handleAs: 'arraybuffer'
}).then(function(response){
assert.strictEqual(response.constructor, ArrayBuffer);
});
} else {
this.skip('No responseType to test');
}
},
'document': function(){
if (!hasResponseType) {
this.skip('No responseType to test');
}
return xhr.get('/__services/request/xhr/responseTypeDoc', {
handleAs: 'document'
}).then(function(response){
assert.strictEqual(response.constructor, document.constructor);
});
},
'document POST': function(){
if (!hasResponseType) {
this.skip('No responseType to test');
}
return xhr.post('/__services/request/xhr/responseTypeDoc', {
handleAs: 'document'
}).then(function(response){
assert.strictEqual(response.constructor, document.constructor);
});
}
},
'Web Workers': {
'from blob': function(){
if (!('URL' in global)) {
this.skip('URL is not supported');
}
if (!('Worker' in global)) {
this.skip('Worker is not supported');
}
if (!('Blob' in global)) {
this.skip('Blob is not supported');
}
if (!URL.createObjectURL) {
this.skip('URL.createObjectURL is not supported');
}
var dfd = this.async();
var baseUrl = location.origin + '/' + require.toUrl('testing');
var testUrl = location.origin + '/' + require.toUrl('./support/truthy.json');
var workerFunction = function(){
self.addEventListener('message', function(event){
if (event.data.baseUrl) {
testXhr(event.data.baseUrl, event.data.testUrl);
}
});
dojoConfig = {async: true};
function testXhr(baseUrl, testUrl){
var xhr = new XMLHttpRequest();
dojoConfig.baseUrl = baseUrl;
xhr.onreadystatechange = function(){
if (xhr.readyState === 4 && xhr.status === 200) {
var blob = new Blob([xhr.response], {type: 'application/javascript'});
var blobURL = URL.createObjectURL(blob);
importScripts(blobURL);
require([
'dojo/request/xhr'
], function(xhr){
xhr.get(testUrl).then(function(response){
if (response === 'true') {
self.postMessage('success');
} else {
throw new Error(response);
}
}, function(error){
throw error;
});
});
}
};
xhr.open('GET', baseUrl + '/dojo.js', true);
xhr.send();
}
};
var blob = new Blob(['(' + workerFunction.toString() + ')()'], {type: 'application/javascript'});
var worker = new Worker(URL.createObjectURL(blob));
worker.addEventListener('error', function(error){
dfd.reject(error);
});
worker.addEventListener('message', function(message){
if (message.data === 'success') {
dfd.resolve();
} else {
dfd.reject(message);
}
});
worker.postMessage({
baseUrl: baseUrl,
testUrl: testUrl
});
}
}
});
});