import { useRoute } from "@react-navigation/native"; import { fireEvent, screen, waitFor } from "@testing-library/react-native"; import ObsDetailsContainer from "components/ObsDetailsSharedComponents/ObsDetailsContainer"; import { t } from "i18next"; import React from "react"; import useAuthenticatedQuery from "sharedHooks/useAuthenticatedQuery"; import * as useCurrentUser from "sharedHooks/useCurrentUser"; import * as useLocalObservation from "sharedHooks/useLocalObservation"; import factory from "tests/factory"; import faker from "tests/helpers/faker"; import { renderComponent } from "tests/helpers/render"; const mockObservation = factory( "LocalObservation", { _created_at: faker.date.past( ), created_at: "2022-11-27T19:07:41-08:00", time_observed_at: "2023-12-14T21:07:41-09:30", observationPhotos: [ factory( "LocalObservationPhoto", { photo: { id: faker.number.int( ), attribution: faker.lorem.sentence( ), licenseCode: "cc-by-nc", url: faker.image.url( ), }, } ), ], taxon: factory( "LocalTaxon", { name: faker.person.firstName( ), rank: "species", rank_level: 10, preferred_common_name: faker.person.fullName( ), defaultPhoto: { id: faker.number.int( ), attribution: faker.lorem.sentence( ), licenseCode: "cc-by-nc", url: faker.image.url( ), }, } ), user: factory( "LocalUser", { login: faker.internet.userName( ), iconUrl: faker.image.url( ), locale: "en", } ), identifications: [], } ); const mockNoEvidenceObservation = factory( "LocalObservation", { _created_at: faker.date.past( ), created_at: "2022-11-27T19:07:41-08:00", time_observed_at: "2023-12-14T21:07:41-09:30", taxon: factory( "LocalTaxon", { name: faker.person.firstName( ), rank: "species", rank_level: 10, preferred_common_name: faker.person.fullName( ), defaultPhoto: { id: faker.number.int( ), attribution: faker.lorem.sentence( ), licenseCode: "cc-by-nc", url: faker.image.url( ), }, } ), user: factory( "LocalUser", { login: faker.internet.userName( ), iconUrl: faker.image.url( ), locale: "en", } ), identifications: [], } ); mockNoEvidenceObservation.observationPhotos = []; mockNoEvidenceObservation.observationSounds = []; const mockUser = factory( "LocalUser", { login: faker.internet.userName( ), iconUrl: faker.image.url( ), id: "1234", } ); jest.mock( "sharedHooks/useLocalObservation", () => ( { __esModule: true, default: jest.fn( () => ( { localObservation: null, } ) ), } ) ); jest.mock( "sharedHooks/useCurrentUser", () => ( { __esModule: true, default: () => mockUser, } ) ); const mockNavigate = jest.fn(); useRoute.mockImplementation( ( ) => ( { params: { uuid: mockObservation.uuid }, } ) ); jest.mock( "@react-navigation/native", () => { const actualNav = jest.requireActual( "@react-navigation/native" ); return { ...actualNav, useRoute: jest.fn( ), useNavigation: () => ( { navigate: mockNavigate, addListener: jest.fn(), setOptions: jest.fn(), canGoBack: jest.fn(), } ), }; } ); jest.mock( "sharedHooks/useAuthenticatedQuery", () => ( { __esModule: true, default: jest.fn( () => ( { data: mockObservation, } ) ), } ) ); const mockMutate = jest.fn(); jest.mock( "sharedHooks/useAuthenticatedMutation", () => ( { __esModule: true, default: ( ) => ( { mutate: mockMutate, } ), } ) ); jest.mock( "sharedHooks/useObservationsUpdates", () => ( { __esModule: true, default: jest.fn( () => ( { refetch: jest.fn(), } ) ), } ) ); const mockRefetchRemoteObservation = jest.fn(); const mockMarkViewedLocally = jest.fn(); const mockMarkDeletedLocally = jest.fn(); const mockSetRemoteObsWasDeleted = jest.fn(); const defaultProps = { belongsToCurrentUser: false, currentUser: mockUser, fetchRemoteObservationError: null, isConnected: true, isRefetching: false, localObservation: null, markDeletedLocally: mockMarkDeletedLocally, markViewedLocally: mockMarkViewedLocally, observation: mockObservation, refetchRemoteObservation: mockRefetchRemoteObservation, remoteObservation: mockObservation, remoteObsWasDeleted: false, setRemoteObsWasDeleted: mockSetRemoteObsWasDeleted, uuid: mockObservation.uuid, }; const renderObsDetailsContainer = ( props = {} ) => renderComponent( , ); describe( "ObsDetailsContainer", () => { beforeAll( async () => { jest.useFakeTimers( ); } ); it( "renders obs details from remote call", async () => { renderObsDetailsContainer( ); const obs = await screen.findByTestId( `ObsDetails.${mockObservation.uuid}` ); await waitFor( ( ) => { expect( obs ).toBeTruthy(); } ); expect( screen.getByText( mockObservation.taxon.name ) ).toBeTruthy(); } ); describe( "Observation with no evidence", () => { beforeEach( () => { useAuthenticatedQuery.mockReturnValue( { data: mockNoEvidenceObservation, } ); } ); it( "should render fallback image icon instead of photos", async () => { renderObsDetailsContainer( { observation: mockNoEvidenceObservation, remoteObservation: mockNoEvidenceObservation, uuid: mockNoEvidenceObservation.uuid, } ); const labelText = t( "Observation-has-no-photos-and-no-sounds" ); const fallbackImage = await screen.findByLabelText( labelText ); expect( fallbackImage ).toBeTruthy(); } ); afterEach( () => { useAuthenticatedQuery.mockReturnValue( { data: mockObservation, } ); } ); } ); describe( "viewing someone else's observation", ( ) => { it( "should agree with another user's identification when agree button pressed", async ( ) => { const firstIdentification = factory( "RemoteIdentification", { taxon: factory( "RemoteTaxon", { preferred_common_name: "Red Fox", name: "Vulpes vulpes", is_active: true, } ), user: factory( "RemoteUser" ), } ); const otherUserObservation = mockObservation; otherUserObservation.identifications = [ firstIdentification, ]; jest.spyOn( useLocalObservation, "default" ).mockImplementation( () => ( { localObservation: null, } ) ); useAuthenticatedQuery.mockReturnValue( { data: otherUserObservation, } ); jest.spyOn( useCurrentUser, "default" ).mockImplementation( () => mockUser ); renderObsDetailsContainer( { observation: otherUserObservation, remoteObservation: otherUserObservation, uuid: otherUserObservation.uuid, belongsToCurrentUser: false, localObservation: null, } ); const agreeButton = screen.getByTestId( `ActivityItem.AgreeIdButton.${firstIdentification.taxon.id}`, ); expect( agreeButton ).toBeTruthy( ); fireEvent.press( agreeButton ); const confirmButton = screen.getByTestId( "ObsDetail.AgreeId.cvSuggestionsButton" ); expect( confirmButton ).toBeTruthy( ); fireEvent.press( confirmButton ); expect( mockMutate ).toHaveBeenCalledWith( { identification: { observation_id: otherUserObservation.uuid, taxon_id: firstIdentification.taxon.id, }, } ); } ); } ); } );