Files
iNaturalistReactNative/tests/integration/sharedHooks/useTaxon.test.js
Ken-ichi 9429fd0996 fix: prevent iconic taxon common names from disappearing in the local db (#2631)
Ensure useAuthenticatedQuery only executes the query when it knows if the user
is signed in or not, and appends that state to the query key so signed in and
signed out results are distinct.

The problem here was that useIconicTaxa was mysteriously returning stale,
signed out results while offline.

Closes MOB-383
2025-01-22 17:17:26 -08:00

134 lines
5.1 KiB
JavaScript

import { waitFor } from "@testing-library/react-native";
import inatjs from "inaturalistjs";
import safeRealmWrite from "sharedHelpers/safeRealmWrite";
import { useTaxon } from "sharedHooks";
import factory, { makeResponse } from "tests/factory";
import faker from "tests/helpers/faker";
import { renderHook } from "tests/helpers/render";
import setupUniqueRealm from "tests/helpers/uniqueRealm";
// 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]
}
};
} );
beforeAll( uniqueRealmBeforeAll );
afterAll( uniqueRealmAfterAll );
// /UNIQUE REALM SETUP
const mockRemoteTaxon = factory( "RemoteTaxon", {
default_photo: {
url: faker.image.url( )
}
} );
const mockTaxon = factory( "LocalTaxon", {
_syncedAt: faker.date.recent( { days: 1 } ),
default_photo: {
url: faker.image.url( )
}
} );
const mockOutdatedTaxon = factory( "LocalTaxon", {
_syncedAt: faker.date.recent( { days: 1, refDate: "2024-01-01" } ),
default_photo: {
url: faker.image.url( )
}
} );
describe( "with local taxon", ( ) => {
beforeEach( ( ) => {
jest.restoreAllMocks( );
// Write mock taxon to realm
safeRealmWrite( global.mockRealms[mockRealmIdentifier], ( ) => {
global.mockRealms[mockRealmIdentifier].create( "Taxon", mockTaxon, "modified" );
}, "write mock taxon, useTaxon test" );
} );
it( "should return an object", ( ) => {
const { result } = renderHook( ( ) => useTaxon( mockTaxon ) );
expect( result.current ).toBeInstanceOf( Object );
} );
describe( "when there is a local taxon with taxon id", ( ) => {
it( "should return local taxon with default photo", ( ) => {
const { result } = renderHook( ( ) => useTaxon( mockTaxon ) );
const { taxon: resultTaxon } = result.current;
expect( resultTaxon ).toHaveProperty( "default_photo" );
expect( resultTaxon.default_photo.url ).toEqual( mockTaxon.default_photo.url );
} );
it( "should request a taxon from the API if the local copy is out of date", async ( ) => {
inatjs.taxa.fetch.mockResolvedValue( makeResponse( [mockRemoteTaxon] ) );
safeRealmWrite( global.mockRealms[mockRealmIdentifier], ( ) => {
global.mockRealms[mockRealmIdentifier].create( "Taxon", mockOutdatedTaxon, "modified" );
}, "write mock outdated taxon, useTaxon test" );
renderHook( ( ) => useTaxon( mockOutdatedTaxon ) );
await waitFor( ( ) => expect( inatjs.taxa.fetch ).toHaveBeenCalled( ) );
} );
} );
} );
describe( "when there is no local taxon with taxon id", ( ) => {
beforeAll( ( ) => {
safeRealmWrite( global.mockRealms[mockRealmIdentifier], ( ) => {
global.mockRealms[mockRealmIdentifier].deleteAll( );
}, "delete all realm, useTaxon test" );
} );
describe( "with fetchRemote: true", ( ) => {
it( "should request the taxon from the API", async ( ) => {
expect(
global.mockRealms[mockRealmIdentifier].objectForPrimaryKey( "Taxon", mockTaxon.id )
).toBeNull( );
renderHook( ( ) => useTaxon( mockTaxon ) );
await waitFor( ( ) => expect( inatjs.taxa.fetch ).toHaveBeenCalled( ) );
} );
it( "should return the argument taxon if request fails", ( ) => {
// I don't love this. While it kind of mocks at the edge of the code
// we need to integrate, it doesn't test out API error handling code.
// I tried mocking inatjs to make it throw, but that always seems to
// result in a failure in the test, even though useQuery should catch
// those errors. ~~~kueda20240305
jest.mock( "@tanstack/react-query", () => ( {
useQuery: jest.fn( ( ) => ( {
error: { }
} ) )
} ) );
const partialTaxon = { id: faker.number.int( ), foo: "bar" };
const { result } = renderHook( ( ) => useTaxon( partialTaxon ) );
expect( result.current.taxon.foo ).toEqual( "bar" );
jest.unmock( "@tanstack/react-query" );
} );
it( "should return a taxon like a local taxon record if the request succeeds", async ( ) => {
const { result } = renderHook( ( ) => useTaxon( { id: mockTaxon.id } ) );
await waitFor( ( ) => expect( result.current.taxon ).toHaveProperty( "default_photo" ) );
} );
} );
describe( "with fetchRemote: false", ( ) => {
it( "should not call the API and return passed in taxon", ( ) => {
const taxonId = faker.number.int( );
expect(
global.mockRealms[mockRealmIdentifier].objectForPrimaryKey( "Taxon", taxonId )
).toBeNull( );
const { result } = renderHook( ( ) => useTaxon( { id: taxonId, foo: "bar" }, false ) );
expect( result.current.taxon ).not.toHaveProperty( "default_photo" );
expect( result.current.taxon.foo ).toEqual( "bar" );
} );
} );
} );