mirror of
https://github.com/inaturalist/iNaturalistReactNative.git
synced 2026-05-04 05:33:21 -04:00
* Upgrade helper changes JS side * Upgrade helper Android * Upgrade helper iOS side * Update project.pbxproj * Create react-native-modal+14.0.0-rc.1.patch * BackHandler.removeEventListener is deprecated * Update react-native-modal * Update .flowconfig * Update package-lock.json * Update Podfile.lock * Update Podfile.lock from main * Replace toBeVisible with toBeOnTheScreen This is not recommended by react-navigation, because even though toBeOnTheScreen makes sure the components are in the tree it does not mean they are visible to the user. For example, in terms of navigation a previous screen is still i the tree but not visible to the user in the app. I spent around a day trying to figure out why the isVisible check stopped working, and still have no clear answer. Testing in the actual app shows that all of those flows are still working as expected, so it is a test-environment-only problem. My suggestion would be to re-visit this problem after we have updated RN to latest, and testing related libraries to latest versions.
177 lines
6.1 KiB
JavaScript
177 lines
6.1 KiB
JavaScript
import {
|
|
screen,
|
|
userEvent,
|
|
waitFor,
|
|
within
|
|
} from "@testing-library/react-native";
|
|
import initI18next from "i18n/initI18next";
|
|
import inatjs from "inaturalistjs";
|
|
import * as ImagePicker from "react-native-image-picker";
|
|
import { SCREEN_AFTER_PHOTO_EVIDENCE } from "stores/createLayoutSlice.ts";
|
|
import factory, { makeResponse } from "tests/factory";
|
|
import faker from "tests/helpers/faker";
|
|
import { renderApp } from "tests/helpers/render";
|
|
import setStoreStateLayout from "tests/helpers/setStoreStateLayout";
|
|
import setupUniqueRealm from "tests/helpers/uniqueRealm";
|
|
|
|
// We're explicitly testing navigation here so we want react-navigation
|
|
// working normally
|
|
jest.unmock( "@react-navigation/native" );
|
|
|
|
const directory = faker.string.uuid( );
|
|
const mockFileName = `${faker.string.uuid( )}.jpg`;
|
|
const mockUri = `file:///var/mobile/Containers/Data/Application/${directory}/tmp/${mockFileName}`;
|
|
|
|
const mockImageLibraryResponse = {
|
|
assets: [
|
|
{
|
|
uri: mockUri,
|
|
fileName: mockFileName
|
|
}
|
|
]
|
|
};
|
|
|
|
const mockImageLibraryResponseMultiplePhotos = {
|
|
assets: [
|
|
{
|
|
uri: "some_uri",
|
|
fileName: "some_file_name"
|
|
},
|
|
{
|
|
uri: mockUri,
|
|
fileName: mockFileName
|
|
}
|
|
]
|
|
};
|
|
|
|
jest.mock( "react-native-image-picker", ( ) => ( {
|
|
launchImageLibrary: jest.fn( ( ) => mockImageLibraryResponse )
|
|
} ) );
|
|
|
|
// UNIQUE REALM SETUP
|
|
const mockRealmIdentifier = __filename;
|
|
const { mockRealmModelsIndex, uniqueRealmBeforeAll, uniqueRealmAfterAll } = setupUniqueRealm(
|
|
mockRealmIdentifier
|
|
);
|
|
jest.mock( "realmModels/index", ( ) => mockRealmModelsIndex );
|
|
jest.mock( "providers/contexts", ( ) => {
|
|
const originalModule = jest.requireActual( "providers/contexts" );
|
|
return {
|
|
__esModule: true,
|
|
...originalModule,
|
|
RealmContext: {
|
|
...originalModule.RealmContext,
|
|
useRealm: ( ) => global.mockRealms[mockRealmIdentifier],
|
|
useQuery: ( ) => []
|
|
}
|
|
};
|
|
} );
|
|
beforeAll( uniqueRealmBeforeAll );
|
|
afterAll( uniqueRealmAfterAll );
|
|
// /UNIQUE REALM SETUP
|
|
|
|
const mockUser = factory( "LocalUser" );
|
|
// Mock useCurrentUser hook
|
|
jest.mock( "sharedHooks/useCurrentUser", () => ( {
|
|
__esModule: true,
|
|
default: jest.fn( () => mockUser )
|
|
} ) );
|
|
|
|
// Mock the response from inatjs.computervision.score_image
|
|
const topSuggestion = {
|
|
taxon: factory.states( "genus" )( "RemoteTaxon", { name: "Primum" } ),
|
|
combined_score: 90
|
|
};
|
|
|
|
beforeAll( async () => {
|
|
await initI18next();
|
|
jest.useFakeTimers( );
|
|
} );
|
|
|
|
beforeEach( ( ) => {
|
|
setStoreStateLayout( {
|
|
isDefaultMode: false,
|
|
screenAfterPhotoEvidence: SCREEN_AFTER_PHOTO_EVIDENCE.SUGGESTIONS,
|
|
isAllAddObsOptionsMode: true
|
|
} );
|
|
inatjs.computervision.score_image.mockResolvedValue( makeResponse( [topSuggestion] ) );
|
|
} );
|
|
|
|
describe( "Photo Import", ( ) => {
|
|
const actor = userEvent.setup( );
|
|
|
|
async function importPhotoForNewObs() {
|
|
const tabBar = await screen.findByTestId( "CustomTabBar" );
|
|
const addObsButton = await within( tabBar ).findByLabelText( "Add observations" );
|
|
await actor.press( addObsButton );
|
|
const photoImportButton = await within( tabBar ).findByLabelText( "Photo importer" );
|
|
await actor.press( photoImportButton );
|
|
}
|
|
|
|
async function groupPhotosIntoObservation() {
|
|
const groupPhotosText = await screen.findByText( /Group Photos/ );
|
|
// We used toBeVisible here but the update to RN0.77 broke this expectation
|
|
expect( groupPhotosText ).toBeOnTheScreen( );
|
|
const path = "file://document/directory/path/galleryPhotos/";
|
|
const firstUri = `${path}${mockImageLibraryResponseMultiplePhotos.assets[0].fileName}`;
|
|
const secondUri = `${path}${mockImageLibraryResponseMultiplePhotos.assets[1].fileName}`;
|
|
const firstPhoto = await screen.findByTestId( `GroupPhotos.${firstUri}` );
|
|
await actor.press( firstPhoto );
|
|
const secondPhoto = await screen.findByTestId( `GroupPhotos.${secondUri}` );
|
|
await actor.press( secondPhoto );
|
|
const combineButton = await screen.findByLabelText( /Combine Photos/ );
|
|
await actor.press( combineButton );
|
|
const importButton = await screen.findByText( /IMPORT 1 OBSERVATION/ );
|
|
await actor.press( importButton );
|
|
}
|
|
|
|
async function viewSuggestionsAndAddId() {
|
|
const topTaxonResultButton = await screen.findByTestId(
|
|
`SuggestionsList.taxa.${topSuggestion.taxon.id}.checkmark`
|
|
);
|
|
await actor.press( topTaxonResultButton );
|
|
}
|
|
|
|
async function saveObservationWithPhoto() {
|
|
// Make sure we're on ObsEdit
|
|
const evidenceTitle = await screen.findByText( "EVIDENCE" );
|
|
// We used toBeVisible here but the update to RN0.77 broke this expectation
|
|
expect( evidenceTitle ).toBeOnTheScreen( );
|
|
|
|
const localFilePath = `file://document/directory/path/photoUploads/${mockFileName}`;
|
|
const photoEvidence = await screen.findByTestId( `EvidenceList.${localFilePath}` );
|
|
// We used toBeVisible here but the update to RN0.77 broke this expectation
|
|
expect( photoEvidence ).toBeOnTheScreen( );
|
|
const saveButton = await screen.findByText( "SAVE" );
|
|
await actor.press( saveButton );
|
|
const okButton = await screen.findByText( "OK" );
|
|
await actor.press( okButton );
|
|
await actor.press( saveButton );
|
|
// Wait until header shows that there's an obs to upload
|
|
await screen.findByText( /Upload \d observation/ );
|
|
const obsGridItems = await screen.findAllByTestId( /MyObservations\.obsGridItem\..*/ );
|
|
await waitFor( () => {
|
|
// We used toBeVisible here but the update to RN0.77 broke this expectation
|
|
expect( obsGridItems[0] ).toBeOnTheScreen( );
|
|
}, { timeout: 3_000, interval: 500 } );
|
|
}
|
|
|
|
it( "should create and save an observation with an imported photo", async ( ) => {
|
|
renderApp( );
|
|
await importPhotoForNewObs( );
|
|
await viewSuggestionsAndAddId( );
|
|
await saveObservationWithPhoto( );
|
|
} );
|
|
|
|
it( "should create and save an observation with multiple imported photos", async ( ) => {
|
|
jest.spyOn( ImagePicker, "launchImageLibrary" ).mockImplementation(
|
|
( ) => mockImageLibraryResponseMultiplePhotos
|
|
);
|
|
renderApp( );
|
|
await importPhotoForNewObs( );
|
|
await groupPhotosIntoObservation( );
|
|
await viewSuggestionsAndAddId( );
|
|
await saveObservationWithPhoto( );
|
|
} );
|
|
} );
|