Merge pull request #241 from ing-bank/fix/formRegIssues
Fix/form reg issues
This commit is contained in:
commit
dbff4bfc55
8 changed files with 390 additions and 332 deletions
|
|
@ -43,6 +43,7 @@
|
||||||
"test:update-snapshots": "karma start --update-snapshots",
|
"test:update-snapshots": "karma start --update-snapshots",
|
||||||
"test:prune-snapshots": "karma start --prune-snapshots",
|
"test:prune-snapshots": "karma start --prune-snapshots",
|
||||||
"test:bs": "karma start karma.bs.config.js --coverage",
|
"test:bs": "karma start karma.bs.config.js --coverage",
|
||||||
|
"test:bs:legacy": "karma start --legacy karma.bs.config.js --coverage",
|
||||||
"lint": "run-p lint:*",
|
"lint": "run-p lint:*",
|
||||||
"lint:eclint": "git ls-files | xargs eclint check",
|
"lint:eclint": "git ls-files | xargs eclint check",
|
||||||
"lint:eslint": "eslint --ext .js,.html .",
|
"lint:eslint": "eslint --ext .js,.html .",
|
||||||
|
|
|
||||||
|
|
@ -29,19 +29,14 @@ export const FormRegisteringMixin = dedupeMixin(
|
||||||
|
|
||||||
__setupRegistrationHook() {
|
__setupRegistrationHook() {
|
||||||
if (formRegistrarManager.ready) {
|
if (formRegistrarManager.ready) {
|
||||||
this._registerFormElement();
|
this._dispatchRegistration();
|
||||||
} else {
|
} else {
|
||||||
formRegistrarManager.addEventListener('all-forms-open-for-registration', () => {
|
formRegistrarManager.addEventListener('all-forms-open-for-registration', () => {
|
||||||
this._registerFormElement();
|
this._dispatchRegistration();
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
_registerFormElement() {
|
|
||||||
this._dispatchRegistration();
|
|
||||||
this._requestParentFormGroupUpdateOfResetModelValue();
|
|
||||||
}
|
|
||||||
|
|
||||||
_dispatchRegistration() {
|
_dispatchRegistration() {
|
||||||
this.dispatchEvent(
|
this.dispatchEvent(
|
||||||
new CustomEvent('form-element-register', {
|
new CustomEvent('form-element-register', {
|
||||||
|
|
@ -56,16 +51,5 @@ export const FormRegisteringMixin = dedupeMixin(
|
||||||
this.__parentFormGroup.removeFormElement(this);
|
this.__parentFormGroup.removeFormElement(this);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
|
||||||
* Makes sure our parentFormGroup has the most up to date resetModelValue
|
|
||||||
* FormGroups will call the same on their parentFormGroup so the full tree gets the correct
|
|
||||||
* values.
|
|
||||||
*/
|
|
||||||
_requestParentFormGroupUpdateOfResetModelValue() {
|
|
||||||
if (this.__parentFormGroup && this.__parentFormGroup._updateResetModelValue) {
|
|
||||||
this.__parentFormGroup._updateResetModelValue();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
},
|
},
|
||||||
);
|
);
|
||||||
|
|
|
||||||
|
|
@ -101,6 +101,11 @@ export class LionField extends FormControlMixin(
|
||||||
this.submitted = false;
|
this.submitted = false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
firstUpdated(c) {
|
||||||
|
super.firstUpdated(c);
|
||||||
|
this._initialModelValue = this.modelValue;
|
||||||
|
}
|
||||||
|
|
||||||
connectedCallback() {
|
connectedCallback() {
|
||||||
// TODO: Normally we put super calls on top for predictability,
|
// TODO: Normally we put super calls on top for predictability,
|
||||||
// here we temporarily need to do attribute delegation before,
|
// here we temporarily need to do attribute delegation before,
|
||||||
|
|
@ -117,14 +122,6 @@ export class LionField extends FormControlMixin(
|
||||||
|
|
||||||
disconnectedCallback() {
|
disconnectedCallback() {
|
||||||
super.disconnectedCallback();
|
super.disconnectedCallback();
|
||||||
|
|
||||||
if (this.__parentFormGroup) {
|
|
||||||
const event = new CustomEvent('form-element-unregister', {
|
|
||||||
detail: { element: this },
|
|
||||||
bubbles: true,
|
|
||||||
});
|
|
||||||
this.__parentFormGroup.dispatchEvent(event);
|
|
||||||
}
|
|
||||||
this.inputElement.removeEventListener('change', this._onChange);
|
this.inputElement.removeEventListener('change', this._onChange);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -164,6 +161,11 @@ export class LionField extends FormControlMixin(
|
||||||
this.submitted = false;
|
this.submitted = false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
reset() {
|
||||||
|
this.modelValue = this._initialModelValue;
|
||||||
|
this.resetInteractionState();
|
||||||
|
}
|
||||||
|
|
||||||
clear() {
|
clear() {
|
||||||
if (super.clear) {
|
if (super.clear) {
|
||||||
// Let validationMixin and interactionStateMixin clear their
|
// Let validationMixin and interactionStateMixin clear their
|
||||||
|
|
|
||||||
121
packages/field/test-suites/FormRegistrationMixins.suite.js
Normal file
121
packages/field/test-suites/FormRegistrationMixins.suite.js
Normal file
|
|
@ -0,0 +1,121 @@
|
||||||
|
import { expect, fixture, html, defineCE, unsafeStatic } from '@open-wc/testing';
|
||||||
|
import { LitElement } from '@lion/core';
|
||||||
|
|
||||||
|
import { FormRegistrarMixin } from '../src/FormRegistrarMixin.js';
|
||||||
|
import { FormRegisteringMixin } from '../src/FormRegisteringMixin.js';
|
||||||
|
import { formRegistrarManager } from '../src/formRegistrarManager.js';
|
||||||
|
|
||||||
|
export const runRegistrationSuite = customConfig => {
|
||||||
|
const cfg = {
|
||||||
|
baseElement: HTMLElement,
|
||||||
|
suffix: null,
|
||||||
|
...customConfig,
|
||||||
|
};
|
||||||
|
|
||||||
|
describe(`FormRegistrationMixins${cfg.suffix ? ` (${cfg.suffix})` : ''}`, () => {
|
||||||
|
let parentTag;
|
||||||
|
let childTag;
|
||||||
|
|
||||||
|
before(async () => {
|
||||||
|
if (!cfg.parentTagString) {
|
||||||
|
cfg.parentTagString = defineCE(class extends FormRegistrarMixin(cfg.baseElement) {});
|
||||||
|
}
|
||||||
|
if (!cfg.childTagString) {
|
||||||
|
cfg.childTagString = defineCE(class extends FormRegisteringMixin(cfg.baseElement) {});
|
||||||
|
}
|
||||||
|
|
||||||
|
parentTag = unsafeStatic(cfg.parentTagString);
|
||||||
|
childTag = unsafeStatic(cfg.childTagString);
|
||||||
|
});
|
||||||
|
|
||||||
|
it('can register a formElement', async () => {
|
||||||
|
const el = await fixture(html`
|
||||||
|
<${parentTag}>
|
||||||
|
<${childTag}></${childTag}>
|
||||||
|
</${parentTag}>
|
||||||
|
`);
|
||||||
|
await el.registrationReady;
|
||||||
|
expect(el.formElements.length).to.equal(1);
|
||||||
|
});
|
||||||
|
|
||||||
|
it('supports nested registration parents', async () => {
|
||||||
|
const el = await fixture(html`
|
||||||
|
<${parentTag}>
|
||||||
|
<${parentTag}>
|
||||||
|
<${childTag}></${childTag}>
|
||||||
|
<${childTag}></${childTag}>
|
||||||
|
</${parentTag}>
|
||||||
|
</${parentTag}>
|
||||||
|
`);
|
||||||
|
await el.registrationReady;
|
||||||
|
expect(el.formElements.length).to.equal(1);
|
||||||
|
expect(el.querySelector(cfg.parentTagString).formElements.length).to.equal(2);
|
||||||
|
});
|
||||||
|
|
||||||
|
it('forgets disconnected registrars', async () => {
|
||||||
|
const el = await fixture(html`
|
||||||
|
<${parentTag}>
|
||||||
|
<${parentTag}>
|
||||||
|
<${childTag}</${childTag}
|
||||||
|
</${parentTag}>
|
||||||
|
</${parentTag}>
|
||||||
|
`);
|
||||||
|
|
||||||
|
const secondRegistrar = await fixture(html`
|
||||||
|
<${parentTag}>
|
||||||
|
<${childTag}</${childTag}
|
||||||
|
</${parentTag}>
|
||||||
|
`);
|
||||||
|
|
||||||
|
el.appendChild(secondRegistrar);
|
||||||
|
expect(formRegistrarManager.__elements.length).to.equal(3);
|
||||||
|
|
||||||
|
el.removeChild(secondRegistrar);
|
||||||
|
expect(formRegistrarManager.__elements.length).to.equal(2);
|
||||||
|
});
|
||||||
|
|
||||||
|
it('works for components that have a delayed render', async () => {
|
||||||
|
const tagWrapperString = defineCE(
|
||||||
|
class extends FormRegistrarMixin(LitElement) {
|
||||||
|
async performUpdate() {
|
||||||
|
await new Promise(resolve => setTimeout(() => resolve(), 10));
|
||||||
|
await super.performUpdate();
|
||||||
|
}
|
||||||
|
|
||||||
|
render() {
|
||||||
|
return html`
|
||||||
|
<slot></slot>
|
||||||
|
`;
|
||||||
|
}
|
||||||
|
},
|
||||||
|
);
|
||||||
|
const tagWrapper = unsafeStatic(tagWrapperString);
|
||||||
|
const el = await fixture(html`
|
||||||
|
<${tagWrapper}>
|
||||||
|
<${childTag}></${childTag}>
|
||||||
|
</${tagWrapper}>
|
||||||
|
`);
|
||||||
|
await el.registrationReady;
|
||||||
|
expect(el.formElements.length).to.equal(1);
|
||||||
|
});
|
||||||
|
|
||||||
|
it('can dynamically add/remove elements', async () => {
|
||||||
|
const el = await fixture(html`
|
||||||
|
<${parentTag}>
|
||||||
|
<${childTag}></${childTag}>
|
||||||
|
</${parentTag}>
|
||||||
|
`);
|
||||||
|
const newField = await fixture(html`
|
||||||
|
<${childTag}></${childTag}>
|
||||||
|
`);
|
||||||
|
|
||||||
|
expect(el.formElements.length).to.equal(1);
|
||||||
|
|
||||||
|
el.appendChild(newField);
|
||||||
|
expect(el.formElements.length).to.equal(2);
|
||||||
|
|
||||||
|
el.removeChild(newField);
|
||||||
|
expect(el.formElements.length).to.equal(1);
|
||||||
|
});
|
||||||
|
});
|
||||||
|
};
|
||||||
|
|
@ -1,129 +1,19 @@
|
||||||
import { expect, fixture, html, defineCE, unsafeStatic } from '@open-wc/testing';
|
import { html } from '@open-wc/testing';
|
||||||
import sinon from 'sinon';
|
import { UpdatingElement, LitElement } from '@lion/core';
|
||||||
import { LitElement, UpdatingElement } from '@lion/core';
|
import { runRegistrationSuite } from '../test-suites/FormRegistrationMixins.suite.js';
|
||||||
|
|
||||||
import { formRegistrarManager } from '../src/formRegistrarManager.js';
|
runRegistrationSuite({
|
||||||
import { FormRegisteringMixin } from '../src/FormRegisteringMixin.js';
|
suffix: 'with UpdatingElement',
|
||||||
import { FormRegistrarMixin } from '../src/FormRegistrarMixin.js';
|
baseElement: UpdatingElement,
|
||||||
|
});
|
||||||
describe('FormRegistrationMixins', () => {
|
|
||||||
before(async () => {
|
runRegistrationSuite({
|
||||||
const FormRegistrarEl = class extends FormRegistrarMixin(UpdatingElement) {};
|
suffix: 'with LitElement, using shadow dom',
|
||||||
customElements.define('form-registrar', FormRegistrarEl);
|
baseElement: class ShadowElement extends LitElement {
|
||||||
const FormRegisteringEl = class extends FormRegisteringMixin(UpdatingElement) {};
|
render() {
|
||||||
customElements.define('form-registering', FormRegisteringEl);
|
return html`
|
||||||
});
|
<slot></slot>
|
||||||
|
`;
|
||||||
it('can register a formElement', async () => {
|
}
|
||||||
const el = await fixture(html`
|
},
|
||||||
<form-registrar>
|
|
||||||
<form-registering></form-registering>
|
|
||||||
</form-registrar>
|
|
||||||
`);
|
|
||||||
await el.registrationReady;
|
|
||||||
expect(el.formElements.length).to.equal(1);
|
|
||||||
});
|
|
||||||
|
|
||||||
it('supports nested registrar', async () => {
|
|
||||||
const el = await fixture(html`
|
|
||||||
<form-registrar>
|
|
||||||
<form-registrar>
|
|
||||||
<form-registering></form-registering>
|
|
||||||
</form-registrar>
|
|
||||||
</form-registrar>
|
|
||||||
`);
|
|
||||||
await el.registrationReady;
|
|
||||||
expect(el.formElements.length).to.equal(1);
|
|
||||||
expect(el.querySelector('form-registrar').formElements.length).to.equal(1);
|
|
||||||
});
|
|
||||||
|
|
||||||
it('forgets disconnected registrars', async () => {
|
|
||||||
const el = await fixture(html`
|
|
||||||
<form-registrar>
|
|
||||||
<form-registrar>
|
|
||||||
<form-registering></form-registering>
|
|
||||||
</form-registrar>
|
|
||||||
</form-registrar>
|
|
||||||
`);
|
|
||||||
|
|
||||||
const secondRegistrar = await fixture(html`
|
|
||||||
<form-registrar>
|
|
||||||
<form-registering></form-registering>
|
|
||||||
</form-registrar>
|
|
||||||
`);
|
|
||||||
|
|
||||||
el.appendChild(secondRegistrar);
|
|
||||||
expect(formRegistrarManager.__elements.length).to.equal(3);
|
|
||||||
|
|
||||||
el.removeChild(secondRegistrar);
|
|
||||||
expect(formRegistrarManager.__elements.length).to.equal(2);
|
|
||||||
});
|
|
||||||
|
|
||||||
it('works for component that have a delayed render', async () => {
|
|
||||||
const tagWrapperString = defineCE(
|
|
||||||
class extends FormRegistrarMixin(LitElement) {
|
|
||||||
async performUpdate() {
|
|
||||||
await new Promise(resolve => setTimeout(() => resolve(), 10));
|
|
||||||
await super.performUpdate();
|
|
||||||
}
|
|
||||||
|
|
||||||
render() {
|
|
||||||
return html`
|
|
||||||
<slot></slot>
|
|
||||||
`;
|
|
||||||
}
|
|
||||||
},
|
|
||||||
);
|
|
||||||
const tagWrapper = unsafeStatic(tagWrapperString);
|
|
||||||
const registerSpy = sinon.spy();
|
|
||||||
const el = await fixture(html`
|
|
||||||
<${tagWrapper} @form-element-register=${registerSpy}>
|
|
||||||
<form-registering></form-registering>
|
|
||||||
</${tagWrapper}>
|
|
||||||
`);
|
|
||||||
await el.registrationReady;
|
|
||||||
expect(el.formElements.length).to.equal(1);
|
|
||||||
});
|
|
||||||
|
|
||||||
it('requests update of the resetModelValue function of its parent formGroup', async () => {
|
|
||||||
const ParentFormGroupClass = class extends FormRegistrarMixin(LitElement) {
|
|
||||||
_updateResetModelValue() {
|
|
||||||
this.resetModelValue = 'foo';
|
|
||||||
}
|
|
||||||
};
|
|
||||||
const ChildFormGroupClass = class extends FormRegisteringMixin(LitElement) {
|
|
||||||
constructor() {
|
|
||||||
super();
|
|
||||||
this.__parentFormGroup = this.parentNode;
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
const parentClass = defineCE(ParentFormGroupClass);
|
|
||||||
const formGroup = unsafeStatic(parentClass);
|
|
||||||
const childClass = defineCE(ChildFormGroupClass);
|
|
||||||
const childFormGroup = unsafeStatic(childClass);
|
|
||||||
const parentFormEl = await fixture(html`
|
|
||||||
<${formGroup}><${childFormGroup} id="child" name="child[]"></${childFormGroup}></${formGroup}>
|
|
||||||
`);
|
|
||||||
expect(parentFormEl.resetModelValue).to.equal('foo');
|
|
||||||
});
|
|
||||||
|
|
||||||
it('can dynamically add/remove elements', async () => {
|
|
||||||
const el = await fixture(html`
|
|
||||||
<form-registrar>
|
|
||||||
<form-registering></form-registering>
|
|
||||||
</form-registrar>
|
|
||||||
`);
|
|
||||||
const newField = await fixture(html`
|
|
||||||
<form-registering></form-registering>
|
|
||||||
`);
|
|
||||||
|
|
||||||
expect(el.formElements.length).to.equal(1);
|
|
||||||
|
|
||||||
el.appendChild(newField);
|
|
||||||
expect(el.formElements.length).to.equal(2);
|
|
||||||
|
|
||||||
el.removeChild(newField);
|
|
||||||
expect(el.formElements.length).to.equal(1);
|
|
||||||
});
|
|
||||||
});
|
});
|
||||||
|
|
|
||||||
|
|
@ -31,12 +31,12 @@ 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(`<${tagString}>${inputSlotString}</${tagString}>`);
|
const el = await fixture(html`<${tag}>${inputSlot}</${tag}>`);
|
||||||
expect(el.$$slot('input').id).to.equal(el._inputId);
|
expect(el.$$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 () => {
|
||||||
const el = await fixture(`<${tagString}>${inputSlotString}</${tagString}>`);
|
const el = await fixture(html`<${tag}>${inputSlot}</${tag}>`);
|
||||||
const cbFocusHost = sinon.spy();
|
const cbFocusHost = sinon.spy();
|
||||||
el.addEventListener('focus', cbFocusHost);
|
el.addEventListener('focus', cbFocusHost);
|
||||||
const cbFocusNativeInput = sinon.spy();
|
const cbFocusNativeInput = sinon.spy();
|
||||||
|
|
@ -68,33 +68,30 @@ describe('<lion-field>', () => {
|
||||||
expect(cbBlurNativeInput.callCount).to.equal(2);
|
expect(cbBlurNativeInput.callCount).to.equal(2);
|
||||||
});
|
});
|
||||||
|
|
||||||
|
it('offers simple getter "this.focused" returning true/false for the current focus state', async () => {
|
||||||
|
const el = await fixture(html`<${tag}>${inputSlot}</${tag}>`);
|
||||||
|
expect(el.focused).to.equal(false);
|
||||||
|
await triggerFocusFor(el);
|
||||||
|
expect(el.focused).to.equal(true);
|
||||||
|
await triggerBlurFor(el);
|
||||||
|
expect(el.focused).to.equal(false);
|
||||||
|
});
|
||||||
|
|
||||||
it('can be disabled via attribute', async () => {
|
it('can be disabled via attribute', async () => {
|
||||||
const elDisabled = await fixture(`<${tagString} disabled>${inputSlotString}</${tagString}>`);
|
const elDisabled = await fixture(html`<${tag} disabled>${inputSlot}</${tag}>`);
|
||||||
expect(elDisabled.disabled).to.equal(true);
|
expect(elDisabled.disabled).to.equal(true);
|
||||||
expect(elDisabled.inputElement.disabled).to.equal(true);
|
expect(elDisabled.inputElement.disabled).to.equal(true);
|
||||||
});
|
});
|
||||||
|
|
||||||
it('can be disabled via property', async () => {
|
it('can be disabled via property', async () => {
|
||||||
const el = await fixture(`<${tagString}>${inputSlotString}</${tagString}>`);
|
const el = await fixture(html`<${tag}>${inputSlot}</${tag}>`);
|
||||||
el.disabled = true;
|
el.disabled = true;
|
||||||
await el.updateComplete;
|
await el.updateComplete;
|
||||||
expect(el.inputElement.disabled).to.equal(true);
|
expect(el.inputElement.disabled).to.equal(true);
|
||||||
});
|
});
|
||||||
|
|
||||||
// classes are added only for backward compatibility - they are deprecated
|
|
||||||
it('sets a state-disabled class when disabled', async () => {
|
|
||||||
const el = await fixture(`<${tagString} disabled>${inputSlotString}</${tagString}>`);
|
|
||||||
await el.updateComplete;
|
|
||||||
expect(el.classList.contains('state-disabled')).to.equal(true);
|
|
||||||
el.disabled = false;
|
|
||||||
await el.updateComplete;
|
|
||||||
expect(el.classList.contains('state-disabled')).to.equal(false);
|
|
||||||
});
|
|
||||||
|
|
||||||
it('can be cleared which erases value, validation and interaction states', async () => {
|
it('can be cleared which erases value, validation and interaction states', async () => {
|
||||||
const el = await fixture(
|
const el = await fixture(html`<${tag} value="Some value from attribute">${inputSlot}</${tag}>`);
|
||||||
`<${tagString} value="Some value from attribute">${inputSlotString}</${tagString}>`,
|
|
||||||
);
|
|
||||||
el.clear();
|
el.clear();
|
||||||
expect(el.value).to.equal('');
|
expect(el.value).to.equal('');
|
||||||
el.value = 'Some value from property';
|
el.value = 'Some value from property';
|
||||||
|
|
@ -103,35 +100,34 @@ describe('<lion-field>', () => {
|
||||||
expect(el.value).to.equal('');
|
expect(el.value).to.equal('');
|
||||||
});
|
});
|
||||||
|
|
||||||
|
it('can be reset which restores original modelValue', async () => {
|
||||||
|
const el = await fixture(html`
|
||||||
|
<${tag} .modelValue="${'foo'}">
|
||||||
|
${inputSlot}
|
||||||
|
</${tag}>`);
|
||||||
|
expect(el._initialModelValue).to.equal('foo');
|
||||||
|
el.modelValue = 'bar';
|
||||||
|
el.reset();
|
||||||
|
expect(el.modelValue).to.equal('foo');
|
||||||
|
});
|
||||||
|
|
||||||
it('reads initial value from attribute value', async () => {
|
it('reads initial value from attribute value', async () => {
|
||||||
const el = await fixture(`<${tagString} value="one">${inputSlotString}</${tagString}>`);
|
const el = await fixture(html`<${tag} value="one">${inputSlot}</${tag}>`);
|
||||||
expect(el.$$slot('input').value).to.equal('one');
|
expect(el.$$slot('input').value).to.equal('one');
|
||||||
});
|
});
|
||||||
|
|
||||||
it('delegates value property', async () => {
|
it('delegates value property', async () => {
|
||||||
const el = await fixture(`<${tagString}>${inputSlotString}</${tagString}>`);
|
const el = await fixture(html`<${tag}>${inputSlot}</${tag}>`);
|
||||||
expect(el.$$slot('input').value).to.equal('');
|
expect(el.$$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.$$slot('input').value).to.equal('one');
|
expect(el.$$slot('input').value).to.equal('one');
|
||||||
});
|
});
|
||||||
|
|
||||||
it('has a name which is reflected to an attribute and is synced down to the native input', async () => {
|
|
||||||
const el = await fixture(`<${tagString}>${inputSlotString}</${tagString}>`);
|
|
||||||
expect(el.name).to.equal('');
|
|
||||||
expect(el.getAttribute('name')).to.equal('');
|
|
||||||
expect(el.inputElement.getAttribute('name')).to.equal('');
|
|
||||||
|
|
||||||
el.name = 'foo';
|
|
||||||
await el.updateComplete;
|
|
||||||
expect(el.getAttribute('name')).to.equal('foo');
|
|
||||||
expect(el.inputElement.getAttribute('name')).to.equal('foo');
|
|
||||||
});
|
|
||||||
|
|
||||||
// TODO: find out if we could put all listeners on this.value (instead of this.inputElement.value)
|
// TODO: find out if we could put all listeners on this.value (instead of this.inputElement.value)
|
||||||
// and make it act on this.value again
|
// and make it act on this.value again
|
||||||
it('has a class "state-filled" if this.value is filled', async () => {
|
it('has a class "state-filled" if this.value is filled', async () => {
|
||||||
const el = await fixture(`<${tagString} value="filled">${inputSlotString}</${tagString}>`);
|
const el = await fixture(html`<${tag} value="filled">${inputSlot}</${tag}>`);
|
||||||
expect(el.classList.contains('state-filled')).to.equal(true);
|
expect(el.classList.contains('state-filled')).to.equal(true);
|
||||||
el.value = '';
|
el.value = '';
|
||||||
await el.updateComplete;
|
await el.updateComplete;
|
||||||
|
|
@ -142,7 +138,7 @@ describe('<lion-field>', () => {
|
||||||
});
|
});
|
||||||
|
|
||||||
it('preserves the caret position on value change for native text fields (input|textarea)', async () => {
|
it('preserves the caret position on value change for native text fields (input|textarea)', async () => {
|
||||||
const el = await fixture(`<${tagString}>${inputSlotString}</${tagString}>`);
|
const el = await fixture(html`<${tag}>${inputSlot}</${tag}>`);
|
||||||
await triggerFocusFor(el);
|
await triggerFocusFor(el);
|
||||||
await el.updateComplete;
|
await el.updateComplete;
|
||||||
el.inputElement.value = 'hello world';
|
el.inputElement.value = 'hello world';
|
||||||
|
|
@ -155,7 +151,7 @@ describe('<lion-field>', () => {
|
||||||
|
|
||||||
// TODO: add pointerEvents test for disabled
|
// TODO: add pointerEvents test for disabled
|
||||||
it('has a class "state-disabled"', async () => {
|
it('has a class "state-disabled"', async () => {
|
||||||
const el = await fixture(`<${tagString}>${inputSlotString}</${tagString}>`);
|
const el = await fixture(html`<${tag}>${inputSlot}</${tag}>`);
|
||||||
expect(el.classList.contains('state-disabled')).to.equal(false);
|
expect(el.classList.contains('state-disabled')).to.equal(false);
|
||||||
expect(el.inputElement.hasAttribute('disabled')).to.equal(false);
|
expect(el.inputElement.hasAttribute('disabled')).to.equal(false);
|
||||||
|
|
||||||
|
|
@ -166,7 +162,7 @@ describe('<lion-field>', () => {
|
||||||
expect(el.classList.contains('state-disabled')).to.equal(true);
|
expect(el.classList.contains('state-disabled')).to.equal(true);
|
||||||
expect(el.inputElement.hasAttribute('disabled')).to.equal(true);
|
expect(el.inputElement.hasAttribute('disabled')).to.equal(true);
|
||||||
|
|
||||||
const disabledel = await fixture(`<${tagString} disabled>${inputSlotString}</${tagString}>`);
|
const disabledel = await fixture(html`<${tag} disabled>${inputSlot}</${tag}>`);
|
||||||
expect(disabledel.classList.contains('state-disabled')).to.equal(true);
|
expect(disabledel.classList.contains('state-disabled')).to.equal(true);
|
||||||
expect(disabledel.inputElement.hasAttribute('disabled')).to.equal(true);
|
expect(disabledel.inputElement.hasAttribute('disabled')).to.equal(true);
|
||||||
});
|
});
|
||||||
|
|
@ -186,12 +182,12 @@ describe('<lion-field>', () => {
|
||||||
<div slot="feedback" id="feedback-[id]">[feedback] </span>
|
<div slot="feedback" id="feedback-[id]">[feedback] </span>
|
||||||
</lion-field>
|
</lion-field>
|
||||||
~~~`, async () => {
|
~~~`, async () => {
|
||||||
const el = await fixture(`<${tagString}>
|
const el = await fixture(html`<${tag}>
|
||||||
<label slot="label">My Name</label>
|
<label slot="label">My Name</label>
|
||||||
${inputSlotString}
|
${inputSlot}
|
||||||
<span slot="help-text">Enter your Name</span>
|
<span slot="help-text">Enter your Name</span>
|
||||||
<span slot="feedback">No name entered</span>
|
<span slot="feedback">No name entered</span>
|
||||||
</${tagString}>
|
</${tag}>
|
||||||
`);
|
`);
|
||||||
const nativeInput = el.$$slot('input');
|
const nativeInput = el.$$slot('input');
|
||||||
|
|
||||||
|
|
@ -202,13 +198,13 @@ describe('<lion-field>', () => {
|
||||||
|
|
||||||
it(`allows additional slots (prefix, suffix, before, after) to be included in labelledby
|
it(`allows additional slots (prefix, suffix, before, after) to be included in labelledby
|
||||||
(via attribute data-label) and in describedby (via attribute data-description)`, async () => {
|
(via attribute data-label) and in describedby (via attribute data-description)`, async () => {
|
||||||
const el = await fixture(`<${tagString}>
|
const el = await fixture(html`<${tag}>
|
||||||
${inputSlotString}
|
${inputSlot}
|
||||||
<span slot="before" data-label>[before]</span>
|
<span slot="before" data-label>[before]</span>
|
||||||
<span slot="after" data-label>[after]</span>
|
<span slot="after" data-label>[after]</span>
|
||||||
<span slot="prefix" data-description>[prefix]</span>
|
<span slot="prefix" data-description>[prefix]</span>
|
||||||
<span slot="suffix" data-description>[suffix]</span>
|
<span slot="suffix" data-description>[suffix]</span>
|
||||||
</${tagString}>
|
</${tag}>
|
||||||
`);
|
`);
|
||||||
|
|
||||||
const nativeInput = el.$$slot('input');
|
const nativeInput = el.$$slot('input');
|
||||||
|
|
@ -223,45 +219,45 @@ describe('<lion-field>', () => {
|
||||||
// TODO: put this test on FormControlMixin test once there
|
// TODO: put this test on FormControlMixin test once there
|
||||||
it(`allows to add to aria description or label via addToAriaLabel() and
|
it(`allows to add to aria description or label via addToAriaLabel() and
|
||||||
addToAriaDescription()`, async () => {
|
addToAriaDescription()`, async () => {
|
||||||
const wrapper = await fixture(`
|
const wrapper = await fixture(html`
|
||||||
<div id="wrapper">
|
<div id="wrapper">
|
||||||
<${tagString}>
|
<${tag}>
|
||||||
${inputSlotString}
|
${inputSlot}
|
||||||
<label slot="label">Added to label by default</label>
|
<label slot="label">Added to label by default</label>
|
||||||
<div slot="feedback">Added to description by default</div>
|
<div slot="feedback">Added to description by default</div>
|
||||||
</${tagString}>
|
</${tag}>
|
||||||
<div id="additionalLabel"> This also needs to be read whenever the input has focus</div>
|
<div id="additionalLabel"> This also needs to be read whenever the input has focus</div>
|
||||||
<div id="additionalDescription"> Same for this </div>
|
<div id="additionalDescription"> Same for this </div>
|
||||||
</div>`);
|
</div>`);
|
||||||
const el = wrapper.querySelector(`${tagString}`);
|
const el = wrapper.querySelector(tagString);
|
||||||
// wait until the field element is done rendering
|
// wait until the field element is done rendering
|
||||||
await el.updateComplete;
|
await el.updateComplete;
|
||||||
|
await el.updateComplete;
|
||||||
|
|
||||||
const { inputElement } = el;
|
const { inputElement } = el;
|
||||||
const get = by => inputElement.getAttribute(`aria-${by}`);
|
|
||||||
|
|
||||||
// 1. addToAriaLabel()
|
// 1. addToAriaLabel()
|
||||||
// Check if the aria attr is filled initially
|
// Check if the aria attr is filled initially
|
||||||
expect(get('labelledby')).to.contain(`label-${el._inputId}`);
|
expect(inputElement.getAttribute('aria-labelledby')).to.contain(`label-${el._inputId}`);
|
||||||
el.addToAriaLabel('additionalLabel');
|
el.addToAriaLabel('additionalLabel');
|
||||||
// Now check if ids are added to the end (not overridden)
|
// Now check if ids are added to the end (not overridden)
|
||||||
expect(get('labelledby')).to.contain(`label-${el._inputId}`);
|
expect(inputElement.getAttribute('aria-labelledby')).to.contain(`label-${el._inputId}`);
|
||||||
// Should be placed in the end
|
// Should be placed in the end
|
||||||
expect(
|
expect(
|
||||||
get('labelledby').indexOf(`label-${el._inputId}`) <
|
inputElement.getAttribute('aria-labelledby').indexOf(`label-${el._inputId}`) <
|
||||||
get('labelledby').indexOf('additionalLabel'),
|
inputElement.getAttribute('aria-labelledby').indexOf('additionalLabel'),
|
||||||
);
|
);
|
||||||
|
|
||||||
// 2. addToAriaDescription()
|
// 2. addToAriaDescription()
|
||||||
// Check if the aria attr is filled initially
|
// Check if the aria attr is filled initially
|
||||||
expect(get('describedby')).to.contain(`feedback-${el._inputId}`);
|
expect(inputElement.getAttribute('aria-describedby')).to.contain(`feedback-${el._inputId}`);
|
||||||
el.addToAriaDescription('additionalDescription');
|
el.addToAriaDescription('additionalDescription');
|
||||||
// Now check if ids are added to the end (not overridden)
|
// Now check if ids are added to the end (not overridden)
|
||||||
expect(get('describedby')).to.contain(`feedback-${el._inputId}`);
|
expect(inputElement.getAttribute('aria-describedby')).to.contain(`feedback-${el._inputId}`);
|
||||||
// Should be placed in the end
|
// Should be placed in the end
|
||||||
expect(
|
expect(
|
||||||
get('describedby').indexOf(`feedback-${el._inputId}`) <
|
inputElement.getAttribute('aria-describedby').indexOf(`feedback-${el._inputId}`) <
|
||||||
get('describedby').indexOf('additionalDescription'),
|
inputElement.getAttribute('aria-describedby').indexOf('additionalDescription'),
|
||||||
);
|
);
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
@ -285,7 +281,7 @@ describe('<lion-field>', () => {
|
||||||
function hasX(str) {
|
function hasX(str) {
|
||||||
return { hasX: str.indexOf('x') > -1 };
|
return { hasX: str.indexOf('x') > -1 };
|
||||||
}
|
}
|
||||||
const el = await fixture(`<${tagString}>${inputSlotString}</${tagString}>`);
|
const el = await fixture(html`<${tag}>${inputSlot}</${tag}>`);
|
||||||
const feedbackEl = el._feedbackElement;
|
const feedbackEl = el._feedbackElement;
|
||||||
|
|
||||||
el.modelValue = 'a@b.nl';
|
el.modelValue = 'a@b.nl';
|
||||||
|
|
@ -355,17 +351,17 @@ describe('<lion-field>', () => {
|
||||||
|
|
||||||
describe(`Content projection${nameSuffix}`, () => {
|
describe(`Content projection${nameSuffix}`, () => {
|
||||||
it('renders correctly all slot elements in light DOM', async () => {
|
it('renders correctly all slot elements in light DOM', async () => {
|
||||||
const el = await fixture(`
|
const el = await fixture(html`
|
||||||
<${tagString}>
|
<${tag}>
|
||||||
<label slot="label">[label]</label>
|
<label slot="label">[label]</label>
|
||||||
${inputSlotString}
|
${inputSlot}
|
||||||
<span slot="help-text">[help-text]</span>
|
<span slot="help-text">[help-text]</span>
|
||||||
<span slot="before">[before]</span>
|
<span slot="before">[before]</span>
|
||||||
<span slot="after">[after]</span>
|
<span slot="after">[after]</span>
|
||||||
<span slot="prefix">[prefix]</span>
|
<span slot="prefix">[prefix]</span>
|
||||||
<span slot="suffix">[suffix]</span>
|
<span slot="suffix">[suffix]</span>
|
||||||
<span slot="feedback">[feedback]</span>
|
<span slot="feedback">[feedback]</span>
|
||||||
</${tagString}>
|
</${tag}>
|
||||||
`);
|
`);
|
||||||
|
|
||||||
const names = [
|
const names = [
|
||||||
|
|
@ -388,9 +384,9 @@ describe('<lion-field>', () => {
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
describe(`Delegation${nameSuffix}`, () => {
|
describe('Delegation', () => {
|
||||||
it('delegates property value', async () => {
|
it('delegates property value', async () => {
|
||||||
const el = await fixture(`<${tagString}>${inputSlotString}</${tagString}>`);
|
const el = await fixture(html`<${tag}>${inputSlot}</${tag}>`);
|
||||||
expect(el.inputElement.value).to.equal('');
|
expect(el.inputElement.value).to.equal('');
|
||||||
el.value = 'one';
|
el.value = 'one';
|
||||||
expect(el.value).to.equal('one');
|
expect(el.value).to.equal('one');
|
||||||
|
|
|
||||||
|
|
@ -11,7 +11,7 @@ const pascalCase = str => str.charAt(0).toUpperCase() + str.slice(1);
|
||||||
/**
|
/**
|
||||||
* LionFieldset: fieldset wrapper providing extra features and integration with lion-field elements.
|
* LionFieldset: fieldset wrapper providing extra features and integration with lion-field elements.
|
||||||
*
|
*
|
||||||
* @customElement
|
* @customElement lion-fieldset
|
||||||
* @extends LionLitElement
|
* @extends LionLitElement
|
||||||
*/
|
*/
|
||||||
export class LionFieldset extends FormRegistrarMixin(
|
export class LionFieldset extends FormRegistrarMixin(
|
||||||
|
|
@ -176,7 +176,14 @@ export class LionFieldset extends FormRegistrarMixin(
|
||||||
}
|
}
|
||||||
|
|
||||||
resetGroup() {
|
resetGroup() {
|
||||||
this.modelValue = this.resetModelValue;
|
this.formElementsArray.forEach(child => {
|
||||||
|
if (typeof child.resetGroup === 'function') {
|
||||||
|
child.resetGroup();
|
||||||
|
} else if (typeof child.reset === 'function') {
|
||||||
|
child.reset();
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
this.resetInteractionState();
|
this.resetInteractionState();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -245,7 +252,7 @@ export class LionFieldset extends FormRegistrarMixin(
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Get's triggered by event 'validatin-done' which enabled us to handle 2 different situations
|
* Gets triggered by event 'validation-done' which enabled us to handle 2 different situations
|
||||||
* - react on modelValue change, which says something about the validity as a whole
|
* - react on modelValue change, which says something about the validity as a whole
|
||||||
* (at least two checkboxes for instance) and nothing about the children's values
|
* (at least two checkboxes for instance) and nothing about the children's values
|
||||||
* - children validatity states have changed, so fieldset needs to update itself based on that
|
* - children validatity states have changed, so fieldset needs to update itself based on that
|
||||||
|
|
@ -348,23 +355,16 @@ export class LionFieldset extends FormRegistrarMixin(
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Updates the resetModelValue of this fieldset and asks it's parent fieldset/group to also
|
* Gathers initial model values of all children. Used
|
||||||
* update.
|
* when resetGroup() is called.
|
||||||
* This is needed as the upgrade order is not guaranteed. We have 3 main cases:
|
|
||||||
* 1. if `street-name` gets updated last then `address` and `details` needs to update their
|
|
||||||
* resetModelValue to also incorporate the correct value of `street-name`/`address`.
|
|
||||||
* 2. If `address` get updated last then it already has the correct `street-name` so it
|
|
||||||
* requests an update only for `details`.
|
|
||||||
* 3. If `details` get updated last nothing happens here as all data are up to date
|
|
||||||
*
|
|
||||||
* @example
|
|
||||||
* <lion-fieldset name="details">
|
|
||||||
* <lion-fieldset name="address">
|
|
||||||
* <lion-input name="street-name" .modelValue=${'street 1'}>
|
|
||||||
*/
|
*/
|
||||||
_updateResetModelValue() {
|
get _initialModelValue() {
|
||||||
this.resetModelValue = this.modelValue;
|
return this._getFromAllFormElements('_initialModelValue');
|
||||||
this._requestParentFormGroupUpdateOfResetModelValue();
|
}
|
||||||
|
|
||||||
|
/** @deprecated */
|
||||||
|
get resetModelValue() {
|
||||||
|
return this._initialModelValue;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|
|
||||||
|
|
@ -14,12 +14,14 @@ import '../lion-fieldset.js';
|
||||||
|
|
||||||
const tagString = 'lion-fieldset';
|
const tagString = 'lion-fieldset';
|
||||||
const tag = unsafeStatic(tagString);
|
const tag = unsafeStatic(tagString);
|
||||||
const inputSlotString = `
|
const childTagString = 'lion-input';
|
||||||
<lion-input name="gender[]"></lion-input>
|
const childTag = unsafeStatic(childTagString);
|
||||||
<lion-input name="gender[]"></lion-input>
|
const inputSlots = html`
|
||||||
<lion-input name="color"></lion-input>
|
<${childTag} name="gender[]"></${childTag}>
|
||||||
<lion-input name="hobbies[]"></lion-input>
|
<${childTag} name="gender[]"></${childTag}>
|
||||||
<lion-input name="hobbies[]"></lion-input>
|
<${childTag} name="color"></${childTag}>
|
||||||
|
<${childTag} name="hobbies[]"></${childTag}>
|
||||||
|
<${childTag} name="hobbies[]"></${childTag}>
|
||||||
`;
|
`;
|
||||||
const nonPrefilledModelValue = '';
|
const nonPrefilledModelValue = '';
|
||||||
const prefilledModelValue = 'prefill';
|
const prefilledModelValue = 'prefill';
|
||||||
|
|
@ -30,7 +32,7 @@ beforeEach(() => {
|
||||||
|
|
||||||
describe('<lion-fieldset>', () => {
|
describe('<lion-fieldset>', () => {
|
||||||
it(`${tagString} has an up to date list of every form element in #formElements`, async () => {
|
it(`${tagString} has an up to date list of every form element in #formElements`, async () => {
|
||||||
const fieldset = await fixture(`<${tagString}>${inputSlotString}</${tagString}>`);
|
const fieldset = await fixture(html`<${tag}>${inputSlots}</${tag}>`);
|
||||||
await nextFrame();
|
await nextFrame();
|
||||||
expect(Object.keys(fieldset.formElements).length).to.equal(3);
|
expect(Object.keys(fieldset.formElements).length).to.equal(3);
|
||||||
expect(fieldset.formElements['hobbies[]'].length).to.equal(2);
|
expect(fieldset.formElements['hobbies[]'].length).to.equal(2);
|
||||||
|
|
@ -40,12 +42,12 @@ describe('<lion-fieldset>', () => {
|
||||||
});
|
});
|
||||||
|
|
||||||
it(`supports in html wrapped form elements`, async () => {
|
it(`supports in html wrapped form elements`, async () => {
|
||||||
const el = await fixture(`
|
const el = await fixture(html`
|
||||||
<lion-fieldset>
|
<${tag}>
|
||||||
<div>
|
<div>
|
||||||
<lion-input name="foo"></lion-input>
|
<${childTag} name="foo"></${childTag}>
|
||||||
</div>
|
</div>
|
||||||
</lion-fieldset>
|
</${tag}>
|
||||||
`);
|
`);
|
||||||
await nextFrame();
|
await nextFrame();
|
||||||
expect(el.formElementsArray.length).to.equal(1);
|
expect(el.formElementsArray.length).to.equal(1);
|
||||||
|
|
@ -54,7 +56,7 @@ describe('<lion-fieldset>', () => {
|
||||||
});
|
});
|
||||||
|
|
||||||
it('handles names with ending [] as an array', async () => {
|
it('handles names with ending [] as an array', async () => {
|
||||||
const fieldset = await fixture(`<${tagString}>${inputSlotString}</${tagString}>`);
|
const fieldset = await fixture(html`<${tag}>${inputSlots}</${tag}>`);
|
||||||
await nextFrame();
|
await nextFrame();
|
||||||
fieldset.formElements['gender[]'][0].modelValue = { value: 'male' };
|
fieldset.formElements['gender[]'][0].modelValue = { value: 'male' };
|
||||||
fieldset.formElements['hobbies[]'][0].modelValue = { checked: false, value: 'chess' };
|
fieldset.formElements['hobbies[]'][0].modelValue = { checked: false, value: 'chess' };
|
||||||
|
|
@ -75,7 +77,7 @@ describe('<lion-fieldset>', () => {
|
||||||
console.info = () => {};
|
console.info = () => {};
|
||||||
|
|
||||||
let error = false;
|
let error = false;
|
||||||
const el = await fixture(`<lion-fieldset></lion-fieldset>`);
|
const el = await fixture(html`<${tag}></${tag}>`);
|
||||||
try {
|
try {
|
||||||
// we test the api directly as errors thrown from a web component are in a
|
// we test the api directly as errors thrown from a web component are in a
|
||||||
// different context and we can not catch them here => register fake elements
|
// different context and we can not catch them here => register fake elements
|
||||||
|
|
@ -94,7 +96,7 @@ describe('<lion-fieldset>', () => {
|
||||||
console.info = () => {};
|
console.info = () => {};
|
||||||
|
|
||||||
let error = false;
|
let error = false;
|
||||||
const el = await fixture(`<lion-fieldset name="foo"></lion-fieldset>`);
|
const el = await fixture(html`<${tag} name="foo"></${tag}>`);
|
||||||
try {
|
try {
|
||||||
// we test the api directly as errors thrown from a web component are in a
|
// we test the api directly as errors thrown from a web component are in a
|
||||||
// different context and we can not catch them here => register fake elements
|
// different context and we can not catch them here => register fake elements
|
||||||
|
|
@ -113,7 +115,7 @@ describe('<lion-fieldset>', () => {
|
||||||
console.info = () => {};
|
console.info = () => {};
|
||||||
|
|
||||||
let error = false;
|
let error = false;
|
||||||
const el = await fixture(`<lion-fieldset></lion-fieldset>`);
|
const el = await fixture(html`<${tag}></${tag}>`);
|
||||||
try {
|
try {
|
||||||
// we test the api directly as errors thrown from a web component are in a
|
// we test the api directly as errors thrown from a web component are in a
|
||||||
// different context and we can not catch them here => register fake elements
|
// different context and we can not catch them here => register fake elements
|
||||||
|
|
@ -132,8 +134,8 @@ describe('<lion-fieldset>', () => {
|
||||||
/* eslint-enable no-console */
|
/* eslint-enable no-console */
|
||||||
|
|
||||||
it('can dynamically add/remove elements', async () => {
|
it('can dynamically add/remove elements', async () => {
|
||||||
const fieldset = await fixture(`<${tagString}>${inputSlotString}</${tagString}>`);
|
const fieldset = await fixture(html`<${tag}>${inputSlots}</${tag}>`);
|
||||||
const newField = await fixture(`<lion-input name="lastName"></lion-input>`);
|
const newField = await fixture(html`<${childTag} name="lastName"></${childTag}>`);
|
||||||
|
|
||||||
expect(Object.keys(fieldset.formElements).length).to.equal(3);
|
expect(Object.keys(fieldset.formElements).length).to.equal(3);
|
||||||
|
|
||||||
|
|
@ -145,11 +147,11 @@ describe('<lion-fieldset>', () => {
|
||||||
});
|
});
|
||||||
|
|
||||||
it('can read/write all values (of every input) via this.modelValue', async () => {
|
it('can read/write all values (of every input) via this.modelValue', async () => {
|
||||||
const fieldset = await fixture(`
|
const fieldset = await fixture(html`
|
||||||
<lion-fieldset>
|
<${tag}>
|
||||||
<lion-input name="lastName"></lion-input>
|
<${childTag} name="lastName"></${childTag}>
|
||||||
<${tagString} name="newfieldset">${inputSlotString}</${tagString}>
|
<${tag} name="newfieldset">${inputSlots}</${tag}>
|
||||||
</lion-fieldset>
|
</${tag}>
|
||||||
`);
|
`);
|
||||||
await fieldset.registrationReady;
|
await fieldset.registrationReady;
|
||||||
const newFieldset = fieldset.querySelector('lion-fieldset');
|
const newFieldset = fieldset.querySelector('lion-fieldset');
|
||||||
|
|
@ -190,10 +192,10 @@ describe('<lion-fieldset>', () => {
|
||||||
|
|
||||||
it('does not throw if setter data of this.modelValue can not be handled', async () => {
|
it('does not throw if setter data of this.modelValue can not be handled', async () => {
|
||||||
const el = await fixture(html`
|
const el = await fixture(html`
|
||||||
<lion-fieldset>
|
<${tag}>
|
||||||
<lion-input name="firstName" .modelValue=${'foo'}></lion-input>
|
<${childTag} name="firstName" .modelValue=${'foo'}></${childTag}>
|
||||||
<lion-input name="lastName" .modelValue=${'bar'}></lion-input>
|
<${childTag} name="lastName" .modelValue=${'bar'}></${childTag}>
|
||||||
</lion-fieldset>
|
</${tag}>
|
||||||
`);
|
`);
|
||||||
await nextFrame();
|
await nextFrame();
|
||||||
const initState = {
|
const initState = {
|
||||||
|
|
@ -210,7 +212,7 @@ describe('<lion-fieldset>', () => {
|
||||||
});
|
});
|
||||||
|
|
||||||
it('disables/enables all its formElements if it becomes disabled/enabled', async () => {
|
it('disables/enables all its formElements if it becomes disabled/enabled', async () => {
|
||||||
const el = await fixture(`<${tagString} disabled>${inputSlotString}</${tagString}>`);
|
const el = await fixture(html`<${tag} disabled>${inputSlots}</${tag}>`);
|
||||||
await nextFrame();
|
await nextFrame();
|
||||||
expect(el.formElements.color.disabled).to.equal(true);
|
expect(el.formElements.color.disabled).to.equal(true);
|
||||||
expect(el.formElements['hobbies[]'][0].disabled).to.equal(true);
|
expect(el.formElements['hobbies[]'][0].disabled).to.equal(true);
|
||||||
|
|
@ -225,7 +227,7 @@ describe('<lion-fieldset>', () => {
|
||||||
|
|
||||||
it('does not propagate/override initial disabled value on nested form elements', async () => {
|
it('does not propagate/override initial disabled value on nested form elements', async () => {
|
||||||
const el = await fixture(
|
const el = await fixture(
|
||||||
`<${tagString}><${tagString} name="sub" disabled>${inputSlotString}</${tagString}></${tagString}>`,
|
html`<${tag}><${tag} name="sub" disabled>${inputSlots}</${tag}></${tag}>`,
|
||||||
);
|
);
|
||||||
await el.updateComplete;
|
await el.updateComplete;
|
||||||
expect(el.disabled).to.equal(false);
|
expect(el.disabled).to.equal(false);
|
||||||
|
|
@ -237,7 +239,7 @@ describe('<lion-fieldset>', () => {
|
||||||
|
|
||||||
// classes are added only for backward compatibility - they are deprecated
|
// classes are added only for backward compatibility - they are deprecated
|
||||||
it('sets a state-disabled class when disabled', async () => {
|
it('sets a state-disabled class when disabled', async () => {
|
||||||
const el = await fixture(`<${tagString} disabled>${inputSlotString}</${tagString}>`);
|
const el = await fixture(html`<${tag} disabled>${inputSlots}</${tag}>`);
|
||||||
await nextFrame();
|
await nextFrame();
|
||||||
expect(el.classList.contains('state-disabled')).to.equal(true);
|
expect(el.classList.contains('state-disabled')).to.equal(true);
|
||||||
el.disabled = false;
|
el.disabled = false;
|
||||||
|
|
@ -252,10 +254,10 @@ describe('<lion-fieldset>', () => {
|
||||||
}
|
}
|
||||||
const el = await fixture(html`
|
const el = await fixture(html`
|
||||||
<${tag}>
|
<${tag}>
|
||||||
<lion-input name="color"
|
<${childTag} name="color"
|
||||||
.errorValidators=${[[isCat]]}
|
.errorValidators=${[[isCat]]}
|
||||||
.modelValue=${'blue'}
|
.modelValue=${'blue'}
|
||||||
></lion-input>
|
></${childTag}>
|
||||||
</${tag}>
|
</${tag}>
|
||||||
`);
|
`);
|
||||||
await nextFrame();
|
await nextFrame();
|
||||||
|
|
@ -263,7 +265,7 @@ describe('<lion-fieldset>', () => {
|
||||||
});
|
});
|
||||||
|
|
||||||
it('validates when a value changes', async () => {
|
it('validates when a value changes', async () => {
|
||||||
const fieldset = await fixture(`<${tagString}>${inputSlotString}</${tagString}>`);
|
const fieldset = await fixture(html`<${tag}>${inputSlots}</${tag}>`);
|
||||||
await nextFrame();
|
await nextFrame();
|
||||||
const spy = sinon.spy(fieldset, 'validate');
|
const spy = sinon.spy(fieldset, 'validate');
|
||||||
fieldset.formElements.color.modelValue = { checked: true, value: 'red' };
|
fieldset.formElements.color.modelValue = { checked: true, value: 'red' };
|
||||||
|
|
@ -277,10 +279,10 @@ describe('<lion-fieldset>', () => {
|
||||||
|
|
||||||
const el = await fixture(html`
|
const el = await fixture(html`
|
||||||
<${tag}>
|
<${tag}>
|
||||||
<lion-input name="color"
|
<${childTag} name="color"
|
||||||
.errorValidators=${[[isCat]]}
|
.errorValidators=${[[isCat]]}
|
||||||
.modelValue=${'blue'}
|
.modelValue=${'blue'}
|
||||||
></lion-input>
|
></${childTag}>
|
||||||
</${tag}>
|
</${tag}>
|
||||||
`);
|
`);
|
||||||
await nextFrame();
|
await nextFrame();
|
||||||
|
|
@ -297,12 +299,12 @@ describe('<lion-fieldset>', () => {
|
||||||
}
|
}
|
||||||
const el = await fixture(html`
|
const el = await fixture(html`
|
||||||
<${tag} .errorValidators=${[[hasEvenNumberOfChildren]]}>
|
<${tag} .errorValidators=${[[hasEvenNumberOfChildren]]}>
|
||||||
<lion-input id="c1" name="c1"></lion-input>
|
<${childTag} id="c1" name="c1"></${childTag}>
|
||||||
</${tag}>
|
</${tag}>
|
||||||
`);
|
`);
|
||||||
const child2 = await fixture(
|
const child2 = await fixture(
|
||||||
html`
|
html`
|
||||||
<lion-input name="c2"></lion-input>
|
<${childTag} name="c2"></${childTag}>
|
||||||
`,
|
`,
|
||||||
);
|
);
|
||||||
|
|
||||||
|
|
@ -326,7 +328,7 @@ describe('<lion-fieldset>', () => {
|
||||||
|
|
||||||
describe('interaction states', () => {
|
describe('interaction states', () => {
|
||||||
it('has false states (dirty, touched, prefilled) on init', async () => {
|
it('has false states (dirty, touched, prefilled) on init', async () => {
|
||||||
const fieldset = await fixture(`<${tagString}>${inputSlotString}</${tagString}>`);
|
const fieldset = await fixture(html`<${tag}>${inputSlots}</${tag}>`);
|
||||||
await nextFrame();
|
await nextFrame();
|
||||||
expect(fieldset.dirty).to.equal(false, 'dirty');
|
expect(fieldset.dirty).to.equal(false, 'dirty');
|
||||||
expect(fieldset.touched).to.equal(false, 'touched');
|
expect(fieldset.touched).to.equal(false, 'touched');
|
||||||
|
|
@ -334,14 +336,14 @@ describe('<lion-fieldset>', () => {
|
||||||
});
|
});
|
||||||
|
|
||||||
it('sets dirty when value changed', async () => {
|
it('sets dirty when value changed', async () => {
|
||||||
const fieldset = await fixture(`<${tagString}>${inputSlotString}</${tagString}>`);
|
const fieldset = await fixture(html`<${tag}>${inputSlots}</${tag}>`);
|
||||||
await nextFrame();
|
await nextFrame();
|
||||||
fieldset.formElements['hobbies[]'][0].modelValue = { checked: true, value: 'football' };
|
fieldset.formElements['hobbies[]'][0].modelValue = { checked: true, value: 'football' };
|
||||||
expect(fieldset.dirty).to.equal(true);
|
expect(fieldset.dirty).to.equal(true);
|
||||||
});
|
});
|
||||||
|
|
||||||
it('sets touched when field left after focus', async () => {
|
it('sets touched when field left after focus', async () => {
|
||||||
const fieldset = await fixture(`<${tagString}>${inputSlotString}</${tagString}>`);
|
const fieldset = await fixture(html`<${tag}>${inputSlots}</${tag}>`);
|
||||||
await nextFrame();
|
await nextFrame();
|
||||||
await triggerFocusFor(fieldset.formElements['gender[]'][0].inputElement);
|
await triggerFocusFor(fieldset.formElements['gender[]'][0].inputElement);
|
||||||
await triggerBlurFor(fieldset.formElements['gender[]'][0].inputElement);
|
await triggerBlurFor(fieldset.formElements['gender[]'][0].inputElement);
|
||||||
|
|
@ -349,7 +351,7 @@ describe('<lion-fieldset>', () => {
|
||||||
});
|
});
|
||||||
|
|
||||||
it('sets a class "state-(touched|dirty)"', async () => {
|
it('sets a class "state-(touched|dirty)"', async () => {
|
||||||
const fieldset = await fixture(`<${tagString}>${inputSlotString}</${tagString}>`);
|
const fieldset = await fixture(html`<${tag}>${inputSlots}</${tag}>`);
|
||||||
await nextFrame();
|
await nextFrame();
|
||||||
fieldset.formElements.color.touched = true;
|
fieldset.formElements.color.touched = true;
|
||||||
await fieldset.updateComplete;
|
await fieldset.updateComplete;
|
||||||
|
|
@ -364,7 +366,7 @@ describe('<lion-fieldset>', () => {
|
||||||
});
|
});
|
||||||
|
|
||||||
it('sets prefilled when field left and value non-empty', async () => {
|
it('sets prefilled when field left and value non-empty', async () => {
|
||||||
const fieldset = await fixture(`<${tagString}>${inputSlotString}</${tagString}>`);
|
const fieldset = await fixture(html`<${tag}>${inputSlots}</${tag}>`);
|
||||||
await nextFrame();
|
await nextFrame();
|
||||||
fieldset.formElements['hobbies[]'][0].modelValue = { checked: false, value: 'chess' };
|
fieldset.formElements['hobbies[]'][0].modelValue = { checked: false, value: 'chess' };
|
||||||
fieldset.formElements['hobbies[]'][1].modelValue = { checked: false, value: 'football' };
|
fieldset.formElements['hobbies[]'][1].modelValue = { checked: false, value: 'football' };
|
||||||
|
|
@ -385,17 +387,17 @@ describe('<lion-fieldset>', () => {
|
||||||
|
|
||||||
it('sets prefilled once instantiated', async () => {
|
it('sets prefilled once instantiated', async () => {
|
||||||
// no prefilled when nothing has value
|
// no prefilled when nothing has value
|
||||||
const fieldsetNotPrefilled = await fixture(html`<${tag}>${inputSlotString}</${tag}>`);
|
const fieldsetNotPrefilled = await fixture(html`<${tag}>${inputSlots}</${tag}>`);
|
||||||
expect(fieldsetNotPrefilled.prefilled).to.equal(false, 'not prefilled on init');
|
expect(fieldsetNotPrefilled.prefilled).to.equal(false, 'not prefilled on init');
|
||||||
|
|
||||||
// prefilled when at least one child has value
|
// prefilled when at least one child has value
|
||||||
const fieldsetPrefilled = await fixture(html`
|
const fieldsetPrefilled = await fixture(html`
|
||||||
<${tag}>
|
<${tag}>
|
||||||
<lion-input name="gender[]" .modelValue=${prefilledModelValue}></lion-input>
|
<${childTag} name="gender[]" .modelValue=${prefilledModelValue}></${childTag}>
|
||||||
<lion-input name="gender[]"></lion-input>
|
<${childTag} name="gender[]"></${childTag}>
|
||||||
<lion-input name="color"></lion-input>
|
<${childTag} name="color"></${childTag}>
|
||||||
<lion-input name="hobbies[]"></lion-input>
|
<${childTag} name="hobbies[]"></${childTag}>
|
||||||
<lion-input name="hobbies[]"></lion-input>
|
<${childTag} name="hobbies[]"></${childTag}>
|
||||||
</${tag}>
|
</${tag}>
|
||||||
`);
|
`);
|
||||||
await nextFrame();
|
await nextFrame();
|
||||||
|
|
@ -405,7 +407,7 @@ describe('<lion-fieldset>', () => {
|
||||||
|
|
||||||
describe('serialize', () => {
|
describe('serialize', () => {
|
||||||
it('use form elements serializedValue', async () => {
|
it('use form elements serializedValue', async () => {
|
||||||
const fieldset = await fixture(`<${tagString}>${inputSlotString}</${tagString}>`);
|
const fieldset = await fixture(html`<${tag}>${inputSlots}</${tag}>`);
|
||||||
await nextFrame();
|
await nextFrame();
|
||||||
fieldset.formElements['hobbies[]'][0].serializer = v => `${v.value}-serialized`;
|
fieldset.formElements['hobbies[]'][0].serializer = v => `${v.value}-serialized`;
|
||||||
fieldset.formElements['hobbies[]'][0].modelValue = { checked: false, value: 'Bar' };
|
fieldset.formElements['hobbies[]'][0].modelValue = { checked: false, value: 'Bar' };
|
||||||
|
|
@ -422,7 +424,7 @@ describe('<lion-fieldset>', () => {
|
||||||
});
|
});
|
||||||
|
|
||||||
it('form elements which are not disabled', async () => {
|
it('form elements which are not disabled', async () => {
|
||||||
const fieldset = await fixture(`<${tagString}>${inputSlotString}</${tagString}>`);
|
const fieldset = await fixture(html`<${tag}>${inputSlots}</${tag}>`);
|
||||||
await nextFrame();
|
await nextFrame();
|
||||||
fieldset.formElements.color.modelValue = { checked: false, value: 'blue' };
|
fieldset.formElements.color.modelValue = { checked: false, value: 'blue' };
|
||||||
fieldset.formElements['hobbies[]'][0].modelValue = { checked: true, value: 'football' };
|
fieldset.formElements['hobbies[]'][0].modelValue = { checked: true, value: 'football' };
|
||||||
|
|
@ -445,11 +447,11 @@ describe('<lion-fieldset>', () => {
|
||||||
});
|
});
|
||||||
|
|
||||||
it('allows for nested fieldsets', async () => {
|
it('allows for nested fieldsets', async () => {
|
||||||
const fieldset = await fixture(`
|
const fieldset = await fixture(html`
|
||||||
<lion-fieldset name="userData">
|
<${tag} name="userData">
|
||||||
<lion-input name="comment"></lion-input>
|
<${childTag} name="comment"></${childTag}>
|
||||||
<${tagString} name="newfieldset">${inputSlotString}</${tagString}>
|
<${tag} name="newfieldset">${inputSlots}</${tag}>
|
||||||
</lion-fieldset>
|
</${tag}>
|
||||||
`);
|
`);
|
||||||
await nextFrame();
|
await nextFrame();
|
||||||
const newFieldset = fieldset.querySelector('lion-fieldset');
|
const newFieldset = fieldset.querySelector('lion-fieldset');
|
||||||
|
|
@ -472,11 +474,11 @@ describe('<lion-fieldset>', () => {
|
||||||
});
|
});
|
||||||
|
|
||||||
it('will exclude form elements within an disabled fieldset', async () => {
|
it('will exclude form elements within an disabled fieldset', async () => {
|
||||||
const fieldset = await fixture(`
|
const fieldset = await fixture(html`
|
||||||
<lion-fieldset name="userData">
|
<${tag} name="userData">
|
||||||
<lion-input name="comment"></lion-input>
|
<${childTag} name="comment"></${childTag}>
|
||||||
<${tagString} name="newfieldset">${inputSlotString}</${tagString}>
|
<${tag} name="newfieldset">${inputSlots}</${tag}>
|
||||||
</lion-fieldset>
|
</${tag}>
|
||||||
`);
|
`);
|
||||||
await nextFrame();
|
await nextFrame();
|
||||||
|
|
||||||
|
|
@ -509,7 +511,7 @@ describe('<lion-fieldset>', () => {
|
||||||
});
|
});
|
||||||
|
|
||||||
it('treats names with ending [] as arrays', async () => {
|
it('treats names with ending [] as arrays', async () => {
|
||||||
const fieldset = await fixture(`<${tagString}>${inputSlotString}</${tagString}>`);
|
const fieldset = await fixture(html`<${tag}>${inputSlots}</${tag}>`);
|
||||||
await nextFrame();
|
await nextFrame();
|
||||||
fieldset.formElements['hobbies[]'][0].modelValue = { checked: false, value: 'chess' };
|
fieldset.formElements['hobbies[]'][0].modelValue = { checked: false, value: 'chess' };
|
||||||
fieldset.formElements['hobbies[]'][1].modelValue = { checked: false, value: 'rugby' };
|
fieldset.formElements['hobbies[]'][1].modelValue = { checked: false, value: 'rugby' };
|
||||||
|
|
@ -524,11 +526,11 @@ describe('<lion-fieldset>', () => {
|
||||||
});
|
});
|
||||||
|
|
||||||
it('does not serialize undefined values (nb radios/checkboxes are always serialized)', async () => {
|
it('does not serialize undefined values (nb radios/checkboxes are always serialized)', async () => {
|
||||||
const fieldset = await fixture(`
|
const fieldset = await fixture(html`
|
||||||
<lion-fieldset>
|
<${tag}>
|
||||||
<lion-input name="custom[]"></lion-input>
|
<${childTag} name="custom[]"></${childTag}>
|
||||||
<lion-input name="custom[]"></lion-input>
|
<${childTag} name="custom[]"></${childTag}>
|
||||||
</lion-fieldset>
|
</${tag}>
|
||||||
`);
|
`);
|
||||||
await nextFrame();
|
await nextFrame();
|
||||||
fieldset.formElements['custom[]'][0].modelValue = 'custom 1';
|
fieldset.formElements['custom[]'][0].modelValue = 'custom 1';
|
||||||
|
|
@ -543,9 +545,9 @@ describe('<lion-fieldset>', () => {
|
||||||
describe('reset', () => {
|
describe('reset', () => {
|
||||||
it('restores default values if changes were made', async () => {
|
it('restores default values if changes were made', async () => {
|
||||||
const el = await fixture(html`
|
const el = await fixture(html`
|
||||||
<lion-fieldset>
|
<${tag}>
|
||||||
<lion-input id="firstName" name="firstName" .modelValue="${'Foo'}"></lion-input>
|
<${childTag} id="firstName" name="firstName" .modelValue="${'Foo'}"></${childTag}>
|
||||||
</lion-fieldset>
|
</${tag}>
|
||||||
`);
|
`);
|
||||||
await el.querySelector('lion-input').updateComplete;
|
await el.querySelector('lion-input').updateComplete;
|
||||||
|
|
||||||
|
|
@ -562,9 +564,9 @@ describe('<lion-fieldset>', () => {
|
||||||
|
|
||||||
it('restores default values of arrays if changes were made', async () => {
|
it('restores default values of arrays if changes were made', async () => {
|
||||||
const el = await fixture(html`
|
const el = await fixture(html`
|
||||||
<lion-fieldset>
|
<${tag}>
|
||||||
<lion-input id="firstName" name="firstName[]" .modelValue="${'Foo'}"></lion-input>
|
<${childTag} id="firstName" name="firstName[]" .modelValue="${'Foo'}"></${childTag}>
|
||||||
</lion-fieldset>
|
</${tag}>
|
||||||
`);
|
`);
|
||||||
await el.querySelector('lion-input').updateComplete;
|
await el.querySelector('lion-input').updateComplete;
|
||||||
|
|
||||||
|
|
@ -581,11 +583,11 @@ describe('<lion-fieldset>', () => {
|
||||||
|
|
||||||
it('restores default values of a nested fieldset if changes were made', async () => {
|
it('restores default values of a nested fieldset if changes were made', async () => {
|
||||||
const el = await fixture(html`
|
const el = await fixture(html`
|
||||||
<lion-fieldset>
|
<${tag}>
|
||||||
<lion-fieldset id="name" name="name[]">
|
<${tag} id="name" name="name[]">
|
||||||
<lion-input id="firstName" name="firstName" .modelValue="${'Foo'}"></lion-input>
|
<${childTag} id="firstName" name="firstName" .modelValue="${'Foo'}"></${childTag}>
|
||||||
</lion-fieldset>
|
</${tag}>
|
||||||
</lion-fieldset>
|
</${tag}>
|
||||||
`);
|
`);
|
||||||
await Promise.all([
|
await Promise.all([
|
||||||
el.querySelector('lion-fieldset').updateComplete,
|
el.querySelector('lion-fieldset').updateComplete,
|
||||||
|
|
@ -607,7 +609,7 @@ describe('<lion-fieldset>', () => {
|
||||||
});
|
});
|
||||||
|
|
||||||
it('clears interaction state', async () => {
|
it('clears interaction state', async () => {
|
||||||
const fieldset = await fixture(`<${tagString}>${inputSlotString}</${tagString}>`);
|
const fieldset = await fixture(html`<${tag}>${inputSlots}</${tag}>`);
|
||||||
await nextFrame();
|
await nextFrame();
|
||||||
// Safety check initially
|
// Safety check initially
|
||||||
fieldset._setValueForAllFormElements('dirty', true);
|
fieldset._setValueForAllFormElements('dirty', true);
|
||||||
|
|
@ -636,7 +638,7 @@ describe('<lion-fieldset>', () => {
|
||||||
});
|
});
|
||||||
|
|
||||||
it('clears submitted state', async () => {
|
it('clears submitted state', async () => {
|
||||||
const fieldset = await fixture(`<${tagString}>${inputSlotString}</${tagString}>`);
|
const fieldset = await fixture(html`<${tag}>${inputSlots}</${tag}>`);
|
||||||
await nextFrame();
|
await nextFrame();
|
||||||
fieldset.submitted = true;
|
fieldset.submitted = true;
|
||||||
fieldset.resetGroup();
|
fieldset.resetGroup();
|
||||||
|
|
@ -656,8 +658,8 @@ describe('<lion-fieldset>', () => {
|
||||||
|
|
||||||
const el = await fixture(html`
|
const el = await fixture(html`
|
||||||
<${tag} .errorValidators=${[[containsA]]}>
|
<${tag} .errorValidators=${[[containsA]]}>
|
||||||
<lion-input name="color" .errorValidators=${[[isCat]]}></lion-input>
|
<${childTag} name="color" .errorValidators=${[[isCat]]}></${childTag}>
|
||||||
<lion-input name="color2"></lion-input>
|
<${childTag} name="color2"></${childTag}>
|
||||||
</${tag}>
|
</${tag}>
|
||||||
`);
|
`);
|
||||||
await el.registrationReady;
|
await el.registrationReady;
|
||||||
|
|
@ -678,6 +680,68 @@ describe('<lion-fieldset>', () => {
|
||||||
expect(el.error.containsA).to.be.true;
|
expect(el.error.containsA).to.be.true;
|
||||||
expect(el.formElements.color.errorState).to.be.false;
|
expect(el.formElements.color.errorState).to.be.false;
|
||||||
});
|
});
|
||||||
|
|
||||||
|
it('has access to `_initialModelValue` based on initial children states', async () => {
|
||||||
|
const el = await fixture(html`
|
||||||
|
<${tag}>
|
||||||
|
<${childTag} name="child[]" .modelValue="${'foo1'}">
|
||||||
|
</${childTag}>
|
||||||
|
<${childTag} name="child[]" .modelValue="${'bar1'}">
|
||||||
|
</${childTag}>
|
||||||
|
</${tag}>
|
||||||
|
`);
|
||||||
|
await el.updateComplete;
|
||||||
|
el.modelValue['child[]'] = ['foo2', 'bar2'];
|
||||||
|
expect(el._initialModelValue['child[]']).to.eql(['foo1', 'bar1']);
|
||||||
|
});
|
||||||
|
|
||||||
|
it('does not wrongly recompute `_initialModelValue` after dynamic changes of children', async () => {
|
||||||
|
const el = await fixture(html`
|
||||||
|
<${tag}>
|
||||||
|
<${childTag} name="child[]" .modelValue="${'foo1'}">
|
||||||
|
</${childTag}>
|
||||||
|
</${tag}>
|
||||||
|
`);
|
||||||
|
el.modelValue['child[]'] = ['foo2'];
|
||||||
|
const childEl = await fixture(html`
|
||||||
|
<${childTag} name="child[]" .modelValue="${'bar1'}">
|
||||||
|
</${childTag}>
|
||||||
|
`);
|
||||||
|
el.appendChild(childEl);
|
||||||
|
expect(el._initialModelValue['child[]']).to.eql(['foo1', 'bar1']);
|
||||||
|
});
|
||||||
|
|
||||||
|
describe('resetGroup method', () => {
|
||||||
|
it('calls resetGroup on children fieldsets', async () => {
|
||||||
|
const el = await fixture(html`
|
||||||
|
<${tag} name="parentFieldset">
|
||||||
|
<${tag} name="childFieldset">
|
||||||
|
<${childTag} name="child[]" .modelValue="${'foo1'}">
|
||||||
|
</${childTag}>
|
||||||
|
</${tag}>
|
||||||
|
</${tag}>
|
||||||
|
`);
|
||||||
|
const childFieldsetEl = el.querySelector(tagString);
|
||||||
|
const resetGroupSpy = sinon.spy(childFieldsetEl, 'resetGroup');
|
||||||
|
el.resetGroup();
|
||||||
|
expect(resetGroupSpy.callCount).to.equal(1);
|
||||||
|
});
|
||||||
|
|
||||||
|
it('calls reset on children fields', async () => {
|
||||||
|
const el = await fixture(html`
|
||||||
|
<${tag} name="parentFieldset">
|
||||||
|
<${tag} name="childFieldset">
|
||||||
|
<${childTag} name="child[]" .modelValue="${'foo1'}">
|
||||||
|
</${childTag}>
|
||||||
|
</${tag}>
|
||||||
|
</${tag}>
|
||||||
|
`);
|
||||||
|
const childFieldsetEl = el.querySelector(childTagString);
|
||||||
|
const resetSpy = sinon.spy(childFieldsetEl, 'reset');
|
||||||
|
el.resetGroup();
|
||||||
|
expect(resetSpy.callCount).to.equal(1);
|
||||||
|
});
|
||||||
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
describe('a11y', () => {
|
describe('a11y', () => {
|
||||||
|
|
@ -686,7 +750,7 @@ describe('<lion-fieldset>', () => {
|
||||||
// });
|
// });
|
||||||
|
|
||||||
it('has role="group" set', async () => {
|
it('has role="group" set', async () => {
|
||||||
const fieldset = await fixture(`<${tagString}>${inputSlotString}</${tagString}>`);
|
const fieldset = await fixture(html`<${tag}>${inputSlots}</${tag}>`);
|
||||||
await nextFrame();
|
await nextFrame();
|
||||||
fieldset.formElements['hobbies[]'][0].modelValue = { checked: false, value: 'chess' };
|
fieldset.formElements['hobbies[]'][0].modelValue = { checked: false, value: 'chess' };
|
||||||
fieldset.formElements['hobbies[]'][1].modelValue = { checked: false, value: 'rugby' };
|
fieldset.formElements['hobbies[]'][1].modelValue = { checked: false, value: 'rugby' };
|
||||||
|
|
@ -698,11 +762,11 @@ describe('<lion-fieldset>', () => {
|
||||||
});
|
});
|
||||||
|
|
||||||
it('has an aria-labelledby from element with slot="label"', async () => {
|
it('has an aria-labelledby from element with slot="label"', async () => {
|
||||||
const el = await fixture(`
|
const el = await fixture(html`
|
||||||
<${tagString}>
|
<${tag}>
|
||||||
<label slot="label">My Label</label>
|
<label slot="label">My Label</label>
|
||||||
${inputSlotString}
|
${inputSlots}
|
||||||
</${tagString}>
|
</${tag}>
|
||||||
`);
|
`);
|
||||||
const label = el.querySelector('[slot="label"]');
|
const label = el.querySelector('[slot="label"]');
|
||||||
expect(el.hasAttribute('aria-labelledby')).to.equal(true);
|
expect(el.hasAttribute('aria-labelledby')).to.equal(true);
|
||||||
|
|
@ -724,40 +788,40 @@ describe('<lion-fieldset>', () => {
|
||||||
childAriaFixture = async (
|
childAriaFixture = async (
|
||||||
msgSlotType = 'feedback', // eslint-disable-line no-shadow
|
msgSlotType = 'feedback', // eslint-disable-line no-shadow
|
||||||
) => {
|
) => {
|
||||||
const dom = await fixture(`
|
const dom = await fixture(html`
|
||||||
<lion-fieldset name="l1_g">
|
<${tag} name="l1_g">
|
||||||
<lion-input name="l1_fa">
|
<${childTag} name="l1_fa">
|
||||||
<div slot="${msgSlotType}" id="msg_l1_fa"></div>
|
<div slot="${msgSlotType}" id="msg_l1_fa"></div>
|
||||||
<!-- field referred by: #msg_l1_fa (local), #msg_l1_g (parent/group) -->
|
<!-- field referred by: #msg_l1_fa (local), #msg_l1_g (parent/group) -->
|
||||||
</lion-input>
|
</${childTag}>
|
||||||
|
|
||||||
<lion-input name="l1_fb">
|
<${childTag} name="l1_fb">
|
||||||
<div slot="${msgSlotType}" id="msg_l1_fb"></div>
|
<div slot="${msgSlotType}" id="msg_l1_fb"></div>
|
||||||
<!-- field referred by: #msg_l1_fb (local), #msg_l1_g (parent/group) -->
|
<!-- field referred by: #msg_l1_fb (local), #msg_l1_g (parent/group) -->
|
||||||
</lion-input>
|
</${childTag}>
|
||||||
|
|
||||||
<!-- [ INNER FIELDSET ] -->
|
<!-- [ INNER FIELDSET ] -->
|
||||||
|
|
||||||
<lion-fieldset name="l2_g">
|
<${tag} name="l2_g">
|
||||||
<lion-input name="l2_fa">
|
<${childTag} name="l2_fa">
|
||||||
<div slot="${msgSlotType}" id="msg_l2_fa"></div>
|
<div slot="${msgSlotType}" id="msg_l2_fa"></div>
|
||||||
<!-- field referred by: #msg_l2_fa (local), #msg_l2_g (parent/group), #msg_l1_g (grandparent/group.group) -->
|
<!-- field referred by: #msg_l2_fa (local), #msg_l2_g (parent/group), #msg_l1_g (grandparent/group.group) -->
|
||||||
</lion-input>
|
</${childTag}>
|
||||||
|
|
||||||
<lion-input name="l2_fb">
|
<${childTag} name="l2_fb">
|
||||||
<div slot="${msgSlotType}" id="msg_l2_fb"></div>
|
<div slot="${msgSlotType}" id="msg_l2_fb"></div>
|
||||||
<!-- field referred by: #msg_l2_fb (local), #msg_l2_g (parent/group), #msg_l1_g (grandparent/group.group) -->
|
<!-- field referred by: #msg_l2_fb (local), #msg_l2_g (parent/group), #msg_l1_g (grandparent/group.group) -->
|
||||||
</lion-input>
|
</${childTag}>
|
||||||
|
|
||||||
<div slot="${msgSlotType}" id="msg_l2_g"></div>
|
<div slot="${msgSlotType}" id="msg_l2_g"></div>
|
||||||
<!-- group referred by: #msg_l2_g (local), #msg_l1_g (parent/group) -->
|
<!-- group referred by: #msg_l2_g (local), #msg_l1_g (parent/group) -->
|
||||||
</lion-fieldset>
|
</${tag}>
|
||||||
|
|
||||||
<!-- [ / INNER FIELDSET ] -->
|
<!-- [ / INNER FIELDSET ] -->
|
||||||
|
|
||||||
<div slot="${msgSlotType}" id="msg_l1_g"></div>
|
<div slot="${msgSlotType}" id="msg_l1_g"></div>
|
||||||
<!-- group referred by: #msg_l1_g (local) -->
|
<!-- group referred by: #msg_l1_g (local) -->
|
||||||
</lion-fieldset>
|
</${tag}>
|
||||||
`);
|
`);
|
||||||
return dom;
|
return dom;
|
||||||
};
|
};
|
||||||
|
|
|
||||||
Loading…
Reference in a new issue