Permalink
Fetching contributors…
Cannot retrieve contributors at this time
1580 lines (1397 sloc) 50.2 KB
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8">
<meta name="viewport" content="initial-scale=1.0, maximum-scale=1.0, user-scalable=0">
<link rel="stylesheet" href="test.css">
<title>Zepto Ajax unit tests</title>
<script src="../vendor/evidence.js"></script>
<script src="evidence_runner.js"></script>
<script>
// avoid caching
(function(){
function load(scripts){
scripts.split(' ').forEach(function(script){
document.write('<script src="../src/'+script+'.js?'+(+new Date)+'"></scr'+'ipt>')
})
}
load('zepto event ajax ie')
})()
</script>
</head>
<body>
<h1>Zepto Ajax unit tests</h1>
<p id="results">
Running… see browser console for results
</p>
<div id="fixtures">
<div id="ajax_load"></div>
</div>
<script>
(function(){
function deferredResume(t, fn) {
setTimeout(function() { t.resume(fn || function(){}) }, 5)
}
function resumeOnAjaxError(t) {
$(document).on('ajaxError', function(e, xhr){
deferredResume(t, function(){
t.assert(false, "request errored out: " + xhr.responseText)
})
})
}
function toArray(list) {
if ($.type(list) == "string") return list.split(/(?:\s*,\s*|\s+)/)
else return list
}
Evidence.Assertions.assertEqualList = function(expected, actual, message) {
var expectedList = toArray(expected),
actualList = toArray(actual)
this._assertExpression(
expectedList.join(' ') == actualList.join(' '),
message || "Lists don't match.",
'Expected %o, got %o.', expectedList, actualList
)
}
Evidence.Assertions.assertLine = function(line, string, message) {
var lines = string.split("\n")
this._assertExpression(
$.inArray(line, lines) >= 0,
message || "Line not found.",
'Expected line %s in %s.', line, string
)
}
Evidence.Assertions.assertLinePattern = function(pattern, string, message) {
var lines = string.split("\n")
var i, match = false
if (lines.length) {
for (i = 0; i < lines.length; i++) {
if (lines[i].search(pattern) !== -1) {
match = true
break
}
}
}
this._assertExpression(
match === true,
message || "Pattern not found.",
'Expected pattern %s in %s.', pattern, string
)
}
var slice = [].slice
function CallbackRegistry(t) {
this.testCase = t
this.called = []
}
$.extend(CallbackRegistry.prototype, {
register: function(name, context, args){
this.called.push([name, context, args])
},
handler: function(name, fn){
var that = this
return function(){
that.register(name, this, slice.call(arguments))
if (fn) return fn.apply(this, arguments)
}
},
resumeHandler: function(name, fn){
var that = this
return this.handler(name, function(){
var context = this, args = arguments
setTimeout(function(){
that.testCase.resume(function(){
if (fn) fn.apply(context, args)
})
}, 5)
})
},
handlers: function(){
var that = this, hash = {}
$.each(arguments, function(i, name){
hash[name] = that.handler(name)
})
return hash
},
events: function(){
return $.map(this.called, function(item){ return item[0] })
},
context: function(name){
return this.find(name, function(item){ return item[1] })
},
args: function(name){
return this.find(name, function(item){ return item[2] })
},
target: function(name){
var args = this.args(name)
return args && args[0].target
},
find: function(name, fn){
var obj
$.each(this.called, function(i, item){
if (item[0] == name) {
obj = fn(item)
return false
}
})
return obj
}
})
Evidence('ZeptoAjaxTest', {
setUp: function() {
var reg = new CallbackRegistry(this),
globals = toArray('ajaxBeforeSend ajaxSend ajaxSuccess ajaxError ajaxComplete')
$(document).on(reg.handlers.apply(reg, globals))
this.reg = reg
window.jsonpDummy = $.noop
},
tearDown: function() {
$(document).off()
for (var key in window)
if (/^(Zepto\d+|blah)$/.test(key) && window[key] === undefined)
delete window[key]
},
testAjaxBase: function(t){
t.pause()
var xhr = $.ajax({
url: 'fixtures/ajax_load_simple.html',
success: t.reg.handler('success'),
error: t.reg.handler('error'),
complete: t.reg.resumeHandler('complete', function(){
t.assertEqualList('ajaxBeforeSend ajaxSend success ajaxSuccess complete ajaxComplete', t.reg.events())
})
})
t.assert($.isFunction(xhr.getResponseHeader))
},
testAjaxGet: function(t){
t.pause()
var xhr = $.get('echo', t.reg.resumeHandler('success', function(response){
t.assertIdentical(window, this)
t.assertLine("GET ?{}", response)
t.assertEqualList('ajaxBeforeSend ajaxSend success ajaxSuccess ajaxComplete', t.reg.events())
}))
t.assertIn('abort', xhr)
},
testAjaxGetWithParams: function(t){
t.pause()
$.get('echo', { sample: 'data' }, t.reg.resumeHandler('success', function(response){
t.assertLine('GET ?{"sample":"data"}', response)
t.assertLine("accept: */*", response)
}))
},
testAjaxGetWithParamsAndType: function(t){
t.pause()
$.get('echo', { sample: 'plain' }, t.reg.resumeHandler('success', function(response){
t.assertLine('GET ?{"sample":"plain"}', response)
t.assertLine("accept: text/plain", response)
}), 'text')
},
testAjaxGetWithParamsAndTypeNoCallback: function(t){
t.pause()
$(document).on('ajaxSuccess', function(e, xhr, settings, response){
deferredResume(t, function(){
t.assertLine('GET ?{"sample":"plain"}', response)
t.assertLine("accept: text/plain", response)
t.assertEqualList('ajaxBeforeSend ajaxSend ajaxSuccess ajaxComplete', t.reg.events())
})
})
$.get('echo', { sample: 'plain' }, 'text')
},
testAjaxGetWithParamsAutoParsesJSON: function(t) {
t.pause()
$.get('json', { sample: 'data' }, t.reg.resumeHandler('success', function(data){
t.assertEqual('data', data.query.sample)
t.assertEqual('world', data.hello)
}))
},
testAjaxGetNoParamsAutoParsesJSON: function(t) {
t.pause()
$.get('json', t.reg.resumeHandler('success', function(data){
t.assertIdentical(0, $.map(data.query).length)
t.assertEqual('world', data.hello)
}))
},
testAjaxGetNullParamsAutoParsesJSON: function(t) {
t.pause()
$.get('json', null, t.reg.resumeHandler('success', function(data){
t.assertIdentical(0, $.map(data.query).length)
t.assertEqual('world', data.hello)
}))
},
testAjaxBeforeSendSetRequestHeader: function(t){
t.pause()
$.ajax({
url: 'echo',
beforeSend: function(xhr, settings){
xhr.setRequestHeader('Accept', 'text/plain')
t.assertUndefined(settings.headers)
},
success: t.reg.resumeHandler('success', function(response){
t.assertLine("accept: text/plain", response)
})
})
},
testAjaxPost: function(t){
t.pause()
var xhr = $.post('echo', t.reg.resumeHandler('success', function(response){
t.assertIdentical(window, this)
t.assertLine("POST ?{}", response)
t.assertLine("accept: */*", response)
t.assertLine('{}', response)
t.assertEqualList('ajaxBeforeSend ajaxSend success ajaxSuccess ajaxComplete', t.reg.events())
}))
t.assertIn('abort', xhr)
},
testAjaxPostWithPayloadAndType: function(t) {
t.pause()
var payload = { sample: 'data' }
$.post('echo', payload, t.reg.resumeHandler('success', function(response){
t.assertLine("content-type: application/x-www-form-urlencoded", response)
t.assertLine("accept: text/plain", response)
t.assertLine('{"sample":"data"}', response)
}), 'text')
},
testAjaxPostAutoParsesJSON: function(t) {
t.pause()
var payload = { sample: 'data' }
$.post('create', payload, t.reg.resumeHandler('success', function(data){
t.assertEqual('data', data.payload.sample)
}))
},
testNumberOfActiveRequests: function(t) {
var maxActive = 0, ajaxStarted = 0, ajaxEnded = 0, requestsCompleted = 0
t.assertIdentical(0, $.active, 'initial count mismatch')
$(document)
.on('ajaxStart', function() { ajaxStarted++ })
.on('ajaxEnd', function() { ajaxEnded++ })
.on('ajaxSend', function() {
if ($.active > maxActive) maxActive = $.active
})
.on('ajaxComplete', function() {
if (++requestsCompleted == 3)
deferredResume(t, function() {
this.assertEqual(3, maxActive)
this.assertIdentical(0, $.active)
})
})
t.pause()
$.ajax({ url: 'echo' })
$.ajax({ url: 'echo' })
$.ajax({ url: 'echo' })
},
testAjaxJSON: function(t){
t.pause()
resumeOnAjaxError(t)
$.ajax({
url: 'json',
headers: { accept: 'application/json' },
success: t.reg.resumeHandler('success', function(data){
t.assertEqual('world', data.hello)
})
})
},
testAjaxDataFilterJSON: function(t){
t.pause()
resumeOnAjaxError(t)
$.ajax({
url: 'taintedJSON',
dataFilter: function(data, type) {
if (!data) return
return data.replace(/^\s*while\(1\);\s*/, '')
},
headers: { accept: 'application/json' },
success: t.reg.resumeHandler('success', function(data){
t.assertEqual('world', data.hello)
})
})
},
testAjaxGetJSON: function(t){
t.pause()
resumeOnAjaxError(t)
var xhr = $.getJSON(
'json',
t.reg.resumeHandler('success', function(data){
t.assertEqual('world', data.hello)
t.assert($.isEmptyObject(data.query))
t.assertEqualList('ajaxBeforeSend ajaxSend success ajaxSuccess ajaxComplete', t.reg.events())
})
)
t.assertIn('abort', xhr)
},
testAjaxGetJSONWithParams: function(t){
t.pause()
resumeOnAjaxError(t)
$.getJSON(
'json', { sample: 'data' },
t.reg.resumeHandler('success', function(data){
t.assertEqual('data', data.query.sample)
}),
'text' // ignored
)
},
testAjaxJSONParserError: function(t){
t.pause()
$.ajax({
url: 'json',
dataType: 'json',
data: { invalid: true },
success: t.reg.handler('success'),
error: t.reg.handler('error'),
complete: t.reg.resumeHandler('complete', function(){
t.assertEqualList('ajaxBeforeSend ajaxSend error ajaxError complete ajaxComplete', t.reg.events())
var errorArgs = t.reg.args('error')
t.assertEqual('parsererror', errorArgs[1])
t.assert(errorArgs[2] instanceof SyntaxError)
var globalErrorArgs = t.reg.args('ajaxError')
t.assert(globalErrorArgs[3] instanceof SyntaxError)
t.assertEqual(0, $('script[src^=slow]').size())
})
})
},
testAjaxEqualQuestionmarkIsNotAlwaysJSONP: function(t){
t.pause()
resumeOnAjaxError(t)
$.ajax({
url: 'echo=?',
dataType: 'text',
success: t.reg.resumeHandler('success', function(data){
t.assertLine('GET ?{}', data)
t.assertLine("accept: text/plain", data)
})
})
},
testAjaxGetJSONP: function(t){
t.pause()
$.getJSON(
'jsonp?callback=?&timestamp='+(+new Date),
t.reg.resumeHandler('success', function(data){
t.assertEqual('world', data.hello)
t.assertEqualList('ajaxBeforeSend ajaxSend success ajaxSuccess ajaxComplete', t.reg.events())
t.assertEqual(0, $('script[src^=jsonp]').size())
})
)
t.assertEqual(1, $('script[src^=jsonp]').size())
},
testAjaxGetJSONPWithParams: function(t){
t.pause()
$.getJSON(
'jsonp?callback=?&timestamp='+(+new Date),
{ sample: 'data' },
t.reg.resumeHandler('success', function(data){
t.assertEqual('data', data.query.sample)
})
)
},
testAjaxJSONP: function(t){
t.pause()
var xhr = $.ajaxJSONP({
url: 'jsonp?callback=?&timestamp='+(+new Date),
success: t.reg.handler('success'),
complete: t.reg.resumeHandler('complete', function(data){
var successArgs = t.reg.args('success')
t.assertEqual('world', successArgs[0].hello)
t.assertEqualList('ajaxBeforeSend ajaxSend success ajaxSuccess complete ajaxComplete', t.reg.events())
t.assertEqual(0, $('script[src^=jsonp]').size())
})
})
t.assertIn('abort', xhr)
},
testAjaxJSONPBeforeSend: function(t){
t.pause()
$(document).on('ajaxBeforeSend', function(){ return false })
$.ajax({
url: 'jsonp?callback=?&timestamp='+(+new Date),
beforeSend: t.reg.resumeHandler('beforeSend', function(){
t.assertEqualList('beforeSend ajaxBeforeSend ajaxError complete ajaxComplete', t.reg.events())
}),
success: t.reg.handler('success'),
complete: t.reg.handler('complete')
})
},
testAjaxGetJSONPErrorCallback: function(t){
t.pause()
$.ajax({
type: 'GET',
url: 'fixtures/404.js?timestamp='+(+new Date),
dataType: 'jsonp',
success: t.reg.handler('success'),
error: t.reg.handler('error'),
complete: t.reg.resumeHandler('complete', function(){
t.assertEqualList('ajaxBeforeSend ajaxSend error ajaxError complete ajaxComplete', t.reg.events())
t.assertEqual(0, $('script[src^=fixtures]').size())
})
})
},
testAjaxGetJSONPErrorWithoutCallback: function(t){
t.pause()
$.ajax({
type: 'GET',
url: 'fixtures/404.js?timestamp='+(+new Date),
dataType: 'jsonp',
success: t.reg.handler('success'),
complete: t.reg.resumeHandler('complete', function(){
t.assertEqualList('ajaxBeforeSend ajaxSend ajaxError complete ajaxComplete', t.reg.events())
t.assertEqual(0, $('script[src^=fixtures]').size())
})
})
},
testAjaxJSONPTimeout: function(t){
t.pause()
$.ajax({
url: 'slow?timestamp='+(+new Date),
dataType: 'jsonp',
jsonpCallback: 'jsonpDummy',
timeout: 20,
success: t.reg.handler('success'),
error: t.reg.handler('error'),
complete: t.reg.resumeHandler('complete', function(){
t.assertEqualList('ajaxBeforeSend ajaxSend error ajaxError complete ajaxComplete', t.reg.events())
var errorArgs = t.reg.args('error')
t.assertEqual('timeout', errorArgs[1])
var globalErrorArgs = t.reg.args('ajaxError')
t.assertEqual('timeout', globalErrorArgs[3])
t.assertEqual(0, $('script[src^=slow]').size())
})
})
},
testAjaxJSONPAbort: function(t){
t.pause()
var xhr = $.ajax({
url: 'slow?timestamp='+(+new Date),
dataType: 'jsonp',
jsonpCallback: 'jsonpDummy',
timeout: 30,
success: t.reg.handler('success'),
error: t.reg.handler('error'),
complete: t.reg.handler('complete')
})
setTimeout(function(){ xhr.abort() }, 10)
setTimeout(function(){
t.resume(function(){
t.assertEqualList('ajaxBeforeSend ajaxSend error ajaxError complete ajaxComplete', t.reg.events())
var errorArgs = t.reg.args('error')
t.assertEqual('abort', errorArgs[1])
var globalErrorArgs = t.reg.args('ajaxError')
t.assertEqual('abort', globalErrorArgs[3])
t.assertEqual(0, $('script[src^=slow]').size())
})
}, 50)
},
testAjaxJSONPError: function(t){
t.pause()
var xhr = $.ajax({
url: 'error?timestamp='+(+new Date),
dataType: 'jsonp',
success: t.reg.handler('success'),
error: t.reg.handler('error'),
complete: t.reg.resumeHandler('complete', function(){
t.assertEqualList('ajaxBeforeSend ajaxSend error ajaxError complete ajaxComplete', t.reg.events())
var errorArgs = t.reg.args('error')
t.assertEqual('error', errorArgs[1])
t.assertEqual(0, $('script[src^=error]').size())
})
})
},
testAjaxJSONPWithDataSupport: function(t) {
t.pause()
var xhr = $.ajax({
url: 'jsonp?callback=?&timestamp='+(+new Date),
data: {
param1: 'val1',
param2: 'val2'
},
success: t.reg.resumeHandler('success', function(data){
t.assertEqual('val1', data.query.param1)
t.assertEqual('val2', data.query.param2)
})
})
},
testAjaxJSONPWithCallbackName: function(t) {
var xhr = $.ajax({
url: 'jsonp',
dataType: 'jsonp',
jsonpCallback: 'blah',
success: t.reg.resumeHandler('success', function(data){
t.assertUndefined(window.blah)
})
})
t.assert($.isFunction(window.blah))
t.pause()
},
testAjaxJSONPWithCallbackNameAsFunction: function(t) {
var xhr = $.ajax({
url: 'jsonp',
dataType: 'jsonp',
jsonpCallback: function(){ return 'blah' },
success: t.reg.resumeHandler('success', function(data){
t.assertUndefined(window.blah)
})
})
t.assert($.isFunction(window.blah))
t.pause()
},
testAjaxJSONPWithCallbackNameAndJSONPsetToFalse: function(t) {
var xhr = $.ajax({
url: 'jsonpBlah',
dataType: 'jsonp',
jsonp: false,
jsonpCallback: 'blah',
success: t.reg.resumeHandler('success', function(data){
t.assertUndefined(window.blah)
})
})
var scriptSrc = $('head script:last-child').attr('src')
t.assert(/^jsonpBlah\?_=[\d]{13}$/.test(scriptSrc), scriptSrc)
t.assert($.isFunction(window.blah))
t.pause()
},
testAjaxJSONPWithCallbackNameAsFunctionAndJSONPsetToFalse: function(t) {
var xhr = $.ajax({
url: 'jsonpBlah',
dataType: 'jsonp',
jsonp: false,
jsonpCallback: function(){ return 'blah' },
success: t.reg.resumeHandler('success', function(data){
t.assertUndefined(window.blah)
})
})
var scriptSrc = $('head script:last-child').attr('src')
t.assert(/^jsonpBlah\?_=[\d]{13}$/.test(scriptSrc), scriptSrc)
t.assert($.isFunction(window.blah))
t.pause()
},
testAjaxJSONPWithData: function(t) {
t.pause()
$.ajax({
url: 'jsonp',
type: 'post',
data: { foo: 'bar' },
dataType: 'jsonp',
success: t.reg.resumeHandler('success', function(data){
t.assertEqual('bar', data.query.foo)
})
})
},
testNoCacheParam: function(t) {
t.pause()
var xhr = $.ajax({
url:'echo',
cache: false,
success: t.reg.resumeHandler('success', function(response){
// check that the no-cache param (or an element of it) looks like a timestamp
t.assertLinePattern(/"_":(\[".*",)?"[\d]{13}"/g, response)
})
})
},
testNoCacheParameterWithParam: function(t) {
t.pause()
var xhr = $.ajax({
url:'echo',
data:{ data: 'sample' },
cache: false,
success: t.reg.resumeHandler('success', function(response){
// check that the no-cache param (or an element of it) looks like a timestamp
t.assertLinePattern(/"_":(\[".*",)?"[\d]{13}"/g, response)
})
})
},
testNoCacheParameterAlreadyPresent: function(t) {
t.pause()
var xhr = $.ajax({
url:'echo',
data:{ _: 'test' },
cache: false,
success: t.reg.resumeHandler('success', function(response){
// check that the no-cache param (or an element of it) looks like a timestamp
t.assertLinePattern(/"_":(\[".*",)?"[\d]{13}"/g, response)
})
})
},
testNoCacheParameterAlreadyPresentWithParam: function(t) {
t.pause()
var xhr = $.ajax({
url:'echo',
data:{ _: 'test', data: 'sample' },
cache: false,
success: t.reg.resumeHandler('success', function(response){
// check that the no-cache param (or an element of it) looks like a timestamp
t.assertLinePattern(/"_":(\[".*",)?"[\d]{13}"/g, response)
})
})
},
testJSONPCacheBustingByDefault: function(t) {
$.ajax({
url: 'jsonp?callback=?',
success: t.reg.resumeHandler('success')
})
var scriptSrc = $('head script:last-child').attr('src')
t.assert(/^jsonp\?callback=Zepto\d+&_=[\d]{13}$/.test(scriptSrc), scriptSrc)
t.pause()
},
testJSONPCacheBustingDisabled: function(t) {
$.ajax({
url: 'jsonp?callback=?',
cache: true,
success: t.reg.resumeHandler('success')
})
var scriptSrc = $('head script:last-child').attr('src')
t.assert(/^jsonp\?callback=Zepto\d+$/.test(scriptSrc), scriptSrc)
t.pause()
},
testBrowserCaching: function(t) {
t.pause()
resumeOnAjaxError(t)
$.ajax({
url: 'cached',
cache: true,
success: function(firstResponse){
$.ajax({
url: 'cached',
cache: true,
success: t.reg.resumeHandler('success', function(secondResponse){
t.assertEqual(secondResponse, firstResponse)
})
})
}
})
},
testAjaxLoad: function(t) {
t.pause()
var testEl = $('#ajax_load')
var el = testEl.load(
'fixtures/ajax_load_simple.html',
t.reg.resumeHandler('success', function(response, status, xhr){
t.assertIdentical(testEl, this)
t.assertEqual("simple ajax load\n", response.replace(/\r\n|\r/,"\n"))
t.assertEqual('simple ajax load', testEl.html().trim())
t.assertEqual('success', status)
t.assertIn('abort', xhr)
t.assertEqualList('ajaxBeforeSend ajaxSend success ajaxSuccess ajaxComplete', t.reg.events())
})
)
t.assertIdentical(testEl, el)
},
testAjaxLoadWithSelector: function(t) {
t.pause()
var testEl = $('#ajax_load')
testEl.load(
'fixtures/ajax_load_selector.html #ajax_load_test_div',
t.reg.resumeHandler('success', function(){
t.assertEqual(
'<div id="ajax_load_test_div">ajax load with selector</div>',
testEl.html().trim()
)
})
)
},
testAjaxLoadWithJavaScript: function (t) {
var testEl = $('#ajax_load')
t.pause()
window.testValue = 0
testEl.load('fixtures/ajax_load_selector_javascript.html', function(){
deferredResume(t, function(){
this.assertEqual(window.testValue, 1)
delete window.testValue
})
})
},
testAjaxLoadWithSelectorAndJavaScript: function (t) {
var testEl = $('#ajax_load')
t.pause()
window.testValue = 0
testEl.load('fixtures/ajax_load_selector_javascript.html #ajax_load_test_div', function() {
deferredResume(t, function(){
this.assertEqual(window.testValue, 0)
delete window.testValue
})
})
},
testAjaxWithContext: function(t) {
t.pause()
var body = $('body')
$.ajax({
url: 'fixtures/ajax_load_simple.html',
context: body,
beforeSend: t.reg.handler('beforeSend'),
success: t.reg.handler('success'),
complete: t.reg.resumeHandler('complete', function(){
t.assertIdentical(body, this)
t.assertIdentical(body, t.reg.context('beforeSend'))
t.assertIdentical(body, t.reg.context('success'))
t.assertIdentical(document.body, t.reg.target('ajaxBeforeSend'))
t.assertIdentical(document.body, t.reg.target('ajaxSuccess'))
})
})
},
testAjaxWithContextPlainObject: function(t) {
t.pause()
var obj = {}
$.ajax({
url: 'fixtures/ajax_load_simple.html',
context: obj,
beforeSend: t.reg.handler('beforeSend'),
success: t.reg.handler('success'),
complete: t.reg.resumeHandler('complete', function(){
t.assertIdentical(obj, this)
t.assertIdentical(obj, t.reg.context('beforeSend'))
t.assertIdentical(obj, t.reg.context('success'))
t.assertUndefined(t.reg.target('ajaxBeforeSend'))
t.assertUndefined(t.reg.target('ajaxSuccess'))
})
})
},
testAjaxLoadJavaScript: function (t) {
t.pause()
window.testValue = 0
var xhr = $.ajax({
url:'fixtures/ajax_load_javascript.js',
success: t.reg.resumeHandler('success', function(response){
// check that the javascript has loaded and executed.
t.assertEqual(window.testValue, 1)
delete window.testValue
})
})
},
testAjaxBasicAuth: function(t) {
t.pause()
resumeOnAjaxError(t)
$.ajax({
url: 'auth?realm=zepto',
username: 'zepto',
password: 'doge',
success: t.reg.resumeHandler('success')
})
}
})
var OriginalXHR = $.ajaxSettings.xhr
function MockXHR() {
this.headers = []
this.responseHeaders = {}
MockXHR.last = this
}
MockXHR.prototype = {
open: function(method, url, async) {
this.method = method
this.url = url
this.async = async
},
setRequestHeader: function(name, value) {
if (!this.method) throw "setRequestHeader() called before open()"
this.headers.push({ name: name, value: value })
},
getResponseHeader: function(name) {
return this.responseHeaders[name]
},
overrideMimeType: function(type) {
this.responseHeaders['content-type'] = type
},
withCredentials: false,
send: function(data) {
this.data = data
},
abort: function() {
this.aborted = true
},
ready: function(readyState, status, responseText, headers) {
this.readyState = readyState
this.status = status
this.responseText = responseText
$.extend(this.responseHeaders, headers)
this.onreadystatechange()
},
onreadystatechange: function() {}
}
function matchHeader(name, value) {
return function(header) {
return header.name == name && (!value || header.value == value)
}
}
Evidence('ZeptoAjaxTest2', {
setUp: function() {
$.ajaxSettings.xhr = function(){ return new MockXHR }
},
tearDown: function() {
$.ajaxSettings.xhr = OriginalXHR
$(document).off()
$.active = 0
},
testTypeDefaultsToGET: function(t) {
$.ajax({
url: '/foo',
beforeSend: function(xhr, settings) {
t.assertFalse(settings.crossDomain)
}
})
t.assertEqual('GET', MockXHR.last.method)
},
testURLDefaultsToWindowLocation: function(t) {
$.ajax()
t.assertEqual(window.location, MockXHR.last.url)
},
testCrossDomainCrossOrigin: function(t) {
$.ajax({
url: 'http://example.com/foo',
beforeSend: function(xhr, settings) {
t.assertTrue(settings.crossDomain)
}
})
},
testCrossDomainSameOrigin: function(t) {
$.ajax({
url: window.location.href,
beforeSend: function(xhr, settings) {
t.assertFalse(settings.crossDomain)
}
})
},
testCrossDomainLeadingSpace: function(t) {
$.ajax({
url: ' http://example.com/foo',
beforeSend: function(xhr, settings) {
t.assertTrue(settings.crossDomain)
}
})
},
testCrossDomainTrippleSlash: function(t) {
$.ajax({
url: 'http:///example.com/foo',
beforeSend: function(xhr, settings) {
t.assertTrue(settings.crossDomain)
}
})
},
testCrossDomainWithQuery: function(t) {
$.ajax({
url: window.location.href + "?foo=bar",
beforeSend: function(xhr, settings) {
t.assertFalse(settings.crossDomain)
}
})
},
testCrossDomainDifferentScheme: function(t) {
$.ajax({
url: "foo://" + window.location.host,
beforeSend: function(xhr, settings) {
t.assertTrue(settings.crossDomain)
}
})
},
testCrossDomainPeriodInScheme: function(t) {
$.ajax({
url: "foo.bar://example.com/foo",
beforeSend: function(xhr, settings) {
t.assertTrue(settings.crossDomain)
}
})
},
testDefaultAcceptHeader: function(t) {
$.ajax()
t.assert(MockXHR.last.headers.some(matchHeader('Accept', '*/*')))
},
testDataTypeOptionSetsAcceptHeader: function(t) {
$.ajax({ dataType: 'json' })
t.assert(MockXHR.last.headers.some(matchHeader('Accept', 'application/json')))
// verifies overrideMimeType:
t.assertEqual('application/json', MockXHR.last.getResponseHeader('content-type'))
$.ajax({ dataType: 'script' })
//check that the head matches all of those required for loading scripts.
t.assert(MockXHR.last.headers.some(matchHeader('Accept', 'text/javascript, application/javascript, application/x-javascript')))
},
testMimeTypeOptionOverride: function(t) {
$.ajax({ mimeType: 'text/plain' })
t.assertEqual('text/plain', MockXHR.last.getResponseHeader('content-type'))
},
testContentTypeOptionSetsContentTypeHeader: function(t) {
$.ajax()
t.assert(!MockXHR.last.headers.some(matchHeader('Content-Type')))
$.ajax({ contentType: 'text/html' })
t.assert(MockXHR.last.headers.some(matchHeader('Content-Type', 'text/html')))
$.ajax({ type: 'POST', data: [], contentType: 'application/x-foo' })
t.assert(MockXHR.last.headers.some(matchHeader('Content-Type', 'application/x-foo')))
},
testHeadersOptionCanSetContentType: function(t) {
$.ajax({ type: 'POST', data: [], headers: { 'Content-Type': 'application/hal+json' }})
t.assert(MockXHR.last.headers.some(matchHeader('Content-Type', 'application/hal+json')))
},
testContentTypeDefaultsToUrlEncoded: function(t) {
$.ajax({ type: 'GET', data: 'x' })
t.refute(MockXHR.last.headers.some(matchHeader('Content-Type', 'application/x-www-form-urlencoded')))
$.ajax({ type: 'POST', data: 'x' })
t.assert(MockXHR.last.headers.some(matchHeader('Content-Type', 'application/x-www-form-urlencoded')))
},
testDefaultContentTypeDisabled: function(t) {
$.ajax({ type: 'POST', data: {a:1}, contentType: false })
t.refute(MockXHR.last.headers.some(matchHeader('Content-Type')))
},
testCustomHeader: function(t) {
$.ajax({ headers: {'X-Awesome': 'true'} })
t.assert(MockXHR.last.headers.some(matchHeader('X-Requested-With', 'XMLHttpRequest')))
t.assert(MockXHR.last.headers.some(matchHeader('X-Awesome', 'true')))
},
testXhrFieldsOptionSetsWithCredentialsProperty: function(t) {
var xhr = $.ajax({
url: 'http://example.com/foo',
xhrFields: { withCredentials: true }
})
t.assert(xhr.withCredentials)
},
testScriptDataTypeCacheBustByDefault: function(t) {
$.ajax({ url: '/', dataType: 'script' })
var xhr = MockXHR.last
t.assert(/^\/\?_=[\d]{13}$/.test(xhr.url), xhr.url)
},
testScriptDataTypeCacheBustDisable: function(t) {
$.ajax({ url: '/', dataType: 'script', cache: true })
var xhr = MockXHR.last
t.assertEqual('/', xhr.url)
},
testJSONdataType: function(t) {
var result = {}
$.ajax({ dataType: 'json', success: function(json) {result = json } })
MockXHR.last.ready(4, 200, '{"hello":"world"}')
t.assertEqual("world", result.hello)
},
testJSONcontentType: function(t) {
var result = {}
$.ajax({ success: function(json) {result = json } })
MockXHR.last.ready(4, 200, '{"hello":"world"}', {'content-type': 'application/json'})
t.assertEqual("world", result.hello)
},
testJSONResponseBodiesAreNotParsedWhenDataTypeOptionIsJSONButResponseIsEmptyString: function(t) {
var result, success = false
$.ajax({ dataType: 'json', success: function(json) {result = json; success = true } })
MockXHR.last.ready(4, 200, '')
t.assert(success)
t.assertNull(result)
},
testJSONResponseBodiesAreNotParsedWhenDataTypeOptionIsJSONButResponseIsSingleSpace: function(t) {
var result, success = false
$.ajax({ dataType: 'json', success: function(json) {result = json; success = true } })
MockXHR.last.ready(4, 200, ' ')
t.assert(success)
t.assertNull(result)
},
testDataIsNotSentAsBodyForGetRequests: function(t) {
$.ajax({ type: 'GET', data: {a:'b'} })
t.assertNull(MockXHR.last.data)
},
testDataOptionIsConvertedToSerializedForm: function(t) {
$.ajax({
type: 'POST',
data: {hello: 'world', array: [1,2,3], object: { prop1: 'val', prop2: 2 } }
})
var data = decodeURIComponent(MockXHR.last.data)
t.assertEqual('hello=world&array[]=1&array[]=2&array[]=3&object[prop1]=val&object[prop2]=2', data)
},
testDataOptionIsConvertedToSerializedTraditionalForm: function(t) {
$.ajax({
type: 'POST',
data: {hello: 'world', array: [1,2,3], object: { prop1: 'val', prop2: 2 } },
traditional: true
})
var data = decodeURIComponent(MockXHR.last.data)
t.assertEqual('hello=world&array=1&array=2&array=3&object=[object+Object]', data)
},
testQueryParamsTraditional: function(t) {
$.ajax({
url: '/',
data: {hello: 'world', array: [1,2,3], object: { prop1: 'val', prop2: 2 } },
traditional: true
})
var url = decodeURIComponent(MockXHR.last.url)
t.assertEqual('/?hello=world&array=1&array=2&array=3&object=[object+Object]', url)
},
testProcessDataDisabled: function(t) {
var data = { country: 'Ecuador' }
$.ajax({
data: data,
processData: false,
type: "POST"
})
t.assertIdentical(data, MockXHR.last.data)
},
testDataIsAppendedToGETURL: function(t) {
$.ajax({ url:'test.html', data:'foo=bar' })
t.assertEqual('test.html?foo=bar', MockXHR.last.url)
$.ajax({ url:'test.html', data:'?foo=bar' })
t.assertEqual('test.html?foo=bar', MockXHR.last.url)
$.ajax({ url:'test.html?', data:'foo=bar' })
t.assertEqual('test.html?foo=bar', MockXHR.last.url)
$.ajax({ url:'test.html?baz', data:'foo=bar' })
t.assertEqual('test.html?baz&foo=bar', MockXHR.last.url)
$.ajax({ url:'test.html?bar=baz', data:'foo=bar' })
t.assertEqual('test.html?bar=baz&foo=bar', MockXHR.last.url)
$.ajax({ url:'test.html', data:{foo:'bar'} })
t.assertEqual('test.html?foo=bar', MockXHR.last.url)
},
testDataIsAppendedToGETURLWithHashStripped: function(t) {
$.ajax({ url:'test.html#?ignore=me', data:'foo=bar' })
t.assertEqual('test.html?foo=bar', MockXHR.last.url)
$.ajax({ url:'test.html?a=b#?ignore=me', data:'foo=bar' })
t.assertEqual('test.html?a=b&foo=bar', MockXHR.last.url)
},
testScriptResponseIsEvald: function(t) {
var result
$.ajax({ success: function(text){ result = text } })
MockXHR.last.ready(4, 200, 'this.testValue = 42', {'content-type': 'application/javascript'})
t.assertEqual('this.testValue = 42', result)
t.assertIdentical(42, window.testValue)
delete window.testValue
},
testErrorCallback: function(t) {
var successFired = false, xhr, status
$.ajax({
success: function() { successFired = true },
error: function(x, s) { xhr = x, status = s }
})
MockXHR.last.ready(4, 500, '500 Internal Server Error')
t.assert(!successFired)
t.assertEqual(MockXHR.last, xhr)
t.assertEqual('error', status)
},
testErrorCallbackWithInvalidJSON: function(t) {
var successFired = false, xhr, status, exception
$.ajax({
dataType: 'json',
succes: function() { successFired = true },
error: function(x, s, e) { xhr = x, status = s, exception = e }
})
MockXHR.last.ready(4, 200, '{invalid')
t.assert(!successFired)
t.assertEqual(MockXHR.last, xhr)
t.assertEqual('parsererror', status)
t.assert(exception.toString().match(/SyntaxError/))
},
test201ResponseIsSuccess: function(t) {
var successFired, errorFired
$.ajax({
success: function() { successFired = true },
error: function() { errorFired = true }
})
MockXHR.last.ready(4, 201, 'Created')
t.assert(successFired)
t.refute(errorFired)
},
test304ResponseIsSuccess: function(t) {
var successFired, errorFired
$.ajax({
success: function() { successFired = true },
error: function() { errorFired = true }
})
MockXHR.last.ready(4, 304, 'Not Modified')
t.assert(successFired)
t.refute(errorFired)
},
testXHRParameterInSuccessCallback: function(t) {
var body, status, xhr
$.ajax({
success: function(b, s, x) { body = b, status = s, xhr = x }
})
MockXHR.last.ready(4, 200, 'Hello')
t.assertEqual('Hello', body)
t.assertEqual('success', status)
t.assertEqual(MockXHR.last, xhr)
body = status = xhr = null
$.ajax({
dataType: 'json',
success: function(b, s, x) { body = b, status = s, xhr = x }
})
MockXHR.last.ready(4, 200, '{"message":"Hello"}')
t.assertEqual('Hello', body.message)
t.assertEqual('success', status)
t.assertEqual(MockXHR.last, xhr)
},
testBeforeSendCanChangeUrl: function(t) {
var xhr = $.ajax({
url: 'one',
beforeSend: function(x, s) {
s.url = 'two'
}
})
t.assertEqual('two', xhr.url)
},
testBeforeSendCanChangeMethod: function(t) {
var xhr = $.ajax({
type: 'POST',
beforeSend: function(x, s) {
s.type = 'PUT'
}
})
t.assertEqual('PUT', xhr.method)
},
testBeforeSendCanAccessSerializedPostData: function(t) {
var xhr = $.ajax({
type: 'POST',
data: { a:'b' },
beforeSend: function(x, s) {
s.data = s.data.toUpperCase()
}
})
t.assertEqual('A=B', xhr.data)
},
testBeforeSendCannotAccessRawQueryParams: function(t) {
var url, data
$.ajax({
url: '/',
type: 'GET',
data: { a:'b' },
beforeSend: function(x, s) {
url = s.url
data = s.data
}
})
t.assertEqual('/?a=b', url)
t.assertUndefined(data)
},
testBeforeSendCannotChangeOrAddHeadersViaObject: function(t) {
var xhr = $.ajax({
headers: { a:'b', c:'d' },
beforeSend: function(x, s) {
s.headers['a'] = 'B'
s.headers['e'] = 'f'
}
})
t.assert(xhr.headers.some(matchHeader('a', 'b')))
t.assert(xhr.headers.some(matchHeader('c', 'd')))
t.refute(xhr.headers.some(matchHeader('e', 'f')))
},
testBeforeSendCanChangeAndAddHeadersViaXhr: function(t) {
var xhr = $.ajax({
headers: { a:'b', c:'d' },
beforeSend: function(x, s) {
x.setRequestHeader('a', 'B')
x.setRequestHeader('e', 'f')
}
})
t.assert(xhr.headers.some(matchHeader('a', 'B')))
t.assert(xhr.headers.some(matchHeader('c', 'd')))
t.assert(xhr.headers.some(matchHeader('e', 'f')))
},
testBeforeSendAbortCallback: function(t) {
var xhr, settings
$.ajax({
beforeSend: function(x, s) {
settings = s, xhr = x
}
})
t.assertEqual(MockXHR.last, xhr)
t.assertEqual('GET', settings.type)
},
testBeforeSendAbort: function(t) {
var xhr
$.ajax({ beforeSend: function(x) { xhr = x; return false } })
t.assert(xhr.aborted)
},
testGlobalBeforeSendAbort: function(t) {
$(document).on('ajaxBeforeSend', false)
var xhr = $.ajax()
t.assert(xhr.aborted)
},
testGlobalAjaxSendCantAbort: function(t) {
var xhr
$(document).on('ajaxSend', function(e, x) { xhr = x; return false })
t.assert($.ajax())
t.assert(!xhr.aborted)
},
testCompleteCallback: function(t) {
var status, xhr
$.ajax({ complete: function(x, s) { status = s, xhr = x } })
MockXHR.last.ready(4, 200, 'OK')
t.assertEqual(MockXHR.last, xhr)
t.assertEqual('success', status)
},
testCallbackOrder: function(t) {
var order = []
$.ajax({
beforeSend: function() { order.push('beforeSend') },
success: function() { order.push('success') },
complete: function() { order.push('complete') }
})
MockXHR.last.ready(4, 200, 'OK')
t.assertEqual('beforeSend,success,complete', order.join(','))
},
testGlobalCallbacks: function(t) {
var fired = []
$(document).on('ajaxStart ajaxBeforeSend ajaxSend ajaxSuccess ajaxError ajaxComplete ajaxStop', function(e) {
fired.push(e.type)
})
$.ajax({
beforeSend: function() { fired.push('beforeSend') },
success: function() { fired.push('success') },
error: function() { fired.push('error') },
complete: function() { fired.push('complete') }
})
t.assertEqual('ajaxStart beforeSend ajaxBeforeSend ajaxSend', fired.join(' '))
fired = []
MockXHR.last.ready(4, 200, 'OK')
t.assertEqual('success ajaxSuccess complete ajaxComplete ajaxStop', fired.join(' '))
},
testGlobalCallbacksOff: function(t) {
var fired = []
$(document).on('ajaxStart ajaxBeforeSend ajaxSend ajaxSuccess ajaxError ajaxComplete ajaxStop', function(e) {
fired.push(e.type)
})
$.ajax({
global: false,
beforeSend: function() { fired.push('beforeSend') },
success: function() { fired.push('success') },
error: function() { fired.push('error') },
complete: function() { fired.push('complete') }
})
t.assertEqual('beforeSend', fired.join(' '))
fired = []
MockXHR.last.ready(4, 200, 'OK')
t.assertEqual('success complete', fired.join(' '))
},
testTimeout: function(t) {
var successFired = false, xhr, status, globalStatus
t.pause()
$(document).on('ajaxError', function (e, x, o, s) {
globalStatus = s
})
$.ajax({
timeout: 30,
success: function() { successFired = true },
error: function(x, s) { xhr = x, status = s }
})
setTimeout(function(){
t.assertFalse(successFired)
t.assertUndefined(status)
}, 20)
setTimeout(function(){
t.resume(function(){
t.assertFalse(successFired)
t.assertTrue(xhr.aborted)
t.assertEqual('timeout', status)
t.assertEqual('timeout', globalStatus)
})
}, 40)
},
testAbort: function(t) {
var successFired = false, xhr, status, globalStatus
t.pause()
$(document).on('ajaxError', function (e, x, o, s) {
globalStatus = s
})
$.ajax({
success: function() { successFired = true },
error: function(x, s) { xhr = x, status = s }
})
MockXHR.last.abort()
MockXHR.last.ready(4, 0, 'Aborted')
setTimeout(function(){
t.resume(function(){
t.assertFalse(successFired)
t.assertTrue(xhr.aborted)
t.assertEqual('abort', status)
t.assertEqual('abort', globalStatus)
})
}, 20)
},
testAsyncDefaultsToTrue: function(t) {
$.ajax({ url: '/foo' })
t.assertTrue(MockXHR.last.async)
},
testAsyncFalse: function(t) {
$.ajax({ url: '/foo', async: false })
t.assertFalse(MockXHR.last.async)
}
})
Evidence('ZeptoAjaxHelperMethodsTest', {
testParamMethod: function(t) {
var result = $.param({ libs: ['jQuery', 'script.aculo.us', 'Prototype', 'Dojo'] })
result = decodeURIComponent(result)
t.assertEqual(result, "libs[]=jQuery&libs[]=script.aculo.us&libs[]=Prototype&libs[]=Dojo")
result = $.param({ jquery: 'Javascript', rails: 'Ruby', django: 'Python' })
result = decodeURIComponent(result)
t.assertEqual(result, "jquery=Javascript&rails=Ruby&django=Python")
result = $.param({
title: "Some Countries",
list: ['Ecuador', 'Austria', 'England'],
capitals: { ecuador: 'Quito', austria: 'Vienna', GB: { england: 'London', scotland: 'Edinburgh'} }
})
result = decodeURIComponent(result)
t.assertEqual(result, "title=Some+Countries&list[]=Ecuador&list[]=Austria&list[]=England&capitals[ecuador]=Quito&capitals[austria]=Vienna&capitals[GB][england]=London&capitals[GB][scotland]=Edinburgh")
},
testParamNullValues: function(t) {
t.assertEqual("x=&a[b]=&a[c]=",
decodeURIComponent($.param({ x: null, a: { b: null, c: undefined }})))
t.assertEqual("x=",
decodeURIComponent($.param([{ name: "x", value: null }])))
},
testParamFunctionValues: function(t) {
t.assertEqual("x=&a[b]=B",
decodeURIComponent($.param({ x: function(){}, a: { b: function(){ return "B" }}})))
t.assertEqual("x=&a[b]=B",
decodeURIComponent($.param([{ name: "x", value: null }, { name: "a[b]", value: function(){ return "B" }}])))
},
testParamEscaping: function(t) {
var result = $.param({ 'equation[1]': 'bananas+peaches=smoothie' })
t.assertEqual("equation%5B1%5D=bananas%2Bpeaches%3Dsmoothie", result)
},
testParamSpaces: function(t) {
var result = $.param({ "foo bar": "baz kuux" })
t.assertEqual("foo+bar=baz+kuux", result)
},
testParamComplex: function(t) {
var data = {
a: ['b', 'c', { d:'e', f:['g','h'] }]
}
var result = $.param(data)
result = decodeURIComponent(result)
t.assertEqual("a[]=b&a[]=c&a[2][d]=e&a[2][f][]=g&a[2][f][]=h", result)
},
testParamComplexIssue850: function(t) {
var data = {
$push: { _:[ { name: 'bob', members:['aaa'] } ] }
}
var result = $.param(data)
result = decodeURIComponent(result)
t.assertEqual("$push[_][0][name]=bob&$push[_][0][members][]=aaa", result)
},
testParamComplexNested: function(t) {
var data = {
x: [
[1, { attr1: 2 } ],
3,
{ attr1: 4 },
{ attr1: 5, attr2: [ 6 ] },
[ 7, [8, 9] ],
{ attr1: { attr2: [ [ 10 ] ] } }
]
}
var result = $.param(data)
result = decodeURIComponent(result)
t.assertEqual(
[ "x[0][]=1"
, "x[0][1][attr1]=2"
, "x[]=3"
, "x[2][attr1]=4"
, "x[3][attr1]=5"
, "x[3][attr2][]=6"
, "x[4][]=7"
, "x[4][1][]=8"
, "x[4][1][]=9"
, "x[5][attr1][attr2][0][]=10"
].join('&'), result)
},
testParamShallow: function(t) {
var data = {
libs: ['jQuery', 'Prototype', 'Dojo'],
nested: { will: 'be ignored' }
}
var result = $.param(data, true)
result = decodeURIComponent(result)
t.assertEqual("libs=jQuery&libs=Prototype&libs=Dojo&nested=[object+Object]", result)
},
testParamArray: function(t) {
var data = [
{name:'country', value:'Ecuador'},
{name:'capital', value:'Quito'}
]
var result = $.param(data)
t.assertEqual(result, "country=Ecuador&capital=Quito")
}
})
})()
</script>
</body>
</html>