fix(button): run regexp once instead of every render cycle

chore: add browserDetection utility to @lion/core

Use it to fix test involving checking the userAgent in LionButton

chore: add browserDetection util to aria element sorting
This commit is contained in:
Wessel Loth 2020-02-05 15:01:20 +01:00 committed by Thomas Allmer
parent c0ed437e8f
commit 954adc5659
6 changed files with 47 additions and 27 deletions

View file

@ -1,8 +1,13 @@
import { css, html, SlotMixin, DisabledWithTabIndexMixin, LitElement } from '@lion/core'; import {
css,
html,
browserDetection,
SlotMixin,
DisabledWithTabIndexMixin,
LitElement,
} from '@lion/core';
// eslint-disable-next-line class-methods-use-this
const isKeyboardClickEvent = e => e.keyCode === 32 /* space */ || e.keyCode === 13; /* enter */ const isKeyboardClickEvent = e => e.keyCode === 32 /* space */ || e.keyCode === 13; /* enter */
// eslint-disable-next-line class-methods-use-this
const isSpaceKeyboardClickEvent = e => e.keyCode === 32; /* space */ const isSpaceKeyboardClickEvent = e => e.keyCode === 32; /* space */
export class LionButton extends DisabledWithTabIndexMixin(SlotMixin(LitElement)) { export class LionButton extends DisabledWithTabIndexMixin(SlotMixin(LitElement)) {
@ -27,7 +32,7 @@ export class LionButton extends DisabledWithTabIndexMixin(SlotMixin(LitElement))
return html` return html`
<div class="btn"> <div class="btn">
${this._renderBefore()} ${this._renderBefore()}
${this.constructor.__isIE11() ${browserDetection.isIE11
? html` ? html`
<div id="${this._buttonId}"><slot></slot></div> <div id="${this._buttonId}"><slot></slot></div>
` `
@ -153,7 +158,7 @@ export class LionButton extends DisabledWithTabIndexMixin(SlotMixin(LitElement))
this.active = false; this.active = false;
this.__setupDelegationInConstructor(); this.__setupDelegationInConstructor();
if (this.constructor.__isIE11()) { if (browserDetection.isIE11) {
this._buttonId = `button-${Math.random() this._buttonId = `button-${Math.random()
.toString(36) .toString(36)
.substr(2, 10)}`; .substr(2, 10)}`;
@ -255,10 +260,4 @@ export class LionButton extends DisabledWithTabIndexMixin(SlotMixin(LitElement))
this.click(); this.click();
} }
} }
static __isIE11() {
const ua = window.navigator.userAgent;
const result = /Trident/.test(ua);
return result;
}
} }

View file

@ -9,7 +9,7 @@ import {
keyDownOn, keyDownOn,
keyUpOn, keyUpOn,
} from '@polymer/iron-test-helpers/mock-interactions.js'; } from '@polymer/iron-test-helpers/mock-interactions.js';
import { LionButton } from '../src/LionButton.js'; import { browserDetection } from '@lion/core';
import '../lion-button.js'; import '../lion-button.js';
@ -21,16 +21,6 @@ function getTopElement(el) {
return crossBrowserRoot.elementFromPoint(left + width / 2, top + height / 2); return crossBrowserRoot.elementFromPoint(left + width / 2, top + height / 2);
} }
let originalIsIE11Method;
function mockIsIE11() {
originalIsIE11Method = LionButton.__isIE11;
LionButton.__isIE11 = () => true;
}
function restoreMockIsIE11() {
LionButton.__isIE11 = originalIsIE11Method;
}
describe('lion-button', () => { describe('lion-button', () => {
it('behaves like native `button` in terms of a11y', async () => { it('behaves like native `button` in terms of a11y', async () => {
const el = await fixture(`<lion-button>foo</lion-button>`); const el = await fixture(`<lion-button>foo</lion-button>`);
@ -212,7 +202,7 @@ describe('lion-button', () => {
}); });
it('has an aria-labelledby and wrapper element in IE11', async () => { it('has an aria-labelledby and wrapper element in IE11', async () => {
mockIsIE11(); const browserDetectionStub = sinon.stub(browserDetection, 'isIE11').value(true);
const el = await fixture(`<lion-button>foo</lion-button>`); const el = await fixture(`<lion-button>foo</lion-button>`);
expect(el.hasAttribute('aria-labelledby')).to.be.true; expect(el.hasAttribute('aria-labelledby')).to.be.true;
const wrapperId = el.getAttribute('aria-labelledby'); const wrapperId = el.getAttribute('aria-labelledby');
@ -220,7 +210,7 @@ describe('lion-button', () => {
expect(el.shadowRoot.querySelector(`#${wrapperId}`)).dom.to.equal( expect(el.shadowRoot.querySelector(`#${wrapperId}`)).dom.to.equal(
`<div id="${wrapperId}"><slot></slot></div>`, `<div id="${wrapperId}"><slot></slot></div>`,
); );
restoreMockIsIE11(); browserDetectionStub.restore();
}); });
it('has a native button node with aria-hidden set to true', async () => { it('has a native button node with aria-hidden set to true', async () => {

View file

@ -59,3 +59,4 @@ export { DisabledWithTabIndexMixin } from './src/DisabledWithTabIndexMixin.js';
export { LionSingleton } from './src/LionSingleton.js'; export { LionSingleton } from './src/LionSingleton.js';
export { SlotMixin } from './src/SlotMixin.js'; export { SlotMixin } from './src/SlotMixin.js';
export { UpdateStylesMixin } from './src/UpdateStylesMixin.js'; export { UpdateStylesMixin } from './src/UpdateStylesMixin.js';
export { browserDetection } from './src/browserDetection.js';

View file

@ -0,0 +1,5 @@
const isIE11 = /Trident/.test(window.navigator.userAgent);
export const browserDetection = {
isIE11,
};

View file

@ -1,4 +1,4 @@
const isIE11 = /Trident/.test(window.navigator.userAgent); import { browserDetection } from '@lion/core';
/** /**
* @desc Let the order of adding ids to aria element by DOM order, so that the screen reader * @desc Let the order of adding ids to aria element by DOM order, so that the screen reader
@ -14,9 +14,9 @@ export function getAriaElementsInRightDomOrder(descriptionElements, { reverse }
const pos = a.compareDocumentPosition(b); const pos = a.compareDocumentPosition(b);
// Unfortunately, for IE, we have to switch the order (?) // Unfortunately, for IE, we have to switch the order (?)
if (pos === Node.DOCUMENT_POSITION_PRECEDING || pos === Node.DOCUMENT_POSITION_CONTAINED_BY) { if (pos === Node.DOCUMENT_POSITION_PRECEDING || pos === Node.DOCUMENT_POSITION_CONTAINED_BY) {
return isIE11 ? -1 : 1; return browserDetection.isIE11 ? -1 : 1;
} }
return isIE11 ? 1 : -1; return browserDetection.isIE11 ? 1 : -1;
}; };
const descriptionEls = descriptionElements.filter(el => el); // filter out null references const descriptionEls = descriptionElements.filter(el => el); // filter out null references

View file

@ -1,4 +1,6 @@
import { expect, fixture, html } from '@open-wc/testing'; import { expect, fixture, html } from '@open-wc/testing';
import sinon from 'sinon';
import { browserDetection } from '@lion/core';
import { getAriaElementsInRightDomOrder } from '../../src/utils/getAriaElementsInRightDomOrder.js'; import { getAriaElementsInRightDomOrder } from '../../src/utils/getAriaElementsInRightDomOrder.js';
describe('getAriaElementsInRightDomOrder', () => { describe('getAriaElementsInRightDomOrder', () => {
@ -43,4 +45,27 @@ describe('getAriaElementsInRightDomOrder', () => {
const result = getAriaElementsInRightDomOrder(unorderedNodes, { reverse: true }); const result = getAriaElementsInRightDomOrder(unorderedNodes, { reverse: true });
expect(result).to.eql([c, bChild, b, a]); expect(result).to.eql([c, bChild, b, a]);
}); });
it('orders in reverse for IE11', async () => {
const browserDetectionStub = sinon.stub(browserDetection, 'isIE11').value(true);
const el = await fixture(html`
<div>
<div id="a"></div>
<div></div>
<div id="b">
<div></div>
<div id="b-child"></div>
</div>
<div></div>
<div id="c"></div>
<div></div>
</div>
`);
// eslint-disable-next-line no-unused-vars
const [a, _1, b, _2, bChild, _3, c, _4] = el.querySelectorAll('div');
const unorderedNodes = [bChild, c, a, b];
const result = getAriaElementsInRightDomOrder(unorderedNodes);
expect(result).to.eql([c, bChild, b, a]);
browserDetectionStub.restore();
});
}); });