diff --git a/src/components/NotificationSystem/NotificationSystem.utils.test.tsx b/src/components/NotificationSystem/NotificationSystem.utils.test.tsx index 3689034a7..34227e6d9 100644 --- a/src/components/NotificationSystem/NotificationSystem.utils.test.tsx +++ b/src/components/NotificationSystem/NotificationSystem.utils.test.tsx @@ -78,10 +78,13 @@ describe('NotificationSystem utils', () => { let spies; - const setup = () => { + const setup = ({ screenReaderAnnouncerIsRegistered = true } = {}) => { spies = { autoClose: jest.spyOn(utils, 'calculateAutoClose'), getContainerID: jest.spyOn(utils, 'getContainerID'), + isRegistered: jest + .spyOn(ScreenReaderAnnouncer, 'isRegistered') + .mockReturnValue(screenReaderAnnouncerIsRegistered), announce: jest.spyOn(ScreenReaderAnnouncer, 'announce').mockReturnValue(), }; }; @@ -100,6 +103,7 @@ describe('NotificationSystem utils', () => { }); expect(spies.autoClose).toHaveBeenCalledWith(options); expect(spies.getContainerID).toHaveBeenCalledWith(notificationSystemId, ATTENTION.MEDIUM); + expect(spies.isRegistered).not.toHaveBeenCalled(); expect(spies.announce).not.toHaveBeenCalled(); }); @@ -124,13 +128,14 @@ describe('NotificationSystem utils', () => { }); expect(spies.autoClose).toHaveBeenCalledWith(options); expect(spies.getContainerID).toHaveBeenCalledWith(notificationSystemId, ATTENTION.MEDIUM); + expect(spies.isRegistered).not.toHaveBeenCalled(); expect(spies.announce).toHaveBeenCalledWith( { body: screenReaderAnnouncement }, notificationSystemId ); }); - it('should announce the screenReaderAnnouncement using the announcerIdentity, if provided', () => { + it('should announce the screenReaderAnnouncement using the announcerIdentity, if provided and registered', () => { setup(); const options = { @@ -152,21 +157,54 @@ describe('NotificationSystem utils', () => { }); expect(spies.autoClose).toHaveBeenCalledWith(options); expect(spies.getContainerID).toHaveBeenCalledWith(notificationSystemId, ATTENTION.MEDIUM); + expect(spies.isRegistered).toHaveBeenCalledWith(announcerIdentity); expect(spies.announce).toHaveBeenCalledWith( { body: screenReaderAnnouncement }, announcerIdentity ); }); + + it('should announce the screenReaderAnnouncement using the notificationSystemId, if announcerIdentity not registered', () => { + setup({ screenReaderAnnouncerIsRegistered: false }); + + const options = { + toastId, + onClose, + autoClose, + notificationSystemId, + attention, + screenReaderAnnouncement, + announcerIdentity, + }; + expect(notify(
, options)).toBe(toastId); + + expect(toast).toHaveBeenCalledWith(, { + autoClose: autoClose, + containerId: 'test_containerbla_medium_notification_container', + onClose: onClose, + toastId: toastId, + }); + expect(spies.autoClose).toHaveBeenCalledWith(options); + expect(spies.getContainerID).toHaveBeenCalledWith(notificationSystemId, ATTENTION.MEDIUM); + expect(spies.isRegistered).toHaveBeenCalledWith(announcerIdentity); + expect(spies.announce).toHaveBeenCalledWith( + { body: screenReaderAnnouncement }, + notificationSystemId + ); + }); }); describe('update', () => { let toastId; let spies; - const setup = () => { + const setup = ({ screenReaderAnnouncerIsRegistered = true } = {}) => { toastId = notify(, { notificationSystemId: 'id' }); spies = { getContainerID: jest.spyOn(utils, 'getContainerID'), + isRegistered: jest + .spyOn(ScreenReaderAnnouncer, 'isRegistered') + .mockReturnValue(screenReaderAnnouncerIsRegistered), announce: jest.spyOn(ScreenReaderAnnouncer, 'announce').mockReturnValue(), }; }; @@ -186,6 +224,7 @@ describe('NotificationSystem utils', () => { render: , }); expect(spies.getContainerID).toHaveBeenCalledWith('id', 'medium'); + expect(spies.isRegistered).not.toHaveBeenCalled(); expect(spies.announce).not.toHaveBeenCalled(); }); @@ -205,10 +244,11 @@ describe('NotificationSystem utils', () => { render: , }); expect(spies.getContainerID).toHaveBeenCalledWith('id', 'medium'); + expect(spies.isRegistered).not.toHaveBeenCalled(); expect(spies.announce).toHaveBeenCalledWith({ body: 'some screenreader announcement' }, 'id'); }); - it('should announce the screenReaderAnnouncement using the announcerIdentity, if provided', () => { + it('should announce the screenReaderAnnouncement using the announcerIdentity, if provided and registered', () => { setup(); update(toastId, { @@ -225,11 +265,33 @@ describe('NotificationSystem utils', () => { render: , }); expect(spies.getContainerID).toHaveBeenCalledWith('id', 'medium'); + expect(spies.isRegistered).toHaveBeenCalledWith('some_announcer_id'); expect(spies.announce).toHaveBeenCalledWith( { body: 'some screenreader announcement' }, 'some_announcer_id' ); }); + + it('should announce the screenReaderAnnouncement using the notificationSystemId, if announcerIdentity not registered', () => { + setup({ screenReaderAnnouncerIsRegistered: false }); + + update(toastId, { + toastId: 'new', + render: , + attention: ATTENTION.MEDIUM, + notificationSystemId: 'id', + screenReaderAnnouncement: 'some screenreader announcement', + announcerIdentity: 'some_announcer_id', + }); + expect(toast.update).toHaveBeenCalledWith(toastId, { + containerId: 'id_medium_notification_container', + toastId: 'new', + render: , + }); + expect(spies.getContainerID).toHaveBeenCalledWith('id', 'medium'); + expect(spies.isRegistered).toHaveBeenCalledWith('some_announcer_id'); + expect(spies.announce).toHaveBeenCalledWith({ body: 'some screenreader announcement' }, 'id'); + }); }); describe('dismiss', () => { diff --git a/src/components/NotificationSystem/NotificationSystem.utils.ts b/src/components/NotificationSystem/NotificationSystem.utils.ts index dc2299dcf..58a1659c4 100644 --- a/src/components/NotificationSystem/NotificationSystem.utils.ts +++ b/src/components/NotificationSystem/NotificationSystem.utils.ts @@ -46,13 +46,20 @@ export const notify = (content: ToastContent, options: NotifyOptionsType): Id => attention, onClose, role, - announcerIdentity, + announcerIdentity: announcerIdentityFromOptions, } = options; if (screenReaderAnnouncement) { - ScreenReaderAnnouncer.announce( - { body: screenReaderAnnouncement }, - announcerIdentity || notificationSystemId - ); + let announcerIdentity = notificationSystemId; + if (announcerIdentityFromOptions) { + if (ScreenReaderAnnouncer.isRegistered(announcerIdentityFromOptions)) { + announcerIdentity = announcerIdentityFromOptions; + } else { + console.warn( + `ScreenReaderAnnouncer with identity ${announcerIdentityFromOptions} is not registered, falling back to ${notificationSystemId}` + ); + } + } + ScreenReaderAnnouncer.announce({ body: screenReaderAnnouncement }, announcerIdentity); } return toast(content, { toastId: toastId, @@ -74,14 +81,21 @@ export const update = (toastId: Id, options: UpdateOptionsType): void => { notificationSystemId, attention, screenReaderAnnouncement, - announcerIdentity, + announcerIdentity: announcerIdentityFromOptions, ...updateOptions } = options; if (screenReaderAnnouncement) { - ScreenReaderAnnouncer.announce( - { body: screenReaderAnnouncement }, - announcerIdentity || notificationSystemId - ); + let announcerIdentity = notificationSystemId; + if (announcerIdentityFromOptions) { + if (ScreenReaderAnnouncer.isRegistered(announcerIdentityFromOptions)) { + announcerIdentity = announcerIdentityFromOptions; + } else { + console.warn( + `ScreenReaderAnnouncer with identity ${announcerIdentityFromOptions} is not registered, falling back to ${notificationSystemId}` + ); + } + } + ScreenReaderAnnouncer.announce({ body: screenReaderAnnouncement }, announcerIdentity); } toast.update(toastId, { ...updateOptions, diff --git a/src/components/ScreenReaderAnnouncer/ScreenReaderAnnouncer.tsx b/src/components/ScreenReaderAnnouncer/ScreenReaderAnnouncer.tsx index d9f9f2b66..f5690b57a 100644 --- a/src/components/ScreenReaderAnnouncer/ScreenReaderAnnouncer.tsx +++ b/src/components/ScreenReaderAnnouncer/ScreenReaderAnnouncer.tsx @@ -11,6 +11,7 @@ import { AnnouncerProps, CompoundProps, ScreenReaderAnnouncerAnnounce, + ScreenReaderAnnouncerIsRegistered, } from './ScreenReaderAnnouncer.types'; const registry: Record