Files
Johannes Klein 43443f5cfc Consolidate ObsDetails screens (#3649)
* Create new hook shell

* Revert "Create new hook shell"

This reverts commit b6918db347.

* Copy ObsDetailsDefaultModeScreensWrapper as is to new file

* Copy ObsDetailsContainer as is into new file

* We don't need this param at this level

* Have new ObsDetailsContainer be the next child of screen

* Update props of new child and remove thereby hoisted code

* Move route param extraction into component that needs it

* Extract presentational logic into new component

* Also copy over flow types

* Also copy over flow types

* Return null if no observation

* Remove mode switch logic from navigator

* Remove no longer needed advanced mode container

* Consolidate default mode container into new one as well, and switch over default mode to show default mode UI

* Same as in advanced mode, read param where it is needed

* Remove prop

* Run the integration test on the only container

* Git mv test file and update with new import

* Move test and only keep the UI logic part being tested

* Move tests relevant for ObsDetailsScreen

* Update ObsDetailsScreen.test.js

* Update IdentificationSheets.test.js

* Remove unused screen wrapper
2026-05-27 16:27:27 +02:00

210 lines
6.1 KiB
JavaScript

import { useRoute } from "@react-navigation/native";
import { screen } from "@testing-library/react-native";
import ObsDetailsScreen from "components/ObsDetailsSharedComponents/ObsDetailsScreen";
import inatjs from "inaturalistjs";
import React from "react";
import * as useLocalObservation from "sharedHooks/useLocalObservation";
import factory from "tests/factory";
import faker from "tests/helpers/faker";
import { renderComponent } from "tests/helpers/render";
const mockUuid = "test-123";
const mockCurrentUser = factory( "LocalUser", {
id: 123,
login: faker.internet.userName( ),
} );
const mockLocalObservation = factory( "LocalObservation", {
user: factory( "LocalUser", {
id: 123,
} ),
uuid: mockUuid,
taxon: factory( "LocalTaxon", {
name: faker.person.firstName( ),
rank: "species",
rank_level: 10,
} ),
} );
jest.mock( "@react-native-community/netinfo", () => ( {
useNetInfo: () => ( { isConnected: true } ),
configure: jest.fn( ),
} ) );
jest.mock( "sharedHooks/useCurrentUser", () => ( {
__esModule: true,
default: () => mockCurrentUser,
} ) );
jest.mock( "sharedHooks/useLocalObservation", () => ( {
__esModule: true,
default: jest.fn( () => ( {
localObservation: null,
} ) ),
} ) );
jest.mock( "sharedHooks/useRemoteObservation", ( ) => ( {
__esModule: true,
default: ( _uuid, _fetchRemoteEnabled ) => ( {
remoteObservation: null,
refetchRemoteObservation: jest.fn( ),
isRefetching: false,
fetchRemoteObservationError: null,
} ),
} ) );
useRoute.mockImplementation( ( ) => ( {
params: { uuid: mockUuid },
} ) );
jest.mock( "@react-navigation/native", () => {
const actualNav = jest.requireActual( "@react-navigation/native" );
return {
...actualNav,
useRoute: jest.fn( ),
useNavigation: () => ( {
navigate: jest.fn(),
addListener: jest.fn(),
setOptions: jest.fn(),
canGoBack: jest.fn(),
} ),
};
} );
jest.mock( "sharedHooks/useAuthenticatedQuery", () => ( {
__esModule: true,
default: jest.fn( () => ( {
data: null,
} ) ),
} ) );
jest.mock( "sharedHooks/useAuthenticatedMutation", () => ( {
__esModule: true,
default: ( ) => ( {
mutate: jest.fn(),
} ),
} ) );
jest.mock( "sharedHooks/useObservationsUpdates", () => ( {
__esModule: true,
default: jest.fn( () => ( {
refetch: jest.fn(),
} ) ),
} ) );
describe( "ObsDetailsScreen", ( ) => {
beforeAll( () => {
jest.useFakeTimers( );
} );
describe( "when showSavedMatch is true", ( ) => {
it(
"renders SavedMatchContainer when observation belongs to current user and is not synced",
( ) => {
const unsyncedLocalObservation = {
...mockLocalObservation,
wasSynced: jest.fn( () => false ),
};
jest.spyOn( useLocalObservation, "default" ).mockImplementation( () => ( {
localObservation: unsyncedLocalObservation,
markDeletedLocally: jest.fn( ),
markViewedLocally: jest.fn( ),
} ) );
renderComponent( <ObsDetailsScreen /> );
expect( screen.getByTestId( "SavedMatch.container" ) ).toBeTruthy( );
expect( screen.queryByTestId( "ObsDetails.container" ) ).toBeFalsy( );
},
);
it( "renders SavedMatchContainer when observation has no user and is not synced", ( ) => {
const unsyncedLocalObservationNoUser = factory( "LocalObservation", {
user: null,
uuid: mockUuid,
wasSynced: jest.fn( () => false ),
} );
jest.spyOn( useLocalObservation, "default" ).mockImplementation( () => ( {
localObservation: unsyncedLocalObservationNoUser,
markDeletedLocally: jest.fn( ),
markViewedLocally: jest.fn( ),
} ) );
renderComponent( <ObsDetailsScreen /> );
expect( screen.getByTestId( "SavedMatch.container" ) ).toBeTruthy( );
expect( screen.queryByTestId( "ObsDetails.container" ) ).toBeFalsy( );
} );
it( "does not mark observation updates as viewed", ( ) => {
const unsyncedLocalObservation = {
...mockLocalObservation,
wasSynced: jest.fn( () => false ),
};
jest.spyOn( useLocalObservation, "default" ).mockImplementation( () => ( {
localObservation: unsyncedLocalObservation,
markDeletedLocally: jest.fn( ),
markViewedLocally: jest.fn( ),
} ) );
renderComponent( <ObsDetailsScreen /> );
expect( screen.getByTestId( "SavedMatch.container" ) ).toBeTruthy( );
expect( inatjs.observations.viewedUpdates ).not.toHaveBeenCalled( );
} );
} );
describe( "when showSavedMatch is false", ( ) => {
it( "renders ObsDetailsContainer when observation is synced", ( ) => {
const syncedLocalObservation = {
...mockLocalObservation,
wasSynced: jest.fn( () => true ),
};
jest.spyOn( useLocalObservation, "default" ).mockImplementation( () => ( {
localObservation: syncedLocalObservation,
markDeletedLocally: jest.fn( ),
markViewedLocally: jest.fn( ),
} ) );
renderComponent( <ObsDetailsScreen /> );
expect( screen.getByTestId( "ObsDetails.container" ) ).toBeTruthy( );
expect( screen.queryByTestId( "SavedMatch.container" ) ).toBeFalsy( );
} );
it(
"renders ObsDetailsContainer when observation does not belong to current user",
( ) => {
const otherUserObservation = factory( "LocalObservation", {
user: factory( "LocalUser", {
id: 456,
} ),
uuid: mockUuid,
taxon: factory( "LocalTaxon", {
name: faker.person.firstName( ),
rank: "species",
rank_level: 10,
} ),
wasSynced: jest.fn( () => false ),
} );
jest.spyOn( useLocalObservation, "default" ).mockImplementation( () => ( {
localObservation: otherUserObservation,
markDeletedLocally: jest.fn( ),
markViewedLocally: jest.fn( ),
} ) );
renderComponent( <ObsDetailsScreen /> );
expect( screen.getByTestId( "ObsDetails.container" ) ).toBeTruthy( );
expect( screen.queryByTestId( "SavedMatch.container" ) ).toBeFalsy( );
},
);
} );
} );