Skip to content

Commit

Permalink
feat(feedback): Trigger button aria label configuration (#13008)
Browse files Browse the repository at this point in the history
Adds `triggerAriaLabel` to configure the aria label of the trigger
button.
The aria label is set to the first value that's non-empty: 
1. `triggerAriaLabel`
2. `triggerLabel`
3. TRIGGER_LABEL ("Report a Bug")

Closes #12505
  • Loading branch information
c298lee authored Jul 23, 2024
1 parent edea287 commit 65042b5
Show file tree
Hide file tree
Showing 4 changed files with 77 additions and 4 deletions.
61 changes: 61 additions & 0 deletions packages/feedback/src/core/components/Actor.test.ts
Original file line number Diff line number Diff line change
@@ -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');
});
});
7 changes: 4 additions & 3 deletions packages/feedback/src/core/components/Actor.ts
Original file line number Diff line number Diff line change
@@ -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;
}

Expand All @@ -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');
Expand Down
8 changes: 7 additions & 1 deletion packages/feedback/src/core/integration.ts
Original file line number Diff line number Diff line change
Expand Up @@ -99,6 +99,7 @@ export const buildFeedbackIntegration = ({
submitButtonLabel = SUBMIT_BUTTON_LABEL,
successMessageText = SUCCESS_MESSAGE_TEXT,
triggerLabel = TRIGGER_LABEL,
triggerAriaLabel = '',

// FeedbackCallbacks
onFormOpen,
Expand All @@ -124,6 +125,7 @@ export const buildFeedbackIntegration = ({
themeLight,

triggerLabel,
triggerAriaLabel,
cancelButtonLabel,
submitButtonLabel,
confirmButtonLabel,
Expand Down Expand Up @@ -258,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, shadow });
const actor = Actor({
triggerLabel: mergedOptions.triggerLabel,
triggerAriaLabel: mergedOptions.triggerAriaLabel,
shadow,
});
_attachTo(actor.el, {
...mergedOptions,
onFormOpen() {
Expand Down
5 changes: 5 additions & 0 deletions packages/types/src/feedback/config.ts
Original file line number Diff line number Diff line change
Expand Up @@ -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
*/
Expand Down

0 comments on commit 65042b5

Please sign in to comment.