From 12b0627d6749b99b2ae2631d04d82aaa7cedb4ee Mon Sep 17 00:00:00 2001 From: Catherine Lee <55311782+c298lee@users.noreply.github.com> Date: Mon, 22 Jul 2024 14:37:51 -0400 Subject: [PATCH 1/2] add aria label config --- packages/feedback/src/core/components/Actor.ts | 7 ++++--- packages/feedback/src/core/integration.ts | 4 +++- packages/types/src/feedback/config.ts | 5 +++++ 3 files changed, 12 insertions(+), 4 deletions(-) diff --git a/packages/feedback/src/core/components/Actor.ts b/packages/feedback/src/core/components/Actor.ts index 6b2469e0313c..8dff7d5c7eb5 100644 --- a/packages/feedback/src/core/components/Actor.ts +++ b/packages/feedback/src/core/components/Actor.ts @@ -1,9 +1,10 @@ -import { DOCUMENT } from '../../constants'; +import { DOCUMENT, TRIGGER_LABEL } from '../../constants'; import { createActorStyles } from './Actor.css'; import { FeedbackIcon } from './FeedbackIcon'; export interface ActorProps { triggerLabel: string; + triggerAriaLabel: string; shadow: ShadowRoot; } @@ -22,12 +23,12 @@ export interface ActorComponent { /** * The sentry-provided button to open the feedback modal */ -export function Actor({ triggerLabel, shadow }: ActorProps): ActorComponent { +export function Actor({ triggerLabel, triggerAriaLabel, shadow }: ActorProps): ActorComponent { const el = DOCUMENT.createElement('button'); el.type = 'button'; el.className = 'widget__actor'; el.ariaHidden = 'false'; - el.ariaLabel = triggerLabel; + el.ariaLabel = triggerAriaLabel || triggerLabel || TRIGGER_LABEL; el.appendChild(FeedbackIcon()); if (triggerLabel) { const label = DOCUMENT.createElement('span'); diff --git a/packages/feedback/src/core/integration.ts b/packages/feedback/src/core/integration.ts index 4e8caa85a135..eb15d92a9894 100644 --- a/packages/feedback/src/core/integration.ts +++ b/packages/feedback/src/core/integration.ts @@ -99,6 +99,7 @@ export const buildFeedbackIntegration = ({ submitButtonLabel = SUBMIT_BUTTON_LABEL, successMessageText = SUCCESS_MESSAGE_TEXT, triggerLabel = TRIGGER_LABEL, + triggerAriaLabel = '', // FeedbackCallbacks onFormOpen, @@ -124,6 +125,7 @@ export const buildFeedbackIntegration = ({ themeLight, triggerLabel, + triggerAriaLabel, cancelButtonLabel, submitButtonLabel, confirmButtonLabel, @@ -258,7 +260,7 @@ export const buildFeedbackIntegration = ({ const _createActor = (optionOverrides: OverrideFeedbackConfiguration = {}): ActorComponent => { const mergedOptions = mergeOptions(_options, optionOverrides); const shadow = _createShadow(mergedOptions); - const actor = Actor({ triggerLabel: mergedOptions.triggerLabel, shadow }); + const actor = Actor({ triggerLabel: mergedOptions.triggerLabel, triggerAriaLabel: mergedOptions.triggerAriaLabel, shadow }); _attachTo(actor.el, { ...mergedOptions, onFormOpen() { diff --git a/packages/types/src/feedback/config.ts b/packages/types/src/feedback/config.ts index 2350545941be..01be1586024e 100644 --- a/packages/types/src/feedback/config.ts +++ b/packages/types/src/feedback/config.ts @@ -92,6 +92,11 @@ export interface FeedbackTextConfiguration { */ triggerLabel: string; + /** + * The aria label for the Feedback widget button that opens the dialog + */ + triggerAriaLabel: string; + /** * The label for the Feedback form cancel button that closes dialog */ From 8e4a5b4f6fb00205328ef0cdea33e79a4fe220be Mon Sep 17 00:00:00 2001 From: Catherine Lee <55311782+c298lee@users.noreply.github.com> Date: Tue, 23 Jul 2024 13:25:09 -0400 Subject: [PATCH 2/2] lint + tests --- .../src/core/components/Actor.test.ts | 61 +++++++++++++++++++ .../feedback/src/core/components/Actor.ts | 2 +- packages/feedback/src/core/integration.ts | 6 +- packages/types/src/feedback/config.ts | 4 +- 4 files changed, 69 insertions(+), 4 deletions(-) create mode 100644 packages/feedback/src/core/components/Actor.test.ts diff --git a/packages/feedback/src/core/components/Actor.test.ts b/packages/feedback/src/core/components/Actor.test.ts new file mode 100644 index 000000000000..27c138d5420d --- /dev/null +++ b/packages/feedback/src/core/components/Actor.test.ts @@ -0,0 +1,61 @@ +import { TRIGGER_LABEL } from '../../constants'; +import { getFeedback } from '../getFeedback'; +import { buildFeedbackIntegration } from '../integration'; +import { mockSdk } from '../mockSdk'; + +describe('Actor', () => { + it('renders the actor button', () => { + const feedbackIntegration = buildFeedbackIntegration({ + lazyLoadIntegration: jest.fn(), + }); + + const configuredIntegration = feedbackIntegration({}); + mockSdk({ + sentryOptions: { + integrations: [configuredIntegration], + }, + }); + + const feedback = getFeedback(); + expect(feedback).toBeDefined(); + + const actorComponent = feedback!.createWidget(); + + expect(actorComponent.el).toBeInstanceOf(HTMLButtonElement); + expect(actorComponent.el?.textContent).toBe(TRIGGER_LABEL); + }); + + it('renders the correct aria label for the button', () => { + const feedbackIntegration = buildFeedbackIntegration({ + lazyLoadIntegration: jest.fn(), + }); + + const configuredIntegration = feedbackIntegration({}); + mockSdk({ + sentryOptions: { + integrations: [configuredIntegration], + }, + }); + + const feedback = getFeedback(); + expect(feedback).toBeDefined(); + + // aria label is the same as trigger label when the trigger label isn't empty + const actorDefault = feedback!.createWidget({ triggerLabel: 'Button' }); + + expect(actorDefault.el?.textContent).toBe('Button'); + expect(actorDefault.el?.ariaLabel).toBe('Button'); + + // aria label is default text when trigger label is empty and aria isn't configured + const actorIcon = feedback!.createWidget({ triggerLabel: '' }); + + expect(actorIcon.el?.textContent).toBe(''); + expect(actorIcon.el?.ariaLabel).toBe(TRIGGER_LABEL); + + // aria label is the triggerAriaLabel if it's configured + const actorAria = feedback!.createWidget({ triggerLabel: 'Button', triggerAriaLabel: 'Aria' }); + + expect(actorAria.el?.textContent).toBe('Button'); + expect(actorAria.el?.ariaLabel).toBe('Aria'); + }); +}); diff --git a/packages/feedback/src/core/components/Actor.ts b/packages/feedback/src/core/components/Actor.ts index 8dff7d5c7eb5..f31da8612a9f 100644 --- a/packages/feedback/src/core/components/Actor.ts +++ b/packages/feedback/src/core/components/Actor.ts @@ -28,7 +28,7 @@ export function Actor({ triggerLabel, triggerAriaLabel, shadow }: ActorProps): A el.type = 'button'; el.className = 'widget__actor'; el.ariaHidden = 'false'; - el.ariaLabel = triggerAriaLabel || triggerLabel || TRIGGER_LABEL; + el.ariaLabel = triggerAriaLabel || triggerLabel || TRIGGER_LABEL; el.appendChild(FeedbackIcon()); if (triggerLabel) { const label = DOCUMENT.createElement('span'); diff --git a/packages/feedback/src/core/integration.ts b/packages/feedback/src/core/integration.ts index eb15d92a9894..e2194f43a1d5 100644 --- a/packages/feedback/src/core/integration.ts +++ b/packages/feedback/src/core/integration.ts @@ -260,7 +260,11 @@ export const buildFeedbackIntegration = ({ const _createActor = (optionOverrides: OverrideFeedbackConfiguration = {}): ActorComponent => { const mergedOptions = mergeOptions(_options, optionOverrides); const shadow = _createShadow(mergedOptions); - const actor = Actor({ triggerLabel: mergedOptions.triggerLabel, triggerAriaLabel: mergedOptions.triggerAriaLabel, shadow }); + const actor = Actor({ + triggerLabel: mergedOptions.triggerLabel, + triggerAriaLabel: mergedOptions.triggerAriaLabel, + shadow, + }); _attachTo(actor.el, { ...mergedOptions, onFormOpen() { diff --git a/packages/types/src/feedback/config.ts b/packages/types/src/feedback/config.ts index 01be1586024e..977bf6ef7640 100644 --- a/packages/types/src/feedback/config.ts +++ b/packages/types/src/feedback/config.ts @@ -93,8 +93,8 @@ export interface FeedbackTextConfiguration { triggerLabel: string; /** - * The aria label for the Feedback widget button that opens the dialog - */ + * The aria label for the Feedback widget button that opens the dialog + */ triggerAriaLabel: string; /**