Skip to content

fix(snack-bar): prevent content from overriding configured aria-live message #12294

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
5 changes: 4 additions & 1 deletion src/lib/snack-bar/snack-bar-config.ts
Original file line number Diff line number Diff line change
Expand Up @@ -26,7 +26,10 @@ export class MatSnackBarConfig<D = any> {
/** The politeness level for the MatAriaLiveAnnouncer announcement. */
politeness?: AriaLivePoliteness = 'assertive';

/** Message to be announced by the MatAriaLiveAnnouncer */
/**
* Message to be announced by the LiveAnnouncer. When opening a snackbar without a custom
* component or template, the announcement message will default to the specified message.
*/
announcementMessage?: string = '';

/** The view container to place the overlay for the snack bar into. */
Expand Down
54 changes: 42 additions & 12 deletions src/lib/snack-bar/snack-bar.spec.ts
Original file line number Diff line number Diff line change
Expand Up @@ -75,21 +75,21 @@ describe('MatSnackBar', () => {
.toBe('alert', 'Expected snack bar container to have role="alert"');
});

it('should open and close a snackbar without a ViewContainerRef', fakeAsync(() => {
let snackBarRef = snackBar.open('Snack time!', 'Chew');
viewContainerFixture.detectChanges();
it('should open and close a snackbar without a ViewContainerRef', fakeAsync(() => {
let snackBarRef = snackBar.open('Snack time!', 'Chew');
viewContainerFixture.detectChanges();

let messageElement = overlayContainerElement.querySelector('snack-bar-container')!;
expect(messageElement.textContent).toContain('Snack time!',
'Expected snack bar to show a message without a ViewContainerRef');
let messageElement = overlayContainerElement.querySelector('snack-bar-container')!;
expect(messageElement.textContent).toContain('Snack time!',
'Expected snack bar to show a message without a ViewContainerRef');

snackBarRef.dismiss();
viewContainerFixture.detectChanges();
flush();
snackBarRef.dismiss();
viewContainerFixture.detectChanges();
flush();

expect(overlayContainerElement.childNodes.length)
.toBe(0, 'Expected snack bar to be dismissed without a ViewContainerRef');
}));
expect(overlayContainerElement.childNodes.length)
.toBe(0, 'Expected snack bar to be dismissed without a ViewContainerRef');
}));

it('should open a simple message with a button', () => {
let config: MatSnackBarConfig = {viewContainerRef: testViewContainerRef};
Expand Down Expand Up @@ -153,6 +153,36 @@ describe('MatSnackBar', () => {
.toBe(0, 'Expected the overlay container element to have no child elements');
}));


it('should default to the passed message for the announcement message', fakeAsync(() => {
spyOn(liveAnnouncer, 'announce');

snackBar.open(simpleMessage);
viewContainerFixture.detectChanges();

expect(overlayContainerElement.childElementCount)
.toBe(1, 'Expected the overlay with the default announcement message to be added');

// Expect the live announcer to have been called with the display message and some
// string for the politeness. We do not want to test for the default politeness here.
expect(liveAnnouncer.announce).toHaveBeenCalledWith(simpleMessage, jasmine.any(String));
}));

it('should be able to specify a custom announcement message', fakeAsync(() => {
spyOn(liveAnnouncer, 'announce');

snackBar.open(simpleMessage, '', {
announcementMessage: 'Custom announcement',
politeness: 'assertive'
});
viewContainerFixture.detectChanges();

expect(overlayContainerElement.childElementCount)
.toBe(1, 'Expected the overlay with a custom `announcementMessage` to be added');

expect(liveAnnouncer.announce).toHaveBeenCalledWith('Custom announcement', 'assertive');
}));

it('should be able to get dismissed through the service', fakeAsync(() => {
snackBar.open(simpleMessage);
viewContainerFixture.detectChanges();
Expand Down
5 changes: 4 additions & 1 deletion src/lib/snack-bar/snack-bar.ts
Original file line number Diff line number Diff line change
Expand Up @@ -112,7 +112,10 @@ export class MatSnackBar {
// Since the user doesn't have access to the component, we can
// override the data to pass in our own message and action.
_config.data = {message, action};
_config.announcementMessage = message;

if (!_config.announcementMessage) {
_config.announcementMessage = message;
}

return this.openFromComponent(SimpleSnackBar, _config);
}
Expand Down