From 7b3a1ff699614fd008390ab824ca8e142d13ec67 Mon Sep 17 00:00:00 2001 From: Adam Setch Date: Wed, 28 Oct 2026 18:54:31 -0400 Subject: [PATCH 1/2] test: migrate getByTestId queries to accessible queries Fix back button accessible name in Header (aria-labelledby -> aria-label). Refs #3510 --- src/renderer/components/Sidebar.test.tsx | 62 +++++++++------- .../filters/FilterCheckbox.test.tsx | 4 +- .../notifications/NotificationRow.test.tsx | 28 ++++---- .../components/primitives/Header.test.tsx | 4 +- src/renderer/components/primitives/Header.tsx | 2 +- .../__snapshots__/Header.test.tsx.snap | 12 +++- src/renderer/routes/AccountScopes.test.tsx | 4 +- src/renderer/routes/Accounts.test.tsx | 72 ++++++++++--------- src/renderer/routes/Filters.test.tsx | 4 +- src/renderer/routes/Settings.test.tsx | 36 +++++++--- .../LoginWithPersonalAccessToken.test.tsx | 4 +- .../LoginWithPersonalAccessToken.test.tsx | 2 +- .../github/LoginWithDeviceFlow.test.tsx | 34 ++++----- .../routes/github/LoginWithGitHubCLI.test.tsx | 14 ++-- .../routes/github/LoginWithOAuthApp.test.tsx | 4 +- .../LoginWithPersonalAccessToken.test.tsx | 4 +- .../LoginWithGitHubCLI.test.tsx.snap | 22 ++++-- .../LoginWithPersonalAccessToken.test.tsx | 2 +- 18 files changed, 184 insertions(+), 130 deletions(-) diff --git a/src/renderer/components/Sidebar.test.tsx b/src/renderer/components/Sidebar.test.tsx index 4b89e30db..4be7f15ba 100644 --- a/src/renderer/components/Sidebar.test.tsx +++ b/src/renderer/components/Sidebar.test.tsx @@ -76,15 +76,15 @@ describe('renderer/components/Sidebar.tsx', () => { accounts: [], }); - expect(screen.queryByTestId('sidebar-notifications')).not.toBeInTheDocument(); - expect(screen.queryByTestId('sidebar-my-issues')).not.toBeInTheDocument(); - expect(screen.queryByTestId('sidebar-my-pull-requests')).not.toBeInTheDocument(); + expect(screen.queryByRole('button', { name: /^Notifications/ })).not.toBeInTheDocument(); + expect(screen.queryByRole('button', { name: /^My issues/ })).not.toBeInTheDocument(); + expect(screen.queryByRole('button', { name: /^My pull requests/ })).not.toBeInTheDocument(); }); it('navigates home when clicking logo', async () => { renderWithProviders(); - await userEvent.click(screen.getByTestId('sidebar-home')); + await userEvent.click(screen.getByRole('button', { name: new RegExp(`^${APPLICATION.NAME}`) })); expect(navigateMock).toHaveBeenCalledTimes(1); expect(navigateMock).toHaveBeenCalledWith('/', { replace: true }); @@ -96,7 +96,7 @@ describe('renderer/components/Sidebar.tsx', () => { accounts: [mockGitHubCloudAccount], }); - await userEvent.click(screen.getByTestId('sidebar-notifications')); + await userEvent.click(screen.getByRole('button', { name: /^Notifications/ })); expect(openExternalLinkSpy).toHaveBeenCalledTimes(1); expect(openExternalLinkSpy).toHaveBeenCalledWith('https://github.com/notifications'); @@ -134,7 +134,7 @@ describe('renderer/components/Sidebar.tsx', () => { settings: { ...mockSettings, participating: false }, }); - expect(screen.getByTestId('sidebar-focused-mode')).toHaveAttribute( + expect(screen.getByRole('button', { name: /^Toggle focused mode/ })).toHaveAttribute( 'data-variant', 'invisible', ); @@ -146,7 +146,10 @@ describe('renderer/components/Sidebar.tsx', () => { settings: { ...mockSettings, participating: true }, }); - expect(screen.getByTestId('sidebar-focused-mode')).toHaveAttribute('data-variant', 'primary'); + expect(screen.getByRole('button', { name: /^Toggle focused mode/ })).toHaveAttribute( + 'data-variant', + 'primary', + ); }); it('toggles participating when clicked', async () => { @@ -156,7 +159,7 @@ describe('renderer/components/Sidebar.tsx', () => { fetchNotifications: fetchNotificationsMock, }); - await userEvent.click(screen.getByTestId('sidebar-focused-mode')); + await userEvent.click(screen.getByRole('button', { name: /^Toggle focused mode/ })); expect(updateSettingSpy).toHaveBeenCalledTimes(1); expect(updateSettingSpy).toHaveBeenCalledWith('participating', true); @@ -169,7 +172,7 @@ describe('renderer/components/Sidebar.tsx', () => { accounts: [mockGitHubCloudAccount], }); - await userEvent.click(screen.getByTestId('sidebar-filter-notifications')); + await userEvent.click(screen.getByRole('button', { name: /^Filters/ })); expect(navigateMock).toHaveBeenCalledTimes(1); expect(navigateMock).toHaveBeenCalledWith('/filters'); @@ -181,7 +184,7 @@ describe('renderer/components/Sidebar.tsx', () => { accounts: [mockGitHubCloudAccount], }); - await userEvent.click(screen.getByTestId('sidebar-filter-notifications')); + await userEvent.click(screen.getByRole('button', { name: /^Filters/ })); expect(navigateMock).toHaveBeenCalledTimes(1); expect(navigateMock).toHaveBeenCalledWith('/', { replace: true }); @@ -194,7 +197,7 @@ describe('renderer/components/Sidebar.tsx', () => { filters: { reasons: ['assign'] }, }); - expect(screen.getByTestId('sidebar-filter-notifications')).toHaveAttribute( + expect(screen.getByRole('button', { name: /^Filters/ })).toHaveAttribute( 'data-variant', 'primary', ); @@ -207,7 +210,7 @@ describe('renderer/components/Sidebar.tsx', () => { accounts: [mockGitHubCloudAccount], }); - await userEvent.click(screen.getByTestId('sidebar-my-issues')); + await userEvent.click(screen.getByRole('button', { name: /^My issues/ })); expect(openExternalLinkSpy).toHaveBeenCalledTimes(1); expect(openExternalLinkSpy).toHaveBeenCalledWith('https://github.com/issues'); @@ -218,7 +221,7 @@ describe('renderer/components/Sidebar.tsx', () => { accounts: [mockGitHubCloudAccount], }); - await userEvent.click(screen.getByTestId('sidebar-my-pull-requests')); + await userEvent.click(screen.getByRole('button', { name: /^My pull requests/ })); expect(openExternalLinkSpy).toHaveBeenCalledTimes(1); expect(openExternalLinkSpy).toHaveBeenCalledWith('https://github.com/pulls'); @@ -233,7 +236,7 @@ describe('renderer/components/Sidebar.tsx', () => { status: 'success', }); - await userEvent.click(screen.getByTestId('sidebar-refresh')); + await userEvent.click(screen.getByRole('button', { name: /^Refresh/ })); expect(fetchNotificationsMock).toHaveBeenCalledTimes(1); }); @@ -245,7 +248,7 @@ describe('renderer/components/Sidebar.tsx', () => { status: 'loading', }); - await userEvent.click(screen.getByTestId('sidebar-refresh')); + await userEvent.click(screen.getByRole('button', { name: /^Refresh/ })); expect(fetchNotificationsMock).not.toHaveBeenCalled(); }); @@ -256,8 +259,11 @@ describe('renderer/components/Sidebar.tsx', () => { status: 'loading', }); - expect(screen.getByTestId('sidebar-refresh')).toHaveAttribute('data-loading', 'true'); - expect(screen.getByTestId('sidebar-refresh')).toBeDisabled(); + expect(screen.getByRole('button', { name: /^Refresh/ })).toHaveAttribute( + 'data-loading', + 'true', + ); + expect(screen.getByRole('button', { name: /^Refresh/ })).toBeDisabled(); }); it('shows a loading spinner on the refresh icon while a background fetch is in flight, regardless of settled status', () => { @@ -267,9 +273,12 @@ describe('renderer/components/Sidebar.tsx', () => { isFetching: true, }); - expect(screen.getByTestId('sidebar-refresh')).toHaveAttribute('data-loading', 'true'); + expect(screen.getByRole('button', { name: /^Refresh/ })).toHaveAttribute( + 'data-loading', + 'true', + ); expect(tree.container.querySelector('[data-component="Spinner"]')).toBeInTheDocument(); - expect(screen.getByTestId('sidebar-refresh')).toBeDisabled(); + expect(screen.getByRole('button', { name: /^Refresh/ })).toBeDisabled(); }); it('does not show a loading spinner on the refresh icon when settled and no fetch is in flight', () => { @@ -279,8 +288,11 @@ describe('renderer/components/Sidebar.tsx', () => { isFetching: false, }); - expect(screen.getByTestId('sidebar-refresh')).toHaveAttribute('data-loading', 'false'); - expect(screen.getByTestId('sidebar-refresh')).toBeEnabled(); + expect(screen.getByRole('button', { name: /^Refresh/ })).toHaveAttribute( + 'data-loading', + 'false', + ); + expect(screen.getByRole('button', { name: /^Refresh/ })).toBeEnabled(); }); }); @@ -290,7 +302,7 @@ describe('renderer/components/Sidebar.tsx', () => { accounts: [mockGitHubCloudAccount], }); - await userEvent.click(screen.getByTestId('sidebar-settings')); + await userEvent.click(screen.getByRole('button', { name: /^Settings/ })); expect(navigateMock).toHaveBeenCalledTimes(1); expect(navigateMock).toHaveBeenCalledWith('/settings'); @@ -303,7 +315,7 @@ describe('renderer/components/Sidebar.tsx', () => { fetchNotifications: fetchNotificationsMock, }); - await userEvent.click(screen.getByTestId('sidebar-settings')); + await userEvent.click(screen.getByRole('button', { name: /^Settings/ })); expect(fetchNotificationsMock).toHaveBeenCalledTimes(1); expect(navigateMock).toHaveBeenCalledTimes(1); @@ -318,7 +330,9 @@ describe('renderer/components/Sidebar.tsx', () => { accounts: [], }); - await userEvent.click(screen.getByTestId('sidebar-quit')); + await userEvent.click( + screen.getByRole('button', { name: new RegExp(`^Quit ${APPLICATION.NAME}`) }), + ); expect(quitAppSpy).toHaveBeenCalledTimes(1); }); diff --git a/src/renderer/components/filters/FilterCheckbox.test.tsx b/src/renderer/components/filters/FilterCheckbox.test.tsx index fedf0c5be..02fe144ea 100644 --- a/src/renderer/components/filters/FilterCheckbox.test.tsx +++ b/src/renderer/components/filters/FilterCheckbox.test.tsx @@ -11,7 +11,7 @@ describe('renderer/components/filters/FilterCheckbox.tsx', () => { , ); - expect(screen.getByTestId('checkbox-issues')).toBeChecked(); + expect(screen.getByRole('checkbox', { name: 'Issues' })).toBeChecked(); expect(screen.getByText('Issues')).toBeInTheDocument(); expect(screen.getByText('3')).toBeInTheDocument(); }); @@ -28,7 +28,7 @@ describe('renderer/components/filters/FilterCheckbox.tsx', () => { />, ); - expect(screen.getByTestId('checkbox-issues')).toBeDisabled(); + expect(screen.getByRole('checkbox', { name: 'Issues' })).toBeDisabled(); await userEvent.click(screen.getByTestId('tooltip-icon-tooltip-issues')); diff --git a/src/renderer/components/notifications/NotificationRow.test.tsx b/src/renderer/components/notifications/NotificationRow.test.tsx index 0e13a34f3..d17eecf66 100644 --- a/src/renderer/components/notifications/NotificationRow.test.tsx +++ b/src/renderer/components/notifications/NotificationRow.test.tsx @@ -243,7 +243,7 @@ describe('renderer/components/notifications/NotificationRow.tsx', () => { markNotificationsAsRead: markNotificationsAsReadMock, }); - await userEvent.click(screen.getByTestId('notification-mark-as-read')); + await userEvent.click(screen.getByRole('button', { name: 'Mark as read' })); expect(markNotificationsAsReadMock).toHaveBeenCalledTimes(1); }); @@ -259,7 +259,7 @@ describe('renderer/components/notifications/NotificationRow.tsx', () => { renderWithProviders(); - expect(screen.queryByTestId('notification-mark-as-read')).not.toBeInTheDocument(); + expect(screen.queryByRole('button', { name: 'Mark as read' })).not.toBeInTheDocument(); }); it('marks notifications as done', async () => { @@ -275,7 +275,7 @@ describe('renderer/components/notifications/NotificationRow.tsx', () => { markNotificationsAsDone: markNotificationsAsDoneMock, }); - await userEvent.click(screen.getByTestId('notification-mark-as-done')); + await userEvent.click(screen.getByRole('button', { name: 'Mark as done' })); expect(markNotificationsAsDoneMock).toHaveBeenCalledTimes(1); }); @@ -291,7 +291,7 @@ describe('renderer/components/notifications/NotificationRow.tsx', () => { renderWithProviders(); - expect(screen.queryByTestId('notification-mark-as-done')).not.toBeInTheDocument(); + expect(screen.queryByRole('button', { name: 'Mark as done' })).not.toBeInTheDocument(); }); it('shows mark as done button when fetchReadNotifications is enabled and notification is unread', async () => { @@ -304,8 +304,8 @@ describe('renderer/components/notifications/NotificationRow.tsx', () => { settings: { ...mockSettings, fetchReadNotifications: true }, }); - expect(screen.getByTestId('notification-mark-as-done')).toBeInTheDocument(); - expect(screen.getByTestId('notification-mark-as-read')).toBeInTheDocument(); + expect(screen.getByRole('button', { name: 'Mark as done' })).toBeInTheDocument(); + expect(screen.getByRole('button', { name: 'Mark as read' })).toBeInTheDocument(); }); it('unsubscribes from a notification thread', async () => { @@ -320,7 +320,7 @@ describe('renderer/components/notifications/NotificationRow.tsx', () => { unsubscribeNotification: unsubscribeNotificationMock, }); - await userEvent.click(screen.getByTestId('notification-unsubscribe-from-thread')); + await userEvent.click(screen.getByRole('button', { name: 'Unsubscribe from thread' })); expect(unsubscribeNotificationMock).toHaveBeenCalledTimes(1); }); @@ -333,7 +333,9 @@ describe('renderer/components/notifications/NotificationRow.tsx', () => { renderWithProviders(); - expect(screen.queryByTestId('notification-unsubscribe-from-thread')).not.toBeInTheDocument(); + expect( + screen.queryByRole('button', { name: 'Unsubscribe from thread' }), + ).not.toBeInTheDocument(); }); }); @@ -365,7 +367,7 @@ describe('renderer/components/notifications/NotificationRow.tsx', () => { renderWithProviders(); - expect(screen.getByTestId('notification-mark-as-read')).toHaveAttribute( + expect(screen.getByRole('button', { name: 'Mark as read' })).toHaveAttribute( 'title', 'Mark as read', ); @@ -381,9 +383,9 @@ describe('renderer/components/notifications/NotificationRow.tsx', () => { markNotificationsAsRead: vi.fn().mockResolvedValue(false), }); - await userEvent.click(screen.getByTestId('notification-mark-as-read')); + await userEvent.click(screen.getByRole('button', { name: 'Mark as read' })); - expect(screen.getByTestId('notification-mark-as-read')).toBeInTheDocument(); + expect(screen.getByRole('button', { name: 'Mark as read' })).toBeInTheDocument(); }); it('styles and explains only the action that failed', () => { @@ -407,11 +409,11 @@ describe('renderer/components/notifications/NotificationRow.tsx', () => { 'title', expect.stringContaining('You can also try opening this notification in your browser.'), ); - expect(screen.getByTestId('notification-mark-as-done')).toHaveAttribute( + expect(screen.getByRole('button', { name: 'Mark as done' })).toHaveAttribute( 'title', 'Mark as done', ); - expect(screen.getByTestId('notification-unsubscribe-from-thread')).toHaveAttribute( + expect(screen.getByRole('button', { name: 'Unsubscribe from thread' })).toHaveAttribute( 'title', 'Unsubscribe from thread', ); diff --git a/src/renderer/components/primitives/Header.test.tsx b/src/renderer/components/primitives/Header.test.tsx index f2fd19488..0d6d85f72 100644 --- a/src/renderer/components/primitives/Header.test.tsx +++ b/src/renderer/components/primitives/Header.test.tsx @@ -19,7 +19,7 @@ describe('renderer/components/primitives/Header.tsx', () => { it('navigates back', async () => { renderWithProviders(
Test Header
); - await userEvent.click(screen.getByTestId('header-nav-back')); + await userEvent.click(screen.getByRole('button', { name: 'Go back' })); expect(navigateMock).toHaveBeenCalledTimes(1); expect(navigateMock).toHaveBeenCalledWith(-1); @@ -33,7 +33,7 @@ describe('renderer/components/primitives/Header.tsx', () => { { fetchNotifications: fetchNotificationsMock }, ); - await userEvent.click(screen.getByTestId('header-nav-back')); + await userEvent.click(screen.getByRole('button', { name: 'Go back' })); expect(fetchNotificationsMock).toHaveBeenCalledTimes(1); expect(navigateMock).toHaveBeenCalledTimes(1); diff --git a/src/renderer/components/primitives/Header.tsx b/src/renderer/components/primitives/Header.tsx index 9f9446438..d25ff3502 100644 --- a/src/renderer/components/primitives/Header.tsx +++ b/src/renderer/components/primitives/Header.tsx @@ -22,7 +22,7 @@ export function Header(props: Readonly) {
{ diff --git a/src/renderer/components/primitives/__snapshots__/Header.test.tsx.snap b/src/renderer/components/primitives/__snapshots__/Header.test.tsx.snap index 5cb848f07..c4a2f0ee5 100644 --- a/src/renderer/components/primitives/__snapshots__/Header.test.tsx.snap +++ b/src/renderer/components/primitives/__snapshots__/Header.test.tsx.snap @@ -15,7 +15,7 @@ exports[`renderer/components/primitives/Header.tsx > renders itself & its childr data-wrap="nowrap" > +
diff --git a/src/renderer/routes/AccountScopes.test.tsx b/src/renderer/routes/AccountScopes.test.tsx index 62392f833..405dcb769 100644 --- a/src/renderer/routes/AccountScopes.test.tsx +++ b/src/renderer/routes/AccountScopes.test.tsx @@ -174,7 +174,7 @@ describe('renderer/routes/AccountScopes.tsx', () => { renderWithProviders(); }); - await userEvent.click(screen.getByTestId('account-scopes-manage-link')); + await userEvent.click(screen.getByRole('button', { name: 'Developer settings' })); expect(openAccountSettingsSpy).toHaveBeenCalledTimes(1); }); @@ -184,7 +184,7 @@ describe('renderer/routes/AccountScopes.tsx', () => { renderWithProviders(); }); - await userEvent.click(screen.getByTestId('header-nav-back')); + await userEvent.click(screen.getByRole('button', { name: 'Go back' })); expect(navigateMock).toHaveBeenCalledWith(-1); }); diff --git a/src/renderer/routes/Accounts.test.tsx b/src/renderer/routes/Accounts.test.tsx index 30ca679cc..e954cac07 100644 --- a/src/renderer/routes/Accounts.test.tsx +++ b/src/renderer/routes/Accounts.test.tsx @@ -41,7 +41,7 @@ describe('renderer/routes/Accounts.tsx', () => { renderWithProviders(); }); - await userEvent.click(screen.getByTestId('header-nav-back')); + await userEvent.click(screen.getByRole('button', { name: 'Go back' })); expect(navigateMock).toHaveBeenCalledTimes(1); expect(navigateMock).toHaveBeenCalledWith(-1); @@ -244,7 +244,7 @@ describe('renderer/routes/Accounts.tsx', () => { // Clicking the scopes button for the account with missing scopes // navigates to the scopes route where the user can investigate. - await userEvent.click(screen.getAllByTestId('account-view-scopes')[0]); + await userEvent.click(screen.getAllByRole('button', { name: /^View scopes for / })[0]); expect(navigateMock).toHaveBeenCalledWith('/account-scopes', { state: { @@ -265,9 +265,9 @@ describe('renderer/routes/Accounts.tsx', () => { expect(screen.getByTestId('accounts')).toBeInTheDocument(); // All 3 accounts render the primary/set-primary button - expect(screen.getAllByTestId('account-set-primary')).toHaveLength(3); + expect(screen.getAllByRole('button', { name: /^Set as primary account/ })).toHaveLength(3); - await userEvent.click(screen.getAllByTestId('account-set-primary')[1]); + await userEvent.click(screen.getAllByRole('button', { name: /^Set as primary account/ })[1]); expect(useAccountsStore.getState().accounts[0]).toBe(mockOAuthAccount); expect(navigateMock).toHaveBeenCalledWith('/accounts', { replace: true }); @@ -284,7 +284,7 @@ describe('renderer/routes/Accounts.tsx', () => { }); }); - await userEvent.click(screen.getByTestId('account-refresh')); + await userEvent.click(screen.getByRole('button', { name: /^Refresh / })); expect(refreshAccountSpy).toHaveBeenCalledTimes(1); expect(navigateMock).toHaveBeenCalledTimes(1); @@ -303,7 +303,7 @@ describe('renderer/routes/Accounts.tsx', () => { }); }); - await userEvent.click(screen.getByTestId('account-logout')); + await userEvent.click(screen.getByRole('button', { name: /^Logout / })); expect(logoutFromAccountMock).toHaveBeenCalledTimes(1); }); @@ -315,7 +315,7 @@ describe('renderer/routes/Accounts.tsx', () => { }); }); - expect(screen.getAllByTestId('account-view-scopes')).toHaveLength(3); + expect(screen.getAllByRole('button', { name: /^View scopes for / })).toHaveLength(3); }); it('navigates to account-scopes when clicking view-scopes', async () => { @@ -325,7 +325,7 @@ describe('renderer/routes/Accounts.tsx', () => { }); }); - await userEvent.click(screen.getByTestId('account-view-scopes')); + await userEvent.click(screen.getByRole('button', { name: /^View scopes for / })); expect(navigateMock).toHaveBeenCalledWith('/account-scopes', { state: { account: mockPersonalAccessTokenAccount }, @@ -341,15 +341,15 @@ describe('renderer/routes/Accounts.tsx', () => { }); }); - await userEvent.click(screen.getByTestId('account-add-new')); + await userEvent.click(screen.getByRole('button', { name: 'Add new account' })); - expect(screen.getByTestId('account-add-forge-github')).toHaveTextContent('GitHub'); + expect(screen.getByRole('menuitem', { name: /^GitHub/ })).toHaveTextContent('GitHub'); - await userEvent.click(screen.getByTestId('account-add-forge-github')); + await userEvent.click(screen.getByRole('menuitem', { name: /^GitHub/ })); - expect(screen.getByTestId('account-add-github')).toHaveTextContent('GitHub'); + expect(screen.getByRole('menuitem', { name: /^GitHub$/ })).toHaveTextContent('GitHub'); - await userEvent.click(screen.getByTestId('account-add-github')); + await userEvent.click(screen.getByRole('menuitem', { name: /^GitHub$/ })); expect(navigateMock).toHaveBeenCalledTimes(1); expect(navigateMock).toHaveBeenCalledWith('/login/github/device-flow', { @@ -364,12 +364,14 @@ describe('renderer/routes/Accounts.tsx', () => { }); }); - await userEvent.click(screen.getByTestId('account-add-new')); - await userEvent.click(screen.getByTestId('account-add-forge-github')); + await userEvent.click(screen.getByRole('button', { name: 'Add new account' })); + await userEvent.click(screen.getByRole('menuitem', { name: /^GitHub/ })); - expect(screen.getByTestId('account-add-pat')).toHaveTextContent('Personal Access Token'); + expect(screen.getByRole('menuitem', { name: /^Personal Access Token/ })).toHaveTextContent( + 'Personal Access Token', + ); - await userEvent.click(screen.getByTestId('account-add-pat')); + await userEvent.click(screen.getByRole('menuitem', { name: /^Personal Access Token/ })); expect(navigateMock).toHaveBeenCalledTimes(1); expect(navigateMock).toHaveBeenCalledWith('/login/github/personal-access-token', { @@ -384,12 +386,12 @@ describe('renderer/routes/Accounts.tsx', () => { }); }); - await userEvent.click(screen.getByTestId('account-add-new')); - await userEvent.click(screen.getByTestId('account-add-forge-github')); + await userEvent.click(screen.getByRole('button', { name: 'Add new account' })); + await userEvent.click(screen.getByRole('menuitem', { name: /^GitHub/ })); - expect(screen.getByTestId('account-add-oauth-app')).toHaveTextContent('OAuth App'); + expect(screen.getByRole('menuitem', { name: /^OAuth App/ })).toHaveTextContent('OAuth App'); - await userEvent.click(screen.getByTestId('account-add-oauth-app')); + await userEvent.click(screen.getByRole('menuitem', { name: /^OAuth App/ })); expect(navigateMock).toHaveBeenCalledTimes(1); expect(navigateMock).toHaveBeenCalledWith('/login/github/oauth-app', { @@ -404,11 +406,11 @@ describe('renderer/routes/Accounts.tsx', () => { }); }); - await userEvent.click(screen.getByTestId('account-add-new')); + await userEvent.click(screen.getByRole('button', { name: 'Add new account' })); - expect(screen.getByTestId('account-add-forge-gitea')).toHaveTextContent('Gitea'); + expect(screen.getByRole('menuitem', { name: /^Gitea/ })).toHaveTextContent('Gitea'); - await userEvent.click(screen.getByTestId('account-add-forge-gitea')); + await userEvent.click(screen.getByRole('menuitem', { name: /^Gitea/ })); expect(navigateMock).toHaveBeenCalledTimes(1); expect(navigateMock).toHaveBeenCalledWith('/login/gitea/personal-access-token', { @@ -423,11 +425,11 @@ describe('renderer/routes/Accounts.tsx', () => { }); }); - await userEvent.click(screen.getByTestId('account-add-new')); + await userEvent.click(screen.getByRole('button', { name: 'Add new account' })); - expect(screen.getByTestId('account-add-forge-bitbucket')).toHaveTextContent('Bitbucket'); + expect(screen.getByRole('menuitem', { name: /^Bitbucket/ })).toHaveTextContent('Bitbucket'); - await userEvent.click(screen.getByTestId('account-add-forge-bitbucket')); + await userEvent.click(screen.getByRole('menuitem', { name: /^Bitbucket/ })); expect(navigateMock).toHaveBeenCalledTimes(1); expect(navigateMock).toHaveBeenCalledWith('/login/bitbucket/personal-access-token', { @@ -451,9 +453,9 @@ describe('renderer/routes/Accounts.tsx', () => { }); }); - expect(screen.queryByTestId('account-view-scopes')).not.toBeInTheDocument(); + expect(screen.queryByRole('button', { name: /^View scopes for / })).not.toBeInTheDocument(); - await userEvent.click(screen.getByTestId('account-reauthenticate')); + await userEvent.click(screen.getByRole('button', { name: /^Re-authenticate / })); expect(navigateMock).toHaveBeenCalledTimes(1); expect(navigateMock).toHaveBeenCalledWith('/login/github/personal-access-token', { @@ -476,7 +478,7 @@ describe('renderer/routes/Accounts.tsx', () => { }); }); - await userEvent.click(screen.getByTestId('account-reauthenticate')); + await userEvent.click(screen.getByRole('button', { name: /^Re-authenticate / })); expect(navigateMock).toHaveBeenCalledTimes(1); expect(navigateMock).toHaveBeenCalledWith('/login/github/device-flow', { @@ -499,7 +501,7 @@ describe('renderer/routes/Accounts.tsx', () => { }); }); - await userEvent.click(screen.getByTestId('account-reauthenticate')); + await userEvent.click(screen.getByRole('button', { name: /^Re-authenticate / })); expect(navigateMock).toHaveBeenCalledTimes(1); expect(navigateMock).toHaveBeenCalledWith('/login/github/oauth-app', { @@ -522,7 +524,7 @@ describe('renderer/routes/Accounts.tsx', () => { }); }); - await userEvent.click(screen.getByTestId('account-reauthenticate')); + await userEvent.click(screen.getByRole('button', { name: /^Re-authenticate / })); expect(navigateMock).toHaveBeenCalledTimes(1); expect(navigateMock).toHaveBeenCalledWith('/login/gitea/personal-access-token', { @@ -552,7 +554,7 @@ describe('renderer/routes/Accounts.tsx', () => { }); }); - await userEvent.click(screen.getByTestId('account-reauthenticate')); + await userEvent.click(screen.getByRole('button', { name: /^Re-authenticate / })); expect(navigateMock).not.toHaveBeenCalled(); expect(rendererLogErrorSpy).toHaveBeenCalledWith( @@ -599,7 +601,7 @@ describe('renderer/routes/Accounts.tsx', () => { }); }); - await userEvent.click(screen.getByTestId('account-refresh')); + await userEvent.click(screen.getByRole('button', { name: /^Refresh / })); expect(refreshAccountSpy).toHaveBeenCalledTimes(1); expect(navigateMock).toHaveBeenCalledWith('/accounts', { replace: true }); @@ -614,7 +616,7 @@ describe('renderer/routes/Accounts.tsx', () => { }); }); - expect(screen.queryByTestId('account-view-scopes')).not.toBeInTheDocument(); + expect(screen.queryByRole('button', { name: /^View scopes for / })).not.toBeInTheDocument(); }); }); }); diff --git a/src/renderer/routes/Filters.test.tsx b/src/renderer/routes/Filters.test.tsx index 1789333b2..ba8f537e7 100644 --- a/src/renderer/routes/Filters.test.tsx +++ b/src/renderer/routes/Filters.test.tsx @@ -111,7 +111,7 @@ describe('renderer/routes/Filters.tsx', () => { }); }); - await userEvent.click(screen.getByTestId('header-nav-back')); + await userEvent.click(screen.getByRole('button', { name: 'Go back' })); expect(fetchNotificationsMock).toHaveBeenCalledTimes(1); expect(navigateMock).toHaveBeenCalledTimes(1); @@ -125,7 +125,7 @@ describe('renderer/routes/Filters.tsx', () => { renderWithProviders(); }); - await userEvent.click(screen.getByTestId('filters-clear')); + await userEvent.click(screen.getByRole('button', { name: 'Clear filters' })); expect(resetSpy).toHaveBeenCalled(); }); diff --git a/src/renderer/routes/Settings.test.tsx b/src/renderer/routes/Settings.test.tsx index 0d4f595b9..3ebb69779 100644 --- a/src/renderer/routes/Settings.test.tsx +++ b/src/renderer/routes/Settings.test.tsx @@ -130,17 +130,33 @@ describe('renderer/routes/Settings.tsx', () => { const alerts = section('Alerts'); const system = section('System'); - expect(within(inbox).getByTestId('switch-showPills')).toBeInTheDocument(); - expect(within(inbox).getByTestId('switch-wrapNotificationTitle')).toBeInTheDocument(); - expect(within(inbox).queryByTestId('switch-showNotifications')).not.toBeInTheDocument(); expect( - within(appearance).queryByTestId('switch-wrapNotificationTitle'), + within(inbox).getByRole('button', { name: 'Show notification metrics', hidden: true }), + ).toBeInTheDocument(); + expect( + within(inbox).getByRole('button', { name: 'Show full notification title' }), + ).toBeInTheDocument(); + expect( + within(inbox).queryByRole('button', { name: 'Show desktop notifications' }), + ).not.toBeInTheDocument(); + expect( + within(appearance).queryByRole('button', { name: 'Show full notification title' }), + ).not.toBeInTheDocument(); + expect( + within(alerts).getByRole('button', { name: 'Show desktop notifications' }), + ).toBeInTheDocument(); + expect( + within(alerts).getByRole('button', { name: 'Show app update notifications' }), + ).toBeInTheDocument(); + expect( + within(alerts).queryByRole('button', { name: 'Show notification metrics', hidden: true }), + ).not.toBeInTheDocument(); + expect( + within(system).queryByRole('button', { name: 'Show desktop notifications' }), + ).not.toBeInTheDocument(); + expect( + within(system).queryByRole('button', { name: 'Show app update notifications' }), ).not.toBeInTheDocument(); - expect(within(alerts).getByTestId('switch-showNotifications')).toBeInTheDocument(); - expect(within(alerts).getByTestId('switch-showUpdateNotifications')).toBeInTheDocument(); - expect(within(alerts).queryByTestId('switch-showPills')).not.toBeInTheDocument(); - expect(within(system).queryByTestId('switch-showNotifications')).not.toBeInTheDocument(); - expect(within(system).queryByTestId('switch-showUpdateNotifications')).not.toBeInTheDocument(); }); it('goes back by pressing the icon', async () => { @@ -151,7 +167,7 @@ describe('renderer/routes/Settings.tsx', () => { }); }); - await userEvent.click(screen.getByTestId('header-nav-back')); + await userEvent.click(screen.getByRole('button', { name: 'Go back' })); expect(fetchNotificationsMock).toHaveBeenCalledTimes(1); expect(navigateMock).toHaveBeenCalledTimes(1); diff --git a/src/renderer/routes/bitbucket/LoginWithPersonalAccessToken.test.tsx b/src/renderer/routes/bitbucket/LoginWithPersonalAccessToken.test.tsx index 84b10ef8b..17a8c2a27 100644 --- a/src/renderer/routes/bitbucket/LoginWithPersonalAccessToken.test.tsx +++ b/src/renderer/routes/bitbucket/LoginWithPersonalAccessToken.test.tsx @@ -94,7 +94,7 @@ describe('renderer/routes/bitbucket/LoginWithPersonalAccessToken.tsx', () => { it('opens help docs in the browser', async () => { renderWithProviders(); - await userEvent.click(screen.getByTestId('login-docs')); + await userEvent.click(screen.getByRole('button', { name: 'Docs' })); expect(openExternalLinkSpy).toHaveBeenCalledTimes(1); expect(openExternalLinkSpy).toHaveBeenCalledWith( @@ -118,6 +118,6 @@ describe('renderer/routes/bitbucket/LoginWithPersonalAccessToken.tsx', () => { 'user@example.com', ); // hostname is always bitbucket.org and not shown as an editable field - expect(screen.queryByTestId('login-hostname')).not.toBeInTheDocument(); + expect(screen.queryByRole('textbox', { name: /hostname/i })).not.toBeInTheDocument(); }); }); diff --git a/src/renderer/routes/gitea/LoginWithPersonalAccessToken.test.tsx b/src/renderer/routes/gitea/LoginWithPersonalAccessToken.test.tsx index cbfc43de5..ab3132816 100644 --- a/src/renderer/routes/gitea/LoginWithPersonalAccessToken.test.tsx +++ b/src/renderer/routes/gitea/LoginWithPersonalAccessToken.test.tsx @@ -108,7 +108,7 @@ describe('renderer/routes/gitea/LoginWithPersonalAccessToken.tsx', () => { it('opens help docs in the browser', async () => { renderWithProviders(); - await userEvent.click(screen.getByTestId('login-docs')); + await userEvent.click(screen.getByRole('button', { name: 'Docs' })); expect(openExternalLinkSpy).toHaveBeenCalledTimes(1); expect(openExternalLinkSpy).toHaveBeenCalledWith( diff --git a/src/renderer/routes/github/LoginWithDeviceFlow.test.tsx b/src/renderer/routes/github/LoginWithDeviceFlow.test.tsx index fbd02b89f..01ce51d51 100644 --- a/src/renderer/routes/github/LoginWithDeviceFlow.test.tsx +++ b/src/renderer/routes/github/LoginWithDeviceFlow.test.tsx @@ -30,8 +30,8 @@ describe('renderer/routes/github/LoginWithDeviceFlow.tsx', () => { }); expect(screen.getByText('Receive notifications for:')).toBeInTheDocument(); - expect(screen.getByTestId('device-scope-public')).toBeInTheDocument(); - expect(screen.getByTestId('device-scope-full')).toBeInTheDocument(); + expect(screen.getByRole('button', { name: /^Public Limited/ })).toBeInTheDocument(); + expect(screen.getByRole('button', { name: /Public and Private/ })).toBeInTheDocument(); // Device flow should not start until user makes a choice expect(loginWithDeviceFlowStartMock).not.toHaveBeenCalled(); @@ -52,7 +52,7 @@ describe('renderer/routes/github/LoginWithDeviceFlow.tsx', () => { loginWithDeviceFlowStart: loginWithDeviceFlowStartMock, }); - await userEvent.click(screen.getByTestId('device-scope-public')); + await userEvent.click(screen.getByRole('button', { name: /^Public Limited/ })); expect(loginWithDeviceFlowStartMock).toHaveBeenCalledWith('github', undefined, [ 'notifications', @@ -61,7 +61,7 @@ describe('renderer/routes/github/LoginWithDeviceFlow.tsx', () => { ]); await screen.findByTestId('device-user-code'); - expect(screen.getByTestId('open-browser-button')).toBeInTheDocument(); + expect(screen.getByRole('button', { name: /^Open / })).toBeInTheDocument(); // Verify auto-copy and auto-open were called expect(copyToClipboardSpy).toHaveBeenCalledWith('USER-1234'); @@ -83,7 +83,7 @@ describe('renderer/routes/github/LoginWithDeviceFlow.tsx', () => { loginWithDeviceFlowStart: loginWithDeviceFlowStartMock, }); - await userEvent.click(screen.getByTestId('device-scope-full')); + await userEvent.click(screen.getByRole('button', { name: /Public and Private/ })); expect(loginWithDeviceFlowStartMock).toHaveBeenCalledWith('github', undefined, [ 'notifications', @@ -109,7 +109,7 @@ describe('renderer/routes/github/LoginWithDeviceFlow.tsx', () => { loginWithDeviceFlowStart: loginWithDeviceFlowStartMock, }); - await userEvent.click(screen.getByTestId('device-scope-public')); + await userEvent.click(screen.getByRole('button', { name: /^Public Limited/ })); await screen.findByTestId('device-user-code'); expect(screen.getByText('Code copied to clipboard')).toBeInTheDocument(); @@ -132,17 +132,17 @@ describe('renderer/routes/github/LoginWithDeviceFlow.tsx', () => { loginWithDeviceFlowStart: loginWithDeviceFlowStartMock, }); - await userEvent.click(screen.getByTestId('device-scope-public')); + await userEvent.click(screen.getByRole('button', { name: /^Public Limited/ })); await screen.findByTestId('device-user-code'); // Reset spies to isolate button interactions openExternalLinkSpy.mockClear(); copyToClipboardSpy.mockClear(); - await userEvent.click(screen.getByTestId('open-browser-button')); + await userEvent.click(screen.getByRole('button', { name: /^Open / })); expect(openExternalLinkSpy).toHaveBeenCalledWith('https://github.com/login/device'); - await userEvent.click(screen.getByTestId('copy-link-button')); + await userEvent.click(screen.getByRole('button', { name: 'Copy link' })); expect(copyToClipboardSpy).toHaveBeenCalledWith('https://github.com/login/device'); }); @@ -161,13 +161,13 @@ describe('renderer/routes/github/LoginWithDeviceFlow.tsx', () => { loginWithDeviceFlowStart: loginWithDeviceFlowStartMock, }); - await userEvent.click(screen.getByTestId('device-scope-public')); + await userEvent.click(screen.getByRole('button', { name: /^Public Limited/ })); await screen.findByTestId('device-user-code'); // Clear the auto-copy call from initialization copyToClipboardSpy.mockClear(); - await userEvent.click(screen.getByTestId('copy-device-code')); + await userEvent.click(screen.getByRole('button', { name: 'Copy device code' })); expect(copyToClipboardSpy).toHaveBeenCalledWith('USER-1234'); }); @@ -180,7 +180,7 @@ describe('renderer/routes/github/LoginWithDeviceFlow.tsx', () => { loginWithDeviceFlowStart: loginWithDeviceFlowStartMock, }); - await userEvent.click(screen.getByTestId('device-scope-full')); + await userEvent.click(screen.getByRole('button', { name: /Public and Private/ })); await screen.findByText(/Failed to start authentication/); expect(rendererLogErrorSpy).toHaveBeenCalledTimes(1); @@ -201,7 +201,7 @@ describe('renderer/routes/github/LoginWithDeviceFlow.tsx', () => { loginWithDeviceFlowStart: loginWithDeviceFlowStartMock, }); - await userEvent.click(screen.getByTestId('cancel-button')); + await userEvent.click(screen.getByRole('button', { name: 'Cancel' })); expect(navigateMock).toHaveBeenCalledWith(-1); }); @@ -225,7 +225,7 @@ describe('renderer/routes/github/LoginWithDeviceFlow.tsx', () => { loginWithDeviceFlowComplete: loginWithDeviceFlowCompleteMock, }); - await userEvent.click(screen.getByTestId('device-scope-public')); + await userEvent.click(screen.getByRole('button', { name: /^Public Limited/ })); await screen.findByTestId('device-user-code'); await waitFor(() => { @@ -259,7 +259,7 @@ describe('renderer/routes/github/LoginWithDeviceFlow.tsx', () => { loginWithDeviceFlowPoll: loginWithDeviceFlowPollMock, }); - await userEvent.click(screen.getByTestId('device-scope-public')); + await userEvent.click(screen.getByRole('button', { name: /^Public Limited/ })); await screen.findByTestId('device-user-code'); await waitFor(() => { @@ -286,7 +286,7 @@ describe('renderer/routes/github/LoginWithDeviceFlow.tsx', () => { loginWithDeviceFlowPoll: loginWithDeviceFlowPollMock, }); - await userEvent.click(screen.getByTestId('device-scope-public')); + await userEvent.click(screen.getByRole('button', { name: /^Public Limited/ })); await screen.findByTestId('device-user-code'); await waitFor(() => { @@ -322,7 +322,7 @@ describe('renderer/routes/github/LoginWithDeviceFlow.tsx', () => { ], }); - await userEvent.click(screen.getByTestId('device-scope-full')); + await userEvent.click(screen.getByRole('button', { name: /Public and Private/ })); expect(loginWithDeviceFlowStartMock).toHaveBeenCalledWith( 'github', diff --git a/src/renderer/routes/github/LoginWithGitHubCLI.test.tsx b/src/renderer/routes/github/LoginWithGitHubCLI.test.tsx index ce07115d6..d0f778b88 100644 --- a/src/renderer/routes/github/LoginWithGitHubCLI.test.tsx +++ b/src/renderer/routes/github/LoginWithGitHubCLI.test.tsx @@ -23,7 +23,7 @@ describe('renderer/routes/github/LoginWithGitHubCLI.tsx', () => { expect(screen.queryByTestId('login-token')).not.toBeInTheDocument(); - await userEvent.click(screen.getByTestId('login-submit')); + await userEvent.click(screen.getByRole('button', { name: 'Login' })); await waitFor(() => { expect(loginWithCliMock).toHaveBeenCalledWith('github', 'github.com'); @@ -36,10 +36,10 @@ describe('renderer/routes/github/LoginWithGitHubCLI.tsx', () => { renderWithProviders(, { loginWithCli: loginWithCliMock }); - const hostname = screen.getByTestId('login-hostname'); + const hostname = screen.getByRole('textbox', { name: /Hostname/ }); await userEvent.clear(hostname); await userEvent.type(hostname, 'github.gitify.io'); - await userEvent.click(screen.getByTestId('login-submit')); + await userEvent.click(screen.getByRole('button', { name: 'Login' })); await waitFor(() => expect(loginWithCliMock).toHaveBeenCalledWith('github', 'github.gitify.io'), @@ -56,7 +56,7 @@ describe('renderer/routes/github/LoginWithGitHubCLI.tsx', () => { ], }); - expect(screen.getByTestId('login-hostname')).toHaveValue( + expect(screen.getByRole('textbox', { name: /Hostname/ })).toHaveValue( mockGitHubEnterpriseServerAccount.hostname, ); }); @@ -64,10 +64,10 @@ describe('renderer/routes/github/LoginWithGitHubCLI.tsx', () => { it('rejects a malformed hostname before reaching the CLI', async () => { renderWithProviders(, { loginWithCli: loginWithCliMock }); - const hostname = screen.getByTestId('login-hostname'); + const hostname = screen.getByRole('textbox', { name: /Hostname/ }); await userEvent.clear(hostname); await userEvent.type(hostname, 'hello'); - await userEvent.click(screen.getByTestId('login-submit')); + await userEvent.click(screen.getByRole('button', { name: 'Login' })); expect(screen.getByTestId('login-errors')).toHaveTextContent('Hostname format is invalid'); expect(loginWithCliMock).not.toHaveBeenCalled(); @@ -81,7 +81,7 @@ describe('renderer/routes/github/LoginWithGitHubCLI.tsx', () => { renderWithProviders(, { loginWithCli: loginWithCliMock }); - await userEvent.click(screen.getByTestId('login-submit')); + await userEvent.click(screen.getByRole('button', { name: 'Login' })); await waitFor(() => expect(screen.getByTestId('login-errors')).toHaveTextContent( diff --git a/src/renderer/routes/github/LoginWithOAuthApp.test.tsx b/src/renderer/routes/github/LoginWithOAuthApp.test.tsx index 0a0343040..23f76bed2 100644 --- a/src/renderer/routes/github/LoginWithOAuthApp.test.tsx +++ b/src/renderer/routes/github/LoginWithOAuthApp.test.tsx @@ -26,7 +26,7 @@ describe('renderer/routes/github/LoginWithOAuthApp.tsx', () => { it('let us go back', async () => { renderWithProviders(); - await userEvent.click(screen.getByTestId('header-nav-back')); + await userEvent.click(screen.getByRole('button', { name: 'Go back' })); expect(navigateMock).toHaveBeenCalledTimes(1); expect(navigateMock).toHaveBeenCalledWith(-1); @@ -136,7 +136,7 @@ describe('renderer/routes/github/LoginWithOAuthApp.tsx', () => { it('opens help docs in the browser', async () => { renderWithProviders(); - await userEvent.click(screen.getByTestId('login-docs')); + await userEvent.click(screen.getByRole('button', { name: 'Docs' })); expect(openExternalLinkSpy).toHaveBeenCalledTimes(1); }); diff --git a/src/renderer/routes/github/LoginWithPersonalAccessToken.test.tsx b/src/renderer/routes/github/LoginWithPersonalAccessToken.test.tsx index 6a6926ad9..c641e3595 100644 --- a/src/renderer/routes/github/LoginWithPersonalAccessToken.test.tsx +++ b/src/renderer/routes/github/LoginWithPersonalAccessToken.test.tsx @@ -28,7 +28,7 @@ describe('renderer/routes/github/LoginWithPersonalAccessToken.tsx', () => { it('let us go back', async () => { renderWithProviders(); - await userEvent.click(screen.getByTestId('header-nav-back')); + await userEvent.click(screen.getByRole('button', { name: 'Go back' })); expect(navigateMock).toHaveBeenCalledTimes(1); expect(navigateMock).toHaveBeenCalledWith(-1); @@ -138,7 +138,7 @@ describe('renderer/routes/github/LoginWithPersonalAccessToken.tsx', () => { loginWithPersonalAccessToken: loginWithPersonalAccessTokenMock, }); - await userEvent.click(screen.getByTestId('login-docs')); + await userEvent.click(screen.getByRole('button', { name: 'Docs' })); expect(openExternalLinkSpy).toHaveBeenCalledTimes(1); }); diff --git a/src/renderer/routes/github/__snapshots__/LoginWithGitHubCLI.test.tsx.snap b/src/renderer/routes/github/__snapshots__/LoginWithGitHubCLI.test.tsx.snap index 8e7cdc759..fe81c6bdb 100644 --- a/src/renderer/routes/github/__snapshots__/LoginWithGitHubCLI.test.tsx.snap +++ b/src/renderer/routes/github/__snapshots__/LoginWithGitHubCLI.test.tsx.snap @@ -19,7 +19,7 @@ exports[`renderer/routes/github/LoginWithGitHubCLI.tsx > renders correctly 1`] = data-wrap="nowrap" > +
@@ -159,8 +169,8 @@ exports[`renderer/routes/github/LoginWithGitHubCLI.tsx > renders correctly 1`] =