import React from 'react'; import { cleanup, fireEvent, render, RenderResult, waitFor, } from '@testing-library/react'; import userEvent from '@testing-library/user-event'; import startCase from 'lodash/startCase'; import { constructOrganizationURL, dataFixtures, hostDefaults, urlFixtures, } from '../data'; import { defaultMongoNavContext, MongoNavContextProps, MongoNavProvider, } from '../MongoNavContext'; import { ActiveNavElement, CurrentOrganizationInterface } from '../types'; import OrgNav, { OrgNavProps } from './OrgNav'; // data const { account, currentOrganization, organizations, currentProject } = dataFixtures; const { orgNav: { billing, allClusters, admin }, } = urlFixtures; // this avoids having to explicitly type orgNav with nullable fields // and then extend it to allow string indexes const linkNamesToUrls: Record = { billing, allClusters, admin, }; const linkNamesToText: Record = { allClusters: 'All Clusters', admin: 'Admin', billing: 'Billing', }; describe('packages/mongo-nav/src/org-nav', () => { let onOrganizationChange: jest.Mock; beforeEach(() => { onOrganizationChange = jest.fn(); }); afterEach(() => { jest.restoreAllMocks(); cleanup(); }); /** * Utility function to render the OrgNav with given props and context */ function renderComponent( props?: Partial, withContext?: Partial, ): RenderResult { const context: MongoNavContextProps = { ...defaultMongoNavContext, currentOrg: currentOrganization, currentProject: currentProject, activeNav: ActiveNavElement.OrgNavOrgSettings, ...withContext, }; return render( , ); } describe('when rendered with default props', () => { it(`does not display the version`, () => { const { queryByTestId } = renderComponent(); const version = queryByTestId('org-nav-on-prem-version'); expect(version).not.toBeInTheDocument(); }); it(`displays the UserMenu and does not display the onPrem User Menu`, () => { const { queryByTestId } = renderComponent(); const userMenu = queryByTestId('user-menu-trigger'); const onPremUserMenu = queryByTestId('om-user-menu-trigger'); expect(userMenu).toBeVisible(); expect(onPremUserMenu).toBeNull(); }); Object.keys(linkNamesToUrls).forEach(linkName => { const isVisible = linkName !== 'admin'; it(`${isVisible ? 'displays' : 'does not display'} the ${startCase( linkName, )} nav`, () => { const { queryByText } = renderComponent(); const navLink = queryByText(linkNamesToText[linkName])?.closest('a, button') ?? null; if (isVisible) { expect(navLink).toBeVisible(); expect((navLink as HTMLAnchorElement).href).toEqual( linkNamesToUrls[linkName], ); } else { expect(navLink).toBeNull(); } }); }); it(`does not display the payment status badge`, () => { const { queryByTestId } = renderComponent(); const badge = queryByTestId('org-nav-payment-status'); expect(badge).toBeNull(); }); test('it does not render the FedRAMP banner', () => { const { queryByTestId } = renderComponent(); expect(queryByTestId('org-nav-fedramp-banner')).toBeNull(); }); test('it displays a Get Help menu to the nav by default', () => { const { getByTestId } = renderComponent(); const getHelp = getByTestId('org-nav-dropdown-get-help'); expect(getHelp).toBeInTheDocument(); }); }); describe('when rendered as an admin without an active preferences nav', () => { it(`displays the payment status badge`, () => { const { queryByTestId } = renderComponent( { admin: true, }, { currentOrg: currentOrganization, }, ); const badge = queryByTestId('org-nav-payment-status'); expect(badge).toBeInTheDocument(); expect(badge!.textContent).toEqual('OK'); }); it(`displays the payment status badge with the provided displayName`, () => { const { queryByTestId } = renderComponent( { admin: true, }, { currentOrg: { ...currentOrganization, paymentStatusDisplayName: 'INACTIVE', } as CurrentOrganizationInterface, }, ); const badge = queryByTestId('org-nav-payment-status'); expect(badge).toBeInTheDocument(); expect(badge!.textContent).toEqual('INACTIVE'); }); it(`displays the payment status badge when no displayName is provided`, () => { const { queryByTestId } = renderComponent( { admin: true, }, { currentOrg: { ...currentOrganization, paymentStatusDisplayName: undefined, } as CurrentOrganizationInterface, }, ); const badge = queryByTestId('org-nav-payment-status'); expect(badge).toBeInTheDocument(); expect(badge!.textContent).toEqual(currentOrganization!.paymentStatus); }); describe('Links', () => { Object.keys(linkNamesToUrls).forEach( linkName => { it(`displays the ${startCase(linkName)} nav`, () => { const { queryByText } = renderComponent( { admin: true }, { currentOrg: currentOrganization, }, ); const navLink = queryByText(linkNamesToText[linkName])?.closest('a, button') ?? null; expect(navLink).toBeVisible(); expect((navLink as HTMLAnchorElement).href).toEqual( linkNamesToUrls[linkName], ); }); }, // testForNavLink(linkName), ); }); }); describe('when rendered as an admin with an active preferences nav', () => { const cloudUserNavItems = [ ActiveNavElement.UserMenuCloudInvitations, ActiveNavElement.UserMenuCloudMFA, ActiveNavElement.UserMenuCloudOrganizations, ActiveNavElement.UserMenuCloudOther, ActiveNavElement.UserMenuCloudUserPreferences, ]; cloudUserNavItems.forEach(activeNav => { describe(`when the element ${activeNav as string} is active`, () => { let queryByTestId: RenderResult['queryByTestId']; let queryByText: RenderResult['queryByText']; beforeEach(() => { ({ queryByTestId, queryByText } = renderComponent( { admin: true, }, { activeNav, }, )); }); it(`does not display the payment status badge`, () => { const badge = queryByTestId('org-nav-payment-status'); expect(badge).toBeNull(); }); it(`does not display the version`, () => { const version = queryByTestId('org-nav-on-prem-version'); expect(version).toBeNull(); }); Object.keys(linkNamesToUrls).forEach(linkName => { const isVisible = ['allClusters', 'admin'].includes(linkName); it(`${isVisible ? 'displays' : 'does not display'} the ${startCase( linkName, )} nav`, () => { const navLink = queryByText(linkNamesToText[linkName])?.closest('a, button') ?? null; if (isVisible) { expect(navLink).toBeVisible(); expect((navLink as HTMLAnchorElement).href).toEqual( linkNamesToUrls[linkName], ); } else { expect(navLink).toBeNull(); } }); }); }); }); }); describe('the Get Help dropdown displays correctly', () => { test('support link appears in menu', () => { const { getByTestId } = renderComponent(); const getHelp = getByTestId('org-nav-dropdown-get-help'); userEvent.click(getHelp); const support = getByTestId('org-nav-support-link'); expect(support).toBeInTheDocument(); }); test('docs link appears in menu', () => { const { getByTestId } = renderComponent(); const getHelp = getByTestId('org-nav-dropdown-get-help'); userEvent.click(getHelp); const docs = getByTestId('org-nav-docs-link'); expect(docs).toBeInTheDocument(); }); }); describe('when rendered without project nav', () => { it('shows project access as disabled', () => { const { getByTestId } = renderComponent({ showProjectNav: false, }); const accessMgrDropdown = getByTestId('org-nav-access-manager-dropdown'); userEvent.click(accessMgrDropdown); const accessManagerProject = getByTestId( 'org-nav-dropdown-project-access-manager', ); expect(accessManagerProject).toHaveAttribute('aria-disabled', 'true'); expect(accessManagerProject).toContainHTML('None'); }); }); describe('when rendered onPrem', () => { let queryByTestId: RenderResult['queryByTestId']; let getByTestId: RenderResult['getByTestId']; let queryByText: RenderResult['queryByText']; beforeEach( () => ({ queryByTestId, getByTestId, queryByText } = renderComponent({ onPremEnabled: true, onPremVersion: '4.4.0', })), ); it(`does not display the payment status badge`, () => { const badge = queryByTestId('org-nav-payment-status'); expect(badge).toBeNull(); }); it(`displays the version`, () => { const version = queryByTestId('org-nav-on-prem-version'); expect(version).toBeVisible(); }); it(`does not display the UserMenu and displays the onPrem User Menu`, () => { const userMenu = queryByTestId('user-menu-trigger'); const onPremUserMenu = queryByTestId('om-user-menu-trigger'); expect(onPremUserMenu).toBeVisible(); expect(userMenu).toBeNull(); }); it(`does not display the MFA option`, () => { const onPremUserMenu = getByTestId('om-user-menu-trigger'); fireEvent.click(onPremUserMenu); const onPremUserMenuMFA = queryByTestId('om-user-menuitem-mfa'); expect(onPremUserMenuMFA).toBeNull(); }); Object.keys(linkNamesToUrls).forEach(linkName => { const isVisible = !['billing', 'admin'].includes(linkName); it(`${isVisible ? 'displays' : 'does not display'} the ${startCase( linkName, )} nav`, () => { const navLink = queryByText(linkNamesToText[linkName])?.closest('a, button') ?? null; if (isVisible) { expect(navLink).toBeVisible(); expect((navLink as HTMLAnchorElement).href).toEqual( linkNamesToUrls[linkName], ); } else { expect(navLink).toBeNull(); } }); }); }); describe('when rendered onPrem and onPremMFA is true', () => { let queryByTestId: RenderResult['queryByTestId']; let getByTestId: RenderResult['getByTestId']; beforeEach( () => ({ queryByTestId, getByTestId } = renderComponent({ onPremEnabled: true, onPremMFA: true, })), ); it(`displays the MFA option`, () => { const onPremUserMenu = getByTestId('om-user-menu-trigger'); fireEvent.click(onPremUserMenu); const onPremUserMenuMFA = queryByTestId('om-user-menuitem-mfa'); expect(onPremUserMenuMFA).toBeInTheDocument(); expect((onPremUserMenuMFA as HTMLAnchorElement).href).toBe( 'https://cloud.mongodb.com/v2#/account/2fa', ); }); }); describe('when rendered onPrem and admin is set to true', () => { let queryByText: RenderResult['queryByText']; beforeEach( () => ({ queryByText } = renderComponent({ onPremEnabled: true, onPremVersion: '4.4.0', admin: true, })), ); Object.keys(linkNamesToUrls).forEach( linkName => { const isVisible = linkName !== 'billing'; it(`${isVisible ? 'displays' : 'does not display'} the ${startCase( linkName, )} nav`, () => { const navLink = queryByText(linkNamesToText[linkName])?.closest('a, button') ?? null; if (isVisible) { expect(navLink).toBeVisible(); expect((navLink as HTMLAnchorElement).href).toEqual( linkNamesToUrls[linkName], ); } else { expect(navLink).toBeNull(); } }); }, // testForNavLink(linkName, ), ); }); describe('when rendered as an ops manager admin with an active account nav', () => { const onPremUserNavItems = [ ActiveNavElement.UserMenuOnPremInvitations, ActiveNavElement.UserMenuOnPremOrganizations, ActiveNavElement.UserMenuOnPremOther, ActiveNavElement.UserMenuOnPremPersonalization, ActiveNavElement.UserMenuOnPremProfile, ActiveNavElement.UserMenuOnPremPublicApiAccess, ActiveNavElement.UserMenuOnPremTwoFactorAuth, ]; onPremUserNavItems.forEach(activeNav => { describe(`when the element ${activeNav as string} is active`, () => { let queryByText: RenderResult['queryByText']; let queryByTestId: RenderResult['queryByTestId']; beforeEach( () => ({ queryByText, queryByTestId } = renderComponent( { onPremEnabled: true, onPremVersion: '4.4.0', admin: true, }, { activeNav, }, )), ); it(`does not display the payment status badge`, () => { const badge = queryByText('org-nav-payment-status'); expect(badge).toBeNull(); }); it('displays the version', () => { const version = queryByTestId('org-nav-on-prem-version'); expect(version).toBeVisible(); }); Object.keys(linkNamesToUrls).forEach(linkName => { const isVisible = ['allClusters', 'admin'].includes(linkName); it(`${isVisible ? 'displays' : 'does not display'} the ${startCase( linkName, )} nav`, () => { const navLink = queryByText(linkNamesToText[linkName])?.closest('a, button') ?? null; if (isVisible) { expect(navLink).toBeVisible(); expect((navLink as HTMLAnchorElement).href).toEqual( linkNamesToUrls[linkName], ); } else { expect(navLink).toBeNull(); } }); }); }); }); }); describe('the Access Manager element displays correctly', () => { describe('renders according to `showUnifiedAccessManagementNav` prop', () => { test('showUnifiedAccessManagementNav == false', () => { const { getByTestId } = renderComponent( { showProjectNav: true, currentProjectName: 'Test Project', currentProjectId: 'test-project-id', }, { showUnifiedAccessManagementNav: false, }, ); const element = getByTestId('org-nav-access-manager-dropdown'); expect(element).toBeInTheDocument(); expect(element.tagName).toBe('BUTTON'); }); test('showUnifiedAccessManagementNav == true', () => { const { getByTestId } = renderComponent( { showProjectNav: true, currentProjectName: 'Test Project', currentProjectId: 'test-project-id', }, { showUnifiedAccessManagementNav: true, }, ); const element = getByTestId('org-nav-access-manager-dropdown'); expect(element).toBeInTheDocument(); expect(element.tagName).toBe('A'); }); }); describe('and the accessibility props are properly set', () => { let getByTestId: RenderResult['getByTestId']; beforeEach( () => ({ getByTestId } = renderComponent({ showProjectNav: true, currentProjectName: 'Test Project', currentProjectId: 'test-project-id', })), ); test('when closed, "aria-expanded" is set to false', () => { expect( getByTestId('org-nav-access-manager-dropdown').getAttribute( 'aria-expanded', ), ).toBe('false'); }); test('when open, "aria-expanded" is set to true', () => { fireEvent.click(getByTestId('org-nav-access-manager-dropdown')); expect( getByTestId('org-nav-access-manager-dropdown').getAttribute( 'aria-expanded', ), ).toBe('true'); }); }); describe('when onPrem is true', () => { test('and currentProject exists, the Project Access Manager link is not disabled and project name is displayed', () => { const { getByTestId } = renderComponent({ onPremEnabled: true, showProjectNav: false, currentProjectName: 'Test Project', currentProjectId: 'test-project-id', }); userEvent.click(getByTestId('org-nav-access-manager-dropdown')); waitFor(() => { const accessManagerProject = getByTestId( 'org-nav-dropdown-project-access-manager', ); expect(accessManagerProject.innerHTML.includes('Test Project')).toBe( true, ); expect(accessManagerProject.getAttribute('aria-disabled')).toBe( 'false', ); }); }); test('and currentProject does not exist, the Project Access Manager link is disabled and the project name appears as "None"', () => { const { getByTestId } = renderComponent({ onPremEnabled: true, showProjectNav: false, }); userEvent.click(getByTestId('org-nav-access-manager-dropdown')); waitFor(() => { const accessManagerProject = getByTestId( 'org-nav-dropdown-project-access-manager', ); expect(accessManagerProject.innerHTML.includes('None')).toBe(true); expect(accessManagerProject.getAttribute('aria-disabled')).toBe( 'true', ); }); }); }); describe('when onPrem is false', () => { test('and showProjectNav is true, the Project Access Manager link is not disabled and project name is displayed', () => { const { getByTestId } = renderComponent({ showProjectNav: true, currentProjectName: 'Test Project', currentProjectId: 'test-project-id', }); userEvent.click(getByTestId('org-nav-access-manager-dropdown')); waitFor(() => { const accessManagerProject = getByTestId( 'org-nav-dropdown-project-access-manager', ); expect(accessManagerProject.innerHTML.includes('Test Project')).toBe( true, ); expect(accessManagerProject.getAttribute('aria-disabled')).toBe( 'false', ); }); }); test('and showProjectNav is false, the Project Access Manager link is disabled and the project name appears as "None"', () => { const { getByTestId } = renderComponent({ showProjectNav: false, }); userEvent.click(getByTestId('org-nav-access-manager-dropdown')); waitFor(() => { const accessManagerProject = getByTestId( 'org-nav-dropdown-project-access-manager', ); expect(accessManagerProject.innerHTML.includes('None')).toBe(true); expect(accessManagerProject.getAttribute('aria-disabled')).toBe( 'true', ); }); }); }); }); describe('when environment is "government"', () => { test('it renders a FedRAMP banner in the org nav', () => { const { getByTestId } = renderComponent({ environment: 'government' }); expect(getByTestId('org-nav-fedramp-banner')).toBeVisible(); }); }); test('when currentOrganization is null', () => { const { getByTestId } = renderComponent({}, { currentOrg: null }); const orgSelect = getByTestId('org-trigger'); const accessManager = getByTestId('org-nav-access-manager-dropdown'); const billing = getByTestId('org-nav-billing'); const userMenu = getByTestId('user-menu-trigger'); expect(orgSelect).toBeInTheDocument(); expect(accessManager).toBeInTheDocument(); expect(billing).toBeInTheDocument(); expect(userMenu).toBeInTheDocument(); expect(orgSelect).not.toBeDisabled(); expect(accessManager).toBeDisabled(); expect(billing).toBeDisabled(); expect(userMenu).not.toBeDisabled(); }); });