Files
iNaturalistReactNative/tests/jest.setup.js
T
Johannes KleinandJohannes Klein b498ffd379 Fix broken integration tests (#3720)
* Move one broken test and switch back to toBeVisible

* Remove comments

* Move without changes

* Add helper function

* Call mock helper in beforeAll

* Add fileName to mock assets

* Refactor navigateToPhotoImporter into helper

* Use fake timers and time travel

* File move without changes

* Add import

* Update addObsBottomSheet.js

* Refactor navigation steps into new helpers

* Add layout setup

* Use skipFakeTimers here

* Remove setup

* Replace final expectation

* Add mock for Mortal in a new helper file

* Sort imports

* Remove superfluous act

* Move file without changes

* Add time travel to final expect

* Use Mortal mock

* Change one test expect

TODO: is this still the same behaviour tested, toBeNull can be of other reasons as well?

* Refactor nav to Standard camera into new helpers

* Replace fireEvent with userEvent

* Update imports

* Move file without changesUpdate firebase mock

* Move file without changes

* Add Mortal mock

* Use toBeVisible again

* Use toBeVisible

* Refactor nav to AI camera into helpers

* Refactor take photo and na into helpers

* Refactor an action of the two previous combined actions

* Somehow there were two identical describe

* Wrong order

* No longer needed

* Refactor last expect of this test into helper

* Use global time travel here

* Remove import

* Move file without changes

* Use toBeVisible again

* Use Mortal mock

* Re-use already made helper fct here

* Fix imports

* Move file without changes

* Enable animated time travel

* Use toBeVisible

* Add time travel to last expects

* Remove double checks for being on the correct screen

* Move file without changes

* Add fileName to mock assets

* Switch back to toBeVisible

* Enable animated time travel

* Add time travel to last expect

* Re-use new navigation helper

* Add mock for InteractionManager

* Move file without changes

* Use toBeVisible again

* Add InteractionManager mock

* Add animate time travel

* Missing import

* Remove from previous commit

* Add helper shell

* Move the Save button press

* Move missing evidence sheet dismissal

* Update MyObservations.test.js

* Set screen after photo import

* Remove import

* Sort imports

* Add a mock for ImagePicker

* Navigate to PhotoImported instead of No evidence option

Does not matter for this test where the new obs comes from

* Re-use helper fct

* Arg name

* Disable lint

* Move file without changes

* Replace with new helper fct

* Enable animated time travel

* Replace also below with new helper

* Move fct call

* Use toBeVisible again

* Use toBeVisible again

* Use toBeVisible again with different find strategy

* Remove trip through Suggestions for this test

* Add InteractionManager mock

* Move beforeEach

* Move function call

* Re-use new helper function

* Handle saveOptions

* Missing imports

* Add helper function

* Wait for toolbar helper

* Wait for the element like we did before this PR

* Wait for one more element

* Update PhotoImport.test.js

* Comment out optional wait

* Rename arg

* File move without changes

* Re-use new helper function

* Re-use new helper function

* Use toBeVisible again

* Enable animated time travel

* Add a new find

* New helper fct

* Remove local version of confirm

* New take photo helper does more, so restrict to not confirm the photo yet here

* Update PhotoDeletion.test.js

* Update PhotoDeletion.test.js

* Remove fake timers

* Missing imports

* Add Mortal mock

* Update PhotoDeletion.test.js

* Update PhotoDeletion.test.js

* Copy PhotoDeletion test into new file to split out tests about existing photos

* Remove other todo test

* Add InteractionManager mock

* Remove Mortal mock

* Remove new photo test

* Delete new photo test

* Remove existing photo test

* Remove existing photo test

* Remove helper fct

* Remove import

* This should not have been deleted

* Refactor to use new helpers to create an obs with photo and wait on ObsEdit

* Add the part until we wait on ObsEdit

* Remove double await

* Rename describe

* This was wrongly inserted here

* Wait with time travel to be on camera

* At this point we have two photos, so tap on first one

* Update PhotoDeletionExisting.test.js

* Move beforeEach

* That was wrong, we should not have taken a second photo

* Remove cv mock

* Add import

* Add import

* Add import

* Remove location mock

* Update PhotoDeletionExisting.test.js

* Move file without changes

* Switch back to toBeVisible again

* Re-use new helper fct

* Add Mortal mock

* Move broken tests without changes

* Mock Mortal

* Use toBeVisible again

* Re-use new helper fct

* Enable animated time trael

* Camera needs different layout state

* This was pressing twice

* Remove tiny local helper

* Re-use local helper

* Remove unused code

* Remove ignore Paths

Yay

* Remove unused helper

* Update react-native-fs.ts

* Move fct out of try/catch

* Revert "Move fct out of try/catch"

This reverts commit f9a138e0dd.

* Only have find text in try catch

* Add mock for useObject

* Remove broken test

---------

Co-authored-by: Johannes Klein <17345891+jtklein@users.noreply.github.com>
2026-06-18 14:37:58 +02:00

222 lines
7.5 KiB
JavaScript

// Recommendation from the uuid library is to import get-random-values before
// uuid, so we're importing it first thing in the entry point.
// https://www.npmjs.com/package/uuid#react-native--expo
// eslint-disable-next-line simple-import-sort/imports
import "react-native-get-random-values";
import "@shopify/flash-list/jestSetup";
import mockBottomSheet from "@gorhom/bottom-sheet/mock";
import mockRNCNetInfo from "@react-native-community/netinfo/jest/netinfo-mock";
import inatjs from "inaturalistjs";
import fetchMock from "jest-fetch-mock";
import mockRNDeviceInfo from "react-native-device-info/jest/react-native-device-info-mock";
import mockSafeAreaContext from "react-native-safe-area-context/jest/mock";
import factory, { makeResponse } from "./factory";
// tests seem to be slower without this global reanimated mock
global.ReanimatedDataMock = {
now: () => 0,
};
global.requestIdleCallback = callback => setTimeout( callback, 0 );
global.cancelIdleCallback = id => clearTimeout( id );
jest.mock( "react-native-volume-manager", () => ( {
VolumeManager: {
getVolume: jest.fn( () => Promise.resolve( 0.5 ) ),
setVolume: jest.fn( ),
addVolumeListener: jest.fn( () => ( { remove: jest.fn() } ) ),
showNativeVolumeUI: jest.fn(),
},
} ) );
// Mock the react-native-logs config because it has a dependency on AuthenticationService
// instead use console.logs for tests
jest.mock( "../react-native-logs.config", () => {
const log = {
extend: jest.fn( () => ( {
debug: msg => console.debug( msg ),
info: msg => console.info( msg ),
warn: msg => console.warn( msg ),
error: msg => console.error( msg ),
debugWithExtra: ( ...args ) => console.debug( ...args ),
infoWithExtra: ( ...args ) => console.info( ...args ),
warnWithExtra: ( ...args ) => console.warn( ...args ),
errorWithExtra: ( ...args ) => console.error( ...args ),
} ) ),
};
return {
log,
legacyLogfilePath: "inaturalist-rn-log.txt",
logFileNamePrefix: "inaturalist-rn-log",
logFileDirectory: "logs",
logWithoutRemote: log,
};
} );
jest.mock( "@gorhom/bottom-sheet", () => ( {
...mockBottomSheet,
__esModule: true,
} ) );
jest.mock( "@react-native-community/netinfo", () => mockRNCNetInfo );
jest.mock( "react-native-device-info", () => mockRNDeviceInfo );
jest.mock( "react-native-safe-area-context", () => mockSafeAreaContext );
// Reanimated 4.2 + Worklets 0.7: Jest loads native worklets which fails in Node. See:
// https://github.com/software-mansion/react-native-reanimated/discussions/8806
// we can remove this once the fix is released
jest.mock( "react-native-worklets", () => require( "react-native-worklets/src/mock" ) );
require( "react-native-reanimated" ).setUpTests();
// Some test environments may need a little more time
jest.setTimeout( 50000 );
// Mock inaturalistjs so we can make some fake responses
jest.mock( "inaturalistjs" );
inatjs.observations.observers.mockResolvedValue( makeResponse( ) );
inatjs.observations.search.mockResolvedValue( makeResponse( ) );
inatjs.observations.speciesCounts.mockResolvedValue( makeResponse( ) );
inatjs.observations.updates.mockResolvedValue( makeResponse( ) );
inatjs.users.projects.mockResolvedValue( makeResponse( ) );
inatjs.computervision.score_image.mockResolvedValue( makeResponse( ) );
// Set up mocked fetch for testing (or disabling) fetch requests
fetchMock.enableMocks( );
fetchMock.dontMock( );
const mockIconicTaxon = factory( "RemoteTaxon", {
is_iconic: true,
name: "Mock iconic taxon",
} );
inatjs.taxa.search.mockResolvedValue( makeResponse( [mockIconicTaxon] ) );
inatjs.announcements.search.mockResolvedValue( makeResponse( ) );
inatjs.observations.updates.mockResolvedValue( makeResponse( ) );
// the following two mocks are both needed for react-native-keep-awake
jest.mock( "@sayem314/react-native-keep-awake" );
jest.mock( "react-native/Libraries/TurboModule/TurboModuleRegistry", () => {
const turboModuleRegistry = jest
.requireActual( "react-native/Libraries/TurboModule/TurboModuleRegistry" );
return {
...turboModuleRegistry,
getEnforcing: name => {
// List of TurboModules libraries to mock.
const modulesToMock = ["ReactNativeKCKeepAwake", "FileReaderModule"];
if ( modulesToMock.includes( name ) ) {
return null;
}
return turboModuleRegistry.getEnforcing( name );
},
};
} );
jest.mock( "react-native-restart", ( ) => ( {
restart: jest.fn( ),
} ) );
jest.mock( "@react-native-firebase/analytics", () => ( {
getAnalytics: jest.fn( ),
logEvent: jest.fn( ),
setAnalyticsCollectionEnabled: jest.fn( ),
} ) );
jest.mock( "@react-native-firebase/perf", () => ( {
getPerformance: jest.fn( ( ) => ( {
dataCollectionEnabled: true,
startTrace: jest.fn( async ( ) => ( {
stop: jest.fn( ),
putAttribute: jest.fn( ),
} ) ),
} ) ),
} ) );
jest.mock( "react-native-legal", () => ( {
launchLicenseListScreen: jest.fn(),
} ) );
// see https://stackoverflow.com/questions/42268673/jest-test-animated-view-for-react-native-app
// for more details about this withAnimatedTimeTravelEnabled approach. basically, this
// allows us to step through animation frames when a screen is first loading when we're using the
// FadeInView animation for navigation screen transitions
global.withAnimatedTimeTravelEnabled = ( options = {} ) => {
beforeEach( () => {
if ( !options.skipFakeTimers ) jest.useFakeTimers();
jest.setSystemTime( new Date( 0 ) );
} );
if ( !options.skipFakeTimers ) {
afterEach( () => {
jest.useRealTimers();
} );
}
};
const frameTime = 10;
global.timeTravel = ( time = frameTime ) => {
const tickTravel = () => {
const now = Date.now();
jest.setSystemTime( new Date( now + frameTime ) );
jest.advanceTimersByTime( frameTime );
};
// Step through each of the frames
const frames = time / frameTime;
for ( let i = 0; i < frames; i += 1 ) {
tickTravel();
}
};
jest.mock( "sharedHelpers/installData", ( ) => ( {
// For most tests it's just going to be burden to dismiss this thing that
// most users only ever see once. If we do want to test it, we can redefine
// this mock
useOnboardingShown: jest.fn( ( ) => [true, jest.fn()] ),
getInstallID: jest.fn( ( ) => "fake-installation-id" ),
} ) );
jest.mock( "components/SharedComponents/Buttons/Button", () => {
const actualButton = jest.requireActual(
"components/SharedComponents/Buttons/Button",
).default;
// Use a very short debounce time (10ms) in tests to simulate the 300ms
// debounce time in the actual Button component
return jest.fn( props => actualButton( { ...props, debounceTime: 10 } ) );
} );
jest.mock( "navigation/FadeInView", () => {
const React = require( "react" );
const { View } = require( "react-native" );
return jest.fn( ( { children } ) => React.createElement( View, null, children ) );
} );
jest.mock( "components/Camera/FadeInOutView", () => {
const React = require( "react" );
const { View } = require( "react-native" );
return jest.fn( ( ) => React.createElement( View, null ) );
} );
// Disable bottom tab fade animation in tests to prevent act() warnings
jest.mock( "navigation/BottomTabNavigator/tabScreenOptions", () => ( {
__esModule: true,
default: {
lazy: true,
freezeOnBlur: true,
headerShown: false,
animation: "none",
},
} ) );
// this silences console methods in jest tests, to make them less noisy
// and easier to debug. uncomment if you want to silence them
global.console = {
...console,
// info: jest.fn(),
// error: jest.fn(),
// warn: jest.fn()
// log: jest.fn()
};