rails--rails/actionview/test/ujs/public/test/call-remote-callbacks.js

269 lines
10 KiB
JavaScript

(function() {
QUnit.module('call-remote-callbacks', {
beforeEach: function() {
$('#qunit-fixture').append($('<form />', {
action: '/echo', method: 'get', 'data-remote': 'true'
}))
},
afterEach: function() {
$(document).undelegate('form[data-remote]', 'ajax:beforeSend')
$(document).undelegate('form[data-remote]', 'ajax:before')
$(document).undelegate('form[data-remote]', 'ajax:send')
$(document).undelegate('form[data-remote]', 'ajax:complete')
$(document).undelegate('form[data-remote]', 'ajax:success')
$(document).unbind('iframe:loading')
}
})
function submit(fn) {
var form = $('#qunit-fixture form')
if (fn) fn(form)
form.triggerNative('submit')
}
QUnit.test('modifying form fields with "ajax:before" sends modified data in request', function(assert) {
const done = assert.async()
$('form[data-remote]')
.append($('<input type="text" name="user_name" value="john">'))
.append($('<input type="text" name="removed_user_name" value="john">'))
.bindNative('ajax:before', function() {
var form = $(this)
form
.append($('<input />', {name: 'other_user_name', value: 'jonathan'}))
.find('input[name="removed_user_name"]').remove()
form
.find('input[name="user_name"]').val('steve')
})
submit(function(form) {
form.bindNative('ajax:success', function(e, data, status, xhr) {
assert.equal(data.params.user_name, 'steve', 'modified field value should have been submitted')
assert.equal(data.params.other_user_name, 'jonathan', 'added field value should have been submitted')
assert.equal(data.params.removed_user_name, undefined, 'removed field value should be undefined')
done()
})
})
})
QUnit.test('modifying data("type") with "ajax:before" requests new dataType in request', function(assert) {
$('form[data-remote]').data('type', 'html')
.bindNative('ajax:before', function() {
this.setAttribute('data-type', 'xml')
})
submit(function(form) {
form.bindNative('ajax:beforeSend', function(e, xhr, settings) {
assert.equal(settings.dataType, 'xml', 'modified dataType should have been requested')
})
})
})
QUnit.test('setting data("with-credentials",true) with "ajax:before" uses new setting in request', function(assert) {
$('form[data-remote]').data('with-credentials', false)
.bindNative('ajax:before', function() {
this.setAttribute('data-with-credentials', true)
})
submit(function(form) {
form.bindNative('ajax:beforeSend', function(e, xhr, settings) {
assert.equal(settings.withCredentials, true, 'setting modified in ajax:before should have forced withCredentials request')
})
})
})
QUnit.test('stopping the "ajax:beforeSend" event aborts the request', function(assert) {
const done = assert.async()
submit(function(form) {
form.bindNative('ajax:beforeSend', function(e) {
assert.ok(true, 'aborting request in ajax:beforeSend')
e.preventDefault()
})
form.unbind('ajax:send').bindNative('ajax:send', function() {
assert.ok(false, 'ajax:send should not run')
})
form.bindNative('ajax:error', function(e, response, status, xhr) {
assert.ok(false, 'ajax:error should not run')
})
form.bindNative('ajax:complete', function() {
assert.ok(false, 'ajax:complete should not run')
})
})
setTimeout(function() { done() }, 13)
})
function skipIt() {
// This test cannot work due to the security feature in browsers which makes the value
// attribute of file input fields readonly, so it cannot be set with default value.
// This is what the test would look like though if browsers let us automate this test.
QUnit.test('non-blank file form input field should abort remote request, but submit normally', function(assert) {
var form = $('form[data-remote]')
.append($('<input type="file" name="attachment" value="default.png">'))
.bindNative('ajax:beforeSend', function() {
ok(false, 'ajax:beforeSend should not run')
})
.bind('iframe:loading', function() {
ok(true, 'form should get submitted')
})
.bindNative('ajax:aborted:file', function(e, data) {
ok(data.length == 1, 'ajax:aborted:file event is passed all non-blank file inputs (jQuery objects)')
ok(data.first().is('input[name="attachment"]'), 'ajax:aborted:file adds non-blank file input to data')
ok(true, 'ajax:aborted:file event should run')
})
.triggerNative('submit')
setTimeout(function() {
form.find('input[type="file"]').val('')
form.unbind('ajax:beforeSend')
submit()
}, 13)
})
QUnit.test('file form input field should not abort remote request if file form input does not have a name attribute', function(assert) {
var form = $('form[data-remote]')
.append($('<input type="file" value="default.png">'))
.bindNative('ajax:beforeSend', function() {
ok(true, 'ajax:beforeSend should run')
})
.bind('iframe:loading', function() {
ok(true, 'form should get submitted')
})
.bindNative('ajax:aborted:file', function(e, data) {
ok(false, 'ajax:aborted:file should not run')
})
.triggerNative('submit')
setTimeout(function() {
form.find('input[type="file"]').val('')
form.unbind('ajax:beforeSend')
submit()
}, 13)
})
QUnit.test('blank file input field should abort request entirely if handler bound to "ajax:aborted:file" event that returns false', function(assert) {
var form = $('form[data-remote]')
.append($('<input type="file" name="attachment" value="default.png">'))
.bindNative('ajax:beforeSend', function() {
ok(false, 'ajax:beforeSend should not run')
})
.bind('iframe:loading', function() {
ok(false, 'form should not get submitted')
})
.bindNative('ajax:aborted:file', function(e) {
e.preventDefault()
})
.triggerNative('submit')
setTimeout(function() {
form.find('input[type="file"]').val('')
form.unbind('ajax:beforeSend')
submit()
}, 13)
})
}
QUnit.test('"ajax:beforeSend" can be observed and stopped with event delegation', function(assert) {
const done = assert.async()
$(document).delegate('form[data-remote]', 'ajax:beforeSend', function(e) {
assert.ok(true, 'ajax:beforeSend observed with event delegation')
e.preventDefault()
})
submit(function(form) {
form.unbind('ajax:send').bindNative('ajax:send', function() {
assert.ok(false, 'ajax:send should not run')
})
form.bindNative('ajax:complete', function() {
assert.ok(false, 'ajax:complete should not run')
})
})
setTimeout(function() { done() }, 13)
})
QUnit.test('"ajax:beforeSend", "ajax:send", "ajax:success" and "ajax:complete" are triggered', function(assert) {
const done = assert.async(4)
submit(function(form) {
form.bindNative('ajax:beforeSend', function(e, xhr, settings) {
assert.ok(xhr.setRequestHeader, 'first argument to "ajax:beforeSend" should be an XHR object')
assert.equal(settings.url, '/echo', 'second argument to "ajax:beforeSend" should be a settings object')
done()
})
form.bindNative('ajax:send', function(e, xhr) {
assert.ok(xhr.abort, 'first argument to "ajax:send" should be an XHR object')
done()
})
form.bindNative('ajax:success', function(e, data, status, xhr) {
assert.ok(data.REQUEST_METHOD, 'first argument to ajax:success should be a data object')
assert.equal(status, 'OK', 'second argument to ajax:success should be a status string')
assert.ok(xhr.getResponseHeader, 'third argument to "ajax:success" should be an XHR object')
done()
})
form.bindNative('ajax:complete', function(e, xhr, status) {
assert.ok(xhr.getResponseHeader, 'first argument to "ajax:complete" should be an XHR object')
assert.equal(status, 'OK', 'second argument to ajax:complete should be a status string')
done()
})
})
})
QUnit.test('"ajax:beforeSend", "ajax:send", "ajax:error" and "ajax:complete" are triggered on error', function(assert) {
const done = assert.async(4)
submit(function(form) {
form.attr('action', '/error')
form.bindNative('ajax:beforeSend', function(arg) {
assert.ok(true, 'ajax:beforeSend')
done()
})
form.bindNative('ajax:send', function(arg) {
assert.ok(true, 'ajax:send')
done()
})
form.bindNative('ajax:error', function(e, response, status, xhr) {
assert.equal(response, '', 'first argument to ajax:error should be an HTTP status response')
assert.equal(status, 'Forbidden', 'second argument to ajax:error should be a status string')
assert.ok(xhr.getResponseHeader, 'third argument to "ajax:error" should be an XHR object')
// Opera returns "0" for HTTP code
assert.equal(xhr.status, window.opera ? 0 : 403, 'status code should be 403')
done()
})
form.bindNative('ajax:complete', function(e, xhr, status) {
assert.ok(xhr.getResponseHeader, 'first argument to "ajax:complete" should be an XHR object')
assert.equal(status, 'Forbidden', 'second argument to ajax:complete should be a status string')
done()
})
})
})
QUnit.test('binding to ajax callbacks via .delegate() triggers handlers properly', function(assert) {
const done = assert.async(4)
$(document)
.delegate('form[data-remote]', 'ajax:beforeSend', function() {
assert.ok(true, 'ajax:beforeSend handler is triggered')
done()
})
.delegate('form[data-remote]', 'ajax:send', function() {
assert.ok(true, 'ajax:send handler is triggered')
done()
})
.delegate('form[data-remote]', 'ajax:success', function() {
assert.ok(true, 'ajax:success handler is triggered')
done()
})
.delegate('form[data-remote]', 'ajax:complete', function() {
assert.ok(true, 'ajax:complete handler is triggered')
done()
})
$('form[data-remote]').triggerNative('submit')
})
})()