import { html, LitElement } from '@lion/core';
import { formFixture as fixture } from '@lion/form-core/test-helpers.js';
import '@lion/fieldset/lion-fieldset.js';
import { LionInput } from '@lion/input';
import { FormGroupMixin, Required } from '@lion/form-core';
import { expect, nextFrame } from '@open-wc/testing';
import { ChoiceGroupMixin } from '../../src/choice-group/ChoiceGroupMixin.js';
import { ChoiceInputMixin } from '../../src/choice-group/ChoiceInputMixin.js';
describe('ChoiceGroupMixin', () => {
before(() => {
class ChoiceInput extends ChoiceInputMixin(LionInput) {}
customElements.define('choice-group-input', ChoiceInput);
class ChoiceGroup extends ChoiceGroupMixin(FormGroupMixin(LitElement)) {}
customElements.define('choice-group', ChoiceGroup);
class ChoiceGroupMultiple extends ChoiceGroupMixin(FormGroupMixin(LitElement)) {
constructor() {
super();
this.multipleChoice = true;
}
}
customElements.define('choice-group-multiple', ChoiceGroupMultiple);
});
it('has a single modelValue representing the currently checked radio value', async () => {
const el = await fixture(html`
`);
await nextFrame();
expect(el.modelValue).to.equal('female');
el.formElements[0].checked = true;
expect(el.modelValue).to.equal('male');
el.formElements[2].checked = true;
expect(el.modelValue).to.equal('other');
});
it('throws if a child element without a modelValue like { value: "foo", checked: false } tries to register', async () => {
const el = await fixture(html`
`);
await nextFrame();
const invalidChild = await fixture(html`
`);
expect(() => {
el.addFormElement(invalidChild);
}).to.throw(
'The choice-group name="gender" does not allow to register choice-group-input with .modelValue="Lara" - The modelValue should represent an Object { value: "foo", checked: false }',
);
});
it('automatically sets the name property of child radios to its own name', async () => {
const el = await fixture(html`
`);
await nextFrame();
expect(el.formElements[0].name).to.equal('gender');
expect(el.formElements[1].name).to.equal('gender');
const validChild = await fixture(html`
`);
el.appendChild(validChild);
expect(el.formElements[2].name).to.equal('gender');
});
it('throws if a child element with a different name than the group tries to register', async () => {
const el = await fixture(html`
`);
await nextFrame();
const invalidChild = await fixture(html`
`);
expect(() => {
el.addFormElement(invalidChild);
}).to.throw(
'The choice-group name="gender" does not allow to register choice-group-input with custom names (name="foo" given)',
);
});
it('can set initial modelValue on creation', async () => {
const el = await fixture(html`
`);
await nextFrame();
await el.registrationReady;
await el.updateComplete;
expect(el.modelValue).to.equal('other');
expect(el.formElements[2].checked).to.be.true;
});
it('can set initial serializedValue on creation', async () => {
const el = await fixture(html`
`);
expect(el.serializedValue).to.equal('other');
});
it('can handle complex data via choiceValue', async () => {
const date = new Date(2018, 11, 24, 10, 33, 30, 0);
const el = await fixture(html`
`);
await nextFrame();
expect(el.modelValue).to.equal(date);
el.formElements[0].checked = true;
expect(el.modelValue).to.deep.equal({ some: 'data' });
});
it('can handle 0 and empty string as valid values', async () => {
const el = await fixture(html`
`);
await nextFrame();
expect(el.modelValue).to.equal(0);
el.formElements[1].checked = true;
expect(el.modelValue).to.equal('');
});
it('can check a radio by supplying an available modelValue', async () => {
const el = await fixture(html`
`);
await nextFrame();
expect(el.modelValue).to.equal('female');
el.modelValue = 'other';
expect(el.formElements[2].checked).to.be.true;
});
it('expect child nodes to only fire one model-value-changed event per instance', async () => {
let counter = 0;
const el = await fixture(html`
{
counter += 1;
}}
>
`);
await nextFrame();
counter = 0; // reset after setup which may result in different results
el.formElements[0].checked = true;
expect(counter).to.equal(1); // male becomes checked, female becomes unchecked
// not changed values trigger no event
el.formElements[0].checked = true;
expect(counter).to.equal(1);
el.formElements[2].checked = true;
expect(counter).to.equal(2); // other becomes checked, male becomes unchecked
// not found values trigger no event
el.modelValue = 'foo';
expect(counter).to.equal(2);
el.modelValue = 'male';
expect(counter).to.equal(3); // male becomes checked, other becomes unchecked
});
it('can be required', async () => {
const el = await fixture(html`
`);
expect(el.hasFeedbackFor).to.include('error');
expect(el.validationStates).to.have.a.property('error');
expect(el.validationStates.error).to.have.a.property('Required');
el.formElements[0].checked = true;
expect(el.hasFeedbackFor).not.to.include('error');
expect(el.validationStates).to.have.a.property('error');
expect(el.validationStates.error).not.to.have.a.property('Required');
el.formElements[1].checked = true;
expect(el.hasFeedbackFor).not.to.include('error');
expect(el.validationStates).to.have.a.property('error');
expect(el.validationStates.error).not.to.have.a.property('Required');
});
it('returns serialized value', async () => {
const el = await fixture(html`
`);
el.formElements[0].checked = true;
expect(el.serializedValue).to.deep.equal('male');
});
it('returns serialized value on unchecked state', async () => {
const el = await fixture(html`
`);
await nextFrame();
expect(el.serializedValue).to.deep.equal('');
});
describe('multipleChoice', () => {
it('has a single modelValue representing all currently checked values', async () => {
const el = await fixture(html`
`);
await nextFrame();
expect(el.modelValue).to.eql(['female']);
el.formElements[0].checked = true;
expect(el.modelValue).to.eql(['male', 'female']);
el.formElements[2].checked = true;
expect(el.modelValue).to.eql(['male', 'female', 'other']);
});
it('can check multiple checkboxes by setting the modelValue', async () => {
const el = await fixture(html`
`);
await nextFrame();
await el.registrationReady;
await el.updateComplete;
el.modelValue = ['male', 'other'];
expect(el.modelValue).to.eql(['male', 'other']);
expect(el.formElements[0].checked).to.be.true;
expect(el.formElements[2].checked).to.be.true;
});
it('unchecks non-matching checkboxes when setting the modelValue', async () => {
const el = await fixture(html`
`);
await nextFrame();
await el.registrationReady;
await el.updateComplete;
expect(el.modelValue).to.eql(['male', 'other']);
expect(el.formElements[0].checked).to.be.true;
expect(el.formElements[2].checked).to.be.true;
el.modelValue = ['female'];
expect(el.formElements[0].checked).to.be.false;
expect(el.formElements[1].checked).to.be.true;
expect(el.formElements[2].checked).to.be.false;
});
});
describe('Integration with a parent form/fieldset', () => {
it('will serialize all children with their serializedValue', async () => {
const el = await fixture(html`
`);
await nextFrame();
await el.registrationReady;
await el.updateComplete;
expect(el.serializedValue).to.eql({
gender: 'female',
});
const choiceGroupEl = el.querySelector('[name="gender"]');
choiceGroupEl.multipleChoice = true;
expect(el.serializedValue).to.eql({
gender: ['female'],
});
});
});
});