mirror of
https://github.com/inaturalist/iNaturalistReactNative.git
synced 2026-06-18 20:50:54 -04:00
* (lint) MOB-1063 enforce trailing commas * autofix trailing commas * manually fix newly introduced maxlen violations * add trailing comma convention to i18n build
228 lines
7.8 KiB
JavaScript
228 lines
7.8 KiB
JavaScript
import * as apiObservations from "api/observations";
|
|
import * as authService from "components/LoginSignUp/AuthenticationService";
|
|
import factory from "tests/factory";
|
|
import * as uploaders from "uploaders";
|
|
import * as mediaUploader from "uploaders/mediaUploader";
|
|
import uploadObservation from "uploaders/observationUploader";
|
|
import * as progressTracker from "uploaders/utils/progressTracker";
|
|
|
|
jest.mock( "components/LoginSignUp/AuthenticationService" );
|
|
jest.mock( "uploaders/utils/progressTracker" );
|
|
jest.mock( "uploaders/mediaUploader" );
|
|
jest.mock( "uploaders" );
|
|
jest.mock( "api/observations" );
|
|
jest.mock( "sharedHelpers/safeRealmWrite", () => jest.fn() );
|
|
jest.mock( "realmModels/Observation", () => {
|
|
const actual = jest.requireActual( "realmModels/Observation" );
|
|
actual.default.upsertRemoteObservations = jest.fn();
|
|
return actual;
|
|
} );
|
|
|
|
describe( "uploadObservation", () => {
|
|
let mockObservation;
|
|
let mockRealm;
|
|
let mockProgressTracker;
|
|
let mockMediaItems;
|
|
|
|
beforeEach( () => {
|
|
jest.clearAllMocks();
|
|
|
|
mockObservation = factory( "LocalObservation", {
|
|
uuid: "test-uuid-123",
|
|
} );
|
|
mockObservation.wasSynced = jest.fn( () => false );
|
|
|
|
mockRealm = {
|
|
objectForPrimaryKey: jest.fn( () => factory( "LocalObservation" ) ),
|
|
};
|
|
|
|
mockProgressTracker = {
|
|
start: jest.fn(),
|
|
complete: jest.fn(),
|
|
error: jest.fn(),
|
|
};
|
|
|
|
mockMediaItems = {
|
|
unsyncedObservationPhotos: [],
|
|
modifiedObservationPhotos: [],
|
|
unsyncedObservationSounds: [],
|
|
};
|
|
|
|
authService.getJWT.mockResolvedValue( "test-json-web-token" );
|
|
progressTracker.trackObservationUpload.mockReturnValue( mockProgressTracker );
|
|
|
|
// Mock the new functions in mediaUploader
|
|
mediaUploader.uploadObservationMedia.mockResolvedValue( mockMediaItems );
|
|
mediaUploader.attachMediaToObservation.mockResolvedValue( undefined );
|
|
|
|
uploaders.prepareObservationForUpload.mockReturnValue( {
|
|
uuid: mockObservation.uuid,
|
|
taxon_id: 12345,
|
|
} );
|
|
|
|
apiObservations.createObservation.mockResolvedValue( {
|
|
results: [{ uuid: mockObservation.uuid }],
|
|
} );
|
|
|
|
apiObservations.updateObservation.mockResolvedValue( {
|
|
results: [{ uuid: mockObservation.uuid }],
|
|
} );
|
|
} );
|
|
|
|
it( "should start and complete progress tracking", async () => {
|
|
await uploadObservation( mockObservation, mockRealm );
|
|
|
|
expect( progressTracker.trackObservationUpload ).toHaveBeenCalledWith( mockObservation.uuid );
|
|
expect( mockProgressTracker.start ).toHaveBeenCalled();
|
|
expect( mockProgressTracker.complete ).toHaveBeenCalled();
|
|
} );
|
|
|
|
it( "should validate the API token", async () => {
|
|
await uploadObservation( mockObservation, mockRealm );
|
|
expect( authService.getJWT ).toHaveBeenCalled();
|
|
} );
|
|
|
|
it( "should throw an error if no API token is available", async () => {
|
|
authService.getJWT.mockResolvedValue( null );
|
|
|
|
await expect( uploadObservation( mockObservation, mockRealm ) )
|
|
.rejects.toThrow( "Gack, tried to upload an observation without API token!" );
|
|
} );
|
|
|
|
it( "should prepare the observation for upload", async () => {
|
|
await uploadObservation( mockObservation, mockRealm );
|
|
expect( uploaders.prepareObservationForUpload ).toHaveBeenCalledWith( mockObservation );
|
|
} );
|
|
|
|
it( "should create a new observation if it was not previously synced", async () => {
|
|
mockObservation.wasSynced.mockReturnValue( false );
|
|
|
|
await uploadObservation( mockObservation, mockRealm );
|
|
|
|
expect( apiObservations.createObservation ).toHaveBeenCalledWith(
|
|
expect.objectContaining( {
|
|
observation: expect.anything(),
|
|
fields: { id: true },
|
|
} ),
|
|
expect.objectContaining( { api_token: "test-json-web-token" } ),
|
|
);
|
|
expect( apiObservations.updateObservation ).not.toHaveBeenCalled();
|
|
} );
|
|
|
|
it( "should update an existing observation if it was previously synced", async () => {
|
|
mockObservation.wasSynced.mockReturnValue( true );
|
|
|
|
await uploadObservation( mockObservation, mockRealm );
|
|
|
|
expect( apiObservations.updateObservation ).toHaveBeenCalledWith(
|
|
expect.objectContaining( {
|
|
observation: expect.anything(),
|
|
fields: { id: true },
|
|
id: mockObservation.uuid,
|
|
ignore_photos: true,
|
|
} ),
|
|
expect.objectContaining( { api_token: "test-json-web-token" } ),
|
|
);
|
|
expect( apiObservations.createObservation ).not.toHaveBeenCalled();
|
|
} );
|
|
|
|
it( "should call uploadObservationMedia with correct parameters", async () => {
|
|
await uploadObservation( mockObservation, mockRealm );
|
|
|
|
expect( mediaUploader.uploadObservationMedia ).toHaveBeenCalledWith(
|
|
mockObservation,
|
|
expect.objectContaining( { api_token: "test-json-web-token" } ),
|
|
mockRealm,
|
|
);
|
|
} );
|
|
|
|
it(
|
|
"should call attachMediaToObservation with correct parameters after observation creation",
|
|
async () => {
|
|
await uploadObservation( mockObservation, mockRealm );
|
|
|
|
expect( mediaUploader.attachMediaToObservation ).toHaveBeenCalledWith(
|
|
mockObservation.uuid,
|
|
mockMediaItems,
|
|
expect.objectContaining( { api_token: "test-json-web-token" } ),
|
|
mockRealm,
|
|
);
|
|
},
|
|
);
|
|
|
|
it( "should mark the record as uploaded after media is attached", async () => {
|
|
await uploadObservation( mockObservation, mockRealm );
|
|
|
|
expect( uploaders.markRecordUploaded ).toHaveBeenCalledWith(
|
|
mockObservation.uuid,
|
|
null,
|
|
"Observation",
|
|
expect.anything(),
|
|
mockRealm,
|
|
);
|
|
} );
|
|
|
|
it( "should return the API response", async () => {
|
|
const mockResponse = { results: [{ uuid: mockObservation.uuid }] };
|
|
apiObservations.createObservation.mockResolvedValue( mockResponse );
|
|
|
|
const result = await uploadObservation( mockObservation, mockRealm );
|
|
|
|
expect( result ).toEqual( mockResponse );
|
|
} );
|
|
|
|
it( "should throw an error if observation creation fails", async () => {
|
|
apiObservations.createObservation.mockRejectedValue( new Error( "API Error" ) );
|
|
|
|
await expect( uploadObservation( mockObservation, mockRealm ) )
|
|
.rejects.toThrow( "API Error" );
|
|
} );
|
|
|
|
it( "should throw an error if media upload fails", async () => {
|
|
mediaUploader.uploadObservationMedia.mockRejectedValue( new Error( "Media Upload Error" ) );
|
|
|
|
await expect( uploadObservation( mockObservation, mockRealm ) )
|
|
.rejects.toThrow( "Media Upload Error" );
|
|
} );
|
|
|
|
it( "should throw an error if media attachment fails", async () => {
|
|
mediaUploader.attachMediaToObservation
|
|
.mockRejectedValue( new Error( "Media Attachment Error" ) );
|
|
|
|
await expect( uploadObservation( mockObservation, mockRealm ) )
|
|
.rejects.toThrow( "Media Attachment Error" );
|
|
} );
|
|
|
|
it( "should not complete progress tracking when errors occur", async () => {
|
|
apiObservations.createObservation.mockRejectedValue( new Error( "API Error" ) );
|
|
|
|
await expect( uploadObservation( mockObservation, mockRealm ) ).rejects.toThrow( "API Error" );
|
|
expect( mockProgressTracker.complete ).not.toHaveBeenCalled();
|
|
} );
|
|
|
|
it( "should throw an error when observation creation returns null response", async () => {
|
|
apiObservations.createObservation.mockResolvedValue( null );
|
|
|
|
await expect( uploadObservation( mockObservation, mockRealm ) )
|
|
.rejects.toThrow( "No response from observation upload" );
|
|
|
|
// Should not attempt to attach media or mark as uploaded
|
|
expect( mediaUploader.attachMediaToObservation ).not.toHaveBeenCalled();
|
|
expect( uploaders.markRecordUploaded ).not.toHaveBeenCalled();
|
|
} );
|
|
|
|
it( "should pass custom options to API calls", async () => {
|
|
const customOpts = { locale: "es-ES" };
|
|
|
|
await uploadObservation( mockObservation, mockRealm, customOpts );
|
|
|
|
expect( apiObservations.createObservation ).toHaveBeenCalledWith(
|
|
expect.anything(),
|
|
expect.objectContaining( {
|
|
api_token: "test-json-web-token",
|
|
locale: "es-ES",
|
|
} ),
|
|
);
|
|
} );
|
|
} );
|