mirror of
https://github.com/bigskysoftware/htmx.git
synced 2025-09-28 05:21:18 +00:00

* Fix old npm dependencies * implement web-test-runner tests for headless alongside Mocha browser tests * Increase test and code coverage * update to 100% coverage and impove eslint * Update testing Doco * revert all htmx changes and updates/disable tests needed * fix browser mocha test * Default testing to use playwrite only instead of puppeter * playwright install fix * Imporve test summary reporting * flatten false looks closer to original
1360 lines
45 KiB
JavaScript
1360 lines
45 KiB
JavaScript
describe('Core htmx AJAX Tests', function() {
|
|
beforeEach(function() {
|
|
this.server = makeServer()
|
|
clearWorkArea()
|
|
})
|
|
afterEach(function() {
|
|
this.server.restore()
|
|
clearWorkArea()
|
|
})
|
|
|
|
// bootstrap test
|
|
it('issues a GET request on click and swaps content', function() {
|
|
this.server.respondWith('GET', '/test', 'Clicked!')
|
|
|
|
var btn = make('<button hx-get="/test">Click Me!</button>')
|
|
btn.click()
|
|
this.server.respond()
|
|
btn.innerHTML.should.equal('Clicked!')
|
|
})
|
|
|
|
it('processes inner content properly', function() {
|
|
this.server.respondWith('GET', '/test', '<a hx-get="/test2">Click Me</a>')
|
|
this.server.respondWith('GET', '/test2', 'Clicked!')
|
|
|
|
var div = make('<div hx-get="/test"></div>')
|
|
div.click()
|
|
this.server.respond()
|
|
div.innerHTML.should.equal('<a hx-get="/test2">Click Me</a>')
|
|
var a = div.querySelector('a')
|
|
a.click()
|
|
this.server.respond()
|
|
a.innerHTML.should.equal('Clicked!')
|
|
})
|
|
|
|
it('handles swap outerHTML properly', function() {
|
|
this.server.respondWith('GET', '/test', '<a id="a1" hx-get="/test2">Click Me</a>')
|
|
this.server.respondWith('GET', '/test2', 'Clicked!')
|
|
|
|
var div = make('<div id="d1" hx-get="/test" hx-swap="outerHTML"></div>')
|
|
div.click()
|
|
should.equal(byId('d1'), div)
|
|
this.server.respond()
|
|
should.equal(byId('d1'), null)
|
|
byId('a1').click()
|
|
this.server.respond()
|
|
byId('a1').innerHTML.should.equal('Clicked!')
|
|
})
|
|
|
|
it('handles beforebegin properly', function() {
|
|
var i = 0
|
|
this.server.respondWith('GET', '/test', function(xhr) {
|
|
i++
|
|
xhr.respond(200, {}, '<a id="a' + i + '" hx-get="/test2" hx-swap="innerHTML">' + i + '</a>')
|
|
})
|
|
this.server.respondWith('GET', '/test2', '*')
|
|
|
|
var div = make('<div hx-get="/test" hx-swap="beforebegin">*</div>')
|
|
var parent = div.parentElement
|
|
div.click()
|
|
this.server.respond()
|
|
div.innerText.should.equal('*')
|
|
removeWhiteSpace(parent.innerText).should.equal('1*')
|
|
|
|
byId('a1').click()
|
|
this.server.respond()
|
|
removeWhiteSpace(parent.innerText).should.equal('**')
|
|
|
|
div.click()
|
|
this.server.respond()
|
|
div.innerText.should.equal('*')
|
|
removeWhiteSpace(parent.innerText).should.equal('*2*')
|
|
|
|
byId('a2').click()
|
|
this.server.respond()
|
|
removeWhiteSpace(parent.innerText).should.equal('***')
|
|
})
|
|
|
|
it('handles afterbegin properly', function() {
|
|
var i = 0
|
|
this.server.respondWith('GET', '/test', function(xhr) {
|
|
i++
|
|
xhr.respond(200, {}, '' + i)
|
|
})
|
|
|
|
var div = make('<div hx-get="/test" hx-swap="afterbegin">*</div>')
|
|
|
|
div.click()
|
|
this.server.respond()
|
|
div.innerText.should.equal('1*')
|
|
|
|
div.click()
|
|
this.server.respond()
|
|
div.innerText.should.equal('21*')
|
|
|
|
div.click()
|
|
this.server.respond()
|
|
div.innerText.should.equal('321*')
|
|
})
|
|
|
|
it('handles afterbegin properly with no initial content', function() {
|
|
var i = 0
|
|
this.server.respondWith('GET', '/test', function(xhr) {
|
|
i++
|
|
xhr.respond(200, {}, '' + i)
|
|
})
|
|
|
|
var div = make('<div hx-get="/test" hx-swap="afterbegin"></div>')
|
|
|
|
div.click()
|
|
this.server.respond()
|
|
div.innerText.should.equal('1')
|
|
|
|
div.click()
|
|
this.server.respond()
|
|
div.innerText.should.equal('21')
|
|
|
|
div.click()
|
|
this.server.respond()
|
|
div.innerText.should.equal('321')
|
|
})
|
|
|
|
it('handles afterend properly', function() {
|
|
var i = 0
|
|
this.server.respondWith('GET', '/test', function(xhr) {
|
|
i++
|
|
xhr.respond(200, {}, '<a id="a' + i + '" hx-get="/test2" hx-swap="innerHTML">' + i + '</a>')
|
|
})
|
|
this.server.respondWith('GET', '/test2', '*')
|
|
|
|
var div = make('<div hx-get="/test" hx-swap="afterend">*</div>')
|
|
var parent = div.parentElement
|
|
div.click()
|
|
this.server.respond()
|
|
div.innerText.should.equal('*')
|
|
removeWhiteSpace(parent.innerText).should.equal('*1')
|
|
|
|
byId('a1').click()
|
|
this.server.respond()
|
|
removeWhiteSpace(parent.innerText).should.equal('**')
|
|
|
|
div.click()
|
|
this.server.respond()
|
|
div.innerText.should.equal('*')
|
|
removeWhiteSpace(parent.innerText).should.equal('*2*')
|
|
|
|
byId('a2').click()
|
|
this.server.respond()
|
|
removeWhiteSpace(parent.innerText).should.equal('***')
|
|
})
|
|
|
|
it('handles beforeend properly', function() {
|
|
var i = 0
|
|
this.server.respondWith('GET', '/test', function(xhr) {
|
|
i++
|
|
xhr.respond(200, {}, '' + i)
|
|
})
|
|
|
|
var div = make('<div hx-get="/test" hx-swap="beforeend">*</div>')
|
|
|
|
div.click()
|
|
this.server.respond()
|
|
div.innerText.should.equal('*1')
|
|
|
|
div.click()
|
|
this.server.respond()
|
|
div.innerText.should.equal('*12')
|
|
|
|
div.click()
|
|
this.server.respond()
|
|
div.innerText.should.equal('*123')
|
|
})
|
|
|
|
it('handles beforeend properly with no initial content', function() {
|
|
var i = 0
|
|
this.server.respondWith('GET', '/test', function(xhr) {
|
|
i++
|
|
xhr.respond(200, {}, '' + i)
|
|
})
|
|
|
|
var div = make('<div hx-get="/test" hx-swap="beforeend"></div>')
|
|
|
|
div.click()
|
|
this.server.respond()
|
|
div.innerText.should.equal('1')
|
|
|
|
div.click()
|
|
this.server.respond()
|
|
div.innerText.should.equal('12')
|
|
|
|
div.click()
|
|
this.server.respond()
|
|
div.innerText.should.equal('123')
|
|
})
|
|
|
|
it('handles hx-target properly', function() {
|
|
this.server.respondWith('GET', '/test', 'Clicked!')
|
|
|
|
var btn = make('<button hx-get="/test" hx-target="#s1">Click Me!</button>')
|
|
var target = make('<span id="s1">Initial</span>')
|
|
btn.click()
|
|
target.innerHTML.should.equal('Initial')
|
|
this.server.respond()
|
|
target.innerHTML.should.equal('Clicked!')
|
|
})
|
|
|
|
it('handles 204 NO CONTENT responses properly', function() {
|
|
this.server.respondWith('GET', '/test', [204, {}, 'No Content!'])
|
|
|
|
var btn = make('<button hx-get="/test">Click Me!</button>')
|
|
btn.click()
|
|
btn.innerHTML.should.equal('Click Me!')
|
|
this.server.respond()
|
|
btn.innerHTML.should.equal('Click Me!')
|
|
})
|
|
|
|
it('handles 304 NOT MODIFIED responses properly', function() {
|
|
this.server.respondWith('GET', '/test-1', [200, {}, 'Content for Tab 1'])
|
|
this.server.respondWith('GET', '/test-2', [200, {}, 'Content for Tab 2'])
|
|
|
|
var target = make('<div id="target"></div>')
|
|
var btn1 = make('<button hx-get="/test-1" hx-target="#target">Tab 1</button>')
|
|
var btn2 = make('<button hx-get="/test-2" hx-target="#target">Tab 2</button>')
|
|
|
|
btn1.click()
|
|
target.innerHTML.should.equal('')
|
|
this.server.respond()
|
|
target.innerHTML.should.equal('Content for Tab 1')
|
|
|
|
btn2.click()
|
|
this.server.respond()
|
|
target.innerHTML.should.equal('Content for Tab 2')
|
|
|
|
this.server.respondWith('GET', '/test-1', [304, {}, 'Content for Tab 1'])
|
|
this.server.respondWith('GET', '/test-2', [304, {}, 'Content for Tab 2'])
|
|
|
|
btn1.click()
|
|
this.server.respond()
|
|
target.innerHTML.should.equal('Content for Tab 1')
|
|
|
|
btn2.click()
|
|
this.server.respond()
|
|
target.innerHTML.should.equal('Content for Tab 2')
|
|
})
|
|
|
|
it('handles hx-trigger with non-default value', function() {
|
|
this.server.respondWith('GET', '/test', 'Clicked!')
|
|
|
|
var form = make('<form hx-get="/test" hx-trigger="click">Click Me!</form>')
|
|
form.click()
|
|
form.innerHTML.should.equal('Click Me!')
|
|
this.server.respond()
|
|
form.innerHTML.should.equal('Clicked!')
|
|
})
|
|
|
|
it('handles hx-trigger with load event', function() {
|
|
this.server.respondWith('GET', '/test', 'Loaded!')
|
|
var div = make('<div hx-get="/test" hx-trigger="load">Load Me!</div>')
|
|
div.innerHTML.should.equal('Load Me!')
|
|
this.server.respond()
|
|
div.innerHTML.should.equal('Loaded!')
|
|
})
|
|
|
|
it('sets the content type of the request properly', function(done) {
|
|
this.server.respondWith('GET', '/test', function(xhr) {
|
|
xhr.respond(200, {}, 'done')
|
|
xhr.overriddenMimeType.should.equal('text/html')
|
|
done()
|
|
})
|
|
var div = make('<div hx-get="/test">Click Me!</div>')
|
|
div.click()
|
|
this.server.respond()
|
|
})
|
|
|
|
it('issues two requests when clicked twice before response', function() {
|
|
var i = 1
|
|
this.server.respondWith('GET', '/test', function(xhr) {
|
|
xhr.respond(200, {}, 'click ' + i)
|
|
i++
|
|
})
|
|
var div = make('<div hx-get="/test"></div>')
|
|
div.click()
|
|
div.click()
|
|
this.server.respond()
|
|
div.innerHTML.should.equal('click 1')
|
|
this.server.respond()
|
|
div.innerHTML.should.equal('click 2')
|
|
})
|
|
|
|
it('issues two requests when clicked three times before response', function() {
|
|
var i = 1
|
|
this.server.respondWith('GET', '/test', function(xhr) {
|
|
xhr.respond(200, {}, 'click ' + i)
|
|
i++
|
|
})
|
|
var div = make('<div hx-get="/test"></div>')
|
|
div.click()
|
|
div.click()
|
|
div.click()
|
|
this.server.respondAll()
|
|
div.innerHTML.should.equal('click 2')
|
|
})
|
|
|
|
it('properly handles hx-select for basic situation', function() {
|
|
var i = 1
|
|
this.server.respondWith('GET', '/test', "<div id='d1'>foo</div><div id='d2'>bar</div>")
|
|
var div = make('<div hx-get="/test" hx-select="#d1"></div>')
|
|
div.click()
|
|
this.server.respond()
|
|
div.innerHTML.should.equal('<div id="d1">foo</div>')
|
|
})
|
|
|
|
it('properly handles hx-select for full html document situation', function() {
|
|
this.server.respondWith('GET', '/test', "<html><body><div id='d1'>foo</div><div id='d2'>bar</div></body></html>")
|
|
var div = make('<div hx-get="/test" hx-select="#d1"></div>')
|
|
div.click()
|
|
this.server.respond()
|
|
div.innerHTML.should.equal('<div id="d1">foo</div>')
|
|
})
|
|
|
|
it('properly settles attributes on interior elements', function(done) {
|
|
this.server.respondWith('GET', '/test', "<div hx-get='/test'><div width='bar' id='d1'></div></div>")
|
|
var div = make("<div hx-get='/test' hx-swap='outerHTML settle:10ms'><div id='d1'></div></div>")
|
|
div.click()
|
|
this.server.respond()
|
|
should.equal(byId('d1').getAttribute('width'), null)
|
|
setTimeout(function() {
|
|
should.equal(byId('d1').getAttribute('width'), 'bar')
|
|
done()
|
|
}, 20)
|
|
})
|
|
|
|
it('properly settles attributes elements with single quotes in id', function(done) {
|
|
this.server.respondWith('GET', '/test', "<div hx-get='/test'><div width='bar' id=\"d1'\"></div></div>")
|
|
var div = make("<div hx-get='/test' hx-swap='outerHTML settle:10ms'><div id=\"d1'\"></div></div>")
|
|
div.click()
|
|
this.server.respond()
|
|
should.equal(byId("d1'").getAttribute('width'), null)
|
|
setTimeout(function() {
|
|
should.equal(byId("d1'").getAttribute('width'), 'bar')
|
|
done()
|
|
}, 20)
|
|
})
|
|
|
|
it('properly settles attributes elements with double quotes in id', function(done) {
|
|
this.server.respondWith('GET', '/test', "<div hx-get='/test'><div width='bar' id='d1\"'></div></div>")
|
|
var div = make("<div hx-get='/test' hx-swap='outerHTML settle:10ms'><div id='d1\"'></div></div>")
|
|
div.click()
|
|
this.server.respond()
|
|
should.equal(byId('d1"').getAttribute('width'), null)
|
|
setTimeout(function() {
|
|
should.equal(byId('d1"').getAttribute('width'), 'bar')
|
|
done()
|
|
}, 20)
|
|
})
|
|
|
|
it('properly handles multiple select input', function() {
|
|
var values
|
|
this.server.respondWith('Post', '/test', function(xhr) {
|
|
values = getParameters(xhr)
|
|
xhr.respond(204, {}, '')
|
|
})
|
|
|
|
var form = make('<form hx-post="/test" hx-trigger="click">' +
|
|
'<select id="multiSelect" name="multiSelect" multiple="multiple">' +
|
|
'<option id="m1" value="m1">m1</option>' +
|
|
'<option id="m2" value="m2">m2</option>' +
|
|
'<option id="m3" value="m3">m3</option>' +
|
|
'<option id="m4" value="m4">m4</option>' +
|
|
'</select>' +
|
|
'</form>')
|
|
|
|
form.click()
|
|
this.server.respond()
|
|
values.should.deep.equal({})
|
|
|
|
byId('m1').selected = true
|
|
form.click()
|
|
this.server.respond()
|
|
values.should.deep.equal({ multiSelect: 'm1' })
|
|
|
|
byId('m1').selected = true
|
|
byId('m3').selected = true
|
|
form.click()
|
|
this.server.respond()
|
|
values.should.deep.equal({ multiSelect: ['m1', 'm3'] })
|
|
})
|
|
|
|
it('properly handles multiple select input when "multiple" attribute is empty string', function() {
|
|
var values
|
|
this.server.respondWith('Post', '/test', function(xhr) {
|
|
values = getParameters(xhr)
|
|
xhr.respond(204, {}, '')
|
|
})
|
|
|
|
var form = make('<form hx-post="/test" hx-trigger="click">' +
|
|
'<select name="multiSelect" id="id_question_list" multiple="" tabindex="-1" aria-hidden="true">' +
|
|
'<option id="m1" value="m1">m1</option>' +
|
|
'<option id="m2" value="m2">m2</option>' +
|
|
'<option id="m3" value="m3">m3</option>' +
|
|
'<option id="m4" value="m4">m4</option>' +
|
|
'</select>' +
|
|
'</form>')
|
|
|
|
form.click()
|
|
this.server.respond()
|
|
values.should.deep.equal({})
|
|
|
|
byId('m1').selected = true
|
|
form.click()
|
|
this.server.respond()
|
|
values.should.deep.equal({ multiSelect: 'm1' })
|
|
|
|
byId('m1').selected = true
|
|
byId('m3').selected = true
|
|
form.click()
|
|
this.server.respond()
|
|
values.should.deep.equal({ multiSelect: ['m1', 'm3'] })
|
|
})
|
|
|
|
it('properly handles two multiple select inputs w/ same name', function() {
|
|
var values
|
|
this.server.respondWith('Post', '/test', function(xhr) {
|
|
values = getParameters(xhr)
|
|
xhr.respond(204, {}, '')
|
|
})
|
|
|
|
var form = make('<form hx-post="/test" hx-trigger="click">' +
|
|
'<select id="multiSelect" name="multiSelect" multiple="multiple">' +
|
|
'<option id="m1" value="m1">m1</option>' +
|
|
'<option id="m2" value="m2">m2</option>' +
|
|
'<option id="m3" value="m3">m3</option>' +
|
|
'<option id="m4" value="m4">m4</option>' +
|
|
'</select>' +
|
|
'<select id="multiSelect" name="multiSelect" multiple="multiple">' +
|
|
'<option id="m5" value="m5">m1</option>' +
|
|
'<option id="m6" value="m6">m2</option>' +
|
|
'<option id="m7" value="m7">m3</option>' +
|
|
'<option id="m8" value="m8">m4</option>' +
|
|
'</select>' +
|
|
'</form>')
|
|
|
|
form.click()
|
|
this.server.respond()
|
|
values.should.deep.equal({})
|
|
|
|
byId('m1').selected = true
|
|
form.click()
|
|
this.server.respond()
|
|
values.should.deep.equal({ multiSelect: 'm1' })
|
|
|
|
byId('m1').selected = true
|
|
byId('m3').selected = true
|
|
byId('m7').selected = true
|
|
byId('m8').selected = true
|
|
form.click()
|
|
this.server.respond()
|
|
values.should.deep.equal({ multiSelect: ['m1', 'm3', 'm7', 'm8'] })
|
|
})
|
|
|
|
it('properly handles multiple email input', function() {
|
|
var values
|
|
this.server.respondWith('Post', '/test', function(xhr) {
|
|
values = getParameters(xhr)
|
|
xhr.respond(204, {}, '')
|
|
})
|
|
|
|
var form = make('<form hx-post="/test" hx-trigger="click">' +
|
|
'<input id="multiEmail" name="multiEmail" multiple>' +
|
|
'</form>')
|
|
|
|
form.click()
|
|
this.server.respond()
|
|
values.should.deep.equal({ multiEmail: '' })
|
|
|
|
byId('multiEmail').value = 'foo@example.com'
|
|
form.click()
|
|
this.server.respond()
|
|
values.should.deep.equal({ multiEmail: 'foo@example.com' })
|
|
|
|
byId('multiEmail').value = 'foo@example.com,bar@example.com'
|
|
form.click()
|
|
this.server.respond()
|
|
values.should.deep.equal({ multiEmail: 'foo@example.com,bar@example.com' })
|
|
})
|
|
|
|
it('properly handles checkbox inputs', function() {
|
|
var values
|
|
this.server.respondWith('Post', '/test', function(xhr) {
|
|
values = getParameters(xhr)
|
|
xhr.respond(204, {}, '')
|
|
})
|
|
|
|
var form = make('<form hx-post="/test" hx-trigger="click">' +
|
|
'<input id="cb1" name="c1" value="cb1" type="checkbox">' +
|
|
'<input id="cb2" name="c1" value="cb2" type="checkbox">' +
|
|
'<input id="cb3" name="c1" value="cb3" type="checkbox">' +
|
|
'<input id="cb4" name="c2" value="cb4" type="checkbox">' +
|
|
'<input id="cb5" name="c2" value="cb5" type="checkbox">' +
|
|
'<input id="cb6" name="c3" value="cb6" type="checkbox">' +
|
|
'</form>')
|
|
|
|
form.click()
|
|
this.server.respond()
|
|
values.should.deep.equal({})
|
|
|
|
byId('cb1').checked = true
|
|
form.click()
|
|
this.server.respond()
|
|
values.should.deep.equal({ c1: 'cb1' })
|
|
|
|
byId('cb1').checked = true
|
|
byId('cb2').checked = true
|
|
form.click()
|
|
this.server.respond()
|
|
values.should.deep.equal({ c1: ['cb1', 'cb2'] })
|
|
|
|
byId('cb1').checked = true
|
|
byId('cb2').checked = true
|
|
byId('cb3').checked = true
|
|
form.click()
|
|
this.server.respond()
|
|
values.should.deep.equal({ c1: ['cb1', 'cb2', 'cb3'] })
|
|
|
|
byId('cb1').checked = true
|
|
byId('cb2').checked = true
|
|
byId('cb3').checked = true
|
|
byId('cb4').checked = true
|
|
form.click()
|
|
this.server.respond()
|
|
values.should.deep.equal({ c1: ['cb1', 'cb2', 'cb3'], c2: 'cb4' })
|
|
|
|
byId('cb1').checked = true
|
|
byId('cb2').checked = true
|
|
byId('cb3').checked = true
|
|
byId('cb4').checked = true
|
|
byId('cb5').checked = true
|
|
form.click()
|
|
this.server.respond()
|
|
values.should.deep.equal({ c1: ['cb1', 'cb2', 'cb3'], c2: ['cb4', 'cb5'] })
|
|
|
|
byId('cb1').checked = true
|
|
byId('cb2').checked = true
|
|
byId('cb3').checked = true
|
|
byId('cb4').checked = true
|
|
byId('cb5').checked = true
|
|
byId('cb6').checked = true
|
|
form.click()
|
|
this.server.respond()
|
|
values.should.deep.equal({ c1: ['cb1', 'cb2', 'cb3'], c2: ['cb4', 'cb5'], c3: 'cb6' })
|
|
|
|
byId('cb1').checked = true
|
|
byId('cb2').checked = false
|
|
byId('cb3').checked = true
|
|
byId('cb4').checked = false
|
|
byId('cb5').checked = true
|
|
byId('cb6').checked = true
|
|
form.click()
|
|
this.server.respond()
|
|
values.should.deep.equal({ c1: ['cb1', 'cb3'], c2: 'cb5', c3: 'cb6' })
|
|
})
|
|
|
|
it('properly handles radio inputs', function() {
|
|
var values
|
|
this.server.respondWith('Post', '/test', function(xhr) {
|
|
values = getParameters(xhr)
|
|
xhr.respond(204, {}, '')
|
|
})
|
|
|
|
var form = make('<form hx-post="/test" hx-trigger="click">' +
|
|
'<div role="radiogroup">' +
|
|
'<input id="rb1" name="r1" value="rb1" type="radio">' +
|
|
'<input id="rb2" name="r1" value="rb2" type="radio">' +
|
|
'<input id="rb3" name="r1" value="rb3" type="radio">' +
|
|
'<input id="rb4" name="r2" value="rb4" type="radio">' +
|
|
'<input id="rb5" name="r2" value="rb5" type="radio">' +
|
|
'<input id="rb6" name="r3" value="rb6" type="radio">' +
|
|
'</div>' +
|
|
'</form>')
|
|
|
|
form.click()
|
|
this.server.respond()
|
|
values.should.deep.equal({})
|
|
|
|
byId('rb1').checked = true
|
|
form.click()
|
|
this.server.respond()
|
|
values.should.deep.equal({ r1: 'rb1' })
|
|
})
|
|
|
|
it('text nodes dont screw up settling via variable capture', function() {
|
|
this.server.respondWith('GET', '/test', "<div id='d1' hx-trigger='click consume' hx-get='/test2'></div>fooo")
|
|
this.server.respondWith('GET', '/test2', 'clicked')
|
|
var div = make("<div hx-get='/test'/>")
|
|
div.click()
|
|
this.server.respond()
|
|
byId('d1').click()
|
|
this.server.respond()
|
|
byId('d1').innerHTML.should.equal('clicked')
|
|
})
|
|
|
|
it('script nodes evaluate', function() {
|
|
var globalWasCalled = false
|
|
window.callGlobal = function() {
|
|
globalWasCalled = true
|
|
}
|
|
try {
|
|
this.server.respondWith('GET', '/test', "<div></div><script type='text/javascript'>callGlobal()</script>")
|
|
var div = make("<div hx-get='/test'></div>")
|
|
div.click()
|
|
this.server.respond()
|
|
globalWasCalled.should.equal(true)
|
|
} finally {
|
|
delete window.callGlobal
|
|
}
|
|
})
|
|
|
|
it('stand alone script nodes evaluate', function() {
|
|
var globalWasCalled = false
|
|
window.callGlobal = function() {
|
|
globalWasCalled = true
|
|
}
|
|
try {
|
|
this.server.respondWith('GET', '/test', "<script type='text/javascript'>callGlobal()</script>")
|
|
var div = make("<div hx-get='/test'></div>")
|
|
div.click()
|
|
this.server.respond()
|
|
globalWasCalled.should.equal(true)
|
|
} finally {
|
|
delete window.callGlobal
|
|
}
|
|
})
|
|
|
|
it('script nodes can define global functions', function() {
|
|
try {
|
|
window.foo = {}
|
|
this.server.respondWith('GET', '/test', "<script type='text/javascript'>foo.bar = function() { return 42 }</script>")
|
|
var div = make("<div hx-get='/test'></div>")
|
|
div.click()
|
|
this.server.respond()
|
|
foo.bar().should.equal(42)
|
|
} finally {
|
|
delete window.foo
|
|
}
|
|
})
|
|
|
|
it('child script nodes evaluate when children', function() {
|
|
var globalWasCalled = false
|
|
window.callGlobal = function() {
|
|
globalWasCalled = true
|
|
}
|
|
try {
|
|
this.server.respondWith('GET', '/test', "<div><script type='text/javascript'>callGlobal()</script></div>")
|
|
var div = make("<div hx-get='/test'></div>")
|
|
div.click()
|
|
this.server.respond()
|
|
globalWasCalled.should.equal(true)
|
|
} finally {
|
|
delete window.callGlobal
|
|
}
|
|
})
|
|
|
|
it('child script nodes evaluate when first child', function() {
|
|
var globalWasCalled = false
|
|
window.callGlobal = function() {
|
|
globalWasCalled = true
|
|
}
|
|
try {
|
|
this.server.respondWith('GET', '/test', "<script type='text/javascript'>callGlobal()</script><div></div>")
|
|
var div = make("<div hx-get='/test'></div>")
|
|
div.click()
|
|
this.server.respond()
|
|
globalWasCalled.should.equal(true)
|
|
} finally {
|
|
delete window.callGlobal
|
|
}
|
|
})
|
|
|
|
it('child script nodes evaluate when not explicitly marked javascript', function() {
|
|
var globalWasCalled = false
|
|
window.callGlobal = function() {
|
|
globalWasCalled = true
|
|
}
|
|
try {
|
|
this.server.respondWith('GET', '/test', '<div><script>callGlobal()</script></div>')
|
|
var div = make("<div hx-get='/test'></div>")
|
|
div.click()
|
|
this.server.respond()
|
|
globalWasCalled.should.equal(true)
|
|
} finally {
|
|
delete window.callGlobal
|
|
}
|
|
})
|
|
|
|
it('script nodes do not evaluate when explicitly marked as something other than javascript', function() {
|
|
var globalWasCalled = false
|
|
window.callGlobal = function() {
|
|
globalWasCalled = true
|
|
}
|
|
try {
|
|
this.server.respondWith('GET', '/test', "<div><script type='text/samplescript'>callGlobal()</script></div>")
|
|
var div = make("<div hx-get='/test'></div>")
|
|
div.click()
|
|
this.server.respond()
|
|
globalWasCalled.should.equal(false)
|
|
} finally {
|
|
delete window.callGlobal
|
|
}
|
|
})
|
|
|
|
it('script nodes evaluate after swap', function() {
|
|
window.callGlobal = function() {
|
|
console.log('Here...')
|
|
window.tempVal = byId('d1').innerText
|
|
}
|
|
try {
|
|
this.server.respondWith('GET', '/test', "<div><script>callGlobal()</script><div id='d1'>After settle...</div> </div>")
|
|
var div = make("<div hx-get='/test'></div>")
|
|
div.click()
|
|
this.server.respond()
|
|
window.tempVal.should.equal('After settle...')
|
|
} finally {
|
|
delete window.callGlobal
|
|
delete window.tempVal
|
|
}
|
|
})
|
|
|
|
it('script node exceptions do not break rendering', function() {
|
|
this.skip('Rendering does not break, but the exception bubbles up and mocha reports it')
|
|
this.server.respondWith('GET', '/test', "clicked<script type='text/javascript'>throw 'foo';</script>")
|
|
var div = make("<div hx-get='/test'></div>")
|
|
div.click()
|
|
this.server.respond()
|
|
div.innerText.should.equal('clicked')
|
|
console.log(div.innerText)
|
|
console.log('here')
|
|
})
|
|
|
|
it('allows empty verb values', function() {
|
|
var path = null
|
|
var div = make("<div hx-get=''/>")
|
|
htmx.on(div, 'htmx:configRequest', function(evt) {
|
|
path = evt.detail.path
|
|
return false
|
|
})
|
|
div.click()
|
|
this.server.respond()
|
|
path.should.not.be.null
|
|
})
|
|
|
|
it('allows blank verb values', function() {
|
|
var path = null
|
|
var div = make('<div hx-get/>')
|
|
htmx.on(div, 'htmx:configRequest', function(evt) {
|
|
path = evt.detail.path
|
|
return false
|
|
})
|
|
div.click()
|
|
this.server.respond()
|
|
path.should.not.be.null
|
|
})
|
|
|
|
it('input values are not settle swapped (causes flicker)', function() {
|
|
this.server.respondWith('GET', '/test', "<input id='i1' value='bar'/>")
|
|
var input = make("<input id='i1' hx-get='/test' value='foo' hx-swap='outerHTML settle:50' hx-trigger='click'/>")
|
|
input.click()
|
|
this.server.respond()
|
|
input = byId('i1')
|
|
input.value.should.equal('bar')
|
|
})
|
|
|
|
it('autofocus attribute works properly', function() {
|
|
this.server.respondWith('GET', '/test', "<input id='i2' value='bar' autofocus/>")
|
|
var input = make("<input id='i1' hx-get='/test' value='foo' hx-swap='afterend' hx-trigger='click'/>")
|
|
input.focus()
|
|
input.click()
|
|
document.activeElement.should.equal(input)
|
|
this.server.respond()
|
|
var input2 = byId('i2')
|
|
document.activeElement.should.equal(input2)
|
|
})
|
|
|
|
it('autofocus attribute works properly w/ child', function() {
|
|
this.server.respondWith('GET', '/test', "<div><input id='i2' value='bar' autofocus/></div>")
|
|
var input = make("<input id='i1' hx-get='/test' value='foo' hx-swap='afterend' hx-trigger='click'/>")
|
|
input.focus()
|
|
input.click()
|
|
document.activeElement.should.equal(input)
|
|
this.server.respond()
|
|
var input2 = byId('i2')
|
|
document.activeElement.should.equal(input2)
|
|
})
|
|
|
|
it('autofocus attribute works properly w/ true value', function() {
|
|
this.server.respondWith('GET', '/test', "<div><input id='i2' value='bar' autofocus='true'/></div>")
|
|
var input = make("<input id='i1' hx-get='/test' value='foo' hx-swap='afterend' hx-trigger='click'/>")
|
|
input.focus()
|
|
input.click()
|
|
document.activeElement.should.equal(input)
|
|
this.server.respond()
|
|
var input2 = byId('i2')
|
|
document.activeElement.should.equal(input2)
|
|
})
|
|
|
|
it('multipart/form-data encoding works', function() {
|
|
this.server.respondWith('POST', '/test', function(xhr) {
|
|
should.equal(xhr.requestHeaders['Content-Type'], undefined)
|
|
if (xhr.requestBody.get) { // IE 11 does not support
|
|
xhr.requestBody.get('i1').should.equal('foo')
|
|
}
|
|
xhr.respond(200, {}, 'body: ' + xhr.requestBody)
|
|
})
|
|
var form = make("<form hx-post='/test' hx-encoding='multipart/form-data' hx-trigger='click'>" +
|
|
"<input name='i1' id='i1' value='foo'/>" +
|
|
'</form>')
|
|
form.focus()
|
|
form.click()
|
|
this.server.respond()
|
|
})
|
|
|
|
it('removed elements do not issue requests', function() {
|
|
var count = 0
|
|
this.server.respondWith('GET', '/test', function(xhr) {
|
|
count++
|
|
xhr.respond(200, {}, '')
|
|
})
|
|
var btn = make('<button hx-get="/test">Click Me!</button>')
|
|
htmx.remove(btn)
|
|
btn.click()
|
|
this.server.respond()
|
|
count.should.equal(0)
|
|
})
|
|
|
|
it('title tags update title', function() {
|
|
this.server.respondWith('GET', '/test', function(xhr) {
|
|
xhr.respond(200, {}, "<title class=''>htmx rocks!</title>Clicked!")
|
|
})
|
|
var btn = make('<button hx-get="/test">Click Me!</button>')
|
|
btn.click()
|
|
this.server.respond()
|
|
btn.innerText.should.equal('Clicked!')
|
|
window.document.title.should.equal('htmx rocks!')
|
|
})
|
|
|
|
it('svg title tags do not update title', function() {
|
|
var originalTitle = window.document.title
|
|
this.server.respondWith('GET', '/test', function(xhr) {
|
|
xhr.respond(200, {}, "<svg class=''><title>" + originalTitle + 'UPDATE' + '</title></svg>Clicked!')
|
|
})
|
|
var btn = make('<button hx-get="/test">Click Me!</button>')
|
|
btn.click()
|
|
this.server.respond()
|
|
btn.innerText.should.equal('Clicked!')
|
|
window.document.title.should.equal(originalTitle)
|
|
})
|
|
|
|
it('first title tag outside svg title tags updates title', function() {
|
|
var originalTitle = window.document.title
|
|
var newTitle = originalTitle + '!!!'
|
|
this.server.respondWith('GET', '/test', function(xhr) {
|
|
xhr.respond(200, {}, "<title class=''>" + newTitle + "</title><svg class=''><title>foo</title></svg>Clicked!<title class=''>x</title>")
|
|
})
|
|
var btn = make('<button hx-get="/test">Click Me!</button>')
|
|
btn.click()
|
|
this.server.respond()
|
|
btn.innerText.should.equal('Clicked!')
|
|
window.document.title.should.equal(newTitle)
|
|
})
|
|
|
|
it('title update does not URL escape', function() {
|
|
this.server.respondWith('GET', '/test', function(xhr) {
|
|
xhr.respond(200, {}, '<title></> htmx rocks!</title>Clicked!')
|
|
})
|
|
var btn = make('<button hx-get="/test">Click Me!</button>')
|
|
btn.click()
|
|
this.server.respond()
|
|
btn.innerText.should.equal('Clicked!')
|
|
window.document.title.should.equal('</> htmx rocks!')
|
|
})
|
|
|
|
it('by default 400 content is not swapped', function() {
|
|
this.server.respondWith('GET', '/test', function(xhr) {
|
|
xhr.respond(400, {}, 'Clicked!')
|
|
})
|
|
var btn = make('<button hx-get="/test">Click Me!</button>')
|
|
btn.click()
|
|
this.server.respond()
|
|
btn.innerText.should.equal('Click Me!')
|
|
})
|
|
|
|
it('400 content can be swapped if configured to do so', function() {
|
|
var handler = htmx.on('htmx:beforeSwap', function(event) {
|
|
if (event.detail.xhr.status === 400) {
|
|
event.detail.shouldSwap = true
|
|
}
|
|
})
|
|
|
|
this.server.respondWith('GET', '/test', function(xhr) {
|
|
xhr.respond(400, {}, 'Clicked!')
|
|
})
|
|
var btn = make('<button hx-get="/test">Click Me!</button>')
|
|
btn.click()
|
|
this.server.respond()
|
|
btn.innerText.should.equal('Clicked!')
|
|
htmx.off('htmx:beforeSwap', handler)
|
|
})
|
|
|
|
it('400 content can be retargeted if configured to do so', function() {
|
|
var handler = htmx.on('htmx:beforeSwap', function(event) {
|
|
if (event.detail.xhr.status === 400) {
|
|
event.detail.shouldSwap = true
|
|
event.detail.target = byId('d1')
|
|
}
|
|
})
|
|
|
|
this.server.respondWith('GET', '/test', function(xhr) {
|
|
xhr.respond(400, {}, 'Clicked!')
|
|
})
|
|
var btn = make('<button hx-get="/test">Click Me!</button>')
|
|
var div = make('<div id="d1"></div>')
|
|
btn.click()
|
|
this.server.respond()
|
|
div.innerText.should.equal('Clicked!')
|
|
htmx.off('htmx:beforeSwap', handler)
|
|
})
|
|
|
|
it('errors are triggered only on 400+', function() {
|
|
var errors = 0
|
|
var handler = htmx.on('htmx:responseError', function() {
|
|
errors++
|
|
})
|
|
this.server.respondWith('GET', '/test1', function(xhr) {
|
|
xhr.respond(204, {}, 'Clicked!')
|
|
})
|
|
this.server.respondWith('GET', '/test2', function(xhr) {
|
|
xhr.respond(400, {}, 'Clicked!')
|
|
})
|
|
var btn1 = make('<button hx-get="/test1">Click Me!</button>')
|
|
var btn2 = make('<button hx-get="/test2">Click Me!</button>')
|
|
btn1.click()
|
|
btn2.click()
|
|
this.server.respond()
|
|
this.server.respond()
|
|
errors.should.equal(1)
|
|
htmx.off('htmx:responseError', handler)
|
|
})
|
|
|
|
it('content can be modified if configured to do so', function() {
|
|
var handler = htmx.on('htmx:beforeSwap', function(event) {
|
|
if (event.detail.xhr.status === 400) {
|
|
event.detail.shouldSwap = true
|
|
event.detail.serverResponse = event.detail.serverResponse + '!!'
|
|
}
|
|
})
|
|
|
|
this.server.respondWith('GET', '/test', function(xhr) {
|
|
xhr.respond(400, {}, 'Clicked!')
|
|
})
|
|
var btn = make('<button hx-get="/test">Click Me!</button>')
|
|
btn.click()
|
|
this.server.respond()
|
|
btn.innerText.should.equal('Clicked!!!')
|
|
htmx.off('htmx:beforeSwap', handler)
|
|
})
|
|
|
|
it('scripts w/ src attribute are properly loaded', function(done) {
|
|
try {
|
|
if (byId('mocha')) {
|
|
this.server.respondWith('GET', '/test', "<script id='setGlobalScript' src='setGlobal.js'></script>")
|
|
} else {
|
|
this.server.respondWith('GET', '/test', "<script id='setGlobalScript' src='/test/setGlobal.js'></script>")
|
|
}
|
|
var div = make("<div hx-get='/test'></div>")
|
|
div.click()
|
|
this.server.respond()
|
|
byId('setGlobalScript').addEventListener('load', function() {
|
|
window.globalWasCalled.should.equal(true)
|
|
delete window.globalWasCalled
|
|
done()
|
|
})
|
|
} finally {
|
|
delete window.globalWasCalled
|
|
}
|
|
})
|
|
|
|
it('should load tags with colon in their names', function() {
|
|
this.server.respondWith('GET', '/test', '<with:colon id="foobar">Foobar</with:colon>')
|
|
|
|
var btn = make('<button hx-get="/test">Give me colons!</button>')
|
|
btn.click()
|
|
this.server.respond()
|
|
|
|
btn.innerHTML.should.equal('<with:colon id="foobar">Foobar</with:colon>')
|
|
})
|
|
|
|
it('properly handles clicked submit button with a value inside a htmx form', function() {
|
|
var values
|
|
this.server.respondWith('Post', '/test', function(xhr) {
|
|
values = getParameters(xhr)
|
|
xhr.respond(204, {}, '')
|
|
})
|
|
|
|
make('<form hx-post="/test">' +
|
|
'<input type="text" name="t1" value="textValue">' +
|
|
'<button id="submit" type="submit" name="b1" value="buttonValue">button</button>' +
|
|
'</form>')
|
|
|
|
byId('submit').click()
|
|
this.server.respond()
|
|
values.should.deep.equal({ t1: 'textValue', b1: 'buttonValue' })
|
|
})
|
|
|
|
it('properly handles clicked submit input with a value inside a htmx form', function() {
|
|
var values
|
|
this.server.respondWith('Post', '/test', function(xhr) {
|
|
values = getParameters(xhr)
|
|
xhr.respond(204, {}, '')
|
|
})
|
|
|
|
make('<form hx-post="/test">' +
|
|
'<input type="text" name="t1" value="textValue">' +
|
|
'<input id="submit" type="submit" name="b1" value="buttonValue">' +
|
|
'</form>')
|
|
|
|
byId('submit').click()
|
|
this.server.respond()
|
|
values.should.deep.equal({ t1: 'textValue', b1: 'buttonValue' })
|
|
})
|
|
|
|
it('properly handles clicked submit button with a value inside a non-htmx form', function() {
|
|
var values
|
|
this.server.respondWith('Post', '/test', function(xhr) {
|
|
values = getParameters(xhr)
|
|
xhr.respond(204, {}, '')
|
|
})
|
|
|
|
make('<form>' +
|
|
'<input type="text" name="t1" value="textValue">' +
|
|
'<button id="submit" type="submit" name="b1" value="buttonValue" hx-post="/test">button</button>' +
|
|
'</form>')
|
|
|
|
byId('submit').click()
|
|
this.server.respond()
|
|
values.should.deep.equal({ t1: 'textValue', b1: 'buttonValue' })
|
|
})
|
|
|
|
it('properly handles clicked submit input with a value inside a non-htmx form', function() {
|
|
var values
|
|
this.server.respondWith('Post', '/test', function(xhr) {
|
|
values = getParameters(xhr)
|
|
xhr.respond(204, {}, '')
|
|
})
|
|
|
|
make('<form>' +
|
|
'<input type="text" name="t1" value="textValue">' +
|
|
'<input id="submit" type="submit" name="b1" value="buttonValue" hx-post="/test">' +
|
|
'</form>')
|
|
|
|
byId('submit').click()
|
|
this.server.respond()
|
|
values.should.deep.equal({ t1: 'textValue', b1: 'buttonValue' })
|
|
})
|
|
|
|
it('properly handles clicked submit button with a value outside a htmx form', function() {
|
|
var values
|
|
this.server.respondWith('Post', '/test', function(xhr) {
|
|
values = getParameters(xhr)
|
|
xhr.respond(204, {}, '')
|
|
})
|
|
|
|
make('<form id="externalForm" hx-post="/test">' +
|
|
'<input type="text" name="t1" value="textValue">' +
|
|
'</form>' +
|
|
'<button id="submit" form="externalForm" type="submit" name="b1" value="buttonValue">button</button>')
|
|
|
|
byId('submit').click()
|
|
this.server.respond()
|
|
values.should.deep.equal({ t1: 'textValue', b1: 'buttonValue' })
|
|
})
|
|
|
|
it('properly handles clicked submit input with a value outside a htmx form', function() {
|
|
var values
|
|
this.server.respondWith('Post', '/test', function(xhr) {
|
|
values = getParameters(xhr)
|
|
xhr.respond(204, {}, '')
|
|
})
|
|
|
|
make('<form id="externalForm" hx-post="/test">' +
|
|
'<input type="text" name="t1" value="textValue">' +
|
|
'</form>' +
|
|
'<input id="submit" form="externalForm" type="submit" name="b1" value="buttonValue">')
|
|
|
|
byId('submit').click()
|
|
this.server.respond()
|
|
values.should.deep.equal({ t1: 'textValue', b1: 'buttonValue' })
|
|
})
|
|
|
|
it('properly handles clicked submit button with a value stacking with regular input', function() {
|
|
var values
|
|
this.server.respondWith('Post', '/test', function(xhr) {
|
|
values = getParameters(xhr)
|
|
xhr.respond(204, {}, '')
|
|
})
|
|
|
|
make('<form hx-post="/test">' +
|
|
'<input type="hidden" name="action" value="A">' +
|
|
'<button id="btnA" type="submit">A</button>' +
|
|
'<button id="btnB" type="submit" name="action" value="B">B</button>' +
|
|
'<button id="btnC" type="submit" name="action" value="C">C</button>' +
|
|
'</form>')
|
|
|
|
byId('btnA').click()
|
|
this.server.respond()
|
|
values.should.deep.equal({ action: 'A' })
|
|
|
|
byId('btnB').click()
|
|
this.server.respond()
|
|
values.should.deep.equal({ action: ['A', 'B'] })
|
|
|
|
byId('btnC').click()
|
|
this.server.respond()
|
|
values.should.deep.equal({ action: ['A', 'C'] })
|
|
})
|
|
|
|
it('properly handles clicked submit input with a value stacking with regular input', function() {
|
|
var values
|
|
this.server.respondWith('Post', '/test', function(xhr) {
|
|
values = getParameters(xhr)
|
|
xhr.respond(204, {}, '')
|
|
})
|
|
|
|
make('<form hx-post="/test">' +
|
|
'<input type="hidden" name="action" value="A">' +
|
|
'<input id="btnA" type="submit">A</input>' +
|
|
'<input id="btnB" type="submit" name="action" value="B">B</input>' +
|
|
'<input id="btnC" type="submit" name="action" value="C">C</input>' +
|
|
'</form>')
|
|
|
|
byId('btnA').click()
|
|
this.server.respond()
|
|
values.should.deep.equal({ action: 'A' })
|
|
|
|
byId('btnB').click()
|
|
this.server.respond()
|
|
values.should.deep.equal({ action: ['A', 'B'] })
|
|
|
|
byId('btnC').click()
|
|
this.server.respond()
|
|
values.should.deep.equal({ action: ['A', 'C'] })
|
|
})
|
|
|
|
it('properly handles clicked submit button with a value inside a form, referencing another form', function() {
|
|
var values
|
|
this.server.respondWith('Post', '/test', function(xhr) {
|
|
values = getParameters(xhr)
|
|
xhr.respond(204, {}, '')
|
|
})
|
|
|
|
make('<form id="externalForm" hx-post="/test">' +
|
|
'<input type="text" name="t1" value="textValue">' +
|
|
'<input type="hidden" name="b1" value="inputValue">' +
|
|
'</form>' +
|
|
'<form hx-post="/test2">' +
|
|
'<button id="submit" form="externalForm" type="submit" name="b1" value="buttonValue">button</button>' +
|
|
'</form>')
|
|
|
|
byId('submit').click()
|
|
this.server.respond()
|
|
values.should.deep.equal({ t1: 'textValue', b1: ['inputValue', 'buttonValue'] })
|
|
})
|
|
|
|
it('properly handles clicked submit input with a value inside a form, referencing another form', function() {
|
|
var values
|
|
this.server.respondWith('Post', '/test', function(xhr) {
|
|
values = getParameters(xhr)
|
|
xhr.respond(204, {}, '')
|
|
})
|
|
|
|
make('<form id="externalForm" hx-post="/test">' +
|
|
'<input type="text" name="t1" value="textValue">' +
|
|
'<input type="hidden" name="b1" value="inputValue">' +
|
|
'</form>' +
|
|
'<form hx-post="/test2">' +
|
|
'<input id="submit" form="externalForm" type="submit" name="b1" value="buttonValue">' +
|
|
'</form>')
|
|
|
|
byId('submit').click()
|
|
this.server.respond()
|
|
values.should.deep.equal({ t1: 'textValue', b1: ['inputValue', 'buttonValue'] })
|
|
})
|
|
|
|
it('sends referenced form values when a button referencing another form is clicked', function() {
|
|
var values
|
|
this.server.respondWith('POST', '/test3', function(xhr) {
|
|
values = getParameters(xhr)
|
|
xhr.respond(205, {}, '')
|
|
})
|
|
|
|
make('<form id="externalForm" hx-post="/test">' +
|
|
'<input type="text" name="t1" value="textValue">' +
|
|
'<input type="hidden" name="b1" value="inputValue">' +
|
|
'</form>' +
|
|
'<form hx-post="/test2">' +
|
|
'<input type="text" name="t1" value="checkValue">' +
|
|
'<button id="submit" form="externalForm" hx-post="/test3" type="submit" name="b1" value="buttonValue">button</button>' +
|
|
'</form>')
|
|
|
|
byId('submit').click()
|
|
this.server.respond()
|
|
values.should.deep.equal({ t1: 'textValue', b1: ['inputValue', 'buttonValue'] })
|
|
})
|
|
|
|
it('sends referenced form values when a submit input referencing another form is clicked', function() {
|
|
var values
|
|
this.server.respondWith('POST', '/test3', function(xhr) {
|
|
values = getParameters(xhr)
|
|
xhr.respond(204, {}, '')
|
|
})
|
|
|
|
make('<form id="externalForm" hx-post="/test">' +
|
|
'<input type="text" name="t1" value="textValue">' +
|
|
'<input type="hidden" name="b1" value="inputValue">' +
|
|
'</form>' +
|
|
'<form hx-post="/test2">' +
|
|
'<input type="text" name="t1" value="checkValue">' +
|
|
'<input id="submit" form="externalForm" hx-post="/test3" type="submit" name="b1" value="buttonValue">' +
|
|
'</form>')
|
|
|
|
byId('submit').click()
|
|
this.server.respond()
|
|
values.should.deep.equal({ t1: 'textValue', b1: ['inputValue', 'buttonValue'] })
|
|
})
|
|
|
|
it('properly handles inputs external to form', function() {
|
|
var values
|
|
this.server.respondWith('Post', '/test', function(xhr) {
|
|
values = getParameters(xhr)
|
|
xhr.respond(204, {}, '')
|
|
})
|
|
|
|
make('<form id="externalForm" hx-post="/test">' +
|
|
' <input type="hidden" name="b1" value="inputValue">' +
|
|
'</form>' +
|
|
'<input type="text" name="t1" value="textValue" form="externalForm">' +
|
|
'<select name="s1" form="externalForm">' +
|
|
' <option value="someValue"></option>' +
|
|
' <option value="selectValue" selected></option>' +
|
|
'</select>' +
|
|
'<button id="submit" form="externalForm" type="submit" name="b1" value="buttonValue">button</button>')
|
|
|
|
byId('submit').click()
|
|
this.server.respond()
|
|
values.should.deep.equal({ t1: 'textValue', b1: ['inputValue', 'buttonValue'], s1: 'selectValue' })
|
|
})
|
|
|
|
it('properly handles buttons with formmethod=dialog', function() {
|
|
var request = false
|
|
this.server.respondWith('POST', '/test', function(xhr) {
|
|
request = true
|
|
xhr.respond(200, {}, '<button>Bar</button>')
|
|
})
|
|
|
|
make('<dialog><form hx-post="/test"><button id="submit" formmethod="dialog" name="foo" value="bar">Submit</button></form></dialog>')
|
|
|
|
byId('submit').click()
|
|
this.server.respond()
|
|
request.should.equal(false)
|
|
})
|
|
|
|
it('can associate submit buttons from outside a form with the current version of the form after swap', function() {
|
|
const template = '<form ' +
|
|
'id="hello" ' +
|
|
'hx-target="#hello" ' +
|
|
'hx-select="#hello" ' +
|
|
'hx-swap="outerHTML" ' +
|
|
'hx-post="/test">\n' +
|
|
'<input id="input" type="text" name="name" />\n' +
|
|
'<button name="value" type="submit">Submit</button>\n' +
|
|
'</form>\n' +
|
|
'<button id="outside" name="outside" form="hello" type="submit">Outside</button>'
|
|
|
|
var values
|
|
this.server.respondWith('/test', function(xhr) {
|
|
values = getParameters(xhr)
|
|
xhr.respond(200, {}, template)
|
|
})
|
|
make(template)
|
|
const button = byId('outside')
|
|
button.focus()
|
|
button.click()
|
|
this.server.respond()
|
|
values.should.deep.equal({ name: '', outside: '' })
|
|
button.focus()
|
|
button.click()
|
|
this.server.respond()
|
|
values.should.deep.equal({ name: '', outside: '' })
|
|
})
|
|
|
|
it('properly handles form reset behaviour with a htmx enabled reset button inside a form', function() {
|
|
var values
|
|
this.server.respondWith('POST', '/reset', function(xhr) {
|
|
values = getParameters(xhr)
|
|
xhr.respond(204, {}, '')
|
|
})
|
|
|
|
make('<form id="externalForm" hx-post="/test">' +
|
|
'<input id="t1" type="text" name="t1" value="defaultValue">' +
|
|
'<button hx-post="/reset" id="reset" type="reset" name="b1" value="buttonValue">reset</button>' +
|
|
'</form>')
|
|
byId('t1').value = 'otherValue'
|
|
byId('reset').click()
|
|
this.server.respond()
|
|
values.should.deep.equal({ b1: 'buttonValue', t1: 'otherValue' })
|
|
byId('t1').value.should.equal('defaultValue')
|
|
})
|
|
|
|
it('properly handles form reset behaviour with a htmx enabled reset button outside a form', function() {
|
|
var values
|
|
this.server.respondWith('POST', '/reset', function(xhr) {
|
|
values = getParameters(xhr)
|
|
xhr.respond(204, {}, '')
|
|
})
|
|
|
|
make('<form id="externalForm" hx-post="/test">' +
|
|
'<input id="t1" type="text" name="t1" value="defaultValue">' +
|
|
'</form>' +
|
|
'<button hx-post="/reset" id="reset" form="externalForm" type="reset" name="b1" value="buttonValue">reset</button>')
|
|
byId('t1').value = 'otherValue'
|
|
byId('reset').click()
|
|
this.server.respond()
|
|
values.should.deep.equal({ b1: 'buttonValue', t1: 'otherValue' })
|
|
byId('t1').value.should.equal('defaultValue')
|
|
})
|
|
|
|
it('script tags get swapped in with nonce applied from inlineScriptNonce', function() {
|
|
var globalWasCalled = false
|
|
window.callGlobal = function() {
|
|
globalWasCalled = true
|
|
}
|
|
htmx.config.inlineScriptNonce = 'testnonce'
|
|
try {
|
|
this.server.respondWith('GET', '/test', "<script id='noncescript'>callGlobal()</script>")
|
|
var div = make("<div hx-get='/test'></div>")
|
|
div.click()
|
|
this.server.respond()
|
|
globalWasCalled.should.equal(true)
|
|
byId('noncescript').nonce.should.equal('testnonce')
|
|
} finally {
|
|
delete window.callGlobal
|
|
htmx.config.inlineScriptNonce = ''
|
|
}
|
|
})
|
|
|
|
it('normalizeScriptTags logs error when insertBefore fails', function() {
|
|
htmx.div = make('<div><script></script></div>')
|
|
htmx.div.insertBefore = undefined
|
|
htmx._('normalizeScriptTags(htmx.div)')
|
|
delete htmx.div
|
|
})
|
|
})
|