diff --git a/react/src/__fixtures__/appConfigurationFixture.ts b/react/src/__fixtures__/appConfigurationFixture.ts index affa8afb..ac4ecfb6 100644 --- a/react/src/__fixtures__/appConfigurationFixture.ts +++ b/react/src/__fixtures__/appConfigurationFixture.ts @@ -1,4 +1,9 @@ -import { AppConfiguration, MapillaryConfiguration } from '@hazmapper/types'; +import { + AppConfiguration, + GeoapiBackendEnvironment, + MapillaryConfiguration, +} from '@hazmapper/types'; +import { getGeoapiUrl } from '@hazmapper/hooks/environment/utils'; export const mapillaryConfig: MapillaryConfiguration = { authUrl: 'https://www.mapillary.com/connect', @@ -14,7 +19,8 @@ export const mapillaryConfig: MapillaryConfiguration = { export const testDevConfiguration: AppConfiguration = { basePath: '/test', - geoapiUrl: 'https://geoapi.unittest', + geoapiEnv: GeoapiBackendEnvironment.Test, + geoapiUrl: getGeoapiUrl(GeoapiBackendEnvironment.Test), designsafePortalUrl: 'https://designsafeci.unittest', tapisUrl: 'https://tapis.io.unittest', mapillary: mapillaryConfig, diff --git a/react/src/components/ManageMapProjectPanel/ManageMapProjectPanel.test.tsx b/react/src/components/ManageMapProjectPanel/ManageMapProjectPanel.test.tsx index c60b436b..394519fc 100644 --- a/react/src/components/ManageMapProjectPanel/ManageMapProjectPanel.test.tsx +++ b/react/src/components/ManageMapProjectPanel/ManageMapProjectPanel.test.tsx @@ -1,38 +1,12 @@ import React from 'react'; -import { screen, fireEvent } from '@testing-library/react'; +import { within, screen, fireEvent } from '@testing-library/react'; import ManageMapProjectPanel from './ManageMapProjectPanel'; import { projectMock } from '@hazmapper/__fixtures__/projectFixtures'; import { renderInTest, testQueryClient } from '@hazmapper/test/testUtil'; -// Mock the child components -jest.mock('./MapTabContent', () => { - return function MockMapTabContent() { - return
Map Tab Content
; - }; -}); - -jest.mock('./MembersTabContent', () => { - return function MockMembersTabContent() { - return
Members Tab Content
; - }; -}); - -jest.mock('./PublicTabContent', () => { - return function MockPublicTabContent() { - return
Public Tab Content
; - }; -}); - -jest.mock('./SaveTabContent', () => { - return function MockSaveTabContent() { - return
Save Tab Content
; - }; -}); - describe('ManageMapProjectPanel', () => { const defaultProps = { project: projectMock, - onProjectUpdate: jest.fn(), }; beforeEach(() => { @@ -40,36 +14,34 @@ describe('ManageMapProjectPanel', () => { testQueryClient.clear(); }); - it('renders all tab buttons', () => { + it('renders the default Map tab content initially', () => { renderInTest(); - expect(screen.getByRole('tab', { name: 'Map' })).toBeTruthy(); - expect(screen.getByRole('tab', { name: 'Members' })).toBeTruthy(); - expect(screen.getByRole('tab', { name: 'Public' })).toBeTruthy(); - expect(screen.getByRole('tab', { name: 'Save' })).toBeTruthy(); - }); + // Get the active tab container + const activeTab = screen.getByRole('tabpanel', { hidden: false }); - it('renders map tab content by default', () => { - renderInTest(); + // Ensure the active tab contains "Map Details" + expect(within(activeTab).getByText(/Map Details/i)).toBeDefined(); - expect(screen.getByTestId('map-tab-content')).toBeTruthy(); + // Ensure other tab content is NOT present in the active tab + expect(within(activeTab).queryByText(/Members/i)).toBeNull(); + expect(within(activeTab).queryByText(/Public Access/i)).toBeNull(); + expect(within(activeTab).queryByText(/Save Location/i)).toBeNull(); }); + it('switches between tabs correctly', () => { renderInTest(); - // Click Members tab - const membersTab = screen.getByRole('tab', { name: 'Members' }); - fireEvent.click(membersTab); - expect(screen.getByTestId('members-tab-content')).toBeTruthy(); + // Click "Members" tab + fireEvent.click(screen.getByRole('tab', { name: 'Members' })); + + // Get the newly active tab container + const activeTab = screen.getByRole('tabpanel', { hidden: false }); - // Click Public tab - const publicTab = screen.getByRole('tab', { name: 'Public' }); - fireEvent.click(publicTab); - expect(screen.getByTestId('public-tab-content')).toBeTruthy(); + // Ensure the "Members" tab content is now visible + expect(within(activeTab).getByText(/Members/i)).toBeDefined(); - // Click Save tab - const saveTab = screen.getByRole('tab', { name: 'Save' }); - fireEvent.click(saveTab); - expect(screen.getByTestId('save-tab-content')).toBeTruthy(); + // Ensure the previous tab content is NOT present in the active tab + expect(within(activeTab).queryByText(/Map Details/i)).toBeNull(); }); }); diff --git a/react/src/components/ManageMapProjectPanel/MapTabContent.test.tsx b/react/src/components/ManageMapProjectPanel/MapTabContent.test.tsx new file mode 100644 index 00000000..f18a57dd --- /dev/null +++ b/react/src/components/ManageMapProjectPanel/MapTabContent.test.tsx @@ -0,0 +1,60 @@ +import React from 'react'; +import { screen, fireEvent, waitFor } from '@testing-library/react'; +import { renderInTest } from '@hazmapper/test/testUtil'; +import { projectMock } from '@hazmapper/__fixtures__/projectFixtures'; +import { testDevConfiguration } from '@hazmapper/__fixtures__/appConfigurationFixture'; +import MapTabContent from './MapTabContent'; + +const mockNavigate = jest.fn(); + +jest.mock('react-router-dom', () => ({ + ...jest.requireActual('react-router-dom'), + useNavigate: () => mockNavigate, +})); + +describe('MapTabContent', () => { + const mockOnProjectUpdate = jest.fn(); + + beforeEach(() => { + mockNavigate.mockClear(); + jest.clearAllMocks(); + }); + + it('renders project details correctly', () => { + renderInTest( + + ); + + expect(screen.getByText('Name:')).toBeDefined(); + expect(screen.getByText(projectMock.name)).toBeDefined(); + + expect(screen.getByText('Description:')).toBeDefined(); + expect(screen.getByText(projectMock.description)).toBeDefined(); + }); + + it('navigates to Taggit when "View in Taggit" button is clicked', async () => { + renderInTest( + + ); + + const taggitButton = screen.getByTestId('taggit-button'); + fireEvent.click(taggitButton); + + await waitFor(() => { + // Taggit will read from local storage + expect(localStorage.getItem('testLastProject')).toBe( + JSON.stringify(projectMock) + ); + }); + await waitFor(() => expect(mockNavigate).toHaveBeenCalledTimes(1)); + expect(mockNavigate).toHaveBeenCalledWith(testDevConfiguration.taggitUrl); + }); +}); diff --git a/react/src/components/ManageMapProjectPanel/MapTabContent.tsx b/react/src/components/ManageMapProjectPanel/MapTabContent.tsx index 423bbecc..3f84d3aa 100644 --- a/react/src/components/ManageMapProjectPanel/MapTabContent.tsx +++ b/react/src/components/ManageMapProjectPanel/MapTabContent.tsx @@ -3,6 +3,7 @@ import { Project, ProjectRequest } from '@hazmapper/types'; import { SectionMessage } from '@tacc/core-components'; import { EditFilled, CheckOutlined, DeleteOutlined } from '@ant-design/icons'; import { Button, Flex, List, Input, Modal } from 'antd'; +import { useNavigate } from 'react-router-dom'; import { useAppConfiguration } from '@hazmapper/hooks'; import DeleteMapModal from '../DeleteMapModal/DeleteMapModal'; @@ -65,6 +66,19 @@ const MapTabContent: React.FC = ({ const config = useAppConfiguration(); + const navigate = useNavigate(); + + const navigateToCorrespondingTaggitGallery = () => { + // We set some info in local storage for Taggit and then navigate to Taggit + + // key for local storage is backend-specific + const lastProjectKeyword = `${config.geoapiEnv}LastProject`; + + // note that entire project gets stringified but only `id` is used by taggit + localStorage.setItem(lastProjectKeyword, JSON.stringify(project)); + navigate(config.taggitUrl); + }; + return ( <> @@ -105,11 +119,9 @@ const MapTabContent: React.FC = ({ diff --git a/react/src/hooks/environment/getLocalAppConfiguration.ts b/react/src/hooks/environment/getLocalAppConfiguration.ts index 17a8df80..b6a134b5 100644 --- a/react/src/hooks/environment/getLocalAppConfiguration.ts +++ b/react/src/hooks/environment/getLocalAppConfiguration.ts @@ -36,11 +36,12 @@ export const getLocalAppConfiguration = ( const appConfig: AppConfiguration = { basePath: basePath, + geoapiEnv: localDevelopmentConfiguration.geoapiBackend, geoapiUrl: getGeoapiUrl(localDevelopmentConfiguration.geoapiBackend), designsafePortalUrl: getDesignsafePortalUrl(designSafePortal), tapisUrl: 'https://designsafe.tapis.io', mapillary: mapillaryConfig, - taggitUrl: origin + '/taggit-staging', + taggitUrl: origin + '/taggit-local', // TODO: we don't support allowing taggit to run at the same time in local dev env }; appConfig.mapillary.clientId = '5156692464392931'; appConfig.mapillary.clientSecret = diff --git a/react/src/hooks/environment/useAppConfiguration.ts b/react/src/hooks/environment/useAppConfiguration.ts index 64531470..8cd83b3b 100644 --- a/react/src/hooks/environment/useAppConfiguration.ts +++ b/react/src/hooks/environment/useAppConfiguration.ts @@ -46,6 +46,7 @@ export const useAppConfiguration = (): AppConfiguration => { ) { const appConfig: AppConfiguration = { basePath: basePath, + geoapiEnv: GeoapiBackendEnvironment.Staging, geoapiUrl: getGeoapiUrl(GeoapiBackendEnvironment.Staging), designsafePortalUrl: getDesignsafePortalUrl( DesignSafePortalEnvironment.PPRD @@ -67,6 +68,7 @@ export const useAppConfiguration = (): AppConfiguration => { ) { const appConfig: AppConfiguration = { basePath: basePath, + geoapiEnv: GeoapiBackendEnvironment.Dev, geoapiUrl: getGeoapiUrl(GeoapiBackendEnvironment.Dev), designsafePortalUrl: getDesignsafePortalUrl( DesignSafePortalEnvironment.PPRD @@ -86,6 +88,7 @@ export const useAppConfiguration = (): AppConfiguration => { } else if (/^hazmapper.tacc.utexas.edu/.test(hostname)) { const appConfig: AppConfiguration = { basePath: basePath, + geoapiEnv: GeoapiBackendEnvironment.Production, geoapiUrl: getGeoapiUrl(GeoapiBackendEnvironment.Production), designsafePortalUrl: getDesignsafePortalUrl( DesignSafePortalEnvironment.Production diff --git a/react/src/hooks/environment/utils.ts b/react/src/hooks/environment/utils.ts index 92b55562..7e6913c8 100644 --- a/react/src/hooks/environment/utils.ts +++ b/react/src/hooks/environment/utils.ts @@ -8,6 +8,8 @@ import { */ export function getGeoapiUrl(backend: GeoapiBackendEnvironment): string { switch (backend) { + case GeoapiBackendEnvironment.Test: + return 'https://geoapi.unittest'; case GeoapiBackendEnvironment.Local: return 'http://localhost:8888'; case GeoapiBackendEnvironment.Experimental: diff --git a/react/src/types/environment.ts b/react/src/types/environment.ts index fb12d0c4..cf8ac619 100644 --- a/react/src/types/environment.ts +++ b/react/src/types/environment.ts @@ -7,6 +7,7 @@ export enum GeoapiBackendEnvironment { Dev = 'dev', Experimental = 'experimental', Local = 'local', + Test = 'test', // for unit testing } /** @@ -72,6 +73,9 @@ export interface AppConfiguration { /** Base URL path for the application. */ basePath: string; + /** Geoapi environments. */ + geoapiEnv: GeoapiBackendEnvironment; + /** URL for the GeoAPI service. */ geoapiUrl: string;