describe('Core htmx Shadow DOM Tests', function() { // Skip these tests if browser doesn't support shadow DOM if (typeof window.ShadowRoot === 'undefined') return const chai = window.chai before(function() { this.initialWorkArea = getWorkArea().outerHTML }) after(function() { getWorkArea().outerHTML = this.initialWorkArea }) beforeEach(function() { this.server = makeServer() clearWorkArea() var workArea = getWorkArea() if (!workArea.shadowRoot) workArea.attachShadow({ mode: 'open' }) workArea.shadowRoot.innerHTML = '' }) afterEach(function() { this.server.restore() clearWorkArea() var workArea = getWorkArea() if (!workArea.shadowRoot) workArea.attachShadow({ mode: 'open' }) workArea.shadowRoot.innerHTML = '' }) // Locally redefine the `byId` and `make` functions to use shadow DOM function byId(id) { return getWorkArea().shadowRoot.getElementById(id) || document.getElementById(id) } function make(htmlStr) { htmlStr = htmlStr.trim() var makeFn = function() { var range = document.createRange() var fragment = range.createContextualFragment(htmlStr) var wa = getWorkArea().shadowRoot var child = null var children = fragment.children || fragment.childNodes // IE var appendedChildren = [] while (children.length > 0) { child = children[0] wa.appendChild(child) appendedChildren.push(child) } htmx.process(wa) return child // return last added element } if (getWorkArea()) { return makeFn() } else { ready(makeFn) } } // special target selector extensions it('properly retrieves shadow root for extended selector', function() { var div = make('
') htmx.defineExtension('test/shadowdom.js', { init: function(api) { api.getTarget(div).should.equal(getWorkArea().shadowRoot) } }) }) it('properly escapes shadow root for extended selector', function() { var div = make('
') htmx.defineExtension('test/shadowdom.js', { init: function(api) { api.getTarget(div).should.equal(getWorkArea()) } }) }) it('properly retrives shadow root host for extended selector', function() { var div = make('
') htmx.defineExtension('test/shadowdom.js', { init: function(api) { api.getTarget(div).should.equal(getWorkArea()) } }) }) // bootstrap test it('issues a GET request on click and swaps content', function() { this.server.respondWith('GET', '/test', 'Clicked!') var btn = make('') btn.click() this.server.respond() btn.innerHTML.should.equal('Clicked!') }) it('processes inner content properly', function() { this.server.respondWith('GET', '/test', 'Click Me') this.server.respondWith('GET', '/test2', 'Clicked!') var div = make('
') div.click() this.server.respond() div.innerHTML.should.equal('Click Me') 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', 'Click Me') this.server.respondWith('GET', '/test2', 'Clicked!') var div = make('
') 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, {}, '' + i + '') }) this.server.respondWith('GET', '/test2', '*') // extra wrapping div here because `ShadowRoot` doesn't support `innerText` or `child.parentElement` var div = make('
*
').children[0] 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.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.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, {}, '' + i + '') }) this.server.respondWith('GET', '/test2', '*') // extra wrapping div here because `ShadowRoot` doesn't support `innerText` or `child.parentElement` var div = make('
*
').children[0] 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.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.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('') var target = make('Initial') 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('') 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('
') var btn1 = make('') var btn2 = make('') 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('
Click Me!
') 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('
Load Me!
') 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('
Click Me!
') 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.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.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', "
foo
bar
") var div = make('
') div.click() this.server.respond() div.innerHTML.should.equal('
foo
') }) it('properly handles hx-select for full html document situation', function() { this.server.respondWith('GET', '/test', "
foo
bar
") var div = make('
') div.click() this.server.respond() div.innerHTML.should.equal('
foo
') }) it('properly settles attributes on interior elements', function(done) { this.server.respondWith('GET', '/test', "
") var div = make("
") 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', "
") var div = make("
") 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', "
") var div = make("
") 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.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.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.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.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.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('text nodes dont screw up settling via variable capture', function() { this.server.respondWith('GET', '/test', "
fooo") this.server.respondWith('GET', '/test2', 'clicked') var div = make("
") 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', "
") var div = make("
") 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', "") var div = make("
") 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', "") var div = make("
") 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', "
") var div = make("
") 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', "
") var div = make("
") 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', '
') var div = make("
") 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', "
") var div = make("
") 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', "
After settle...
") var div = make("
") 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") var div = make("
") 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("
") 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('
') 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', "") var input = make("") input.click() this.server.respond() input = byId('i1') input.value.should.equal('bar') }) it('autofocus attribute works properly', function() { this.server.respondWith('GET', '/test', "") var input = make("") input.focus() input.click() getWorkArea().shadowRoot.activeElement.should.equal(input) this.server.respond() var input2 = byId('i2') getWorkArea().shadowRoot.activeElement.should.equal(input2) }) it('autofocus attribute works properly w/ child', function() { this.server.respondWith('GET', '/test', "
") var input = make("") input.focus() input.click() getWorkArea().shadowRoot.activeElement.should.equal(input) this.server.respond() var input2 = byId('i2') getWorkArea().shadowRoot.activeElement.should.equal(input2) }) it('autofocus attribute works properly w/ true value', function() { this.server.respondWith('GET', '/test', "
") var input = make("") input.focus() input.click() getWorkArea().shadowRoot.activeElement.should.equal(input) this.server.respond() var input2 = byId('i2') getWorkArea().shadowRoot.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.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('') 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, {}, "htmx rocks!Clicked!") }) var btn = make('') 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, {}, "" + originalTitle + 'UPDATE' + 'Clicked!') }) var btn = make('') 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, {}, "" + newTitle + "fooClicked!x") }) var btn = make('') 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, {}, '</> htmx rocks!Clicked!') }) var btn = make('') 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('') 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('') 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('') var div = make('
') 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('') var btn2 = make('') 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('') btn.click() this.server.respond() btn.innerText.should.equal('Clicked!!!') htmx.off('htmx:beforeSwap', handler) }) // This test is causing a global leak because that setGlobal.js script fires twice on load // Skipping only so I can make progress on some other things—this needs to be fixed it.skip('scripts w/ src attribute are properly loaded', function(done) { try { this.server.respondWith('GET', '/test', "") var div = make("
") 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', 'Foobar') var btn = make('') btn.click() this.server.respond() btn.innerHTML.should.equal('Foobar') }) 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('
' + '' + '' + '
') 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('
' + '' + '' + '
') 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('
' + '' + '' + '
') 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('
' + '' + '' + '
') 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('
' + '' + '
' + '') 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('
' + '' + '
' + '') 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('
' + '' + '' + '' + '' + '
') 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('
' + '' + 'A' + 'B' + 'C' + '
') 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('
' + '' + '' + '
' + '
' + '' + '
') 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('
' + '' + '' + '
' + '
' + '' + '
') 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('
' + ' ' + '
' + '' + '' + '') byId('submit').click() this.server.respond() values.should.deep.equal({ t1: 'textValue', b1: ['inputValue', 'buttonValue'], s1: 'selectValue' }) }) it('handles form post with button formmethod dialog properly', function() { var values this.server.respondWith('POST', '/test', function(xhr) { values = getParameters(xhr) xhr.respond(200, {}, '') }) make('
') byId('submit').click() this.server.respond() values.should.deep.equal({ foo: 'bar' }) }) it('handles form get with button formmethod dialog properly', function() { var responded = false this.server.respondWith('GET', '/test', function(xhr) { responded = true xhr.respond(200, {}, '') }) make('
') byId('submit').click() this.server.respond() responded.should.equal(true) }) it('can associate submit buttons from outside a form with the current version of the form after swap', function() { const template = '
\n' + '\n' + '\n' + '
\n' + '' 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('can handle basic events w/ no other attributes', function() { var btn = make("") btn.click() window.foo.should.equal(true) delete window.foo }) it('can handle basic events w/ no other attributes in child', function() { var div = make("
") var btn = div.querySelector('#b1') btn.click() window.foo.should.equal(true) delete window.foo }) it('can target shadow DOM Host and place content below web component', function() { this.server.respondWith('GET', '/test', '
Clicked!
') var btn = make('') btn.click() this.server.respond() var r1 = document.getElementById('r1') r1.innerHTML.should.equal('Clicked!') r1.remove() }) it('can target global id outside shadow DOM and place content', function() { this.server.respondWith('GET', '/test', '
Clicked!
') var btn = make('') btn.click() this.server.respond() var r2 = document.getElementById('r2') r2.innerHTML.should.equal('Clicked!') r2.remove() }) it('can target shadow DOM Host with outerHTML swap and replace it', function() { this.server.respondWith('GET', '/test', '
Clicked!
') var btn = make('') btn.click() chai.expect(getWorkArea().shadowRoot).to.not.be.a('null') this.server.respond() getWorkArea().innerHTML.should.equal('Clicked!') chai.expect(getWorkArea().shadowRoot).to.be.a('null') }) })