diff --git a/projects/storefrontlib/shared/components/ng-select-a11y/ng-select-a11y.directive.spec.ts b/projects/storefrontlib/shared/components/ng-select-a11y/ng-select-a11y.directive.spec.ts index 1701cee113e..7326e85acdb 100644 --- a/projects/storefrontlib/shared/components/ng-select-a11y/ng-select-a11y.directive.spec.ts +++ b/projects/storefrontlib/shared/components/ng-select-a11y/ng-select-a11y.directive.spec.ts @@ -6,22 +6,23 @@ import { FeatureConfigService, TranslationService } from '@spartacus/core'; import { of } from 'rxjs'; import { NgSelectA11yDirective } from './ng-select-a11y.directive'; import { NgSelectA11yModule } from './ng-select-a11y.module'; +import { BreakpointService } from '@spartacus/storefront'; @Component({ template: ` - {{ - val - }}
`, }) class MockComponent { isSearchable: boolean = false; + selected = 1; } class MockFeatureConfigService { @@ -39,6 +40,7 @@ class MockTranslationService { describe('NgSelectA11yDirective', () => { let component: MockComponent; let fixture: ComponentFixture; + let breakpointService: BreakpointService; beforeEach(() => { TestBed.configureTestingModule({ @@ -51,8 +53,8 @@ describe('NgSelectA11yDirective', () => { }).compileComponents(); fixture = TestBed.createComponent(MockComponent); - component = fixture.componentInstance; + breakpointService = TestBed.inject(BreakpointService); }); function getNgSelect(): DebugElement { @@ -89,4 +91,28 @@ describe('NgSelectA11yDirective', () => { done(); }); }); + + it('should append value to aria-label and hide the value element from screen reader on mobile', (done) => { + const isDownSpy = spyOn(breakpointService, 'isDown').and.returnValue( + of(true) + ); + fixture.detectChanges(); + const ngSelectInstance = getNgSelect().componentInstance; + ngSelectInstance.writeValue(component.selected); + ngSelectInstance.detectChanges(); + + // Wait for the mutation observer to update the aria-label + setTimeout(() => { + const select = getNgSelect().nativeElement; + const valueElement = select.querySelector('.ng-value'); + const divCombobox = select.querySelector("[role='combobox']"); + + expect(valueElement.getAttribute('aria-hidden')).toEqual('true'); + expect(divCombobox.getAttribute('aria-label')).toContain( + `, ${component.selected}` + ); + isDownSpy.and.callThrough(); + done(); + }); + }); }); diff --git a/projects/storefrontlib/shared/components/ng-select-a11y/ng-select-a11y.directive.ts b/projects/storefrontlib/shared/components/ng-select-a11y/ng-select-a11y.directive.ts index 570d0d4ceee..4c25b9a7a13 100644 --- a/projects/storefrontlib/shared/components/ng-select-a11y/ng-select-a11y.directive.ts +++ b/projects/storefrontlib/shared/components/ng-select-a11y/ng-select-a11y.directive.ts @@ -119,6 +119,10 @@ export class NgSelectA11yDirective implements AfterViewInit { observerInstance.disconnect(); } + /** + * Hides the input value from the screen reader and provides it as part of the aria-label instead. + * This improves the screen reader output on mobile devices. + */ appendValueToAriaLabel( _changes: any, observer: MutationObserver,