fix: refactor slot selection

This commit is contained in:
Joren Broekema 2019-11-15 14:06:48 +01:00 committed by Thomas Allmer
parent 90e6b4ef36
commit 5999ea9569
21 changed files with 192 additions and 131 deletions

View file

@ -123,7 +123,7 @@ export class LionButton extends DisabledWithTabIndexMixin(SlotMixin(LitElement))
} }
get _nativeButtonNode() { get _nativeButtonNode() {
return this.querySelector('[slot=_button]'); return Array.from(this.children).find(child => child.slot === '_button');
} }
get _form() { get _form() {

View file

@ -70,7 +70,7 @@ describe('DelegateMixin', () => {
get delegations() { get delegations() {
return { return {
...super.delegations, ...super.delegations,
target: () => this.querySelector('[slot=button]'), target: () => Array.from(this.children).find(child => child.slot === 'button'),
events: ['click'], events: ['click'],
methods: ['click'], methods: ['click'],
}; };
@ -89,7 +89,9 @@ describe('DelegateMixin', () => {
<${tag}><button slot="button">click me</button></${tag}>`); <${tag}><button slot="button">click me</button></${tag}>`);
const cb = sinon.spy(); const cb = sinon.spy();
element.addEventListener('click', cb); element.addEventListener('click', cb);
element.querySelector('[slot=button]').click(); Array.from(element.children)
.find(child => child.slot === 'button')
.click();
expect(cb.callCount).to.equal(1); expect(cb.callCount).to.equal(1);
}); });

View file

@ -68,11 +68,11 @@ export class LionSlider extends LionField {
// 3. Proxy property `<my-slider>.mySliderValue` to `<lion-slider>.value` // 3. Proxy property `<my-slider>.mySliderValue` to `<lion-slider>.value`
get value() { get value() {
   return this.querySelector('[slot=input]').mySliderValue;    return Array.from(this.children).find(child => child.slot === 'input').mySliderValue;
} }
set value(newV) { set value(newV) {
   this.querySelector('[slot=input]').mySliderValue = newV;    Array.from(this.children).find(child => child.slot === 'input').mySliderValue = newV;
} }
} }
``` ```

View file

@ -295,7 +295,7 @@ export const FormControlMixin = dedupeMixin(
} }
inputGroupPrefixTemplate() { inputGroupPrefixTemplate() {
return !this.querySelector('[slot=prefix]') return !Array.from(this.children).find(child => child.slot === 'prefix')
? nothing ? nothing
: html` : html`
<div class="input-group__prefix"> <div class="input-group__prefix">
@ -314,7 +314,7 @@ export const FormControlMixin = dedupeMixin(
} }
inputGroupSuffixTemplate() { inputGroupSuffixTemplate() {
return !this.querySelector('[slot=suffix]') return !Array.from(this.children).find(child => child.slot === 'suffix')
? nothing ? nothing
: html` : html`
<div class="input-group__suffix"> <div class="input-group__suffix">

View file

@ -24,6 +24,8 @@ describe('FieldCustomMixin', () => {
const lionField = await fixture(` const lionField = await fixture(`
<${elem} disable-help-text>${inputSlot}</${elem}> <${elem} disable-help-text>${inputSlot}</${elem}>
`); `);
expect(lionField.querySelector('[slot=help-text]')).to.equal(null); expect(Array.from(lionField.children).find(child => child.slot === 'help-text')).to.equal(
undefined,
);
}); });
}); });

View file

@ -27,18 +27,18 @@ describe('FormControlMixin', () => {
const lionFieldAttr = await fixture(html` const lionFieldAttr = await fixture(html`
<${tag} help-text="This email address is already taken">${inputSlot}</${tag}> <${tag} help-text="This email address is already taken">${inputSlot}</${tag}>
`); `);
expect(lionFieldAttr.querySelector('[slot=help-text]').textContent).to.contain( expect(
'This email address is already taken', Array.from(lionFieldAttr.children).find(child => child.slot === 'help-text').textContent,
); ).to.contain('This email address is already taken');
const lionFieldProp = await fixture(html` const lionFieldProp = await fixture(html`
<${tag} <${tag}
.helpText=${'This email address is already taken'} .helpText=${'This email address is already taken'}
>${inputSlot} >${inputSlot}
</${tag}>`); </${tag}>`);
expect(lionFieldProp.querySelector('[slot=help-text]').textContent).to.contain( expect(
'This email address is already taken', Array.from(lionFieldProp.children).find(child => child.slot === 'help-text').textContent,
); ).to.contain('This email address is already taken');
}); });
it('does not duplicate aria-describedby and aria-labelledby ids', async () => { it('does not duplicate aria-describedby and aria-labelledby ids', async () => {
@ -52,8 +52,8 @@ describe('FormControlMixin', () => {
await wrapper.updateComplete; await wrapper.updateComplete;
['aria-describedby', 'aria-labelledby'].forEach(ariaAttributeName => { ['aria-describedby', 'aria-labelledby'].forEach(ariaAttributeName => {
const ariaAttribute = lionField const ariaAttribute = Array.from(lionField.children)
.querySelector('[slot=input]') .find(child => child.slot === 'input')
.getAttribute(ariaAttributeName) .getAttribute(ariaAttributeName)
.trim() .trim()
.split(' '); .split(' ');
@ -70,6 +70,10 @@ describe('FormControlMixin', () => {
</${tag}> </${tag}>
`); `);
expect(lionField.querySelector('[slot=feedback]').getAttribute('aria-live')).to.equal('polite'); expect(
Array.from(lionField.children)
.find(child => child.slot === 'feedback')
.getAttribute('aria-live'),
).to.equal('polite');
}); });
}); });

View file

@ -32,7 +32,7 @@ beforeEach(() => {
describe('<lion-field>', () => { describe('<lion-field>', () => {
it(`puts a unique id "${tagString}-[hash]" on the native input`, async () => { it(`puts a unique id "${tagString}-[hash]" on the native input`, async () => {
const el = await fixture(html`<${tag}>${inputSlot}</${tag}>`); const el = await fixture(html`<${tag}>${inputSlot}</${tag}>`);
expect(el.querySelector('[slot=input]').id).to.equal(el._inputId); expect(Array.from(el.children).find(child => child.slot === 'input').id).to.equal(el._inputId);
}); });
it('fires focus/blur event on host and native input if focused/blurred', async () => { it('fires focus/blur event on host and native input if focused/blurred', async () => {
@ -113,15 +113,15 @@ describe('<lion-field>', () => {
it('reads initial value from attribute value', async () => { it('reads initial value from attribute value', async () => {
const el = await fixture(html`<${tag} value="one">${inputSlot}</${tag}>`); const el = await fixture(html`<${tag} value="one">${inputSlot}</${tag}>`);
expect(el.querySelector('[slot=input]').value).to.equal('one'); expect(Array.from(el.children).find(child => child.slot === 'input').value).to.equal('one');
}); });
it('delegates value property', async () => { it('delegates value property', async () => {
const el = await fixture(html`<${tag}>${inputSlot}</${tag}>`); const el = await fixture(html`<${tag}>${inputSlot}</${tag}>`);
expect(el.querySelector('[slot=input]').value).to.equal(''); expect(Array.from(el.children).find(child => child.slot === 'input').value).to.equal('');
el.value = 'one'; el.value = 'one';
expect(el.value).to.equal('one'); expect(el.value).to.equal('one');
expect(el.querySelector('[slot=input]').value).to.equal('one'); expect(Array.from(el.children).find(child => child.slot === 'input').value).to.equal('one');
}); });
// This is necessary for security, so that _inputNodes autocomplete can be set to 'off' // This is necessary for security, so that _inputNodes autocomplete can be set to 'off'
@ -200,7 +200,7 @@ describe('<lion-field>', () => {
<span slot="feedback">No name entered</span> <span slot="feedback">No name entered</span>
</${tag}> </${tag}>
`); `);
const nativeInput = el.querySelector('[slot=input]'); const nativeInput = Array.from(el.children).find(child => child.slot === 'input');
expect(nativeInput.getAttribute('aria-labelledby')).to.equal(` label-${el._inputId}`); expect(nativeInput.getAttribute('aria-labelledby')).to.equal(` label-${el._inputId}`);
expect(nativeInput.getAttribute('aria-describedby')).to.contain(` help-text-${el._inputId}`); expect(nativeInput.getAttribute('aria-describedby')).to.contain(` help-text-${el._inputId}`);
@ -218,7 +218,7 @@ describe('<lion-field>', () => {
</${tag}> </${tag}>
`); `);
const nativeInput = el.querySelector('[slot=input]'); const nativeInput = Array.from(el.children).find(child => child.slot === 'input');
expect(nativeInput.getAttribute('aria-labelledby')).to.contain( expect(nativeInput.getAttribute('aria-labelledby')).to.contain(
` before-${el._inputId} after-${el._inputId}`, ` before-${el._inputId} after-${el._inputId}`,
); );

View file

@ -828,7 +828,7 @@ describe('<lion-fieldset>', () => {
${inputSlots} ${inputSlots}
</${tag}> </${tag}>
`); `);
const label = el.querySelector('[slot="label"]'); const label = Array.from(el.children).find(child => child.slot === 'label');
expect(el.hasAttribute('aria-labelledby')).to.equal(true); expect(el.hasAttribute('aria-labelledby')).to.equal(true);
expect(el.getAttribute('aria-labelledby')).contains(label.id); expect(el.getAttribute('aria-labelledby')).contains(label.id);
}); });

View file

@ -56,7 +56,7 @@ export class LionInputAmount extends FieldCustomMixin(LocalizeMixin(LionInput))
_onCurrencyChanged({ currency }) { _onCurrencyChanged({ currency }) {
if (this._isPrivateSlot('after')) { if (this._isPrivateSlot('after')) {
this.querySelector('[slot=after]').textContent = currency; Array.from(this.children).find(child => child.slot === 'after').textContent = currency;
} }
this.formatOptions.currency = currency; this.formatOptions.currency = currency;
this._calculateValues(); this._calculateValues();

View file

@ -71,28 +71,32 @@ describe('<lion-input-amount>', () => {
it('shows no currency', async () => { it('shows no currency', async () => {
const el = await fixture(`<lion-input-amount></lion-input-amount>`); const el = await fixture(`<lion-input-amount></lion-input-amount>`);
expect(el.querySelector('[slot=suffix]')).to.be.null; expect(Array.from(el.children).find(child => child.slot === 'suffix')).to.be.undefined;
}); });
it('displays currency if provided', async () => { it('displays currency if provided', async () => {
const el = await fixture(`<lion-input-amount currency="EUR"></lion-input-amount>`); const el = await fixture(`<lion-input-amount currency="EUR"></lion-input-amount>`);
expect(el.querySelector('[slot=after]').innerText).to.equal('EUR'); expect(Array.from(el.children).find(child => child.slot === 'after').innerText).to.equal('EUR');
}); });
it('can update currency', async () => { it('can update currency', async () => {
const el = await fixture(`<lion-input-amount currency="EUR"></lion-input-amount>`); const el = await fixture(`<lion-input-amount currency="EUR"></lion-input-amount>`);
el.currency = 'USD'; el.currency = 'USD';
await el.updateComplete; await el.updateComplete;
expect(el.querySelector('[slot=after]').innerText).to.equal('USD'); expect(Array.from(el.children).find(child => child.slot === 'after').innerText).to.equal('USD');
}); });
it('ignores currency if a suffix is already present', async () => { it('ignores currency if a suffix is already present', async () => {
const el = await fixture( const el = await fixture(
`<lion-input-amount currency="EUR"><span slot="suffix">my-currency</span></lion-input-amount>`, `<lion-input-amount currency="EUR"><span slot="suffix">my-currency</span></lion-input-amount>`,
); );
expect(el.querySelector('[slot=suffix]').innerText).to.equal('my-currency'); expect(Array.from(el.children).find(child => child.slot === 'suffix').innerText).to.equal(
'my-currency',
);
el.currency = 'EUR'; el.currency = 'EUR';
await el.updateComplete; await el.updateComplete;
expect(el.querySelector('[slot=suffix]').innerText).to.equal('my-currency'); expect(Array.from(el.children).find(child => child.slot === 'suffix').innerText).to.equal(
'my-currency',
);
}); });
}); });

View file

@ -3,12 +3,13 @@ import { storiesOf, html } from '@open-wc/demoing-storybook';
import { localize } from '@lion/localize'; import { localize } from '@lion/localize';
import '../lion-input-email.js'; import '../lion-input-email.js';
import '../../fieldset/lion-fieldset.js';
storiesOf('Forms|Input Email', module) storiesOf('Forms|Input Email', module)
.add( .add(
'Default', 'Default',
() => html` () => html`
<lion-input-email label="Label"></lion-input-email> <lion-input-email name="email" label="Label"></lion-input-email>
`, `,
) )
.add( .add(

View file

@ -113,6 +113,9 @@ export const OverlayMixin = dedupeMixin(
this._overlayCtrl = this._defineOverlay({ contentNode, invokerNode }); this._overlayCtrl = this._defineOverlay({ contentNode, invokerNode });
} }
// FIXME: We add an overlay slot to the wrapper, but the content node already has a slot="content"
// This is a big problem, because slots should be direct children of its host element.
// Putting the shadow outlet slot in between breaks that. https://github.com/ing-bank/lion/issues/382
/** /**
* @desc Should be called by Subclasser for local overlay support in shadow roots * @desc Should be called by Subclasser for local overlay support in shadow roots
* Create an outlet slot in shadow dom that our local overlay can pass through * Create an outlet slot in shadow dom that our local overlay can pass through

View file

@ -9,12 +9,14 @@ export class LionPopup extends OverlayMixin(LitElement) {
`; `;
} }
// FIXME: This should be refactored to Array.from(this.children).find(child => child.slot === 'content')
// When this issue is fixed https://github.com/ing-bank/lion/issues/382
get _overlayContentNode() { get _overlayContentNode() {
return this.querySelector('[slot=content]'); return this.querySelector('[slot="content"]');
} }
get _overlayInvokerNode() { get _overlayInvokerNode() {
return this.querySelector('[slot=invoker]'); return Array.from(this.children).find(child => child.slot === 'invoker');
} }
// eslint-disable-next-line class-methods-use-this // eslint-disable-next-line class-methods-use-this

View file

@ -21,7 +21,7 @@ describe('lion-popup', () => {
<lion-button slot="invoker">Popup button</lion-button> <lion-button slot="invoker">Popup button</lion-button>
</lion-popup> </lion-popup>
`); `);
const invoker = el.querySelector('[slot="invoker"]'); const invoker = Array.from(el.children).find(child => child.slot === 'invoker');
invoker.click(); invoker.click();
await el.updateComplete; await el.updateComplete;
@ -38,7 +38,7 @@ describe('lion-popup', () => {
<lion-button slot="invoker">Popup button</lion-button> <lion-button slot="invoker">Popup button</lion-button>
</lion-popup> </lion-popup>
`); `);
const invoker = el.querySelector('[slot="invoker"]'); const invoker = Array.from(el.children).find(child => child.slot === 'invoker');
const event = new Event('click'); const event = new Event('click');
invoker.dispatchEvent(event); invoker.dispatchEvent(event);
await el.updateComplete; await el.updateComplete;

View file

@ -95,12 +95,13 @@ export class LionSelectRich extends OverlayMixin(
} }
get _invokerNode() { get _invokerNode() {
return this.querySelector('[slot=invoker]'); return Array.from(this.children).find(child => child.slot === 'invoker');
} }
get _listboxNode() { get _listboxNode() {
return ( return (
(this._overlayCtrl && this._overlayCtrl.contentNode) || this.querySelector('[slot=input]') (this._overlayCtrl && this._overlayCtrl.contentNode) ||
Array.from(this.children).find(child => child.slot === 'input')
); );
} }

View file

@ -7,7 +7,7 @@ describe('lion-switch', () => {
const el = await fixture(html` const el = await fixture(html`
<lion-switch></lion-switch> <lion-switch></lion-switch>
`); `);
expect(el.querySelector('[slot="input"]')).not.to.be.false; expect(Array.from(el.children).find(child => child.slot === 'input')).not.to.be.false;
}); });
it('should sync its "disabled" state to child button', async () => { it('should sync its "disabled" state to child button', async () => {

View file

@ -216,8 +216,12 @@ export class LionTabs extends LitElement {
if (!(this.__store && this.__store[this.selectedIndex])) { if (!(this.__store && this.__store[this.selectedIndex])) {
return; return;
} }
const previousButton = this.querySelector('[slot="tab"][selected]'); const previousButton = Array.from(this.children).find(
const previousPanel = this.querySelector('[slot="panel"][selected]'); child => child.slot === 'tab' && child.hasAttribute('selected'),
);
const previousPanel = Array.from(this.children).find(
child => child.slot === 'panel' && child.hasAttribute('selected'),
);
if (previousButton) { if (previousButton) {
deselectButton(previousButton); deselectButton(previousButton);
} }

View file

@ -31,10 +31,18 @@ describe('<lion-tabs>', () => {
</lion-tabs> </lion-tabs>
`); `);
expect(el.selectedIndex).to.equal(1); expect(el.selectedIndex).to.equal(1);
expect(el.querySelector('[slot=tab][selected]').textContent).to.equal('tab 2'); expect(
Array.from(el.children).find(
child => child.slot === 'tab' && child.hasAttribute('selected'),
).textContent,
).to.equal('tab 2');
el.selectedIndex = 0; el.selectedIndex = 0;
expect(el.querySelector('[slot=tab][selected]').textContent).to.equal('tab 1'); expect(
Array.from(el.children).find(
child => child.slot === 'tab' && child.hasAttribute('selected'),
).textContent,
).to.equal('tab 1');
}); });
it('has [selected] on current selected tab which serves as styling hook', async () => { it('has [selected] on current selected tab which serves as styling hook', async () => {
@ -79,7 +87,10 @@ describe('<lion-tabs>', () => {
<div slot="panel">panel</div> <div slot="panel">panel</div>
</lion-tabs> </lion-tabs>
`); `);
expect(el.querySelector('[slot=tab]')).to.have.attribute('role', 'tab'); expect(Array.from(el.children).find(child => child.slot === 'tab')).to.have.attribute(
'role',
'tab',
);
}); });
/** /**
@ -219,8 +230,16 @@ describe('<lion-tabs>', () => {
} }
el.selectedIndex = el.children.length / 2 - 1; el.selectedIndex = el.children.length / 2 - 1;
await el.updateComplete; await el.updateComplete;
expect(el.querySelector('[slot=tab][selected]').textContent).to.equal('tab 5'); expect(
expect(el.querySelector('[slot=panel][selected]').textContent).to.equal('panel 5'); Array.from(el.children).find(
child => child.slot === 'tab' && child.hasAttribute('selected'),
).textContent,
).to.equal('tab 5');
expect(
Array.from(el.children).find(
child => child.slot === 'panel' && child.hasAttribute('selected'),
).textContent,
).to.equal('panel 5');
}); });
}); });
@ -234,8 +253,12 @@ describe('<lion-tabs>', () => {
<div slot="panel">panel 2</div> <div slot="panel">panel 2</div>
</lion-tabs> </lion-tabs>
`); `);
expect(el.querySelector('[slot=panel]')).to.not.have.attribute('tabindex'); expect(Array.from(el.children).find(child => child.slot === 'panel')).to.not.have.attribute(
expect(el.querySelector('[slot=panel]')).to.not.have.attribute('tabindex'); 'tabindex',
);
expect(Array.from(el.children).find(child => child.slot === 'panel')).to.not.have.attribute(
'tabindex',
);
}); });
it('makes selected tab focusable (other tabs are unfocusable)', async () => { it('makes selected tab focusable (other tabs are unfocusable)', async () => {

View file

@ -55,7 +55,7 @@ describe('lion-tooltip', () => {
<lion-button slot="invoker">Tooltip button</lion-button> <lion-button slot="invoker">Tooltip button</lion-button>
</lion-tooltip> </lion-tooltip>
`); `);
const invoker = el.querySelector('[slot="invoker"]'); const invoker = Array.from(el.children).find(child => child.slot === 'invoker');
const eventFocusIn = new Event('focusin'); const eventFocusIn = new Event('focusin');
invoker.dispatchEvent(eventFocusIn); invoker.dispatchEvent(eventFocusIn);
await el.updateComplete; await el.updateComplete;
@ -73,7 +73,7 @@ describe('lion-tooltip', () => {
<lion-button slot="invoker">Tooltip button</lion-button> <lion-button slot="invoker">Tooltip button</lion-button>
</lion-tooltip> </lion-tooltip>
`); `);
const invoker = el.querySelector('[slot="invoker"]'); const invoker = Array.from(el.children).find(child => child.slot === 'invoker');
const eventFocusIn = new Event('focusin'); const eventFocusIn = new Event('focusin');
invoker.dispatchEvent(eventFocusIn); invoker.dispatchEvent(eventFocusIn);
await el.updateComplete; await el.updateComplete;
@ -93,7 +93,7 @@ describe('lion-tooltip', () => {
<lion-button slot="invoker">Tooltip button</lion-button> <lion-button slot="invoker">Tooltip button</lion-button>
</lion-tooltip> </lion-tooltip>
`); `);
const invoker = el.querySelector('[slot="invoker"]'); const invoker = Array.from(el.children).find(child => child.slot === 'invoker');
const event = new Event('mouseenter'); const event = new Event('mouseenter');
invoker.dispatchEvent(event); invoker.dispatchEvent(event);
await el.updateComplete; await el.updateComplete;
@ -109,8 +109,11 @@ describe('lion-tooltip', () => {
<lion-button slot="invoker">Tooltip button</lion-button> <lion-button slot="invoker">Tooltip button</lion-button>
</lion-tooltip> </lion-tooltip>
`); `);
const invoker = el.querySelector('[slot="content"]');
expect(invoker.getAttribute('role')).to.be.equal('tooltip'); // FIXME: This should be refactored to Array.from(this.children).find(child => child.slot === 'content')
// When this issue is fixed https://github.com/ing-bank/lion/issues/382
const content = el.querySelector('[slot=content]');
expect(content.getAttribute('role')).to.be.equal('tooltip');
}); });
}); });
}); });

View file

@ -294,11 +294,11 @@ export const ValidateMixin = dedupeMixin(
} }
get _feedbackElement() { get _feedbackElement() {
return this.querySelector('[slot="feedback"]'); return Array.from(this.children).find(child => child.slot === 'feedback');
} }
getFieldName(validatorParams) { getFieldName(validatorParams) {
const labelEl = this.querySelector('[slot=label]'); const labelEl = Array.from(this.children).find(child => child.slot === 'label');
const label = this.label || (labelEl && labelEl.textContent); const label = this.label || (labelEl && labelEl.textContent);
if (validatorParams && validatorParams.fieldName) { if (validatorParams && validatorParams.fieldName) {

View file

@ -707,13 +707,15 @@ describe('ValidateMixin', () => {
>${lightDom}</${tag}> >${lightDom}</${tag}>
`); `);
expect(el.querySelector('[slot=feedback]').innerText).to.equal(''); expect(Array.from(el.children).find(child => child.slot === 'feedback').innerText).to.equal(
'',
);
showErrors = true; showErrors = true;
el.validate(); el.validate();
await el.updateComplete; await el.updateComplete;
expect(el.querySelector('[slot=feedback]').innerText).to.equal( expect(Array.from(el.children).find(child => child.slot === 'feedback').innerText).to.equal(
'This is error message for alwaysFalse', 'This is error message for alwaysFalse',
); );
}); });
@ -725,9 +727,9 @@ describe('ValidateMixin', () => {
.errorValidators=${[[alwaysFalse]]} .errorValidators=${[[alwaysFalse]]}
>${lightDom}</${tag}> >${lightDom}</${tag}>
`); `);
expect(feedbackResult.querySelector('[slot=feedback]').innerText).to.equal( expect(
'This is error message for alwaysFalse', Array.from(feedbackResult.children).find(child => child.slot === 'feedback').innerText,
); ).to.equal('This is error message for alwaysFalse');
}); });
it('rerenders validation outcome to *feedback-element*, when dependent on async resources', async () => { it('rerenders validation outcome to *feedback-element*, when dependent on async resources', async () => {
@ -739,7 +741,9 @@ describe('ValidateMixin', () => {
>${lightDom}</${tag}> >${lightDom}</${tag}>
`); `);
expect(feedbackResult.querySelector('[slot=feedback]').innerText).to.equal(''); expect(
Array.from(feedbackResult.children).find(child => child.slot === 'feedback').innerText,
).to.equal('');
// locale changed or smth // locale changed or smth
localize.reset(); localize.reset();
localize.addData('en-GB', 'lion-validate', { localize.addData('en-GB', 'lion-validate', {
@ -747,9 +751,9 @@ describe('ValidateMixin', () => {
}); });
feedbackResult.onLocaleUpdated(); feedbackResult.onLocaleUpdated();
expect(feedbackResult.querySelector('[slot=feedback]').innerText).to.equal( expect(
'error:alwaysFalseAsyncTransl', Array.from(feedbackResult.children).find(child => child.slot === 'feedback').innerText,
); ).to.equal('error:alwaysFalseAsyncTransl');
}); });
it('allows to overwrite the way messages are translated', async () => { it('allows to overwrite the way messages are translated', async () => {
@ -770,15 +774,15 @@ describe('ValidateMixin', () => {
>${lightDom}</${tag}> >${lightDom}</${tag}>
`); `);
expect(customTranslations.querySelector('[slot=feedback]').innerText).to.equal( expect(
'You should have a lowercase a', Array.from(customTranslations.children).find(child => child.slot === 'feedback').innerText,
); ).to.equal('You should have a lowercase a');
customTranslations.modelValue = 'cat'; customTranslations.modelValue = 'cat';
await customTranslations.updateComplete; await customTranslations.updateComplete;
expect(customTranslations.querySelector('[slot=feedback]').innerText).to.equal( expect(
'You can not pass', Array.from(customTranslations.children).find(child => child.slot === 'feedback').innerText,
); ).to.equal('You can not pass');
}); });
it('allows to overwrite the way messages are rendered/added to dom', async () => { it('allows to overwrite the way messages are rendered/added to dom', async () => {
@ -842,13 +846,15 @@ describe('ValidateMixin', () => {
element.modelValue = 'dog'; element.modelValue = 'dog';
await element.updateComplete; await element.updateComplete;
expect(element.querySelector('[slot=feedback]').innerText).to.equal( expect(
'ERROR on containsLowercaseA', Array.from(element.children).find(child => child.slot === 'feedback').innerText,
); ).to.equal('ERROR on containsLowercaseA');
element.modelValue = 'cat'; element.modelValue = 'cat';
await element.updateComplete; await element.updateComplete;
expect(element.querySelector('[slot=feedback]').innerText).to.equal('ERROR on alwaysFalse'); expect(
Array.from(element.children).find(child => child.slot === 'feedback').innerText,
).to.equal('ERROR on alwaysFalse');
}); });
it('allows to create a custom feedback renderer via the template [to-be-implemented]', async () => { it('allows to create a custom feedback renderer via the template [to-be-implemented]', async () => {
@ -868,21 +874,21 @@ describe('ValidateMixin', () => {
validityFeedback.modelValue = 'a'; validityFeedback.modelValue = 'a';
await validityFeedback.updateComplete; await validityFeedback.updateComplete;
expect(validityFeedback.querySelector('[slot=feedback]').innerText).to.equal( expect(
'This is error message for minLength', Array.from(validityFeedback.children).find(child => child.slot === 'feedback').innerText,
); ).to.equal('This is error message for minLength');
validityFeedback.modelValue = 'abc'; validityFeedback.modelValue = 'abc';
await validityFeedback.updateComplete; await validityFeedback.updateComplete;
expect(validityFeedback.querySelector('[slot=feedback]').innerText).to.equal( expect(
'This is warning message for minLength', Array.from(validityFeedback.children).find(child => child.slot === 'feedback').innerText,
); ).to.equal('This is warning message for minLength');
validityFeedback.modelValue = 'abcde'; validityFeedback.modelValue = 'abcde';
await validityFeedback.updateComplete; await validityFeedback.updateComplete;
expect(validityFeedback.querySelector('[slot=feedback]').innerText).to.equal( expect(
'This is info message for minLength', Array.from(validityFeedback.children).find(child => child.slot === 'feedback').innerText,
); ).to.equal('This is info message for minLength');
}); });
it('shows success message after fixing an error', async () => { it('shows success message after fixing an error', async () => {
@ -896,15 +902,15 @@ describe('ValidateMixin', () => {
validityFeedback.modelValue = 'a'; validityFeedback.modelValue = 'a';
await validityFeedback.updateComplete; await validityFeedback.updateComplete;
expect(validityFeedback.querySelector('[slot=feedback]').innerText).to.equal( expect(
'This is error message for minLength', Array.from(validityFeedback.children).find(child => child.slot === 'feedback').innerText,
); ).to.equal('This is error message for minLength');
validityFeedback.modelValue = 'abcd'; validityFeedback.modelValue = 'abcd';
await validityFeedback.updateComplete; await validityFeedback.updateComplete;
expect(validityFeedback.querySelector('[slot=feedback]').innerText).to.equal( expect(
'This is success message for alwaysFalse', Array.from(validityFeedback.children).find(child => child.slot === 'feedback').innerText,
); ).to.equal('This is success message for alwaysFalse');
}); });
it(`shows only highest priority validation message determined by order of assignment of it(`shows only highest priority validation message determined by order of assignment of
@ -917,25 +923,27 @@ describe('ValidateMixin', () => {
`); `);
validityFeedback.modelValue = 'dog and dog'; validityFeedback.modelValue = 'dog and dog';
await validityFeedback.updateComplete; await validityFeedback.updateComplete;
expect(validityFeedback.querySelector('[slot=feedback]').innerText).to.equal( expect(
'This is error message for containsCat', Array.from(validityFeedback.children).find(child => child.slot === 'feedback').innerText,
); ).to.equal('This is error message for containsCat');
validityFeedback.modelValue = 'dog'; validityFeedback.modelValue = 'dog';
await validityFeedback.updateComplete; await validityFeedback.updateComplete;
expect(validityFeedback.querySelector('[slot=feedback]').innerText).to.equal( expect(
'This is error message for containsCat', Array.from(validityFeedback.children).find(child => child.slot === 'feedback').innerText,
); ).to.equal('This is error message for containsCat');
validityFeedback.modelValue = 'cat'; validityFeedback.modelValue = 'cat';
await validityFeedback.updateComplete; await validityFeedback.updateComplete;
expect(validityFeedback.querySelector('[slot=feedback]').innerText).to.equal( expect(
'This is error message for minLength', Array.from(validityFeedback.children).find(child => child.slot === 'feedback').innerText,
); ).to.equal('This is error message for minLength');
validityFeedback.modelValue = 'dog and cat'; validityFeedback.modelValue = 'dog and cat';
await validityFeedback.updateComplete; await validityFeedback.updateComplete;
expect(validityFeedback.querySelector('[slot=feedback]').innerText).to.equal(''); expect(
Array.from(validityFeedback.children).find(child => child.slot === 'feedback').innerText,
).to.equal('');
}); });
it('supports randomized selection of multiple messages for the same validator', async () => { it('supports randomized selection of multiple messages for the same validator', async () => {
@ -999,13 +1007,15 @@ describe('ValidateMixin', () => {
'Good job!', 'Good job!',
); );
expect(randomTranslations.querySelector('[slot=feedback]').innerText).to.equal( expect(
'You should have a lowercase a', Array.from(randomTranslations.children).find(child => child.slot === 'feedback').innerText,
); ).to.equal('You should have a lowercase a');
randomTranslations.modelValue = 'cat'; randomTranslations.modelValue = 'cat';
await randomTranslations.updateComplete; await randomTranslations.updateComplete;
expect(randomTranslations.querySelector('[slot=feedback]').innerText).to.equal('Good job!'); expect(
Array.from(randomTranslations.children).find(child => child.slot === 'feedback').innerText,
).to.equal('Good job!');
Math.random = () => 0.25; Math.random = () => 0.25;
randomTranslations.__lastGetSuccessResult = false; randomTranslations.__lastGetSuccessResult = false;
@ -1013,9 +1023,9 @@ describe('ValidateMixin', () => {
randomTranslations.modelValue = 'cat'; randomTranslations.modelValue = 'cat';
await randomTranslations.updateComplete; await randomTranslations.updateComplete;
expect(randomTranslations.querySelector('[slot=feedback]').innerText).to.equal( expect(
'You did great!', Array.from(randomTranslations.children).find(child => child.slot === 'feedback').innerText,
); ).to.equal('You did great!');
Math.random = mathRandom; // manually restore Math.random = mathRandom; // manually restore
}); });
@ -1043,15 +1053,15 @@ describe('ValidateMixin', () => {
errorValidators: [[minLength, { min: 4 }]], errorValidators: [[minLength, { min: 4 }]],
}), }),
); );
expect(validityFeedback.querySelector('[slot=feedback]').innerText).to.equal( expect(
'You need to enter at least 4 characters.', Array.from(validityFeedback.children).find(child => child.slot === 'feedback').innerText,
); ).to.equal('You need to enter at least 4 characters.');
localize.locale = 'de-DE'; localize.locale = 'de-DE';
await validityFeedback.updateComplete; await validityFeedback.updateComplete;
expect(validityFeedback.querySelector('[slot=feedback]').innerText).to.equal( expect(
'Es müssen mindestens 4 Zeichen eingegeben werden.', Array.from(validityFeedback.children).find(child => child.slot === 'feedback').innerText,
); ).to.equal('Es müssen mindestens 4 Zeichen eingegeben werden.');
}); });
describe('Field name', () => { describe('Field name', () => {
@ -1070,7 +1080,7 @@ describe('ValidateMixin', () => {
.modelValue=${'cat'} .modelValue=${'cat'}
>${lightDom}</${tag}> >${lightDom}</${tag}>
`); `);
expect(el.querySelector('[slot=feedback]').innerText).to.equal( expect(Array.from(el.children).find(child => child.slot === 'feedback').innerText).to.equal(
'myField needs more characters', 'myField needs more characters',
); );
}); });
@ -1084,9 +1094,9 @@ describe('ValidateMixin', () => {
]} .modelValue=${'cat'} ]} .modelValue=${'cat'}
>${lightDom} >${lightDom}
</${elNameStatic}>`); </${elNameStatic}>`);
expect(validityFeedback.querySelector('[slot=feedback]').innerText).to.equal( expect(
'overrideName needs more characters', Array.from(validityFeedback.children).find(child => child.slot === 'feedback').innerText,
); ).to.equal('overrideName needs more characters');
}); });
it('constructs field name from label or name (in this priority order)', async () => { it('constructs field name from label or name (in this priority order)', async () => {
@ -1098,18 +1108,18 @@ describe('ValidateMixin', () => {
.errorValidators=${[[minLength, { min: 4 }]]} .modelValue=${'cat'} .errorValidators=${[[minLength, { min: 4 }]]} .modelValue=${'cat'}
>${lightDom} >${lightDom}
</${elNameStatic}>`); </${elNameStatic}>`);
expect(validityFeedback.querySelector('[slot=feedback]').innerText).to.equal( expect(
'myField needs more characters', Array.from(validityFeedback.children).find(child => child.slot === 'feedback').innerText,
); ).to.equal('myField needs more characters');
const validityFeedback2 = await fixture(html` const validityFeedback2 = await fixture(html`
<${elNameStatic} .name="${'myName'}" <${elNameStatic} .name="${'myName'}"
.errorValidators=${[[minLength, { min: 4 }]]} .modelValue=${'cat'} .errorValidators=${[[minLength, { min: 4 }]]} .modelValue=${'cat'}
>${lightDom} >${lightDom}
</${elNameStatic}>`); </${elNameStatic}>`);
expect(validityFeedback2.querySelector('[slot=feedback]').innerText).to.equal( expect(
'myName needs more characters', Array.from(validityFeedback2.children).find(child => child.slot === 'feedback').innerText,
); ).to.equal('myName needs more characters');
}); });
}); });
@ -1150,13 +1160,15 @@ describe('ValidateMixin', () => {
element.modelValue = 'dog'; element.modelValue = 'dog';
await element.updateComplete; await element.updateComplete;
expect(element.querySelector('[slot=feedback]').innerText).to.equal( expect(
'ERROR on containsLowercaseA', Array.from(element.children).find(child => child.slot === 'feedback').innerText,
); ).to.equal('ERROR on containsLowercaseA');
element.modelValue = 'cat'; element.modelValue = 'cat';
await element.updateComplete; await element.updateComplete;
expect(element.querySelector('[slot=feedback]').innerText).to.equal(''); expect(
Array.from(element.children).find(child => child.slot === 'feedback').innerText,
).to.equal('');
}); });
}); });
@ -1209,7 +1221,7 @@ describe('ValidateMixin', () => {
}, },
}); });
el._createMessageAndRenderFeedback(); el._createMessageAndRenderFeedback();
expect(el.querySelector('[slot=feedback]').innerText).to.equal( expect(Array.from(el.children).find(child => child.slot === 'feedback').innerText).to.equal(
'lion-validate : orderValidator', 'lion-validate : orderValidator',
); );
@ -1220,7 +1232,7 @@ describe('ValidateMixin', () => {
}, },
}); });
el._createMessageAndRenderFeedback(); el._createMessageAndRenderFeedback();
expect(el.querySelector('[slot=feedback]').innerText).to.equal( expect(Array.from(el.children).find(child => child.slot === 'feedback').innerText).to.equal(
'lion-validate+orderValidator : orderValidator', 'lion-validate+orderValidator : orderValidator',
); );
}); });
@ -1269,7 +1281,7 @@ describe('ValidateMixin', () => {
}, },
}); });
el._createMessageAndRenderFeedback(); el._createMessageAndRenderFeedback();
expect(el.querySelector('[slot=feedback]').innerText).to.equal( expect(Array.from(el.children).find(child => child.slot === 'feedback').innerText).to.equal(
'lion-validate : is12Validator', 'lion-validate : is12Validator',
); );
@ -1280,7 +1292,7 @@ describe('ValidateMixin', () => {
}, },
}); });
el._createMessageAndRenderFeedback(); el._createMessageAndRenderFeedback();
expect(el.querySelector('[slot=feedback]').innerText).to.equal( expect(Array.from(el.children).find(child => child.slot === 'feedback').innerText).to.equal(
'lion-validate+is12Validator : is12Validator', 'lion-validate+is12Validator : is12Validator',
); );
@ -1291,7 +1303,7 @@ describe('ValidateMixin', () => {
}, },
}); });
el._createMessageAndRenderFeedback(); el._createMessageAndRenderFeedback();
expect(el.querySelector('[slot=feedback]').innerText).to.equal( expect(Array.from(el.children).find(child => child.slot === 'feedback').innerText).to.equal(
'my-custom-namespace : is12Validator', 'my-custom-namespace : is12Validator',
); );
@ -1302,7 +1314,7 @@ describe('ValidateMixin', () => {
}, },
}); });
el._createMessageAndRenderFeedback(); el._createMessageAndRenderFeedback();
expect(el.querySelector('[slot=feedback]').innerText).to.equal( expect(Array.from(el.children).find(child => child.slot === 'feedback').innerText).to.equal(
'my-custom-namespace+is12Validator : is12Validator', 'my-custom-namespace+is12Validator : is12Validator',
); );
}); });