Skip to content

Commit

Permalink
fix: aria sync for initialization
Browse files Browse the repository at this point in the history
  • Loading branch information
jeripeierSBB committed May 27, 2024
1 parent 5af8566 commit 42996b9
Show file tree
Hide file tree
Showing 2 changed files with 181 additions and 76 deletions.
224 changes: 169 additions & 55 deletions src/components/radio-button/radio-button/radio-button.e2e.ts
Original file line number Diff line number Diff line change
Expand Up @@ -9,72 +9,186 @@ import { SbbRadioButtonElement } from './radio-button.js';
describe(`sbb-radio-button`, () => {
let element: SbbRadioButtonElement;

beforeEach(async () => {
element = await fixture(html`<sbb-radio-button value="Value">Value label</sbb-radio-button>`);
});
describe('general', () => {
beforeEach(async () => {
element = await fixture(html`<sbb-radio-button value="Value">Value label</sbb-radio-button>`);
});

it('renders', async () => {
assert.instanceOf(element, SbbRadioButtonElement);
});

it('should have corresponding aria values set', async () => {
expect(element).to.have.attribute('aria-checked', 'false');
expect(element).to.have.attribute('aria-required', 'false');
expect(element).not.to.have.attribute('aria-disabled');
});

it('should update aria values', async () => {
element.checked = true;
element.required = true;
element.disabled = true;

await waitForLitRender(element);

it('renders', async () => {
assert.instanceOf(element, SbbRadioButtonElement);
});
expect(element).to.have.attribute('aria-checked', 'true');
expect(element).to.have.attribute('aria-required', 'true');
expect(element).to.have.attribute('aria-disabled', 'true');
});

it('should not render accessibility label about containing state', async () => {
element = element.shadowRoot!.querySelector('.sbb-screen-reader-only:not(input)')!;
expect(element).not.to.be.ok;
});
it('should not render accessibility label about containing state', async () => {
element = element.shadowRoot!.querySelector('.sbb-screen-reader-only:not(input)')!;
expect(element).not.to.be.ok;
});

it('selects radio on click', async () => {
const stateChange = new EventSpy(SbbRadioButtonElement.events.stateChange);
it('selects radio on click', async () => {
const stateChange = new EventSpy(SbbRadioButtonElement.events.stateChange);

element.click();
await waitForLitRender(element);
element.click();
await waitForLitRender(element);

expect(element).to.have.attribute('checked');
await waitForCondition(() => stateChange.events.length === 1);
expect(stateChange.count).to.be.equal(1);
});
expect(element).to.have.attribute('checked');
await waitForCondition(() => stateChange.events.length === 1);
expect(stateChange.count).to.be.equal(1);
});

it('does not deselect radio if already checked', async () => {
const stateChange = new EventSpy(SbbRadioButtonElement.events.stateChange);
it('does not deselect radio if already checked', async () => {
const stateChange = new EventSpy(SbbRadioButtonElement.events.stateChange);

element.click();
await waitForLitRender(element);
expect(element).to.have.attribute('checked');
await waitForCondition(() => stateChange.events.length === 1);
expect(stateChange.count).to.be.equal(1);
element.click();
await waitForLitRender(element);
expect(element).to.have.attribute('checked');
await waitForCondition(() => stateChange.events.length === 1);
expect(stateChange.count).to.be.equal(1);

element.click();
await waitForLitRender(element);
expect(element).to.have.attribute('checked');
await waitForCondition(() => stateChange.events.length === 1);
expect(stateChange.count).to.be.equal(1);
});
element.click();
await waitForLitRender(element);
expect(element).to.have.attribute('checked');
await waitForCondition(() => stateChange.events.length === 1);
expect(stateChange.count).to.be.equal(1);
});

it('allows empty selection', async () => {
const stateChange = new EventSpy(SbbRadioButtonElement.events.stateChange);

element.allowEmptySelection = true;
element.click();
await waitForLitRender(element);
expect(element).to.have.attribute('checked');
await waitForCondition(() => stateChange.events.length === 1);
expect(stateChange.count).to.be.equal(1);

element.click();
await waitForLitRender(element);
expect(element).not.to.have.attribute('checked');
await waitForCondition(() => stateChange.events.length === 2);
expect(stateChange.count).to.be.equal(2);
});
it('allows empty selection', async () => {
const stateChange = new EventSpy(SbbRadioButtonElement.events.stateChange);

element.allowEmptySelection = true;
element.click();
await waitForLitRender(element);
expect(element).to.have.attribute('checked');
await waitForCondition(() => stateChange.events.length === 1);
expect(stateChange.count).to.be.equal(1);

element.click();
await waitForLitRender(element);
expect(element).not.to.have.attribute('checked');
await waitForCondition(() => stateChange.events.length === 2);
expect(stateChange.count).to.be.equal(2);
});

it('should convert falsy checked to false', async () => {
element.checked = true;
(element.checked as any) = undefined;

await waitForLitRender(element);

expect(element.checked).to.equal(false);
expect(element).to.have.attribute('aria-checked', 'false');
});

it('should convert truthy checked to true', async () => {
element.checked = true;
(element.checked as any) = 2;

await waitForLitRender(element);

expect(element.checked).to.equal(true);
expect(element).to.have.attribute('aria-checked', 'true');
});

it('should convert falsy disabled to false', async () => {
element.disabled = true;
(element.disabled as any) = undefined;

await waitForLitRender(element);

expect(element.disabled).to.equal(false);
expect(element).not.to.have.attribute('aria-disabled');
});

it('should convert truthy disabled to true', async () => {
element.disabled = true;
(element.disabled as any) = 2;

await waitForLitRender(element);

expect(element.disabled).to.equal(true);
expect(element).to.have.attribute('aria-disabled', 'true');
});

it('should convert falsy required to false', async () => {
element.required = true;
(element.required as any) = undefined;

await waitForLitRender(element);

expect(element.required).to.equal(false);
expect(element).to.have.attribute('aria-required', 'false');
});

it('should convert truthy required to true', async () => {
element.required = true;
(element.required as any) = 2;

await waitForLitRender(element);

expect(element.required).to.equal(true);
expect(element).to.have.attribute('aria-required', 'true');
});

it('should convert falsy allowEmptySelection to false', async () => {
element.allowEmptySelection = true;
(element.allowEmptySelection as any) = undefined;

await waitForLitRender(element);

expect(element.allowEmptySelection).to.equal(false);
});

it('should convert truthy allowEmptySelection to true', async () => {
element.allowEmptySelection = true;
(element.allowEmptySelection as any) = 2;

await waitForLitRender(element);

it('should convert falsy checked to false', async () => {
element.checked = true;
(element.checked as any) = undefined;
expect(element.checked).to.equal(false);
expect(element.allowEmptySelection).to.equal(true);
});
});

it('should convert truthy checked to true', async () => {
element.checked = true;
(element.checked as any) = 2;
expect(element.checked).to.equal(true);
describe('with initial attributes', () => {
beforeEach(async () => {
element = await fixture(
html`<sbb-radio-button value="Value" checked disabled required>
Value label
</sbb-radio-button>`,
);
});

it('should have corresponding aria values set', async () => {
expect(element).to.have.attribute('aria-checked', 'true');
expect(element).to.have.attribute('aria-required', 'true');
expect(element).to.have.attribute('aria-disabled', 'true');
});

it('should update aria values', async () => {
element.checked = false;
element.required = false;
element.disabled = false;

await waitForLitRender(element);

expect(element).to.have.attribute('aria-checked', 'false');
expect(element).to.have.attribute('aria-required', 'false');
expect(element).not.to.have.attribute('aria-disabled');
});
});
});
33 changes: 12 additions & 21 deletions src/components/radio-button/radio-button/radio-button.ts
Original file line number Diff line number Diff line change
Expand Up @@ -52,7 +52,7 @@ export class SbbRadioButtonElement extends SbbUpdateSchedulerMixin(LitElement) {
*/
@property({ attribute: 'allow-empty-selection', type: Boolean })
public set allowEmptySelection(value: boolean) {
this._allowEmptySelection = value;
this._allowEmptySelection = Boolean(value);
}
public get allowEmptySelection(): boolean {
return this._allowEmptySelection || (this.group?.allowEmptySelection ?? false);
Expand All @@ -69,7 +69,7 @@ export class SbbRadioButtonElement extends SbbUpdateSchedulerMixin(LitElement) {
*/
@property({ reflect: true, type: Boolean })
public set disabled(value: boolean) {
this._disabled = value;
this._disabled = Boolean(value);
}
public get disabled(): boolean {
return this._disabled || (this.group?.disabled ?? false);
Expand All @@ -81,7 +81,7 @@ export class SbbRadioButtonElement extends SbbUpdateSchedulerMixin(LitElement) {
*/
@property({ reflect: true, type: Boolean })
public set required(value: boolean) {
this._required = value;
this._required = Boolean(value);
}
public get required(): boolean {
return this._required || (this.group?.required ?? false);
Expand Down Expand Up @@ -158,22 +158,6 @@ export class SbbRadioButtonElement extends SbbUpdateSchedulerMixin(LitElement) {
SbbRadioButtonElement.events.radioButtonLoaded,
{ bubbles: true },
);

private _handleCheckedChange(currentValue: boolean, previousValue: boolean): void {
if (currentValue !== previousValue) {
this.setAttribute('aria-checked', `${currentValue}`);
this._stateChange.emit({ type: 'checked', checked: currentValue });
this.isSelectionPanelInput && this._updateExpandedLabel();
}
}

private _handleDisabledChange(currentValue: boolean, previousValue: boolean): void {
if (currentValue !== previousValue) {
setOrRemoveAttribute(this, 'aria-disabled', currentValue ? 'true' : null);
this._stateChange.emit({ type: 'disabled', disabled: currentValue });
}
}

private _handleClick(event: Event): void {
event.preventDefault();
this.select();
Expand Down Expand Up @@ -221,10 +205,17 @@ export class SbbRadioButtonElement extends SbbUpdateSchedulerMixin(LitElement) {
super.willUpdate(changedProperties);

if (changedProperties.has('checked')) {
this._handleCheckedChange(this.checked, changedProperties.get('checked')!);
this.setAttribute('aria-checked', `${this.checked}`);
if (this.checked !== changedProperties.get('checked')!) {
this._stateChange.emit({ type: 'checked', checked: this.checked });
this.isSelectionPanelInput && this._updateExpandedLabel();
}
}
if (changedProperties.has('disabled')) {
this._handleDisabledChange(this.disabled, changedProperties.get('disabled')!);
setOrRemoveAttribute(this, 'aria-disabled', this.disabled ? 'true' : null);
if (this.disabled !== changedProperties.get('disabled')!) {
this._stateChange.emit({ type: 'disabled', disabled: this.disabled });
}
}
if (changedProperties.has('required')) {
this.setAttribute('aria-required', `${this.required}`);
Expand Down

0 comments on commit 42996b9

Please sign in to comment.