(function() {
function buildForm(attrs) {
attrs = $.extend({ action: '/echo', 'data-remote': 'true' }, attrs)
$('#qunit-fixture').append($('<form />', attrs))
.find('form').append($('<input type="text" name="user_name" value="john">'))
}
module('call-remote')
function submit(fn) {
$('form')
.bindNative('ajax:success', fn)
.bindNative('ajax:complete', function() { start() })
.triggerNative('submit')
}
asyncTest('form method is read from "method" and not from "data-method"', 1, function() {
buildForm({ method: 'post', 'data-method': 'get' })
submit(function(e, data, status, xhr) {
App.assertPostRequest(data)
})
})
asyncTest('form method is not read from "data-method" attribute in case of missing "method"', 1, function() {
buildForm({ 'data-method': 'put' })
submit(function(e, data, status, xhr) {
App.assertGetRequest(data)
})
})
asyncTest('form method is read from submit button "formmethod" if submit is triggered by that button', 1, function() {
var submitButton = $('<input type="submit" formmethod="get">')
buildForm({ method: 'post' })
$('#qunit-fixture').find('form').append(submitButton)
.bindNative('ajax:success', function(e, data, status, xhr) {
App.assertGetRequest(data)
})
.bindNative('ajax:complete', function() { start() })
submitButton.triggerNative('click')
})
asyncTest('form default method is GET', 1, function() {
buildForm()
submit(function(e, data, status, xhr) {
App.assertGetRequest(data)
})
})
asyncTest('form URL is picked up from "action"', 1, function() {
buildForm({ method: 'post' })
submit(function(e, data, status, xhr) {
App.assertRequestPath(data, '/echo')
})
})
asyncTest('form URL is read from "action" not "href"', 1, function() {
buildForm({ method: 'post', href: '/echo2' })
submit(function(e, data, status, xhr) {
App.assertRequestPath(data, '/echo')
})
})
asyncTest('form URL is read from submit button "formaction" if submit is triggered by that button', 1, function() {
var submitButton = $('<input type="submit" formaction="/echo">')
buildForm({ method: 'post', href: '/echo2' })
$('#qunit-fixture').find('form').append(submitButton)
.bindNative('ajax:success', function(e, data, status, xhr) {
App.assertRequestPath(data, '/echo')
})
.bindNative('ajax:complete', function() { start() })
submitButton.triggerNative('click')
})
asyncTest('prefer JS, but accept any format', 1, function() {
buildForm({ method: 'post' })
submit(function(e, data, status, xhr) {
var accept = data.HTTP_ACCEPT
ok(accept.match(/text\/javascript.+\*\/\*/), 'Accept: ' + accept)
})
})
asyncTest('JS code should be executed', 1, function() {
buildForm({ method: 'post', 'data-type': 'script' })
$('form').append('<input type="text" name="content_type" value="text/javascript">')
$('form').append('<input type="text" name="content" value="ok(true, \'remote code should be run\')">')
submit()
})
asyncTest('ecmascript code should be executed', 1, function() {
buildForm({ method: 'post', 'data-type': 'script' })
$('form').append('<input type="text" name="content_type" value="application/ecmascript">')
$('form').append('<input type="text" name="content" value="ok(true, \'remote code should be run\')">')
submit()
})
asyncTest('execution of JS code does not modify current DOM', 1, function() {
var docLength, newDocLength
function getDocLength() {
return document.documentElement.outerHTML.length
}
buildForm({ method: 'post', 'data-type': 'script' })
$('form').append('<input type="text" name="content_type" value="text/javascript">')
$('form').append('<input type="text" name="content" value="\'remote code should be run\'">')
docLength = getDocLength()
submit(function() {
newDocLength = getDocLength()
ok(docLength === newDocLength, 'executed JS should not present in the document')
})
})
asyncTest('HTML document should be parsed', 1, function() {
buildForm({ method: 'post', 'data-type': 'html' })
$('form').append('<input type="text" name="content_type" value="text/html">')
$('form').append('<input type="text" name="content" value="<p>hello</p>">')
submit(function(e, data, status, xhr) {
ok(data instanceof HTMLDocument, 'returned data should be an HTML document')
})
})
asyncTest('XML document should be parsed', 1, function() {
buildForm({ method: 'post', 'data-type': 'html' })
$('form').append('<input type="text" name="content_type" value="application/xml">')
$('form').append('<input type="text" name="content" value="<p>hello</p>">')
submit(function(e, data, status, xhr) {
ok(data instanceof Document, 'returned data should be an XML document')
})
})
asyncTest('accept application/json if "data-type" is json', 1, function() {
buildForm({ method: 'post', 'data-type': 'json' })
submit(function(e, data, status, xhr) {
equal(data.HTTP_ACCEPT, 'application/json, text/javascript, */*; q=0.01')
})
})
asyncTest('allow empty "data-remote" attribute', 1, function() {
var form = $('#qunit-fixture').append($('<form action="/echo" data-remote />')).find('form')
submit(function() {
ok(true, 'form with empty "data-remote" attribute is also allowed')
})
})
asyncTest('query string in form action should be stripped in a GET request in normal submit', 1, function() {
buildForm({ action: '/echo?param1=abc', 'data-remote': 'false' })
$(document).one('iframe:loaded', function(e, data) {
equal(data.params.param1, undefined, '"param1" should not be passed to server')
start()
})
$('#qunit-fixture form').triggerNative('submit')
})
asyncTest('query string in form action should be stripped in a GET request in ajax submit', 1, function() {
buildForm({ action: '/echo?param1=abc' })
submit(function(e, data, status, xhr) {
equal(data.params.param1, undefined, '"param1" should not be passed to server')
})
})
asyncTest('query string in form action should not be stripped in a POST request in normal submit', 1, function() {
buildForm({ action: '/echo?param1=abc', method: 'post', 'data-remote': 'false' })
$(document).one('iframe:loaded', function(e, data) {
equal(data.params.param1, 'abc', '"param1" should be passed to server')
start()
})
$('#qunit-fixture form').triggerNative('submit')
})
asyncTest('query string in form action should not be stripped in a POST request in ajax submit', 1, function() {
buildForm({ action: '/echo?param1=abc', method: 'post' })
submit(function(e, data, status, xhr) {
equal(data.params.param1, 'abc', '"param1" should be passed to server')
})
})
asyncTest('allow empty form "action"', 1, function() {
var currentLocation, ajaxLocation
buildForm({ action: '' })
$('#qunit-fixture').find('form')
.bindNative('ajax:beforeSend', function(evt, xhr, settings) {
// Get current location (the same way jQuery does)
try {
currentLocation = location.href
} catch(err) {
currentLocation = document.createElement( 'a' )
currentLocation.href = ''
currentLocation = currentLocation.href
}
currentLocation = currentLocation.replace(/\?.*$/, '')
// Actual location (strip out settings.data that jQuery serializes and appends)
// HACK: can no longer use settings.data below to see what was appended to URL, as of
// jQuery 1.6.3 (see http://bugs.jquery.com/ticket/10202 and https://github.com/jquery/jquery/pull/544)
ajaxLocation = settings.url.replace('user_name=john', '').replace(/&$/, '').replace(/\?$/, '')
equal(ajaxLocation.match(/^(.*)/)[1], currentLocation, 'URL should be current page by default')
// Prevent the request from actually getting sent to the current page and
// causing an error.
evt.preventDefault()
})
.triggerNative('submit')
setTimeout(function() { start() }, 13)
})
asyncTest('sends CSRF token in custom header', 1, function() {
buildForm({ method: 'post' })
$('#qunit-fixture').append('<meta name="csrf-token" content="cf50faa3fe97702ca1ae" />')
submit(function(e, data, status, xhr) {
equal(data.HTTP_X_CSRF_TOKEN, 'cf50faa3fe97702ca1ae', 'X-CSRF-Token header should be sent')
})
})
asyncTest('intelligently guesses crossDomain behavior when target URL has a different protocol and/or hostname', 1, function() {
// Don't set data-cross-domain here, just set action to be a different domain than localhost
buildForm({ action: 'http://www.alfajango.com' })
$('#qunit-fixture').append('<meta name="csrf-token" content="cf50faa3fe97702ca1ae" />')
$('#qunit-fixture').find('form')
.bindNative('ajax:beforeSend', function(evt, req, settings) {
equal(settings.crossDomain, true, 'crossDomain should be set to true')
// prevent request from actually getting sent off-domain
evt.preventDefault()
})
.triggerNative('submit')
setTimeout(function() { start() }, 13)
})
asyncTest('intelligently guesses crossDomain behavior when target URL consists of only a path', 1, function() {
// Don't set data-cross-domain here, just set action to be a different domain than localhost
buildForm({ action: '/just/a/path' })
$('#qunit-fixture').append('<meta name="csrf-token" content="cf50faa3fe97702ca1ae" />')
$('#qunit-fixture').find('form')
.bindNative('ajax:beforeSend', function(evt, req, settings) {
equal(settings.crossDomain, false, 'crossDomain should be set to false')
// prevent request from actually getting sent off-domain
evt.preventDefault()
})
.triggerNative('submit')
setTimeout(function() { start() }, 13)
})
})()