From 592865861c4c61fe5decac1299b921d5b4e73b77 Mon Sep 17 00:00:00 2001 From: Jay Goss Date: Thu, 17 Sep 2026 16:08:25 -0500 Subject: [PATCH] fix(onboarding): Name SCM provider pills by their provider AddIntegrationButton sets a static aria-label of "Add integration" on every instance, so the GitHub, GitLab and Bitbucket pills in the SCM onboarding and project creation flows all had the same accessible name and the More menu trigger was named only "More". Each pill is now named "Add" plus the provider name and the trigger is named "More providers". The static label stays the default for every other caller. --- .../onboarding/scm/scmProviderPills.spec.tsx | 16 +++++++++------- .../onboarding/scm/scmProviderPills.tsx | 4 ++++ .../addIntegrationButton.tsx | 2 +- .../integrationButton.tsx | 9 ++++++++- 4 files changed, 22 insertions(+), 9 deletions(-) diff --git a/static/app/components/onboarding/scm/scmProviderPills.spec.tsx b/static/app/components/onboarding/scm/scmProviderPills.spec.tsx index 3e6fd4be451f..32c4121dd8e5 100644 --- a/static/app/components/onboarding/scm/scmProviderPills.spec.tsx +++ b/static/app/components/onboarding/scm/scmProviderPills.spec.tsx @@ -48,9 +48,11 @@ describe('ScmProviderPills', () => { /> ); - expect(screen.getByText('GitHub')).toBeInTheDocument(); - expect(screen.getByText('GitLab')).toBeInTheDocument(); - expect(screen.getByText('Bitbucket')).toBeInTheDocument(); + expect(screen.getByRole('button', {name: 'Add GitHub'})).toHaveTextContent('GitHub'); + expect(screen.getByRole('button', {name: 'Add GitLab'})).toHaveTextContent('GitLab'); + expect(screen.getByRole('button', {name: 'Add Bitbucket'})).toHaveTextContent( + 'Bitbucket' + ); expect(screen.queryByText('More')).not.toBeInTheDocument(); }); @@ -101,7 +103,7 @@ describe('ScmProviderPills', () => { // Secondary providers are hidden behind the "More" dropdown expect(screen.queryByText('Bitbucket Server')).not.toBeInTheDocument(); - await userEvent.click(screen.getByRole('button', {name: 'More'})); + await userEvent.click(screen.getByRole('button', {name: 'More providers'})); expect( screen.getByRole('menuitemradio', {name: 'Bitbucket Server'}) @@ -127,7 +129,7 @@ describe('ScmProviderPills', () => { /> ); - await userEvent.click(screen.getByRole('button', {name: 'More'})); + await userEvent.click(screen.getByRole('button', {name: 'More providers'})); await userEvent.click(screen.getByRole('menuitemradio', {name: 'GitHub Enterprise'})); expect(openPipelineModalSpy).toHaveBeenCalledTimes(1); @@ -147,7 +149,7 @@ describe('ScmProviderPills', () => { /> ); - await userEvent.click(screen.getByRole('button', {name: 'More'})); + await userEvent.click(screen.getByRole('button', {name: 'More providers'})); await userEvent.click(screen.getByRole('menuitemradio', {name: 'GitHub Enterprise'})); expect(trackSpy).toHaveBeenCalledWith( @@ -170,7 +172,7 @@ describe('ScmProviderPills', () => { /> ); - await userEvent.click(screen.getByRole('button', {name: 'More'})); + await userEvent.click(screen.getByRole('button', {name: 'More providers'})); await userEvent.click(screen.getByRole('menuitemradio', {name: 'GitHub Enterprise'})); expect(trackSpy).toHaveBeenCalledWith( diff --git a/static/app/components/onboarding/scm/scmProviderPills.tsx b/static/app/components/onboarding/scm/scmProviderPills.tsx index 459ad3bf8795..13ef85fd1e08 100644 --- a/static/app/components/onboarding/scm/scmProviderPills.tsx +++ b/static/app/components/onboarding/scm/scmProviderPills.tsx @@ -80,6 +80,9 @@ function ScmProviderPillRow({ size: buttonSize, icon: getIntegrationIcon(provider.key, iconSize), buttonText: provider.name, + // AddIntegrationButton names every instance "Add integration"; + // name each pill by its provider instead. + 'aria-label': t('Add %s', provider.name), }} /> @@ -87,6 +90,7 @@ function ScmProviderPillRow({ {moreProviders.length > 0 && ( ({ diff --git a/static/app/views/settings/organizationIntegrations/addIntegrationButton.tsx b/static/app/views/settings/organizationIntegrations/addIntegrationButton.tsx index d1049b2aec8e..f6a4b70a76e5 100644 --- a/static/app/views/settings/organizationIntegrations/addIntegrationButton.tsx +++ b/static/app/views/settings/organizationIntegrations/addIntegrationButton.tsx @@ -61,6 +61,7 @@ export function AddIntegrationButton({ > diff --git a/static/app/views/settings/organizationIntegrations/integrationButton.tsx b/static/app/views/settings/organizationIntegrations/integrationButton.tsx index 221d297b4b34..726dc03ac5f7 100644 --- a/static/app/views/settings/organizationIntegrations/integrationButton.tsx +++ b/static/app/views/settings/organizationIntegrations/integrationButton.tsx @@ -17,7 +17,14 @@ type Props = { */ buttonProps: Pick< React.ComponentProps, - 'size' | 'variant' | 'disabled' | 'style' | 'data-test-id' | 'icon' | 'buttonText' + | 'size' + | 'variant' + | 'disabled' + | 'style' + | 'data-test-id' + | 'icon' + | 'buttonText' + | 'aria-label' >; onAddIntegration: (integration: Integration) => void; onExternalClick: () => void;