UNPKG

@lion/ui

Version:

A package of extendable web components

187 lines (167 loc) 8.57 kB
/* eslint-disable lit-a11y/click-events-have-key-events */ import { LionButtonSubmit } from '@lion/ui/button.js'; import { aTimeout, defineCE, expect, fixture, html, unsafeStatic } from '@open-wc/testing'; import { sendKeys } from '@web/test-runner-commands'; import sinon from 'sinon'; export function LionButtonSubmitSuite({ klass = LionButtonSubmit } = {}) { const tagStringButton = defineCE(class extends klass {}); const tagButton = unsafeStatic(tagStringButton); describe('LionButtonSubmit', () => { it('has .type="submit" and type="submit" by default', async () => { const el = /** @type {LionButtonSubmit} */ ( await fixture(html`<${tagButton}>foo</${tagButton}>`) ); expect(el.type).to.equal('submit'); expect(el.getAttribute('type')).to.be.equal('submit'); }); describe('Implicit form submission', () => { describe('Helper submit button', () => { it('creates a helper submit button when type is "submit"', async () => { let lionBtnEl; const elTypeSubmit = /** @type {HTMLFormElement} */ ( await fixture(html`<form><${tagButton} type="submit">foo</${tagButton}></form>`) ); lionBtnEl = /** @type {LionButtonSubmit} */ (elTypeSubmit.querySelector('[type=submit]')); // @ts-ignore [allow-protected] in test expect(lionBtnEl._nativeButtonNode instanceof HTMLButtonElement).to.be.true; // @ts-ignore [allow-protected] in test expect(lionBtnEl._nativeButtonNode.type).to.equal('submit'); const elTypeReset = /** @type {LionButtonSubmit} */ ( await fixture(html`<form><${tagButton} type="reset">foo</${tagButton}></form>`) ); lionBtnEl = /** @type {LionButtonSubmit} */ (elTypeReset.querySelector('[type=reset]')); // @ts-ignore [allow-protected] in test expect(lionBtnEl._nativeButtonNode).to.be.null; const elTypeButton = /** @type {LionButtonSubmit} */ ( await fixture(html`<form><${tagButton} type="button">foo</${tagButton}></form>`) ); lionBtnEl = /** @type {LionButtonSubmit} */ (elTypeButton.querySelector('[type=button]')); // @ts-ignore [allow-protected] in test expect(lionBtnEl._nativeButtonNode).to.be.null; }); it('only creates a helper submit button when LionButtonSubmit is inside a form', async () => { const elForm = /** @type {HTMLFormElement} */ (await fixture(html`<form></form>`)); const el = /** @type {LionButtonSubmit} */ ( await fixture(html`<${tagButton} type="submit">foo</${tagButton}>`) ); // @ts-ignore [allow-protected] in test expect(el._nativeButtonNode).to.be.null; elForm.appendChild(el); await el.updateComplete; // @ts-ignore [allow-protected] in test expect(el._nativeButtonNode).to.be.not.null; elForm.removeChild(el); // @ts-ignore [allow-protected] in test expect(el._nativeButtonNode).to.be.null; }); it('puts helper submit button at the bottom of a form', async () => { const elForm = /** @type {HTMLFormElement} */ ( await fixture( html`<form><input /><${tagButton} type="submit">foo</${tagButton}><input /></form>`, ) ); const lionBtnEl = /** @type {LionButtonSubmit} */ (elForm.querySelector('[type=submit]')); expect(elForm.children.length).to.equal(4); // 3 + 1 // @ts-ignore [allow-protected] in test expect(lionBtnEl._nativeButtonNode).to.be.not.null; // @ts-ignore [allow-protected] in test expect(elForm.children[3].firstChild).to.equal(lionBtnEl._nativeButtonNode); }); it('creates max one helper submit button per form', async () => { const elForm = /** @type {HTMLFormElement} */ ( await fixture(html` <form> <input /> <${tagButton} type="submit">foo</${tagButton}> <${tagButton} type="submit">foo</${tagButton}> <input /> </form> `) ); const [lionBtnEl1, lionBtnEl2] = /** @type {LionButtonSubmit[]} */ ( Array.from(elForm.querySelectorAll('[type=submit]')) ); const { children } = elForm; expect(children.length).to.equal(5); // 4 + 1 // @ts-ignore [allow-protected] in test expect(lionBtnEl1._nativeButtonNode).to.be.not.null; // @ts-ignore [allow-protected] in test expect(lionBtnEl2._nativeButtonNode).to.be.not.null; // @ts-ignore [allow-protected] in test expect(children[children.length - 1].firstChild).to.equal(lionBtnEl1._nativeButtonNode); // @ts-ignore [allow-protected] in test expect(children[children.length - 1].firstChild).to.equal(lionBtnEl2._nativeButtonNode); }); it('helper submit button gets reconnected when external context changes (rerenders)', async () => { const elForm = /** @type {HTMLFormElement} */ ( await fixture(html`<form><${tagButton} type="submit">foo</${tagButton}></form>`) ); const helperBtnEl = /** @type {HTMLButtonElement} */ ( elForm.querySelector('button[type=submit]') ); helperBtnEl.remove(); expect(elForm).to.not.include(helperBtnEl); await aTimeout(0); expect(elForm).to.include(helperBtnEl); }); it('helper submit button gets removed when last LionbuttonSubmit gets disconnected from form', async () => { const elForm = /** @type {HTMLFormElement} */ ( await fixture( html`<form><${tagButton} type="submit">foo</${tagButton}><${tagButton} type="submit">foo</${tagButton}></form>`, ) ); const [lionBtnEl1, lionBtnEl2] = /** @type {LionButtonSubmit[]} */ ( Array.from(elForm.querySelectorAll('[type=submit]')) ); const helperBtnEl = elForm.children[elForm.children.length - 1].firstChild; // @ts-ignore [allow-protected] in test expect(helperBtnEl).to.equal(lionBtnEl1._nativeButtonNode); // @ts-ignore [allow-protected] in test expect(helperBtnEl).to.equal(lionBtnEl2._nativeButtonNode); elForm.removeChild(lionBtnEl1); // @ts-ignore [allow-protected] in test expect(helperBtnEl).to.equal(lionBtnEl2._nativeButtonNode); elForm.removeChild(lionBtnEl2); // @ts-ignore [allow-protected] in test expect(helperBtnEl).to.not.equal(lionBtnEl2._nativeButtonNode); expect(Array.from(elForm.children)).to.not.include(helperBtnEl); }); it('hides the helper submit button in the UI', async () => { const el = /** @type {LionButtonSubmit} */ ( await fixture(html`<form><${tagButton}>foo</${tagButton}></form>`) ); // @ts-ignore [allow-protected] in test const helperButtonEl = el.querySelector(tagStringButton)._nativeButtonNode; expect(helperButtonEl.getAttribute('tabindex')).to.equal('-1'); expect(window.getComputedStyle(helperButtonEl).clip).to.equal('rect(0px, 0px, 0px, 0px)'); }); }); it('works with implicit form submission on-enter inside an input', async () => { const formSubmitSpy = /** @type {EventListener} */ (sinon.spy(e => e.preventDefault())); const form = await fixture(html` <form @submit="${formSubmitSpy}"> <input name="foo" /> <input name="foo2" /> <${tagButton} type="submit">foo</${tagButton}> </form> `); const input2 = /** @type {HTMLInputElement} */ (form.querySelector('input[name="foo2"]')); input2.focus(); await sendKeys({ press: 'Enter', }); expect(formSubmitSpy).to.have.been.calledOnce; }); }); describe('Accessibility', () => { it('the helper button has aria-hidden set to true', async () => { const el = /** @type {LionButtonSubmit} */ ( await fixture(html`<form><${tagButton}></${tagButton}></form>`) ); // @ts-ignore [allow-protected] in test const helperButtonEl = el.querySelector(tagStringButton)._nativeButtonNode; expect(helperButtonEl.getAttribute('aria-hidden')).to.equal('true'); }); }); }); }