import { expect, fixture, html, aTimeout, oneEvent } from '@open-wc/testing'; import sinon from 'sinon'; import { makeMouseEvent, pressEnter, pressSpace, } from '@polymer/iron-test-helpers/mock-interactions.js'; import '../lion-button.js'; function getTopElement(el) { const { left, top, width, height } = el.getBoundingClientRect(); // to support elementFromPoint() in polyfilled browsers we have to use document const crossBrowserRoot = el.shadowRoot && el.shadowRoot.elementFromPoint ? el.shadowRoot : document; return crossBrowserRoot.elementFromPoint(left + width / 2, top + height / 2); } describe('lion-button', () => { it('behaves like native `button` in terms of a11y', async () => { const el = await fixture(`foo`); expect(el.getAttribute('role')).to.equal('button'); expect(el.getAttribute('tabindex')).to.equal('0'); }); it('has no type by default on the native button', async () => { const el = await fixture(`foo`); const nativeButton = el.$$slot('_button'); expect(nativeButton.getAttribute('type')).to.be.null; }); it('has type="submit" on the native button when set', async () => { const el = await fixture(`foo`); const nativeButton = el.$$slot('_button'); expect(nativeButton.getAttribute('type')).to.equal('submit'); }); it('hides the native button in the UI', async () => { const el = await fixture(`foo`); const nativeButton = el.$$slot('_button'); expect(nativeButton.getAttribute('tabindex')).to.equal('-1'); expect(window.getComputedStyle(nativeButton).visibility).to.equal('hidden'); }); it('can be disabled imperatively', async () => { const el = await fixture(`foo`); expect(el.getAttribute('tabindex')).to.equal('-1'); el.disabled = false; await el.updateComplete; expect(el.getAttribute('tabindex')).to.equal('0'); expect(el.hasAttribute('disabled')).to.equal(false); el.disabled = true; await el.updateComplete; expect(el.getAttribute('tabindex')).to.equal('-1'); expect(el.hasAttribute('disabled')).to.equal(true); }); describe('a11y', () => { it('has a role="button" by default', async () => { const el = await fixture(`foo`); expect(el.getAttribute('role')).to.equal('button'); el.role = 'foo'; await el.updateComplete; expect(el.getAttribute('role')).to.equal('foo'); }); it('does not override user provided role', async () => { const el = await fixture(`foo`); expect(el.getAttribute('role')).to.equal('foo'); }); it('has a tabindex="0" by default', async () => { const el = await fixture(`foo`); expect(el.getAttribute('tabindex')).to.equal('0'); }); it('has a tabindex="-1" when disabled', async () => { const el = await fixture(`foo`); expect(el.getAttribute('tabindex')).to.equal('-1'); el.disabled = false; await el.updateComplete; expect(el.getAttribute('tabindex')).to.equal('0'); el.disabled = true; await el.updateComplete; expect(el.getAttribute('tabindex')).to.equal('-1'); }); it('does not override user provided tabindex', async () => { const el = await fixture(`foo`); expect(el.getAttribute('tabindex')).to.equal('5'); }); it('disabled does not override user provided tabindex', async () => { const el = await fixture(`foo`); expect(el.getAttribute('tabindex')).to.equal('-1'); el.disabled = false; await el.updateComplete; expect(el.getAttribute('tabindex')).to.equal('5'); }); }); describe('form integration', () => { it('behaves like native `button` when clicked', async () => { const formSubmitSpy = sinon.spy(e => e.preventDefault()); const form = await fixture(html`
foo
`); const button = form.querySelector('lion-button'); getTopElement(button).click(); expect(formSubmitSpy.called).to.be.true; }); it('behaves like native `button` when interected with keyboard space', async () => { const formSubmitSpy = sinon.spy(e => e.preventDefault()); const form = await fixture(html`
foo
`); pressSpace(form.querySelector('lion-button')); await aTimeout(); await aTimeout(); expect(formSubmitSpy.called).to.be.true; }); it('behaves like native `button` when interected with keyboard enter', async () => { const formSubmitSpy = sinon.spy(e => e.preventDefault()); const form = await fixture(html`
foo
`); pressEnter(form.querySelector('lion-button')); await aTimeout(); await aTimeout(); expect(formSubmitSpy.called).to.be.true; }); }); describe('click event', () => { it('is fired once', async () => { const clickSpy = sinon.spy(); const el = await fixture( html` foo `, ); getTopElement(el).click(); // trying to wait for other possible redispatched events await aTimeout(); await aTimeout(); expect(clickSpy.callCount).to.equal(1); }); describe('native button behavior', async () => { async function prepareClickEvent(el) { setTimeout(() => { makeMouseEvent('click', { x: 11, y: 11 }, getTopElement(el)); }); return oneEvent(el, 'click'); } let nativeButtonEvent; let lionButtonEvent; before(async () => { const nativeButtonEl = await fixture(''); const lionButtonEl = await fixture('foo'); nativeButtonEvent = await prepareClickEvent(nativeButtonEl); lionButtonEvent = await prepareClickEvent(lionButtonEl); }); const sameProperties = [ 'constructor', 'composed', 'bubbles', 'cancelable', 'clientX', 'clientY', ]; sameProperties.forEach(property => { it(`has same value of the property "${property}" as in native button event`, () => { expect(lionButtonEvent[property]).to.equal(nativeButtonEvent[property]); }); }); it('has host in the target property', async () => { const el = await fixture('foo'); const event = await prepareClickEvent(el); expect(event.target).to.equal(el); }); }); }); });