mirror of
https://github.com/bigskysoftware/htmx.git
synced 2025-09-27 13:01:03 +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
1374 lines
44 KiB
JavaScript
1374 lines
44 KiB
JavaScript
describe('hx-trigger attribute', function() {
|
|
beforeEach(function() {
|
|
this.server = sinon.fakeServer.create()
|
|
clearWorkArea()
|
|
})
|
|
afterEach(function() {
|
|
this.server.restore()
|
|
clearWorkArea()
|
|
})
|
|
|
|
it('non-default value works', 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('changed modifier works', function() {
|
|
var requests = 0
|
|
this.server.respondWith('GET', '/test', function(xhr) {
|
|
requests++
|
|
xhr.respond(200, {}, 'Requests: ' + requests)
|
|
})
|
|
var input = make('<input hx-trigger="click changed" hx-target="#d1" hx-get="/test"/>')
|
|
var div = make('<div id="d1"></div>')
|
|
input.click()
|
|
this.server.respond()
|
|
div.innerHTML.should.equal('')
|
|
input.click()
|
|
this.server.respond()
|
|
div.innerHTML.should.equal('')
|
|
input.value = 'bar'
|
|
input.click()
|
|
this.server.respond()
|
|
div.innerHTML.should.equal('Requests: 1')
|
|
input.click()
|
|
this.server.respond()
|
|
div.innerHTML.should.equal('Requests: 1')
|
|
})
|
|
|
|
it('changed modifier works along from clause with single input', function() {
|
|
var requests = 0
|
|
this.server.respondWith('GET', '/test', function(xhr) {
|
|
requests++
|
|
xhr.respond(200, {}, 'Requests: ' + requests)
|
|
})
|
|
var input = make('<input type="text"/>')
|
|
make('<div hx-trigger="click changed from:input" hx-target="#d1" hx-get="/test"></div>')
|
|
var div = make('<div id="d1"></div>')
|
|
input.click()
|
|
this.server.respond()
|
|
div.innerHTML.should.equal('')
|
|
input.click()
|
|
this.server.respond()
|
|
div.innerHTML.should.equal('')
|
|
input.value = 'bar'
|
|
input.click()
|
|
this.server.respond()
|
|
div.innerHTML.should.equal('Requests: 1')
|
|
input.click()
|
|
this.server.respond()
|
|
div.innerHTML.should.equal('Requests: 1')
|
|
})
|
|
|
|
// This test and the next one should be kept in sync.
|
|
it('changed modifier works along from clause with two inputs', function() {
|
|
var requests = 0
|
|
this.server.respondWith('GET', '/test', function(xhr) {
|
|
requests++
|
|
xhr.respond(200, {}, 'Requests: ' + requests)
|
|
})
|
|
var input1 = make('<input type="text"/>')
|
|
var input2 = make('<input type="text"/>')
|
|
make('<div hx-trigger="click changed from:input" hx-target="#d1" hx-get="/test"></div>')
|
|
var div = make('<div id="d1"></div>')
|
|
|
|
input1.click()
|
|
this.server.respond()
|
|
div.innerHTML.should.equal('')
|
|
input2.click()
|
|
this.server.respond()
|
|
div.innerHTML.should.equal('')
|
|
|
|
input1.value = 'bar'
|
|
input2.click()
|
|
this.server.respond()
|
|
div.innerHTML.should.equal('')
|
|
input1.click()
|
|
this.server.respond()
|
|
div.innerHTML.should.equal('Requests: 1')
|
|
|
|
input1.click()
|
|
this.server.respond()
|
|
div.innerHTML.should.equal('Requests: 1')
|
|
input2.click()
|
|
this.server.respond()
|
|
div.innerHTML.should.equal('Requests: 1')
|
|
|
|
input2.value = 'foo'
|
|
input1.click()
|
|
this.server.respond()
|
|
div.innerHTML.should.equal('Requests: 1')
|
|
input2.click()
|
|
this.server.respond()
|
|
div.innerHTML.should.equal('Requests: 2')
|
|
})
|
|
|
|
// This test and the previous one should be kept in sync.
|
|
it('changed modifier counts each triggerspec separately', function() {
|
|
var requests = 0
|
|
this.server.respondWith('GET', '/test', function(xhr) {
|
|
requests++
|
|
xhr.respond(200, {}, 'Requests: ' + requests)
|
|
})
|
|
var input1 = make('<input type="text"/>')
|
|
var input2 = make('<input type="text"/>')
|
|
make('<div hx-trigger="click changed from:input" hx-target="#d1" hx-get="/test"></div>')
|
|
make('<div hx-trigger="click changed from:input" hx-target="#d1" hx-get="/test"></div>')
|
|
var div = make('<div id="d1"></div>')
|
|
|
|
input1.click()
|
|
this.server.respond()
|
|
div.innerHTML.should.equal('')
|
|
input2.click()
|
|
this.server.respond()
|
|
div.innerHTML.should.equal('')
|
|
|
|
input1.value = 'bar'
|
|
input2.click()
|
|
this.server.respond()
|
|
div.innerHTML.should.equal('')
|
|
input1.click()
|
|
this.server.respond()
|
|
div.innerHTML.should.equal('Requests: 2')
|
|
|
|
input1.click()
|
|
this.server.respond()
|
|
div.innerHTML.should.equal('Requests: 2')
|
|
input2.click()
|
|
this.server.respond()
|
|
div.innerHTML.should.equal('Requests: 2')
|
|
|
|
input2.value = 'foo'
|
|
input1.click()
|
|
this.server.respond()
|
|
div.innerHTML.should.equal('Requests: 2')
|
|
input2.click()
|
|
this.server.respond()
|
|
div.innerHTML.should.equal('Requests: 4')
|
|
})
|
|
|
|
it('separate changed modifier works along from clause with two inputs', function() {
|
|
var requests = 0
|
|
this.server.respondWith('GET', '/test', function(xhr) {
|
|
requests++
|
|
xhr.respond(200, {}, 'Requests: ' + requests)
|
|
})
|
|
var input1 = make('<input type="text"/>')
|
|
var input2 = make('<input type="text"/>')
|
|
make('<div hx-trigger="click changed from:input:nth-child(1), click changed from:input:nth-child(2)" hx-target="#d1" hx-get="/test"></div>')
|
|
var div = make('<div id="d1"></div>')
|
|
|
|
input1.click()
|
|
this.server.respond()
|
|
div.innerHTML.should.equal('')
|
|
input2.click()
|
|
this.server.respond()
|
|
div.innerHTML.should.equal('')
|
|
|
|
input1.value = 'bar'
|
|
input2.click()
|
|
this.server.respond()
|
|
div.innerHTML.should.equal('')
|
|
input1.click()
|
|
this.server.respond()
|
|
div.innerHTML.should.equal('Requests: 1')
|
|
|
|
input1.click()
|
|
this.server.respond()
|
|
div.innerHTML.should.equal('Requests: 1')
|
|
input2.click()
|
|
this.server.respond()
|
|
div.innerHTML.should.equal('Requests: 1')
|
|
|
|
input2.value = 'foo'
|
|
input1.click()
|
|
this.server.respond()
|
|
div.innerHTML.should.equal('Requests: 1')
|
|
input2.click()
|
|
this.server.respond()
|
|
div.innerHTML.should.equal('Requests: 2')
|
|
})
|
|
|
|
it('once modifier works', function() {
|
|
var requests = 0
|
|
this.server.respondWith('GET', '/test', function(xhr) {
|
|
requests++
|
|
xhr.respond(200, {}, 'Requests: ' + requests)
|
|
})
|
|
var input = make('<input hx-trigger="click once" hx-target="#d1" hx-get="/test" value="foo"/>')
|
|
var div = make('<div id="d1"></div>')
|
|
input.click()
|
|
this.server.respond()
|
|
div.innerHTML.should.equal('Requests: 1')
|
|
input.click()
|
|
this.server.respond()
|
|
div.innerHTML.should.equal('Requests: 1')
|
|
input.value = 'bar'
|
|
input.click()
|
|
this.server.respond()
|
|
div.innerHTML.should.equal('Requests: 1')
|
|
input.click()
|
|
this.server.respond()
|
|
div.innerHTML.should.equal('Requests: 1')
|
|
})
|
|
|
|
it('once modifier works with multiple triggers', function() {
|
|
var requests = 0
|
|
this.server.respondWith('GET', '/test', function(xhr) {
|
|
requests++
|
|
xhr.respond(200, {}, 'Requests: ' + requests)
|
|
})
|
|
var input = make('<input hx-trigger="click once, foo" hx-target="#d1" hx-get="/test" value="foo"/>')
|
|
var div = make('<div id="d1"></div>')
|
|
input.click()
|
|
this.server.respond()
|
|
div.innerHTML.should.equal('Requests: 1')
|
|
input.click()
|
|
this.server.respond()
|
|
div.innerHTML.should.equal('Requests: 1')
|
|
input.value = 'bar'
|
|
input.click()
|
|
this.server.respond()
|
|
div.innerHTML.should.equal('Requests: 1')
|
|
input.click()
|
|
this.server.respond()
|
|
div.innerHTML.should.equal('Requests: 1')
|
|
htmx.trigger(input, 'foo')
|
|
this.server.respond()
|
|
div.innerHTML.should.equal('Requests: 2')
|
|
})
|
|
|
|
it('polling works', function(complete) {
|
|
var requests = 0
|
|
this.server.respondWith('GET', '/test', function(xhr) {
|
|
requests++
|
|
if (requests > 5) {
|
|
complete()
|
|
// cancel polling with a
|
|
xhr.respond(286, {}, 'Requests: ' + requests)
|
|
} else {
|
|
xhr.respond(200, {}, 'Requests: ' + requests)
|
|
}
|
|
})
|
|
this.server.autoRespond = true
|
|
this.server.autoRespondAfter = 0
|
|
make('<div hx-trigger="every 10ms" hx-get="/test"/>')
|
|
})
|
|
|
|
it('non-default value works w/ data-* prefix', function() {
|
|
this.server.respondWith('GET', '/test', 'Clicked!')
|
|
var form = make('<form data-hx-get="/test" data-hx-trigger="click">Click Me!</form>')
|
|
form.click()
|
|
form.innerHTML.should.equal('Click Me!')
|
|
this.server.respond()
|
|
form.innerHTML.should.equal('Clicked!')
|
|
})
|
|
|
|
it('works with multiple events', function() {
|
|
var requests = 0
|
|
this.server.respondWith('GET', '/test', function(xhr) {
|
|
requests++
|
|
xhr.respond(200, {}, 'Requests: ' + requests)
|
|
})
|
|
var div = make('<div hx-trigger="load,click" hx-get="/test">Requests: 0</div>')
|
|
div.innerHTML.should.equal('Requests: 0')
|
|
this.server.respond()
|
|
div.innerHTML.should.equal('Requests: 1')
|
|
div.click()
|
|
this.server.respond()
|
|
div.innerHTML.should.equal('Requests: 2')
|
|
})
|
|
|
|
it('parses spec strings', function() {
|
|
var specExamples = {
|
|
'': [{ trigger: 'click' }],
|
|
'every 1s': [{ trigger: 'every', pollInterval: 1000 }],
|
|
'every 0s': [{ trigger: 'every', pollInterval: 0 }],
|
|
'every 0ms': [{ trigger: 'every', pollInterval: 0 }],
|
|
click: [{ trigger: 'click' }],
|
|
customEvent: [{ trigger: 'customEvent' }],
|
|
'event changed': [{ trigger: 'event', changed: true }],
|
|
'event once': [{ trigger: 'event', once: true }],
|
|
'event throttle:1s': [{ trigger: 'event', throttle: 1000 }],
|
|
'event throttle:0s': [{ trigger: 'event', throttle: 0 }],
|
|
'event throttle:0ms': [{ trigger: 'event', throttle: 0 }],
|
|
'event throttle:1s, foo': [{ trigger: 'event', throttle: 1000 }, { trigger: 'foo' }],
|
|
'event delay:1s': [{ trigger: 'event', delay: 1000 }],
|
|
'event delay:1s, foo': [{ trigger: 'event', delay: 1000 }, { trigger: 'foo' }],
|
|
'event delay:0s, foo': [{ trigger: 'event', delay: 0 }, { trigger: 'foo' }],
|
|
'event delay:0ms, foo': [{ trigger: 'event', delay: 0 }, { trigger: 'foo' }],
|
|
'event changed once delay:1s': [{ trigger: 'event', changed: true, once: true, delay: 1000 }],
|
|
'event1,event2': [{ trigger: 'event1' }, { trigger: 'event2' }],
|
|
'event1, event2': [{ trigger: 'event1' }, { trigger: 'event2' }],
|
|
'event1 once, event2 changed': [{ trigger: 'event1', once: true }, { trigger: 'event2', changed: true }],
|
|
'event1,': [{ trigger: 'event1' }],
|
|
' ': [{ trigger: 'click' }]
|
|
}
|
|
|
|
for (var specString in specExamples) {
|
|
var div = make("<div hx-trigger='" + specString + "'></div>")
|
|
var spec = htmx._('getTriggerSpecs')(div)
|
|
spec.should.deep.equal(specExamples[specString], 'Found : ' + JSON.stringify(spec) + ', expected : ' + JSON.stringify(specExamples[specString]) + ' for spec: ' + specString)
|
|
}
|
|
})
|
|
|
|
it('sets default trigger for forms', function() {
|
|
var form = make('<form></form>')
|
|
var spec = htmx._('getTriggerSpecs')(form)
|
|
spec.should.deep.equal([{ trigger: 'submit' }])
|
|
})
|
|
|
|
it('sets default trigger for form elements', function() {
|
|
var form = make('<input></input>')
|
|
var spec = htmx._('getTriggerSpecs')(form)
|
|
spec.should.deep.equal([{ trigger: 'change' }])
|
|
})
|
|
|
|
it('filters properly with false filter spec', function() {
|
|
this.server.respondWith('GET', '/test', 'Called!')
|
|
var form = make('<form hx-get="/test" hx-trigger="evt[foo]">Not Called</form>')
|
|
form.click()
|
|
form.innerHTML.should.equal('Not Called')
|
|
var event = htmx._('makeEvent')('evt')
|
|
form.dispatchEvent(event)
|
|
this.server.respond()
|
|
form.innerHTML.should.equal('Not Called')
|
|
})
|
|
|
|
it('filters properly with true filter spec', function() {
|
|
this.server.respondWith('GET', '/test', 'Called!')
|
|
var form = make('<form hx-get="/test" hx-trigger="evt[foo]">Not Called</form>')
|
|
form.click()
|
|
form.innerHTML.should.equal('Not Called')
|
|
var event = htmx._('makeEvent')('evt')
|
|
event.foo = true
|
|
form.dispatchEvent(event)
|
|
this.server.respond()
|
|
form.innerHTML.should.equal('Called!')
|
|
})
|
|
|
|
it('filters properly compound filter spec', function() {
|
|
this.server.respondWith('GET', '/test', 'Called!')
|
|
var div = make('<div hx-get="/test" hx-trigger="evt[foo&&bar]">Not Called</div>')
|
|
var event = htmx._('makeEvent')('evt')
|
|
event.foo = true
|
|
div.dispatchEvent(event)
|
|
this.server.respond()
|
|
div.innerHTML.should.equal('Not Called')
|
|
event.bar = true
|
|
div.dispatchEvent(event)
|
|
this.server.respond()
|
|
div.innerHTML.should.equal('Called!')
|
|
})
|
|
|
|
it('can refer to target element in condition', function() {
|
|
this.server.respondWith('GET', '/test', 'Called!')
|
|
var div = make('<div hx-get="/test" hx-trigger="evt[target.classList.contains(\'doIt\')]">Not Called</div>')
|
|
var event = htmx._('makeEvent')('evt')
|
|
div.dispatchEvent(event)
|
|
this.server.respond()
|
|
div.innerHTML.should.equal('Not Called')
|
|
div.classList.add('doIt')
|
|
div.dispatchEvent(event)
|
|
this.server.respond()
|
|
div.innerHTML.should.equal('Called!')
|
|
})
|
|
|
|
it('can refer to target element in condition w/ equality', function() {
|
|
this.server.respondWith('GET', '/test', 'Called!')
|
|
var div = make('<div hx-get="/test" hx-trigger="evt[target.id==\'foo\']">Not Called</div>')
|
|
var event = htmx._('makeEvent')('evt')
|
|
div.dispatchEvent(event)
|
|
this.server.respond()
|
|
div.innerHTML.should.equal('Not Called')
|
|
div.id = 'foo'
|
|
div.dispatchEvent(event)
|
|
this.server.respond()
|
|
div.innerHTML.should.equal('Called!')
|
|
})
|
|
|
|
it('negative condition', function() {
|
|
this.server.respondWith('GET', '/test', 'Called!')
|
|
var div = make('<div hx-get="/test" hx-trigger="evt[!target.classList.contains(\'disabled\')]">Not Called</div>')
|
|
div.classList.add('disabled')
|
|
var event = htmx._('makeEvent')('evt')
|
|
div.dispatchEvent(event)
|
|
this.server.respond()
|
|
div.innerHTML.should.equal('Not Called')
|
|
div.classList.remove('disabled')
|
|
div.dispatchEvent(event)
|
|
this.server.respond()
|
|
div.innerHTML.should.equal('Called!')
|
|
})
|
|
|
|
it('global function call works', function() {
|
|
window.globalFun = function(evt) {
|
|
return evt.bar
|
|
}
|
|
try {
|
|
this.server.respondWith('GET', '/test', 'Called!')
|
|
var div = make('<div hx-get="/test" hx-trigger="evt[globalFun(event)]">Not Called</div>')
|
|
var event = htmx._('makeEvent')('evt')
|
|
event.bar = false
|
|
div.dispatchEvent(event)
|
|
this.server.respond()
|
|
div.innerHTML.should.equal('Not Called')
|
|
event.bar = true
|
|
div.dispatchEvent(event)
|
|
this.server.respond()
|
|
div.innerHTML.should.equal('Called!')
|
|
} finally {
|
|
delete window.globalFun
|
|
}
|
|
})
|
|
|
|
it('global property event filter works', function() {
|
|
window.foo = {
|
|
bar: false
|
|
}
|
|
try {
|
|
this.server.respondWith('GET', '/test', 'Called!')
|
|
var div = make('<div hx-get="/test" hx-trigger="evt[foo.bar]">Not Called</div>')
|
|
var event = htmx._('makeEvent')('evt')
|
|
div.dispatchEvent(event)
|
|
this.server.respond()
|
|
div.innerHTML.should.equal('Not Called')
|
|
foo.bar = true
|
|
div.dispatchEvent(event)
|
|
this.server.respond()
|
|
div.innerHTML.should.equal('Called!')
|
|
} finally {
|
|
delete window.foo
|
|
}
|
|
})
|
|
|
|
it('global variable filter works', function() {
|
|
try {
|
|
this.server.respondWith('GET', '/test', 'Called!')
|
|
var div = make('<div hx-get="/test" hx-trigger="evt[foo]">Not Called</div>')
|
|
var event = htmx._('makeEvent')('evt')
|
|
div.dispatchEvent(event)
|
|
this.server.respond()
|
|
div.innerHTML.should.equal('Not Called')
|
|
window.foo = true
|
|
div.dispatchEvent(event)
|
|
this.server.respond()
|
|
div.innerHTML.should.equal('Called!')
|
|
} finally {
|
|
delete window.foo
|
|
}
|
|
})
|
|
|
|
it('can filter polling', function(complete) {
|
|
this.server.respondWith('GET', '/test', 'Called!')
|
|
window.foo = false
|
|
var div = make('<div hx-get="/test" hx-trigger="every 5ms[foo]">Not Called</div>')
|
|
var div2 = make('<div hx-get="/test" hx-trigger="every 5ms">Not Called</div>')
|
|
this.server.autoRespond = true
|
|
this.server.autoRespondAfter = 0
|
|
setTimeout(function() {
|
|
div.innerHTML.should.equal('Not Called')
|
|
div2.innerHTML.should.equal('Called!')
|
|
delete window.foo
|
|
complete()
|
|
}, 100)
|
|
})
|
|
|
|
it('bad condition issues error', function() {
|
|
this.server.respondWith('GET', '/test', 'Called!')
|
|
var div = make('<div hx-get="/test" hx-trigger="evt[a.b]">Not Called</div>')
|
|
var errorEvent = null
|
|
var handler = htmx.on('htmx:eventFilter:error', function(event) {
|
|
errorEvent = event
|
|
})
|
|
try {
|
|
var event = htmx._('makeEvent')('evt')
|
|
div.dispatchEvent(event)
|
|
should.not.equal(null, errorEvent)
|
|
should.not.equal(null, errorEvent.detail.source)
|
|
console.log(errorEvent.detail.source)
|
|
} finally {
|
|
htmx.off('htmx:eventFilter:error', handler)
|
|
}
|
|
})
|
|
|
|
it('filters properly with true for empty condition', function() {
|
|
this.server.respondWith('GET', '/test', 'Called!')
|
|
var form = make('<form hx-get="/test" hx-trigger="evt[]">Not Called</form>')
|
|
form.click()
|
|
form.innerHTML.should.equal('Not Called')
|
|
var event = htmx._('makeEvent')('evt')
|
|
form.dispatchEvent(event)
|
|
this.server.respond()
|
|
form.innerHTML.should.equal('Called!')
|
|
})
|
|
|
|
it('syntax error in condition issues error', function() {
|
|
this.server.respondWith('GET', '/test', 'Called!')
|
|
var errorEvent = null
|
|
var handler = htmx.on('htmx:syntax:error', function(event) {
|
|
errorEvent = event
|
|
})
|
|
var form = make('<form hx-get="/test" hx-trigger="evt[{]">Not Called</form>')
|
|
try {
|
|
var event = htmx._('makeEvent')('evt')
|
|
form.dispatchEvent(event)
|
|
should.not.equal(null, errorEvent)
|
|
should.not.equal(null, errorEvent.detail.source)
|
|
console.log(errorEvent.detail.source)
|
|
} finally {
|
|
htmx.off('htmx:syntax:error', handler)
|
|
}
|
|
})
|
|
|
|
it('filters properly with condition containing square backets', function() {
|
|
this.server.respondWith('GET', '/test', 'Called!')
|
|
var form = make('<form hx-get="/test" hx-trigger="evt[foo[0]]">Not Called</form>')
|
|
form.click()
|
|
form.innerHTML.should.equal('Not Called')
|
|
var event = htmx._('makeEvent')('evt')
|
|
event.foo = [true]
|
|
form.dispatchEvent(event)
|
|
this.server.respond()
|
|
form.innerHTML.should.equal('Called!')
|
|
})
|
|
|
|
it('from clause works', function() {
|
|
var requests = 0
|
|
this.server.respondWith('GET', '/test', function(xhr) {
|
|
requests++
|
|
xhr.respond(200, {}, 'Requests: ' + requests)
|
|
})
|
|
var div2 = make('<div id="d2"></div>')
|
|
var div1 = make('<div hx-trigger="click from:#d2" hx-get="/test">Requests: 0</div>')
|
|
div1.innerHTML.should.equal('Requests: 0')
|
|
div1.click()
|
|
this.server.respond()
|
|
div1.innerHTML.should.equal('Requests: 0')
|
|
div2.click()
|
|
this.server.respond()
|
|
div1.innerHTML.should.equal('Requests: 1')
|
|
})
|
|
|
|
it('from clause works with body selector', function() {
|
|
var requests = 0
|
|
this.server.respondWith('GET', '/test', function(xhr) {
|
|
requests++
|
|
xhr.respond(200, {}, 'Requests: ' + requests)
|
|
})
|
|
var div1 = make('<div hx-trigger="click from:body" hx-get="/test">Requests: 0</div>')
|
|
div1.innerHTML.should.equal('Requests: 0')
|
|
document.body.click()
|
|
this.server.respond()
|
|
div1.innerHTML.should.equal('Requests: 1')
|
|
})
|
|
|
|
it('from clause works with document selector', function() {
|
|
var requests = 0
|
|
this.server.respondWith('GET', '/test', function(xhr) {
|
|
requests++
|
|
xhr.respond(200, {}, 'Requests: ' + requests)
|
|
})
|
|
var div1 = make('<div hx-trigger="foo from:document" hx-get="/test">Requests: 0</div>')
|
|
div1.innerHTML.should.equal('Requests: 0')
|
|
htmx.trigger(document, 'foo')
|
|
this.server.respond()
|
|
div1.innerHTML.should.equal('Requests: 1')
|
|
})
|
|
|
|
it('from clause works with window selector', function() {
|
|
var requests = 0
|
|
this.server.respondWith('GET', '/test', function(xhr) {
|
|
requests++
|
|
xhr.respond(200, {}, 'Requests: ' + requests)
|
|
})
|
|
var div1 = make('<div hx-trigger="foo from:window" hx-get="/test">Requests: 0</div>')
|
|
div1.innerHTML.should.equal('Requests: 0')
|
|
htmx.trigger(window, 'foo')
|
|
this.server.respond()
|
|
div1.innerHTML.should.equal('Requests: 1')
|
|
})
|
|
|
|
it('from clause works with closest clause', function() {
|
|
var requests = 0
|
|
this.server.respondWith('GET', '/test', function(xhr) {
|
|
requests++
|
|
xhr.respond(200, {}, 'Requests: ' + requests)
|
|
})
|
|
var div1 = make('<div><a id="a1" hx-trigger="click from:closest div" hx-get="/test">Requests: 0</a></div>')
|
|
var a1 = byId('a1')
|
|
a1.innerHTML.should.equal('Requests: 0')
|
|
div1.click()
|
|
this.server.respond()
|
|
a1.innerHTML.should.equal('Requests: 1')
|
|
})
|
|
|
|
it('from clause works with find clause', function() {
|
|
var requests = 0
|
|
this.server.respondWith('GET', '/test', function(xhr) {
|
|
requests++
|
|
xhr.respond(200, {}, 'Requests: ' + requests)
|
|
})
|
|
var div1 = make('<div hx-trigger="click from:find a" hx-target="#a1" hx-get="/test"><a id="a1">Requests: 0</a></div>')
|
|
var a1 = byId('a1')
|
|
a1.innerHTML.should.equal('Requests: 0')
|
|
a1.click()
|
|
this.server.respond()
|
|
a1.innerHTML.should.equal('Requests: 1')
|
|
})
|
|
|
|
it('from clause works with next', function() {
|
|
var requests = 0
|
|
this.server.respondWith('GET', '/test', function(xhr) {
|
|
requests++
|
|
xhr.respond(200, {}, 'Requests: ' + requests)
|
|
})
|
|
make('<div hx-trigger="click from:next" hx-target="#a1" hx-get="/test"></div><a id="a1">Requests: 0</a>')
|
|
var a1 = byId('a1')
|
|
a1.innerHTML.should.equal('Requests: 0')
|
|
a1.click()
|
|
this.server.respond()
|
|
a1.innerHTML.should.equal('Requests: 1')
|
|
})
|
|
|
|
it('from clause works with previous', function() {
|
|
var requests = 0
|
|
this.server.respondWith('GET', '/test', function(xhr) {
|
|
requests++
|
|
xhr.respond(200, {}, 'Requests: ' + requests)
|
|
})
|
|
make('<a id="a1">Requests: 0</a><div hx-trigger="click from:previous" hx-target="#a1" hx-get="/test"></div>')
|
|
var a1 = byId('a1')
|
|
a1.innerHTML.should.equal('Requests: 0')
|
|
a1.click()
|
|
this.server.respond()
|
|
a1.innerHTML.should.equal('Requests: 1')
|
|
})
|
|
|
|
it('event listeners on other elements are removed when an element is swapped out', function() {
|
|
var requests = 0
|
|
this.server.respondWith('GET', '/test', function(xhr) {
|
|
requests++
|
|
xhr.respond(200, {}, 'Requests: ' + requests)
|
|
})
|
|
this.server.respondWith('GET', '/test2', 'Clicked')
|
|
|
|
var div1 = make('<div hx-get="/test2">' +
|
|
'<div id="d2" hx-trigger="click from:body" hx-get="/test">Requests: 0</div>' +
|
|
'</div>')
|
|
var div2 = byId('d2')
|
|
|
|
div2.innerHTML.should.equal('Requests: 0')
|
|
document.body.click()
|
|
this.server.respond()
|
|
requests.should.equal(1)
|
|
|
|
requests.should.equal(1)
|
|
|
|
div1.click()
|
|
this.server.respond()
|
|
div1.innerHTML.should.equal('Clicked')
|
|
|
|
requests.should.equal(2)
|
|
|
|
document.body.click()
|
|
this.server.respond()
|
|
|
|
requests.should.equal(2)
|
|
})
|
|
|
|
it('multiple triggers with from clauses mixed in work', function() {
|
|
var requests = 0
|
|
this.server.respondWith('GET', '/test', function(xhr) {
|
|
requests++
|
|
xhr.respond(200, {}, 'Requests: ' + requests)
|
|
})
|
|
var div2 = make('<div id="d2"></div>')
|
|
var div1 = make('<div hx-trigger="click from:#d2, click" hx-get="/test">Requests: 0</div>')
|
|
div1.innerHTML.should.equal('Requests: 0')
|
|
div1.click()
|
|
this.server.respond()
|
|
div1.innerHTML.should.equal('Requests: 1')
|
|
div2.click()
|
|
this.server.respond()
|
|
div1.innerHTML.should.equal('Requests: 2')
|
|
})
|
|
|
|
it('from clause works with multiple extended selectors', function() {
|
|
var requests = 0
|
|
this.server.respondWith('GET', '/test', function(xhr) {
|
|
requests++
|
|
xhr.respond(200, {}, 'Requests: ' + requests)
|
|
})
|
|
make('<button id="btn" type="button">Click me</button>' +
|
|
'<div hx-trigger="click from:(previous button, next a)" hx-target="#a1" hx-get="/test"></div>' +
|
|
'<a id="a1">Requests: 0</a>')
|
|
var btn = byId('btn')
|
|
var a1 = byId('a1')
|
|
a1.innerHTML.should.equal('Requests: 0')
|
|
btn.click()
|
|
this.server.respond()
|
|
a1.innerHTML.should.equal('Requests: 1')
|
|
a1.click()
|
|
this.server.respond()
|
|
a1.innerHTML.should.equal('Requests: 2')
|
|
})
|
|
|
|
it('event listeners can filter on target', function() {
|
|
var requests = 0
|
|
this.server.respondWith('GET', '/test', function(xhr) {
|
|
requests++
|
|
xhr.respond(200, {}, 'Requests: ' + requests)
|
|
})
|
|
|
|
var div1 = make('<div>' +
|
|
'<div id="d1" hx-trigger="click from:body target:#d3" hx-get="/test">Requests: 0</div>' +
|
|
'<div id="d2"></div>' +
|
|
'<div id="d3"></div>' +
|
|
'</div>')
|
|
var div1 = byId('d1')
|
|
var div2 = byId('d2')
|
|
var div3 = byId('d3')
|
|
|
|
div1.innerHTML.should.equal('Requests: 0')
|
|
document.body.click()
|
|
this.server.respond()
|
|
requests.should.equal(0)
|
|
|
|
div1.click()
|
|
this.server.respond()
|
|
requests.should.equal(0)
|
|
|
|
div2.click()
|
|
this.server.respond()
|
|
requests.should.equal(0)
|
|
|
|
div3.click()
|
|
this.server.respond()
|
|
requests.should.equal(1)
|
|
})
|
|
|
|
it('consume prevents event propagation', function() {
|
|
this.server.respondWith('GET', '/foo', 'foo')
|
|
this.server.respondWith('GET', '/bar', 'bar')
|
|
var div = make("<div hx-trigger='click' hx-get='/foo'>" +
|
|
" <div id='d1' hx-trigger='click consume' hx-get='/bar'></div>" +
|
|
'</div>')
|
|
|
|
byId('d1').click()
|
|
this.server.respond()
|
|
|
|
// should not have been replaced by click
|
|
byId('d1').parentElement.should.equal(div)
|
|
byId('d1').innerText.should.equal('bar')
|
|
})
|
|
|
|
it('throttle prevents multiple requests from happening', function(done) {
|
|
var requests = 0
|
|
var server = this.server
|
|
server.respondWith('GET', '/test', function(xhr) {
|
|
requests++
|
|
xhr.respond(200, {}, 'Requests: ' + requests)
|
|
})
|
|
server.respondWith('GET', '/bar', 'bar')
|
|
var div = make("<div hx-trigger='click throttle:10ms' hx-get='/test'></div>")
|
|
|
|
div.click()
|
|
server.respond()
|
|
|
|
div.click()
|
|
server.respond()
|
|
|
|
div.click()
|
|
server.respond()
|
|
|
|
div.click()
|
|
server.respond()
|
|
|
|
// should not have been replaced by click
|
|
div.innerText.should.equal('Requests: 1')
|
|
|
|
setTimeout(function() {
|
|
div.click()
|
|
server.respond()
|
|
div.innerText.should.equal('Requests: 2')
|
|
|
|
div.click()
|
|
server.respond()
|
|
div.innerText.should.equal('Requests: 2')
|
|
|
|
done()
|
|
}, 50)
|
|
})
|
|
|
|
it('A throttle of 0 does not prevent multiple requests from happening', function(done) {
|
|
var requests = 0
|
|
var server = this.server
|
|
server.respondWith('GET', '/test', function(xhr) {
|
|
requests++
|
|
xhr.respond(200, {}, 'Requests: ' + requests)
|
|
})
|
|
server.respondWith('GET', '/bar', 'bar')
|
|
var div = make(
|
|
"<div hx-trigger='click throttle:0ms' hx-get='/test'></div>"
|
|
)
|
|
|
|
div.click()
|
|
server.respond()
|
|
div.innerText.should.equal('Requests: 1')
|
|
|
|
div.click()
|
|
server.respond()
|
|
div.innerText.should.equal('Requests: 2')
|
|
|
|
div.click()
|
|
server.respond()
|
|
div.innerText.should.equal('Requests: 3')
|
|
|
|
div.click()
|
|
server.respond()
|
|
div.innerText.should.equal('Requests: 4')
|
|
|
|
done()
|
|
})
|
|
|
|
it('delay delays the request', function(done) {
|
|
var requests = 0
|
|
var server = this.server
|
|
this.server.respondWith('GET', '/test', function(xhr) {
|
|
requests++
|
|
xhr.respond(200, {}, 'Requests: ' + requests)
|
|
})
|
|
this.server.respondWith('GET', '/bar', 'bar')
|
|
var div = make("<div hx-trigger='click delay:10ms' hx-get='/test'></div>")
|
|
|
|
div.click()
|
|
this.server.respond()
|
|
|
|
div.click()
|
|
this.server.respond()
|
|
|
|
div.click()
|
|
this.server.respond()
|
|
|
|
div.click()
|
|
this.server.respond()
|
|
div.innerText.should.equal('')
|
|
|
|
setTimeout(function() {
|
|
server.respond()
|
|
div.innerText.should.equal('Requests: 1')
|
|
|
|
div.click()
|
|
server.respond()
|
|
div.innerText.should.equal('Requests: 1')
|
|
|
|
done()
|
|
}, 50)
|
|
})
|
|
|
|
it('A 0 delay does not delay the request', function(done) {
|
|
var requests = 0
|
|
this.server.respondWith('GET', '/test', function(xhr) {
|
|
requests++
|
|
xhr.respond(200, {}, 'Requests: ' + requests)
|
|
})
|
|
this.server.respondWith('GET', '/bar', 'bar')
|
|
var div = make(
|
|
"<div hx-trigger='click delay:0ms' hx-get='/test'></div>"
|
|
)
|
|
|
|
div.click()
|
|
this.server.respond()
|
|
div.innerText.should.equal('Requests: 1')
|
|
|
|
div.click()
|
|
this.server.respond()
|
|
div.innerText.should.equal('Requests: 2')
|
|
|
|
div.click()
|
|
this.server.respond()
|
|
div.innerText.should.equal('Requests: 3')
|
|
|
|
div.click()
|
|
this.server.respond()
|
|
div.innerText.should.equal('Requests: 4')
|
|
|
|
done()
|
|
})
|
|
|
|
it('requests are queued with last one winning by default', function() {
|
|
var requests = 0
|
|
var server = this.server
|
|
this.server.respondWith('GET', '/test', function(xhr) {
|
|
requests++
|
|
xhr.respond(200, {}, 'Requests: ' + requests)
|
|
})
|
|
this.server.respondWith('GET', '/bar', 'bar')
|
|
var div = make("<div hx-trigger='click' hx-get='/test'></div>")
|
|
|
|
div.click()
|
|
div.click()
|
|
div.click()
|
|
this.server.respond()
|
|
div.innerText.should.equal('Requests: 1')
|
|
|
|
this.server.respond()
|
|
div.innerText.should.equal('Requests: 2')
|
|
|
|
this.server.respond()
|
|
div.innerText.should.equal('Requests: 2')
|
|
})
|
|
|
|
it('queue:all queues all requests', function() {
|
|
var requests = 0
|
|
var server = this.server
|
|
this.server.respondWith('GET', '/test', function(xhr) {
|
|
requests++
|
|
xhr.respond(200, {}, 'Requests: ' + requests)
|
|
})
|
|
this.server.respondWith('GET', '/bar', 'bar')
|
|
var div = make("<div hx-trigger='click queue:all' hx-get='/test'></div>")
|
|
|
|
div.click()
|
|
div.click()
|
|
div.click()
|
|
this.server.respond()
|
|
div.innerText.should.equal('Requests: 1')
|
|
|
|
this.server.respond()
|
|
div.innerText.should.equal('Requests: 2')
|
|
|
|
this.server.respond()
|
|
div.innerText.should.equal('Requests: 3')
|
|
})
|
|
|
|
it('queue:first queues first request', function() {
|
|
var requests = 0
|
|
var server = this.server
|
|
this.server.respondWith('GET', '/test', function(xhr) {
|
|
requests++
|
|
xhr.respond(200, {}, 'Requests: ' + requests)
|
|
})
|
|
this.server.respondWith('GET', '/bar', 'bar')
|
|
var div = make("<div hx-trigger='click queue:first' hx-get='/test'></div>")
|
|
|
|
div.click()
|
|
div.click()
|
|
div.click()
|
|
this.server.respond()
|
|
div.innerText.should.equal('Requests: 1')
|
|
|
|
this.server.respond()
|
|
div.innerText.should.equal('Requests: 2')
|
|
|
|
this.server.respond()
|
|
div.innerText.should.equal('Requests: 2')
|
|
})
|
|
|
|
it('queue:none queues no requests', function() {
|
|
var requests = 0
|
|
var server = this.server
|
|
this.server.respondWith('GET', '/test', function(xhr) {
|
|
requests++
|
|
xhr.respond(200, {}, 'Requests: ' + requests)
|
|
})
|
|
this.server.respondWith('GET', '/bar', 'bar')
|
|
var div = make("<div hx-trigger='click queue:none' hx-get='/test'></div>")
|
|
|
|
div.click()
|
|
div.click()
|
|
div.click()
|
|
this.server.respond()
|
|
div.innerText.should.equal('Requests: 1')
|
|
|
|
this.server.respond()
|
|
div.innerText.should.equal('Requests: 1')
|
|
|
|
this.server.respond()
|
|
div.innerText.should.equal('Requests: 1')
|
|
})
|
|
|
|
it('load event works w/ positive filters', function() {
|
|
this.server.respondWith('GET', '/test', 'Loaded!')
|
|
var div = make('<div hx-get="/test" hx-trigger="load[true]">Load Me!</div>')
|
|
div.innerHTML.should.equal('Load Me!')
|
|
this.server.respond()
|
|
div.innerHTML.should.equal('Loaded!')
|
|
})
|
|
|
|
it('load event works w/ negative filters', function() {
|
|
this.server.respondWith('GET', '/test', 'Loaded!')
|
|
var div = make('<div hx-get="/test" hx-trigger="load[false]">Load Me!</div>')
|
|
div.innerHTML.should.equal('Load Me!')
|
|
this.server.respond()
|
|
div.innerHTML.should.equal('Load Me!')
|
|
})
|
|
|
|
it('reveal event works on two elements', function() {
|
|
this.server.respondWith('GET', '/test1', 'test 1')
|
|
this.server.respondWith('GET', '/test2', 'test 2')
|
|
var div = make('<div hx-get="/test1" hx-trigger="revealed"></div>')
|
|
var div2 = make('<div hx-get="/test2" hx-trigger="revealed"></div>')
|
|
div.innerHTML.should.equal('')
|
|
div2.innerHTML.should.equal('')
|
|
htmx.trigger(div, 'revealed')
|
|
htmx.trigger(div2, 'revealed')
|
|
this.server.respondAll()
|
|
div.innerHTML.should.equal('test 1')
|
|
div2.innerHTML.should.equal('test 2')
|
|
})
|
|
|
|
it('scrolling triggers revealed event', function(done) {
|
|
this.server.respondWith('GET', '/test', 'test')
|
|
this.server.autoRespond = true
|
|
this.server.autoRespondAfter = 0
|
|
var div = make('<div hx-get="/test" hx-trigger="revealed"></div>')
|
|
div.innerHTML.should.equal('')
|
|
div.scrollIntoView({ block: 'end', behavior: htmx.config.scrollBehavior })
|
|
htmx.trigger(document.body, 'scroll')
|
|
|
|
setTimeout(function() {
|
|
div.innerHTML.should.equal('test')
|
|
done()
|
|
}, 250)
|
|
})
|
|
|
|
if (window.__playwright__binding__) {
|
|
it('scrolling triggers intersect event', function(done) {
|
|
// test only works reliably with playwright
|
|
this.server.respondWith('GET', '/test', 'test')
|
|
this.server.autoRespond = true
|
|
this.server.autoRespondAfter = 0
|
|
var div = make('<div hx-get="/test" hx-trigger="intersect"></div>')
|
|
div.innerHTML.should.equal('')
|
|
div.scrollIntoView({ block: 'end', behavior: htmx.config.scrollBehavior })
|
|
htmx.trigger(document.body, 'scroll')
|
|
|
|
setTimeout(function() {
|
|
div.innerHTML.should.equal('test')
|
|
done()
|
|
}, 250)
|
|
})
|
|
}
|
|
|
|
it('triggering revealed while component not yet inited still works', function(done) {
|
|
this.server.respondWith('GET', '/test', 'test')
|
|
var div = make('<div hx-get="/test" hx-trigger="revealed"></div>')
|
|
var data = div['htmx-internal-data']
|
|
delete data.initHash // simulate not inited or revealed yet
|
|
div.removeAttribute('data-hx-revealed')
|
|
var server1 = this.server
|
|
div.innerHTML.should.equal('')
|
|
div.scrollIntoView({ block: 'end', behavior: htmx.config.scrollBehavior })
|
|
htmx.trigger(document.body, 'scroll')
|
|
setTimeout(function() {
|
|
server1.autoRespond = true
|
|
server1.autoRespondAfter = 0
|
|
htmx.process(div) // processing the div should also trigger revealed event now
|
|
setTimeout(function() {
|
|
div.innerHTML.should.equal('test')
|
|
done()
|
|
}, 10)
|
|
}, 250)
|
|
})
|
|
|
|
it('reveal event works when triggered by window', function() {
|
|
this.server.respondWith('GET', '/test1', 'test 1')
|
|
var div = make('<div hx-get="/test1" hx-trigger="revealed" style="position: fixed; top: 1px; left: 1px; border: 3px solid red">foo</div>')
|
|
div.innerHTML.should.equal('foo')
|
|
this.server.respondAll()
|
|
div.innerHTML.should.equal('test 1')
|
|
})
|
|
|
|
it('revealed can be paired w/ other events', function() {
|
|
var requests = 0
|
|
this.server.respondWith('GET', '/test', function(xhr) {
|
|
requests++
|
|
xhr.respond(200, {}, 'Requests: ' + requests)
|
|
})
|
|
var div = make('<div hx-get="/test" hx-trigger="revealed, click" style="position: fixed; top: 1px; left: 1px; border: 3px solid red">foo</div>')
|
|
div.innerHTML.should.equal('foo')
|
|
this.server.respond()
|
|
div.innerHTML.should.equal('Requests: 1')
|
|
div.click()
|
|
this.server.respond()
|
|
div.innerHTML.should.equal('Requests: 2')
|
|
})
|
|
|
|
it('revealed doesnt cause other events to trigger', function() {
|
|
var requests = 0
|
|
this.server.respondWith('GET', '/test', function(xhr) {
|
|
requests++
|
|
xhr.respond(200, {}, 'Requests: ' + requests)
|
|
})
|
|
var div = make('<div hx-get="/test" hx-trigger="revealedToTheWorld" style="position: fixed; top: 1px; left: 1px; border: 3px solid red">foo</div>')
|
|
div.innerHTML.should.equal('foo')
|
|
this.server.respondAll()
|
|
div.innerHTML.should.equal('foo')
|
|
})
|
|
|
|
it('fires the htmx:trigger event when an AJAX attribute is specified', function() {
|
|
var param = 'foo'
|
|
var handler = htmx.on('htmx:trigger', function(evt) {
|
|
param = 'bar'
|
|
})
|
|
try {
|
|
this.server.respondWith('GET', '/test1', 'test 1')
|
|
var div = make('<button hx-get="/test1">Submit</button>')
|
|
div.click()
|
|
should.equal(param, 'bar')
|
|
} finally {
|
|
htmx.off('htmx:trigger', handler)
|
|
}
|
|
})
|
|
|
|
it('fires the htmx:trigger event when no AJAX attribute is specified', function() {
|
|
var param = 'foo'
|
|
var handler = htmx.on('htmx:trigger', function(evt) {
|
|
param = 'bar'
|
|
})
|
|
try {
|
|
var div = make('<button hx-trigger="click">Submit</button>')
|
|
div.click()
|
|
should.equal(param, 'bar')
|
|
} finally {
|
|
htmx.off('htmx:trigger', handler)
|
|
}
|
|
})
|
|
|
|
it('fires the htmx:trigger event for delayed triggers', function(done) {
|
|
var param = 'foo'
|
|
var handler = htmx.on('htmx:trigger', function(evt) {
|
|
param = 'bar'
|
|
})
|
|
var div = make('<button hx-trigger="click delay:10ms">Submit</button>')
|
|
div.click()
|
|
setTimeout(function() {
|
|
try {
|
|
should.equal(param, 'bar')
|
|
done()
|
|
} finally {
|
|
htmx.off('htmx:trigger', handler)
|
|
}
|
|
}, 50)
|
|
})
|
|
|
|
it('fires the htmx:trigger event when the trigger is a load', function(done) {
|
|
this.server.respondWith(
|
|
'GET',
|
|
'/test',
|
|
'<div hx-trigger="load delay:50ms" hx-on::trigger="this.innerText = \'Done\'">Response</div>'
|
|
)
|
|
|
|
var div = make('<div hx-get="/test">Submit</div>')
|
|
div.click()
|
|
this.server.respond()
|
|
var response = div.children[0]
|
|
response.innerText.should.equal('Response')
|
|
|
|
setTimeout(function() {
|
|
try {
|
|
response.innerText.should.equal('Done')
|
|
done()
|
|
} finally {
|
|
}
|
|
}, 100)
|
|
})
|
|
|
|
it('filters support "this" reference to the current element', function() {
|
|
this.server.respondWith('GET', '/test', 'Called!')
|
|
var form = make('<form hx-get="/test" hx-trigger="click[this.classList.contains(\'bar\')]">Not Called</form>')
|
|
form.click()
|
|
this.server.respond()
|
|
form.innerHTML.should.equal('Not Called')
|
|
|
|
form.classList.add('bar')
|
|
form.click()
|
|
this.server.respond()
|
|
form.innerHTML.should.equal('Called!')
|
|
})
|
|
|
|
it('correctly handles CSS descendant combinators', function() {
|
|
this.server.respondWith('GET', '/test', 'Clicked!')
|
|
|
|
var outer = make(`
|
|
<div>
|
|
<div id='outer'>
|
|
<div id='first'>
|
|
<div id='inner'></div>
|
|
</div>
|
|
<div id='second' hx-get='/test' hx-trigger='click from:previous (#outer div)'>Unclicked.</div>
|
|
</div>
|
|
<div id='other' hx-get='/test' hx-trigger='click from:(div #inner)'>Unclicked.</div>
|
|
</div>
|
|
`)
|
|
|
|
var inner = byId('inner')
|
|
var second = byId('second')
|
|
var other = byId('other')
|
|
|
|
second.innerHTML.should.equal('Unclicked.')
|
|
other.innerHTML.should.equal('Unclicked.')
|
|
|
|
inner.click()
|
|
this.server.respond()
|
|
|
|
second.innerHTML.should.equal('Clicked!')
|
|
other.innerHTML.should.equal('Clicked!')
|
|
})
|
|
|
|
it('correctly handles CSS descendant combinators in modifier target', function() {
|
|
this.server.respondWith('GET', '/test', 'Called')
|
|
|
|
make('<div class="d1"><a id="a1" class="a1">Click me</a><a id="a2" class="a2">Click me</a></div>')
|
|
var div = make('<div hx-trigger="click from:body target:(.d1 .a2)" hx-get="/test">Not Called</div>')
|
|
|
|
byId('a1').click()
|
|
this.server.respond()
|
|
div.innerHTML.should.equal('Not Called')
|
|
|
|
byId('a2').click()
|
|
this.server.respond()
|
|
div.innerHTML.should.equal('Called')
|
|
})
|
|
|
|
it('correctly handles CSS descendant combinators in modifier root', function() {
|
|
this.server.respondWith('GET', '/test', 'Called')
|
|
var errorEvent = null
|
|
var handler = htmx.on('htmx:syntax:error', function(event) {
|
|
errorEvent = event
|
|
})
|
|
var form = make('<div hx-trigger="intersect root:{form input}" hx-get="/test">Not Called</div>')
|
|
try {
|
|
var event = htmx._('makeEvent')('evt')
|
|
form.dispatchEvent(event)
|
|
should.equal(null, errorEvent)
|
|
} finally {
|
|
htmx.off('htmx:syntax:error', handler)
|
|
}
|
|
})
|
|
|
|
it('correctly handles intersect with modifier threshold', function() {
|
|
this.server.respondWith('GET', '/test', 'Called')
|
|
var errorEvent = null
|
|
var handler = htmx.on('htmx:syntax:error', function(event) {
|
|
errorEvent = event
|
|
})
|
|
var form = make('<div hx-trigger="intersect threshold:0.5" hx-get="/test">Not Called</div>')
|
|
try {
|
|
var event = htmx._('makeEvent')('evt')
|
|
form.dispatchEvent(event)
|
|
should.equal(null, errorEvent)
|
|
} finally {
|
|
htmx.off('htmx:syntax:error', handler)
|
|
}
|
|
})
|
|
|
|
it('issues error with invalid trigger spec', function() {
|
|
this.server.respondWith('GET', '/test', 'Called')
|
|
var errorEvent = null
|
|
var handler = htmx.on('htmx:syntax:error', function(event) {
|
|
errorEvent = event
|
|
})
|
|
var form = make('<div hx-trigger="intersect invalid:0.5" hx-get="/test">Not Called</div>')
|
|
try {
|
|
var event = htmx._('makeEvent')('evt')
|
|
form.dispatchEvent(event)
|
|
should.not.equal(null, errorEvent)
|
|
should.not.equal(null, errorEvent.detail.source)
|
|
console.log(errorEvent.detail.source)
|
|
} finally {
|
|
htmx.off('htmx:syntax:error', handler)
|
|
}
|
|
})
|
|
|
|
it('uses trigger specs cache if defined', function() {
|
|
var initialCacheConfig = htmx.config.triggerSpecsCache
|
|
htmx.config.triggerSpecsCache = {}
|
|
|
|
var specExamples = {
|
|
'every 1s': [{ trigger: 'every', pollInterval: 1000 }],
|
|
click: [{ trigger: 'click' }],
|
|
customEvent: [{ trigger: 'customEvent' }],
|
|
'event changed': [{ trigger: 'event', changed: true }],
|
|
'event once': [{ trigger: 'event', once: true }],
|
|
'event delay:1s': [{ trigger: 'event', delay: 1000 }],
|
|
'event throttle:1s': [{ trigger: 'event', throttle: 1000 }],
|
|
'event delay:1s, foo': [{ trigger: 'event', delay: 1000 }, { trigger: 'foo' }],
|
|
'event throttle:1s, foo': [{ trigger: 'event', throttle: 1000 }, { trigger: 'foo' }],
|
|
'event changed once delay:1s': [{ trigger: 'event', changed: true, once: true, delay: 1000 }],
|
|
'event1,event2': [{ trigger: 'event1' }, { trigger: 'event2' }],
|
|
'event1, event2': [{ trigger: 'event1' }, { trigger: 'event2' }],
|
|
'event1 once, event2 changed': [{ trigger: 'event1', once: true }, { trigger: 'event2', changed: true }]
|
|
}
|
|
|
|
for (var specString in specExamples) {
|
|
var div = make("<div hx-trigger='" + specString + "'></div>")
|
|
var spec = htmx._('getTriggerSpecs')(div)
|
|
spec.should.deep.equal(specExamples[specString], 'Found : ' + JSON.stringify(spec) + ', expected : ' + JSON.stringify(specExamples[specString]) + ' for spec: ' + specString)
|
|
}
|
|
|
|
Object.keys(htmx.config.triggerSpecsCache).length.should.greaterThan(0)
|
|
Object.keys(htmx.config.triggerSpecsCache).length.should.equal(Object.keys(specExamples).length)
|
|
|
|
htmx.config.triggerSpecsCache = initialCacheConfig
|
|
})
|
|
|
|
it('correctly reuses trigger specs from the cache if defined', function() {
|
|
var initialCacheConfig = htmx.config.triggerSpecsCache
|
|
htmx.config.triggerSpecsCache = {}
|
|
|
|
var triggerStr = 'event changed once delay:1s'
|
|
var expectedSpec = [{ trigger: 'event', changed: true, once: true, delay: 1000 }]
|
|
|
|
var div = make("<div hx-trigger='event changed once delay:1s'></div>")
|
|
var spec = htmx._('getTriggerSpecs')(div)
|
|
spec.should.deep.equal(expectedSpec, 'Found : ' + JSON.stringify(spec) + ', expected : ' + JSON.stringify(expectedSpec) + ' for spec: ' + triggerStr)
|
|
spec.push('This should be carried to further identical specs thanks to the cache')
|
|
|
|
var div2 = make("<div hx-trigger='event changed once delay:1s'></div>")
|
|
var spec2 = htmx._('getTriggerSpecs')(div2)
|
|
spec2.should.deep.equal(spec, 'Found : ' + JSON.stringify(spec) + ', expected : ' + JSON.stringify(spec2) + ' for cached spec: ' + triggerStr)
|
|
|
|
Object.keys(htmx.config.triggerSpecsCache).length.should.equal(1)
|
|
|
|
htmx.config.triggerSpecsCache = initialCacheConfig
|
|
})
|
|
|
|
it('handles spaces at the end of trigger specs', function() {
|
|
var requests = 0
|
|
this.server.respondWith('GET', '/test', function(xhr) {
|
|
requests++
|
|
xhr.respond(200, {}, 'Requests: ' + requests)
|
|
})
|
|
var div = make('<div hx-trigger="load , click consume " hx-get="/test">Requests: 0</div>')
|
|
div.innerHTML.should.equal('Requests: 0')
|
|
this.server.respond()
|
|
div.innerHTML.should.equal('Requests: 1')
|
|
div.click()
|
|
this.server.respond()
|
|
div.innerHTML.should.equal('Requests: 2')
|
|
})
|
|
|
|
it('Removing polling trigger and processing node removes timeout', function(complete) {
|
|
this.server.respondWith('GET', '/test', 'Called!')
|
|
var div = make('<div hx-get="/test" hx-trigger="every 5ms">Not Called</div>')
|
|
div.removeAttribute('hx-trigger')
|
|
should.not.equal(div['htmx-internal-data'].timeout, undefined)
|
|
htmx.process(div)
|
|
should.equal(div['htmx-internal-data'].timeout, undefined)
|
|
this.server.autoRespond = true
|
|
this.server.autoRespondAfter = 0
|
|
setTimeout(function() {
|
|
div.innerHTML.should.equal('Not Called')
|
|
delete window.foo
|
|
complete()
|
|
}, 30)
|
|
})
|
|
})
|