From f592d7ae22540c8e5eed50a5ab065a426f40bc32 Mon Sep 17 00:00:00 2001 From: Jeremy Davis Date: Wed, 27 Jul 2022 17:27:40 +0200 Subject: [PATCH] SONAR-16683 [891507] focus first item in menus --- .../components/nav/global/GlobalNavUser.tsx | 10 ++- .../global/__tests__/GlobalNavUser-test.tsx | 21 +++-- .../__snapshots__/GlobalNavUser-test.tsx.snap | 66 -------------- .../embed-docs-modal/EmbedDocsPopup.tsx | 29 +++++- .../__tests__/EmbedDocsPopup-test.tsx | 32 ++++++- .../EmbedDocsPopup-test.tsx.snap | 88 ------------------- 6 files changed, 76 insertions(+), 170 deletions(-) delete mode 100644 server/sonar-web/src/main/js/app/components/nav/global/__tests__/__snapshots__/GlobalNavUser-test.tsx.snap delete mode 100644 server/sonar-web/src/main/js/components/embed-docs-modal/__tests__/__snapshots__/EmbedDocsPopup-test.tsx.snap diff --git a/server/sonar-web/src/main/js/app/components/nav/global/GlobalNavUser.tsx b/server/sonar-web/src/main/js/app/components/nav/global/GlobalNavUser.tsx index 089c8705516..14c4221719e 100644 --- a/server/sonar-web/src/main/js/app/components/nav/global/GlobalNavUser.tsx +++ b/server/sonar-web/src/main/js/app/components/nav/global/GlobalNavUser.tsx @@ -33,6 +33,12 @@ interface Props { } export class GlobalNavUser extends React.PureComponent { + focusNode = (node: HTMLAnchorElement | null) => { + if (node) { + node.focus(); + } + }; + handleLogin = (event: React.SyntheticEvent) => { event.preventDefault(); const returnTo = encodeURIComponent(window.location.pathname + window.location.search); @@ -67,7 +73,9 @@ export class GlobalNavUser extends React.PureComponent {
  • - {translate('my_account.page')} + + {translate('my_account.page')} +
  • diff --git a/server/sonar-web/src/main/js/app/components/nav/global/__tests__/GlobalNavUser-test.tsx b/server/sonar-web/src/main/js/app/components/nav/global/__tests__/GlobalNavUser-test.tsx index d683a244ff1..1e4bd02f4c0 100644 --- a/server/sonar-web/src/main/js/app/components/nav/global/__tests__/GlobalNavUser-test.tsx +++ b/server/sonar-web/src/main/js/app/components/nav/global/__tests__/GlobalNavUser-test.tsx @@ -17,23 +17,28 @@ * along with this program; if not, write to the Free Software Foundation, * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. */ -import { shallow } from 'enzyme'; +import { screen } from '@testing-library/react'; +import userEvent from '@testing-library/user-event'; import * as React from 'react'; import { mockCurrentUser, mockLoggedInUser, mockRouter } from '../../../../../helpers/testMocks'; +import { renderComponent } from '../../../../../helpers/testReactTestingUtils'; import { GlobalNavUser } from '../GlobalNavUser'; it('should render the right interface for anonymous user', () => { - expect(shallowRender({ currentUser: mockCurrentUser() })).toMatchSnapshot(); + renderGlobalNavUser({ currentUser: mockCurrentUser() }); + expect(screen.getByText('layout.login')).toBeInTheDocument(); }); -it('should render the right interface for logged in user', () => { - const wrapper = shallowRender(); - wrapper.setState({ open: true }); - expect(wrapper.find('Dropdown')).toMatchSnapshot(); +it('should render the right interface for logged in user', async () => { + const user = userEvent.setup(); + renderGlobalNavUser(); + await user.click(screen.getByRole('link')); + + expect(screen.getByRole('link', { name: 'my_account.page' })).toHaveFocus(); }); -function shallowRender(overrides: Partial = {}) { - return shallow( +function renderGlobalNavUser(overrides: Partial = {}) { + return renderComponent( ); } diff --git a/server/sonar-web/src/main/js/app/components/nav/global/__tests__/__snapshots__/GlobalNavUser-test.tsx.snap b/server/sonar-web/src/main/js/app/components/nav/global/__tests__/__snapshots__/GlobalNavUser-test.tsx.snap deleted file mode 100644 index de81a2b9674..00000000000 --- a/server/sonar-web/src/main/js/app/components/nav/global/__tests__/__snapshots__/GlobalNavUser-test.tsx.snap +++ /dev/null @@ -1,66 +0,0 @@ -// Jest Snapshot v1, https://goo.gl/fbAQLP - -exports[`should render the right interface for anonymous user 1`] = ` - -`; - -exports[`should render the right interface for logged in user 1`] = ` - -
  • -
    - - Skywalker - -
    -
  • -
  • -
  • - - my_account.page - -
  • -
  • - - layout.logout - -
  • - - } -> - - - - -`; diff --git a/server/sonar-web/src/main/js/components/embed-docs-modal/EmbedDocsPopup.tsx b/server/sonar-web/src/main/js/components/embed-docs-modal/EmbedDocsPopup.tsx index 0fd077c50b4..4b063dae646 100644 --- a/server/sonar-web/src/main/js/components/embed-docs-modal/EmbedDocsPopup.tsx +++ b/server/sonar-web/src/main/js/components/embed-docs-modal/EmbedDocsPopup.tsx @@ -30,6 +30,21 @@ interface Props { } export default class EmbedDocsPopup extends React.PureComponent { + firstItem: HTMLAnchorElement | null = null; + + /* + * Will be called by the first suggestion (if any), as well as the first link (documentation) + * Since we don't know if we have any suggestions, we need to allow both to make the call. + * If we have at least 1 suggestion, it will make the call first, and prevent 'documentation' from + * getting the focus. + */ + focusFirstItem = (node: HTMLAnchorElement | null) => { + if (node && !this.firstItem) { + this.firstItem = node; + this.firstItem.focus(); + } + }; + renderTitle(text: string) { return (
  • @@ -45,9 +60,13 @@ export default class EmbedDocsPopup extends React.PureComponent { return (
      {this.renderTitle(translate('embed_docs.suggestion'))} - {suggestions.map(suggestion => ( + {suggestions.map((suggestion, i) => (
    • - + {suggestion.text}
    • @@ -77,7 +96,11 @@ export default class EmbedDocsPopup extends React.PureComponent { {this.renderSuggestions}
      • - + {translate('embed_docs.documentation')}
      • diff --git a/server/sonar-web/src/main/js/components/embed-docs-modal/__tests__/EmbedDocsPopup-test.tsx b/server/sonar-web/src/main/js/components/embed-docs-modal/__tests__/EmbedDocsPopup-test.tsx index f12348ed514..87f7315b3b2 100644 --- a/server/sonar-web/src/main/js/components/embed-docs-modal/__tests__/EmbedDocsPopup-test.tsx +++ b/server/sonar-web/src/main/js/components/embed-docs-modal/__tests__/EmbedDocsPopup-test.tsx @@ -17,11 +17,35 @@ * along with this program; if not, write to the Free Software Foundation, * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. */ -import { shallow } from 'enzyme'; +import { screen } from '@testing-library/react'; import * as React from 'react'; +import { renderComponent } from '../../../helpers/testReactTestingUtils'; +import { SuggestionLink } from '../../../types/types'; import EmbedDocsPopup from '../EmbedDocsPopup'; +import { SuggestionsContext } from '../SuggestionsContext'; -it('should render', () => { - const wrapper = shallow(); - expect(wrapper).toMatchSnapshot(); +it('should render with no suggestions', () => { + renderEmbedDocsPopup(); + + expect(screen.getAllByRole('link')).toHaveLength(5); + expect(screen.getByText('embed_docs.documentation')).toHaveFocus(); }); + +it('should render with suggestions', () => { + renderEmbedDocsPopup([ + { link: '/docs/awesome-doc', text: 'mindblowing' }, + { link: '/docs/whocares', text: 'boring' } + ]); + + expect(screen.getAllByRole('link')).toHaveLength(7); + expect(screen.getByText('mindblowing')).toHaveFocus(); +}); + +function renderEmbedDocsPopup(suggestions: SuggestionLink[] = []) { + return renderComponent( + + + + ); +} diff --git a/server/sonar-web/src/main/js/components/embed-docs-modal/__tests__/__snapshots__/EmbedDocsPopup-test.tsx.snap b/server/sonar-web/src/main/js/components/embed-docs-modal/__tests__/__snapshots__/EmbedDocsPopup-test.tsx.snap deleted file mode 100644 index edd740b4349..00000000000 --- a/server/sonar-web/src/main/js/components/embed-docs-modal/__tests__/__snapshots__/EmbedDocsPopup-test.tsx.snap +++ /dev/null @@ -1,88 +0,0 @@ -// Jest Snapshot v1, https://goo.gl/fbAQLP - -exports[`should render 1`] = ` - - - - -
          -
        • - - embed_docs.documentation - -
        • -
        • - - api_documentation.page - -
        • -
        - - -
        -`; -- 2.39.5