mirror of
https://github.com/inaturalist/iNaturalistReactNative.git
synced 2025-12-23 22:18:36 -05:00
Use fixed header in ObsDetails advanced mode (#2741)
* Use fixed header on ObsDetails advanced mode * Remove test for removed component - using react navigation header instead * Remove tests related to ObsDetails header icon; using react navigation * Add testID to react navigation level back button and fix e2e * Terminate app after every e2e test and maybe help flakiness * Rework termination of app --------- Co-authored-by: Johannes Klein <johannes.t.klein@gmail.com>
This commit is contained in:
committed by
GitHub
parent
1347ca3488
commit
9b1275a6eb
@@ -2,7 +2,7 @@ import {
|
||||
by, device, element, waitFor
|
||||
} from "detox";
|
||||
|
||||
import { iNatE2eBeforeAll, iNatE2eBeforeEach } from "./helpers";
|
||||
import { iNatE2eAfterEach, iNatE2eBeforeAll, iNatE2eBeforeEach } from "./helpers";
|
||||
import closeOnboarding from "./sharedFlows/closeOnboarding";
|
||||
import deleteObservation from "./sharedFlows/deleteObservation";
|
||||
import signIn from "./sharedFlows/signIn";
|
||||
@@ -13,6 +13,7 @@ const TIMEOUT = 10_000;
|
||||
describe( "AICamera", () => {
|
||||
beforeAll( async () => iNatE2eBeforeAll( device ) );
|
||||
beforeEach( async () => iNatE2eBeforeEach( device ) );
|
||||
afterEach( async () => iNatE2eAfterEach( device ) );
|
||||
|
||||
it(
|
||||
"should open the ai camera, take photo, select a suggestion, upload and delete observation",
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
import { execSync } from "child_process";
|
||||
import { exec, execSync } from "child_process";
|
||||
|
||||
export async function iNatE2eBeforeAll( device ) {
|
||||
if ( device.getPlatform() === "android" ) {
|
||||
@@ -53,3 +53,100 @@ export async function iNatE2eBeforeEach( device ) {
|
||||
`plutil -replace restrictedBool.allowPasswordAutoFill.value -bool NO ~/Library/Developer/CoreSimulator/Devices/${device.id}/data/Library/UserConfigurationProfiles/PublicInfo/PublicEffectiveUserSettings.plist`
|
||||
);
|
||||
}
|
||||
|
||||
function execPromise( command ) {
|
||||
return new Promise( ( resolve, reject ) => {
|
||||
exec( command, ( error, stdout, stderr ) => {
|
||||
if ( error ) {
|
||||
console.log( `Error executing command: ${command}` );
|
||||
console.log( `stderr: ${stderr}` );
|
||||
reject( error );
|
||||
return;
|
||||
}
|
||||
resolve( stdout );
|
||||
} );
|
||||
} );
|
||||
}
|
||||
|
||||
async function getSimulatorId() {
|
||||
try {
|
||||
// List all available simulators
|
||||
const output = await execPromise( "xcrun simctl list devices --json" );
|
||||
const { devices } = JSON.parse( output );
|
||||
|
||||
// Use Object.values and Array.find instead of loops
|
||||
const bootedDevice = Object.entries( devices )
|
||||
.flatMap( ( [_runtime, deviceList] ) => deviceList ) // Use _ prefix for unused variables
|
||||
.find( device => device.state === "Booted" );
|
||||
|
||||
if ( bootedDevice ) {
|
||||
console.log( `Found booted simulator: ${bootedDevice.name} (${bootedDevice.udid})` );
|
||||
return bootedDevice.udid;
|
||||
}
|
||||
|
||||
console.log( "No booted simulator found" );
|
||||
return null;
|
||||
} catch ( error ) {
|
||||
console.log( "Error getting simulator ID:", error.message );
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
export function terminateApp( deviceId, bundleId ) {
|
||||
try {
|
||||
console.log( `Attempting to terminate ${bundleId} on device ${deviceId}...` );
|
||||
const result = execSync( `/usr/bin/xcrun simctl terminate ${deviceId} ${bundleId}` );
|
||||
console.log( "App terminated successfully", result.toString() );
|
||||
return true;
|
||||
} catch ( error ) {
|
||||
if ( error.stderr && error.stderr.toString().includes( "found nothing to terminate" ) ) {
|
||||
console.log( "App is not running, nothing to terminate." );
|
||||
return true;
|
||||
}
|
||||
console.error( "Error during app termination:", error.message );
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
export async function iNatE2eAfterEach( device ) {
|
||||
if ( device && device.getPlatform() === "android" ) {
|
||||
return;
|
||||
}
|
||||
|
||||
try {
|
||||
// Try to use device.terminateApp first (the built-in Detox method)
|
||||
if ( device ) {
|
||||
try {
|
||||
await device.terminateApp();
|
||||
console.log( "App terminated through Detox" );
|
||||
// Add a small delay to let Detox processes settle
|
||||
await new Promise( resolve => { setTimeout( resolve, 300 ); } );
|
||||
return;
|
||||
} catch ( detoxError ) {
|
||||
console.log(
|
||||
"Detox terminateApp failed, falling back to manual termination:",
|
||||
detoxError.message
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
// Fall back to manual termination if Detox method fails or device is unavailable
|
||||
const deviceId = await getSimulatorId();
|
||||
const bundleId = "org.inaturalist.iNaturalistMobile";
|
||||
|
||||
if ( deviceId && bundleId ) {
|
||||
console.log( "Using manual termination via simctl" );
|
||||
// Use existing terminateApp, but don't throw errors
|
||||
try {
|
||||
await terminateApp( deviceId, bundleId );
|
||||
} catch ( error ) {
|
||||
console.log( "Manual termination error (non-fatal):", error.message );
|
||||
}
|
||||
|
||||
// Add a delay to let processes settle
|
||||
await new Promise( resolve => { setTimeout( resolve, 500 ); } );
|
||||
}
|
||||
} catch ( error ) {
|
||||
console.log( "Error during cleanup (non-fatal):", error.message );
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,16 +1,13 @@
|
||||
// we don't need this or switchPowerMode.e2e.js.js since they're repetititve
|
||||
// with what we're already doing in the signedIn and aiCamera tests
|
||||
// and we would see any failures there
|
||||
|
||||
import { device } from "detox";
|
||||
|
||||
import { iNatE2eBeforeAll, iNatE2eBeforeEach } from "./helpers";
|
||||
import { iNatE2eAfterEach, iNatE2eBeforeAll, iNatE2eBeforeEach } from "./helpers";
|
||||
import closeOnboarding from "./sharedFlows/closeOnboarding";
|
||||
import signIn from "./sharedFlows/signIn";
|
||||
|
||||
describe( "Shared flow", () => {
|
||||
beforeAll( async () => iNatE2eBeforeAll( device ) );
|
||||
beforeEach( async () => iNatE2eBeforeEach( device ) );
|
||||
afterEach( async ( ) => iNatE2eAfterEach( device ) );
|
||||
|
||||
it( "should sign in the test user", async () => {
|
||||
await closeOnboarding( );
|
||||
|
||||
@@ -2,7 +2,7 @@ import {
|
||||
by, device, element, expect, waitFor
|
||||
} from "detox";
|
||||
|
||||
import { iNatE2eBeforeAll, iNatE2eBeforeEach } from "./helpers";
|
||||
import { iNatE2eAfterEach, iNatE2eBeforeAll, iNatE2eBeforeEach } from "./helpers";
|
||||
import closeOnboarding from "./sharedFlows/closeOnboarding";
|
||||
import deleteObservation from "./sharedFlows/deleteObservation";
|
||||
import signIn from "./sharedFlows/signIn";
|
||||
@@ -11,6 +11,7 @@ import uploadObservation from "./sharedFlows/uploadObservation";
|
||||
describe( "Signed in user", () => {
|
||||
beforeAll( async ( ) => iNatE2eBeforeAll( device ) );
|
||||
beforeEach( async ( ) => iNatE2eBeforeEach( device ) );
|
||||
afterEach( async ( ) => iNatE2eAfterEach( device ) );
|
||||
|
||||
async function createAndUploadObservation( options = { upload: false } ) {
|
||||
const addObsButton = element( by.id( "add-obs-button" ) );
|
||||
@@ -101,7 +102,7 @@ describe( "Signed in user", () => {
|
||||
await element( by.id( `ObsDetails.${uuid}` ) ).scrollTo( "bottom" );
|
||||
const comment = element( by.text( "This is a comment" ) );
|
||||
await waitFor( comment ).toBeVisible().withTimeout( 10000 );
|
||||
await element( by.id( "ObsDetails.BackButton" ) ).tap( );
|
||||
await element( by.id( "header-back-button" ) ).tap( );
|
||||
await waitFor( username ).toBeVisible( ).withTimeout( 10000 );
|
||||
|
||||
/*
|
||||
|
||||
@@ -6,12 +6,13 @@ import {
|
||||
waitFor
|
||||
} from "detox";
|
||||
|
||||
import { iNatE2eBeforeAll, iNatE2eBeforeEach } from "./helpers";
|
||||
import { iNatE2eAfterEach, iNatE2eBeforeAll, iNatE2eBeforeEach } from "./helpers";
|
||||
import closeOnboarding from "./sharedFlows/closeOnboarding";
|
||||
|
||||
describe( "Signed out user", () => {
|
||||
beforeAll( async ( ) => iNatE2eBeforeAll( device ) );
|
||||
beforeEach( async ( ) => iNatE2eBeforeEach( device ) );
|
||||
afterEach( async ( ) => iNatE2eAfterEach( device ) );
|
||||
|
||||
it( "should start at My Observations with log in text", async () => {
|
||||
await closeOnboarding( );
|
||||
|
||||
@@ -3,7 +3,7 @@
|
||||
"strings" : {
|
||||
"CFBundleDisplayName" : {
|
||||
"comment" : "Bundle display name",
|
||||
"shouldTranslate" : false,
|
||||
"extractionState" : "extracted_with_value",
|
||||
"localizations" : {
|
||||
"af" : {
|
||||
"stringUnit" : {
|
||||
@@ -419,12 +419,6 @@
|
||||
"value" : "iNat Next"
|
||||
}
|
||||
},
|
||||
"tl" : {
|
||||
"stringUnit" : {
|
||||
"state" : "new",
|
||||
"value" : "iNat Next"
|
||||
}
|
||||
},
|
||||
"tr" : {
|
||||
"stringUnit" : {
|
||||
"state" : "new",
|
||||
@@ -461,11 +455,12 @@
|
||||
"value" : "iNat Next"
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
"shouldTranslate" : false
|
||||
},
|
||||
"CFBundleName" : {
|
||||
"comment" : "Bundle name",
|
||||
"shouldTranslate" : false,
|
||||
"extractionState" : "extracted_with_value",
|
||||
"localizations" : {
|
||||
"af" : {
|
||||
"stringUnit" : {
|
||||
@@ -881,12 +876,6 @@
|
||||
"value" : "iNaturalistReactNative"
|
||||
}
|
||||
},
|
||||
"tl" : {
|
||||
"stringUnit" : {
|
||||
"state" : "new",
|
||||
"value" : "iNaturalistReactNative"
|
||||
}
|
||||
},
|
||||
"tr" : {
|
||||
"stringUnit" : {
|
||||
"state" : "new",
|
||||
@@ -923,10 +912,12 @@
|
||||
"value" : "iNaturalistReactNative"
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
"shouldTranslate" : false
|
||||
},
|
||||
"NSAppleMusicUsageDescription" : {
|
||||
"comment" : "Description of why we ask for permission to access the music library.",
|
||||
"extractionState" : "extracted_with_value",
|
||||
"localizations" : {
|
||||
"af" : {
|
||||
"stringUnit" : {
|
||||
@@ -1342,12 +1333,6 @@
|
||||
"value" : "เพิ่มเสียงที่บันทึกไว้ไปยังการสังเกตของคุณ"
|
||||
}
|
||||
},
|
||||
"tl" : {
|
||||
"stringUnit" : {
|
||||
"state" : "new",
|
||||
"value" : "Add existing sounds to your observations."
|
||||
}
|
||||
},
|
||||
"tr" : {
|
||||
"stringUnit" : {
|
||||
"state" : "translated",
|
||||
@@ -1804,12 +1789,6 @@
|
||||
"value" : "Camera access lets you use the AI Camera and take photos."
|
||||
}
|
||||
},
|
||||
"tl" : {
|
||||
"stringUnit" : {
|
||||
"state" : "new",
|
||||
"value" : "Camera access lets you use the AI Camera and take photos."
|
||||
}
|
||||
},
|
||||
"tr" : {
|
||||
"stringUnit" : {
|
||||
"state" : "translated",
|
||||
@@ -1850,468 +1829,464 @@
|
||||
},
|
||||
"NSHumanReadableCopyright" : {
|
||||
"comment" : "Copyright (human-readable)",
|
||||
"shouldTranslate" : false,
|
||||
"extractionState" : "extracted_with_value",
|
||||
"localizations" : {
|
||||
"af" : {
|
||||
"stringUnit" : {
|
||||
"state" : "new",
|
||||
"state" : "needs_review",
|
||||
"value" : "(c) iNaturalist"
|
||||
}
|
||||
},
|
||||
"ar" : {
|
||||
"stringUnit" : {
|
||||
"state" : "new",
|
||||
"state" : "needs_review",
|
||||
"value" : "(c) iNaturalist"
|
||||
}
|
||||
},
|
||||
"be" : {
|
||||
"stringUnit" : {
|
||||
"state" : "new",
|
||||
"state" : "needs_review",
|
||||
"value" : "(c) iNaturalist"
|
||||
}
|
||||
},
|
||||
"bg" : {
|
||||
"stringUnit" : {
|
||||
"state" : "new",
|
||||
"state" : "needs_review",
|
||||
"value" : "(c) iNaturalist"
|
||||
}
|
||||
},
|
||||
"br" : {
|
||||
"stringUnit" : {
|
||||
"state" : "new",
|
||||
"state" : "needs_review",
|
||||
"value" : "(c) iNaturalist"
|
||||
}
|
||||
},
|
||||
"bs" : {
|
||||
"stringUnit" : {
|
||||
"state" : "new",
|
||||
"state" : "needs_review",
|
||||
"value" : "(c) iNaturalist"
|
||||
}
|
||||
},
|
||||
"ca" : {
|
||||
"stringUnit" : {
|
||||
"state" : "new",
|
||||
"state" : "needs_review",
|
||||
"value" : "(c) iNaturalist"
|
||||
}
|
||||
},
|
||||
"cs" : {
|
||||
"stringUnit" : {
|
||||
"state" : "new",
|
||||
"state" : "needs_review",
|
||||
"value" : "(c) iNaturalist"
|
||||
}
|
||||
},
|
||||
"da" : {
|
||||
"stringUnit" : {
|
||||
"state" : "new",
|
||||
"state" : "needs_review",
|
||||
"value" : "(c) iNaturalist"
|
||||
}
|
||||
},
|
||||
"de" : {
|
||||
"stringUnit" : {
|
||||
"state" : "new",
|
||||
"state" : "needs_review",
|
||||
"value" : "(c) iNaturalist"
|
||||
}
|
||||
},
|
||||
"el" : {
|
||||
"stringUnit" : {
|
||||
"state" : "new",
|
||||
"state" : "needs_review",
|
||||
"value" : "(c) iNaturalist"
|
||||
}
|
||||
},
|
||||
"en" : {
|
||||
"stringUnit" : {
|
||||
"state" : "new",
|
||||
"value" : "(c) iNaturalist"
|
||||
"value" : ""
|
||||
}
|
||||
},
|
||||
"en-AU" : {
|
||||
"stringUnit" : {
|
||||
"state" : "new",
|
||||
"state" : "needs_review",
|
||||
"value" : "(c) iNaturalist"
|
||||
}
|
||||
},
|
||||
"en-GB" : {
|
||||
"stringUnit" : {
|
||||
"state" : "new",
|
||||
"state" : "needs_review",
|
||||
"value" : "(c) iNaturalist"
|
||||
}
|
||||
},
|
||||
"en-NZ" : {
|
||||
"stringUnit" : {
|
||||
"state" : "new",
|
||||
"state" : "needs_review",
|
||||
"value" : "(c) iNaturalist"
|
||||
}
|
||||
},
|
||||
"eo" : {
|
||||
"stringUnit" : {
|
||||
"state" : "new",
|
||||
"state" : "needs_review",
|
||||
"value" : "(c) iNaturalist"
|
||||
}
|
||||
},
|
||||
"es" : {
|
||||
"stringUnit" : {
|
||||
"state" : "new",
|
||||
"state" : "needs_review",
|
||||
"value" : "(c) iNaturalist"
|
||||
}
|
||||
},
|
||||
"es-AR" : {
|
||||
"stringUnit" : {
|
||||
"state" : "new",
|
||||
"state" : "needs_review",
|
||||
"value" : "(c) iNaturalist"
|
||||
}
|
||||
},
|
||||
"es-CO" : {
|
||||
"stringUnit" : {
|
||||
"state" : "new",
|
||||
"state" : "needs_review",
|
||||
"value" : "(c) iNaturalist"
|
||||
}
|
||||
},
|
||||
"es-CR" : {
|
||||
"stringUnit" : {
|
||||
"state" : "new",
|
||||
"state" : "needs_review",
|
||||
"value" : "(c) iNaturalist"
|
||||
}
|
||||
},
|
||||
"es-MX" : {
|
||||
"stringUnit" : {
|
||||
"state" : "new",
|
||||
"state" : "needs_review",
|
||||
"value" : "(c) iNaturalist"
|
||||
}
|
||||
},
|
||||
"et" : {
|
||||
"stringUnit" : {
|
||||
"state" : "new",
|
||||
"state" : "needs_review",
|
||||
"value" : "(c) iNaturalist"
|
||||
}
|
||||
},
|
||||
"eu" : {
|
||||
"stringUnit" : {
|
||||
"state" : "new",
|
||||
"state" : "needs_review",
|
||||
"value" : "(c) iNaturalist"
|
||||
}
|
||||
},
|
||||
"fa" : {
|
||||
"stringUnit" : {
|
||||
"state" : "new",
|
||||
"state" : "needs_review",
|
||||
"value" : "(c) iNaturalist"
|
||||
}
|
||||
},
|
||||
"fi" : {
|
||||
"stringUnit" : {
|
||||
"state" : "new",
|
||||
"state" : "needs_review",
|
||||
"value" : "(c) iNaturalist"
|
||||
}
|
||||
},
|
||||
"fil" : {
|
||||
"stringUnit" : {
|
||||
"state" : "new",
|
||||
"state" : "needs_review",
|
||||
"value" : "(c) iNaturalist"
|
||||
}
|
||||
},
|
||||
"fr" : {
|
||||
"stringUnit" : {
|
||||
"state" : "new",
|
||||
"state" : "needs_review",
|
||||
"value" : "(c) iNaturalist"
|
||||
}
|
||||
},
|
||||
"fr-CA" : {
|
||||
"stringUnit" : {
|
||||
"state" : "new",
|
||||
"state" : "needs_review",
|
||||
"value" : "(c) iNaturalist"
|
||||
}
|
||||
},
|
||||
"gd" : {
|
||||
"stringUnit" : {
|
||||
"state" : "new",
|
||||
"state" : "needs_review",
|
||||
"value" : "(c) iNaturalist"
|
||||
}
|
||||
},
|
||||
"gl" : {
|
||||
"stringUnit" : {
|
||||
"state" : "new",
|
||||
"state" : "needs_review",
|
||||
"value" : "(c) iNaturalist"
|
||||
}
|
||||
},
|
||||
"gu" : {
|
||||
"stringUnit" : {
|
||||
"state" : "new",
|
||||
"state" : "needs_review",
|
||||
"value" : "(c) iNaturalist"
|
||||
}
|
||||
},
|
||||
"he" : {
|
||||
"stringUnit" : {
|
||||
"state" : "new",
|
||||
"state" : "needs_review",
|
||||
"value" : "(c) iNaturalist"
|
||||
}
|
||||
},
|
||||
"hi" : {
|
||||
"stringUnit" : {
|
||||
"state" : "new",
|
||||
"state" : "needs_review",
|
||||
"value" : "(c) iNaturalist"
|
||||
}
|
||||
},
|
||||
"hr" : {
|
||||
"stringUnit" : {
|
||||
"state" : "new",
|
||||
"state" : "needs_review",
|
||||
"value" : "(c) iNaturalist"
|
||||
}
|
||||
},
|
||||
"hu" : {
|
||||
"stringUnit" : {
|
||||
"state" : "new",
|
||||
"state" : "needs_review",
|
||||
"value" : "(c) iNaturalist"
|
||||
}
|
||||
},
|
||||
"id" : {
|
||||
"stringUnit" : {
|
||||
"state" : "new",
|
||||
"state" : "needs_review",
|
||||
"value" : "(c) iNaturalist"
|
||||
}
|
||||
},
|
||||
"it" : {
|
||||
"stringUnit" : {
|
||||
"state" : "new",
|
||||
"state" : "needs_review",
|
||||
"value" : "(c) iNaturalist"
|
||||
}
|
||||
},
|
||||
"ja" : {
|
||||
"stringUnit" : {
|
||||
"state" : "new",
|
||||
"state" : "needs_review",
|
||||
"value" : "(c) iNaturalist"
|
||||
}
|
||||
},
|
||||
"ka" : {
|
||||
"stringUnit" : {
|
||||
"state" : "new",
|
||||
"state" : "needs_review",
|
||||
"value" : "(c) iNaturalist"
|
||||
}
|
||||
},
|
||||
"kk" : {
|
||||
"stringUnit" : {
|
||||
"state" : "new",
|
||||
"state" : "needs_review",
|
||||
"value" : "(c) iNaturalist"
|
||||
}
|
||||
},
|
||||
"kn" : {
|
||||
"stringUnit" : {
|
||||
"state" : "new",
|
||||
"state" : "needs_review",
|
||||
"value" : "(c) iNaturalist"
|
||||
}
|
||||
},
|
||||
"ko" : {
|
||||
"stringUnit" : {
|
||||
"state" : "new",
|
||||
"state" : "needs_review",
|
||||
"value" : "(c) iNaturalist"
|
||||
}
|
||||
},
|
||||
"lb" : {
|
||||
"stringUnit" : {
|
||||
"state" : "new",
|
||||
"state" : "needs_review",
|
||||
"value" : "(c) iNaturalist"
|
||||
}
|
||||
},
|
||||
"lt" : {
|
||||
"stringUnit" : {
|
||||
"state" : "new",
|
||||
"state" : "needs_review",
|
||||
"value" : "(c) iNaturalist"
|
||||
}
|
||||
},
|
||||
"lv" : {
|
||||
"stringUnit" : {
|
||||
"state" : "new",
|
||||
"state" : "needs_review",
|
||||
"value" : "(c) iNaturalist"
|
||||
}
|
||||
},
|
||||
"mi" : {
|
||||
"stringUnit" : {
|
||||
"state" : "new",
|
||||
"state" : "needs_review",
|
||||
"value" : "(c) iNaturalist"
|
||||
}
|
||||
},
|
||||
"mk" : {
|
||||
"stringUnit" : {
|
||||
"state" : "new",
|
||||
"state" : "needs_review",
|
||||
"value" : "(c) iNaturalist"
|
||||
}
|
||||
},
|
||||
"ml" : {
|
||||
"stringUnit" : {
|
||||
"state" : "new",
|
||||
"state" : "needs_review",
|
||||
"value" : "(c) iNaturalist"
|
||||
}
|
||||
},
|
||||
"mr" : {
|
||||
"stringUnit" : {
|
||||
"state" : "new",
|
||||
"state" : "needs_review",
|
||||
"value" : "(c) iNaturalist"
|
||||
}
|
||||
},
|
||||
"ms" : {
|
||||
"stringUnit" : {
|
||||
"state" : "new",
|
||||
"state" : "needs_review",
|
||||
"value" : "(c) iNaturalist"
|
||||
}
|
||||
},
|
||||
"nb-NO" : {
|
||||
"stringUnit" : {
|
||||
"state" : "new",
|
||||
"state" : "needs_review",
|
||||
"value" : "(c) iNaturalist"
|
||||
}
|
||||
},
|
||||
"nl" : {
|
||||
"stringUnit" : {
|
||||
"state" : "new",
|
||||
"state" : "needs_review",
|
||||
"value" : "(c) iNaturalist"
|
||||
}
|
||||
},
|
||||
"pa" : {
|
||||
"stringUnit" : {
|
||||
"state" : "new",
|
||||
"state" : "needs_review",
|
||||
"value" : "(c) iNaturalist"
|
||||
}
|
||||
},
|
||||
"pl" : {
|
||||
"stringUnit" : {
|
||||
"state" : "new",
|
||||
"state" : "needs_review",
|
||||
"value" : "(c) iNaturalist"
|
||||
}
|
||||
},
|
||||
"pt-BR" : {
|
||||
"stringUnit" : {
|
||||
"state" : "new",
|
||||
"state" : "needs_review",
|
||||
"value" : "(c) iNaturalist"
|
||||
}
|
||||
},
|
||||
"pt-PT" : {
|
||||
"stringUnit" : {
|
||||
"state" : "new",
|
||||
"state" : "needs_review",
|
||||
"value" : "(c) iNaturalist"
|
||||
}
|
||||
},
|
||||
"ro" : {
|
||||
"stringUnit" : {
|
||||
"state" : "new",
|
||||
"state" : "needs_review",
|
||||
"value" : "(c) iNaturalist"
|
||||
}
|
||||
},
|
||||
"ru" : {
|
||||
"stringUnit" : {
|
||||
"state" : "new",
|
||||
"state" : "needs_review",
|
||||
"value" : "(c) iNaturalist"
|
||||
}
|
||||
},
|
||||
"sat" : {
|
||||
"stringUnit" : {
|
||||
"state" : "new",
|
||||
"state" : "needs_review",
|
||||
"value" : "(c) iNaturalist"
|
||||
}
|
||||
},
|
||||
"si" : {
|
||||
"stringUnit" : {
|
||||
"state" : "new",
|
||||
"state" : "needs_review",
|
||||
"value" : "(c) iNaturalist"
|
||||
}
|
||||
},
|
||||
"sk" : {
|
||||
"stringUnit" : {
|
||||
"state" : "new",
|
||||
"state" : "needs_review",
|
||||
"value" : "(c) iNaturalist"
|
||||
}
|
||||
},
|
||||
"sl" : {
|
||||
"stringUnit" : {
|
||||
"state" : "new",
|
||||
"state" : "needs_review",
|
||||
"value" : "(c) iNaturalist"
|
||||
}
|
||||
},
|
||||
"sq" : {
|
||||
"stringUnit" : {
|
||||
"state" : "new",
|
||||
"state" : "needs_review",
|
||||
"value" : "(c) iNaturalist"
|
||||
}
|
||||
},
|
||||
"sr" : {
|
||||
"stringUnit" : {
|
||||
"state" : "new",
|
||||
"state" : "needs_review",
|
||||
"value" : "(c) iNaturalist"
|
||||
}
|
||||
},
|
||||
"sv" : {
|
||||
"stringUnit" : {
|
||||
"state" : "new",
|
||||
"state" : "needs_review",
|
||||
"value" : "(c) iNaturalist"
|
||||
}
|
||||
},
|
||||
"sw" : {
|
||||
"stringUnit" : {
|
||||
"state" : "new",
|
||||
"state" : "needs_review",
|
||||
"value" : "(c) iNaturalist"
|
||||
}
|
||||
},
|
||||
"ta" : {
|
||||
"stringUnit" : {
|
||||
"state" : "new",
|
||||
"state" : "needs_review",
|
||||
"value" : "(c) iNaturalist"
|
||||
}
|
||||
},
|
||||
"te" : {
|
||||
"stringUnit" : {
|
||||
"state" : "new",
|
||||
"state" : "needs_review",
|
||||
"value" : "(c) iNaturalist"
|
||||
}
|
||||
},
|
||||
"th" : {
|
||||
"stringUnit" : {
|
||||
"state" : "new",
|
||||
"value" : "(c) iNaturalist"
|
||||
}
|
||||
},
|
||||
"tl" : {
|
||||
"stringUnit" : {
|
||||
"state" : "new",
|
||||
"state" : "needs_review",
|
||||
"value" : "(c) iNaturalist"
|
||||
}
|
||||
},
|
||||
"tr" : {
|
||||
"stringUnit" : {
|
||||
"state" : "new",
|
||||
"state" : "needs_review",
|
||||
"value" : "(c) iNaturalist"
|
||||
}
|
||||
},
|
||||
"uk" : {
|
||||
"stringUnit" : {
|
||||
"state" : "new",
|
||||
"state" : "needs_review",
|
||||
"value" : "(c) iNaturalist"
|
||||
}
|
||||
},
|
||||
"vi" : {
|
||||
"stringUnit" : {
|
||||
"state" : "new",
|
||||
"state" : "needs_review",
|
||||
"value" : "(c) iNaturalist"
|
||||
}
|
||||
},
|
||||
"zh-Hans" : {
|
||||
"stringUnit" : {
|
||||
"state" : "new",
|
||||
"state" : "needs_review",
|
||||
"value" : "(c) iNaturalist"
|
||||
}
|
||||
},
|
||||
"zh-Hant" : {
|
||||
"stringUnit" : {
|
||||
"state" : "new",
|
||||
"state" : "needs_review",
|
||||
"value" : "(c) iNaturalist"
|
||||
}
|
||||
},
|
||||
"zh-Hant-HK" : {
|
||||
"stringUnit" : {
|
||||
"state" : "new",
|
||||
"state" : "needs_review",
|
||||
"value" : "(c) iNaturalist"
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
"shouldTranslate" : false
|
||||
},
|
||||
"NSLocationAlwaysAndWhenInUseUsageDescription" : {
|
||||
"comment" : "Privacy - Location Always and When In Use Usage Description",
|
||||
"extractionState" : "extracted_with_value",
|
||||
"localizations" : {
|
||||
"af" : {
|
||||
"stringUnit" : {
|
||||
@@ -2727,12 +2702,6 @@
|
||||
"value" : "เราไม่ได้ร้องขอสิทธิ์นี้โดยเจตนา หากคุณพบข้อความนี้ กรุณาถ่ายภาพหน้าจอและส่งอีเมลไปที่ help@inaturalist.org"
|
||||
}
|
||||
},
|
||||
"tl" : {
|
||||
"stringUnit" : {
|
||||
"state" : "new",
|
||||
"value" : "We do not intentionally request this permission. If you are seeing this, please take a screenshot and email it to help@inaturalist.org"
|
||||
}
|
||||
},
|
||||
"tr" : {
|
||||
"stringUnit" : {
|
||||
"state" : "translated",
|
||||
@@ -2773,6 +2742,7 @@
|
||||
},
|
||||
"NSLocationWhenInUseUsageDescription" : {
|
||||
"comment" : "Privacy - Location When In Use Usage Description",
|
||||
"extractionState" : "extracted_with_value",
|
||||
"localizations" : {
|
||||
"af" : {
|
||||
"stringUnit" : {
|
||||
@@ -3188,12 +3158,6 @@
|
||||
"value" : "เพิ่มพิกัด GPS ให้กับการสังเกต แสดงตำแหน่งของคุณบนแผนที่ และอื่น ๆ"
|
||||
}
|
||||
},
|
||||
"tl" : {
|
||||
"stringUnit" : {
|
||||
"state" : "new",
|
||||
"value" : "Add GPS coordinates to observations, show your location on maps, and more."
|
||||
}
|
||||
},
|
||||
"tr" : {
|
||||
"stringUnit" : {
|
||||
"state" : "translated",
|
||||
@@ -3234,6 +3198,7 @@
|
||||
},
|
||||
"NSMicrophoneUsageDescription" : {
|
||||
"comment" : "Privacy - Microphone Usage Description",
|
||||
"extractionState" : "extracted_with_value",
|
||||
"localizations" : {
|
||||
"af" : {
|
||||
"stringUnit" : {
|
||||
@@ -3649,12 +3614,6 @@
|
||||
"value" : "บันทึกเสียงจากธรรมชาติ"
|
||||
}
|
||||
},
|
||||
"tl" : {
|
||||
"stringUnit" : {
|
||||
"state" : "new",
|
||||
"value" : "Record sound observations of nature."
|
||||
}
|
||||
},
|
||||
"tr" : {
|
||||
"stringUnit" : {
|
||||
"state" : "translated",
|
||||
@@ -3695,6 +3654,7 @@
|
||||
},
|
||||
"NSPhotoLibraryAddUsageDescription" : {
|
||||
"comment" : "Privacy - Photo Library Additions Usage Description",
|
||||
"extractionState" : "extracted_with_value",
|
||||
"localizations" : {
|
||||
"af" : {
|
||||
"stringUnit" : {
|
||||
@@ -4110,12 +4070,6 @@
|
||||
"value" : "ส่งออกภาพถ่ายจาก iNaturalist Next ไปยังคลังภาพของคุณ"
|
||||
}
|
||||
},
|
||||
"tl" : {
|
||||
"stringUnit" : {
|
||||
"state" : "new",
|
||||
"value" : "Export iNaturalist Next photos to your library."
|
||||
}
|
||||
},
|
||||
"tr" : {
|
||||
"stringUnit" : {
|
||||
"state" : "translated",
|
||||
@@ -4156,6 +4110,7 @@
|
||||
},
|
||||
"NSPhotoLibraryUsageDescription" : {
|
||||
"comment" : "Privacy - Photo Library Usage Description",
|
||||
"extractionState" : "extracted_with_value",
|
||||
"localizations" : {
|
||||
"af" : {
|
||||
"stringUnit" : {
|
||||
@@ -4571,12 +4526,6 @@
|
||||
"value" : "ส่งออกและนำเข้าภาพถ่ายจาก iNaturalist Next ไปยังคลังภาพของคุณและจากคลังภาพของคุณ"
|
||||
}
|
||||
},
|
||||
"tl" : {
|
||||
"stringUnit" : {
|
||||
"state" : "new",
|
||||
"value" : "Export and import iNaturalist Next photos to and from your library."
|
||||
}
|
||||
},
|
||||
"tr" : {
|
||||
"stringUnit" : {
|
||||
"state" : "translated",
|
||||
|
||||
@@ -29,11 +29,11 @@ import {
|
||||
useTranslation
|
||||
} from "sharedHooks";
|
||||
|
||||
import ObsDetailsHeaderRight from "../ObsDetailsDefaultMode/ObsDetailsDefaultModeHeaderRight";
|
||||
import ActivityTab from "./ActivityTab/ActivityTab";
|
||||
import FloatingButtons from "./ActivityTab/FloatingButtons";
|
||||
import DetailsTab from "./DetailsTab/DetailsTab";
|
||||
import FaveButton from "./FaveButton";
|
||||
import ObsDetailsHeader from "./ObsDetailsHeader";
|
||||
import ObsDetailsOverview from "./ObsDetailsOverview";
|
||||
import ObsMediaDisplayContainer from "./ObsMediaDisplayContainer";
|
||||
import AgreeWithIDSheet from "./Sheets/AgreeWithIDSheet";
|
||||
@@ -129,7 +129,6 @@ const ObsDetails = ( {
|
||||
const scrollViewRef = useRef( );
|
||||
const insets = useSafeAreaInsets();
|
||||
const { t } = useTranslation( );
|
||||
const [invertToWhiteBackground, setInvertToWhiteBackground] = useState( false );
|
||||
|
||||
// Scroll the scrollview to this y position once if set, then unset it.
|
||||
// Could be refactored into a hook if we need this logic elsewher
|
||||
@@ -150,14 +149,6 @@ const ObsDetails = ( {
|
||||
}
|
||||
}, [addingActivityItem] );
|
||||
|
||||
const handleScroll = e => {
|
||||
const scrollY = e.nativeEvent.contentOffset.y;
|
||||
const shouldInvert = !!( scrollY > 150 );
|
||||
if ( shouldInvert !== invertToWhiteBackground ) {
|
||||
setInvertToWhiteBackground( shouldInvert );
|
||||
}
|
||||
};
|
||||
|
||||
const dynamicInsets = useMemo( () => ( {
|
||||
backgroundColor: "#ffffff",
|
||||
paddingTop: insets.top,
|
||||
@@ -196,6 +187,16 @@ const ObsDetails = ( {
|
||||
</HideView>
|
||||
);
|
||||
|
||||
const renderHeaderRight = ( ) => (
|
||||
<ObsDetailsHeaderRight
|
||||
belongsToCurrentUser={belongsToCurrentUser}
|
||||
observationId={observation?.id}
|
||||
uuid={observation?.uuid}
|
||||
refetchSubscriptions={refetchSubscriptions}
|
||||
subscriptions={subscriptions}
|
||||
/>
|
||||
);
|
||||
|
||||
const renderTablet = () => (
|
||||
<View className="flex-1 flex-row bg-white">
|
||||
<View className="w-[33%]">
|
||||
@@ -226,7 +227,6 @@ const ObsDetails = ( {
|
||||
className="flex-1 flex-column"
|
||||
stickyHeaderHiddenOnScroll
|
||||
endFillColor="white"
|
||||
onScroll={handleScroll}
|
||||
>
|
||||
<View className="bg-white h-full">
|
||||
{renderActivityTab( )}
|
||||
@@ -246,15 +246,7 @@ const ObsDetails = ( {
|
||||
/>
|
||||
)}
|
||||
</View>
|
||||
<ObsDetailsHeader
|
||||
belongsToCurrentUser={belongsToCurrentUser}
|
||||
invertToWhiteBackground={invertToWhiteBackground}
|
||||
observationId={observation?.id}
|
||||
rightIconDarkGray
|
||||
uuid={observation?.uuid}
|
||||
refetchSubscriptions={refetchSubscriptions}
|
||||
subscriptions={subscriptions}
|
||||
/>
|
||||
{renderHeaderRight( )}
|
||||
</View>
|
||||
);
|
||||
|
||||
@@ -266,17 +258,9 @@ const ObsDetails = ( {
|
||||
stickyHeaderIndices={[0, 3]}
|
||||
scrollEventThrottle={16}
|
||||
endFillColor="white"
|
||||
onScroll={handleScroll}
|
||||
>
|
||||
<ObsDetailsHeader
|
||||
belongsToCurrentUser={belongsToCurrentUser}
|
||||
subscriptions={subscriptions}
|
||||
invertToWhiteBackground={invertToWhiteBackground}
|
||||
observationId={observation?.id}
|
||||
uuid={observation?.uuid}
|
||||
refetchSubscriptions={refetchSubscriptions}
|
||||
/>
|
||||
<View className="-mt-[64px]">
|
||||
{renderHeaderRight( )}
|
||||
<View>
|
||||
<ObsMediaDisplayContainer observation={observation} />
|
||||
{ currentUser && (
|
||||
<FaveButton
|
||||
|
||||
@@ -1,94 +0,0 @@
|
||||
import classnames from "classnames";
|
||||
import {
|
||||
INatIconButton,
|
||||
OverlayHeader
|
||||
} from "components/SharedComponents";
|
||||
import {
|
||||
LinearGradient
|
||||
} from "components/styledComponents";
|
||||
import React from "react";
|
||||
import DeviceInfo from "react-native-device-info";
|
||||
import type { RealmObservation } from "realmModels/types";
|
||||
import {
|
||||
useLocalObservation,
|
||||
useNavigateToObsEdit,
|
||||
useTranslation
|
||||
} from "sharedHooks";
|
||||
import colors from "styles/tailwindColors";
|
||||
|
||||
import HeaderKebabMenu from "./HeaderKebabMenu";
|
||||
|
||||
const isTablet = DeviceInfo.isTablet( );
|
||||
|
||||
interface Props {
|
||||
belongsToCurrentUser?: boolean,
|
||||
invertToWhiteBackground: boolean,
|
||||
subscriptions: Object,
|
||||
observationId: number,
|
||||
refetchSubscriptions: Function,
|
||||
rightIconDarkGray?: boolean,
|
||||
uuid: string
|
||||
}
|
||||
|
||||
const ObsDetailsHeader = ( {
|
||||
belongsToCurrentUser,
|
||||
invertToWhiteBackground,
|
||||
subscriptions,
|
||||
observationId,
|
||||
refetchSubscriptions,
|
||||
rightIconDarkGray = false,
|
||||
uuid
|
||||
}: Props ) => {
|
||||
const localObservation = useLocalObservation( uuid );
|
||||
const navigateToObsEdit = useNavigateToObsEdit( );
|
||||
const { t } = useTranslation( );
|
||||
|
||||
const whiteIcon = !rightIconDarkGray && !invertToWhiteBackground;
|
||||
|
||||
return (
|
||||
<LinearGradient
|
||||
className={classnames(
|
||||
"h-16 transparent"
|
||||
)}
|
||||
colors={[
|
||||
isTablet
|
||||
? "rgba(0,0,0,0.1)"
|
||||
: "rgba(0,0,0,0.6)",
|
||||
"transparent"
|
||||
]}
|
||||
>
|
||||
<OverlayHeader
|
||||
testID="ObsDetails.BackButton"
|
||||
invertToWhiteBackground={invertToWhiteBackground}
|
||||
headerRight={
|
||||
belongsToCurrentUser
|
||||
? (
|
||||
<INatIconButton
|
||||
testID="ObsDetail.editButton"
|
||||
// TODO remove this cast when useLocalObservation is properly typed
|
||||
onPress={() => navigateToObsEdit( localObservation as RealmObservation )}
|
||||
icon="pencil"
|
||||
color={String(
|
||||
whiteIcon
|
||||
? colors?.white
|
||||
: colors?.darkGray
|
||||
)}
|
||||
accessibilityLabel={t( "Edit" )}
|
||||
/>
|
||||
)
|
||||
: (
|
||||
<HeaderKebabMenu
|
||||
observationId={observationId}
|
||||
white={whiteIcon}
|
||||
subscriptions={subscriptions}
|
||||
uuid={uuid}
|
||||
refetchSubscriptions={refetchSubscriptions}
|
||||
/>
|
||||
)
|
||||
}
|
||||
/>
|
||||
</LinearGradient>
|
||||
);
|
||||
};
|
||||
|
||||
export default ObsDetailsHeader;
|
||||
@@ -21,7 +21,7 @@ interface Props {
|
||||
subscriptions: Object
|
||||
}
|
||||
|
||||
const ObsDetailsDefaultModeHeader = ( {
|
||||
const ObsDetailsDefaultModeHeaderRight = ( {
|
||||
belongsToCurrentUser,
|
||||
observationId,
|
||||
uuid,
|
||||
@@ -73,4 +73,4 @@ const ObsDetailsDefaultModeHeader = ( {
|
||||
return null;
|
||||
};
|
||||
|
||||
export default ObsDetailsDefaultModeHeader;
|
||||
export default ObsDetailsDefaultModeHeaderRight;
|
||||
|
||||
@@ -170,6 +170,12 @@ const LIST_OPTIONS = {
|
||||
lazy: true
|
||||
};
|
||||
|
||||
const OBS_DETAILS_OPTIONS = {
|
||||
unmountOnBlur: true,
|
||||
...showHeader,
|
||||
...blankHeaderTitle
|
||||
};
|
||||
|
||||
const Stack = createNativeStackNavigator( );
|
||||
|
||||
export const SCREEN_NAME_OBS_LIST = "ObsList";
|
||||
@@ -216,20 +222,14 @@ const TabStackNavigator = ( ): Node => {
|
||||
<Stack.Screen
|
||||
name="ObsDetails"
|
||||
component={FadeInObsDetailsDefaultModeContainer}
|
||||
options={{
|
||||
unmountOnBlur: true,
|
||||
...showHeader,
|
||||
...blankHeaderTitle
|
||||
}}
|
||||
options={OBS_DETAILS_OPTIONS}
|
||||
/>
|
||||
)
|
||||
: (
|
||||
<Stack.Screen
|
||||
name="ObsDetails"
|
||||
component={FadeInObsDetailsContainer}
|
||||
options={{
|
||||
unmountOnBlur: true
|
||||
}}
|
||||
options={OBS_DETAILS_OPTIONS}
|
||||
/>
|
||||
)}
|
||||
</Stack.Group>
|
||||
|
||||
@@ -21,7 +21,7 @@ const baseHeaderOptions: Object = {
|
||||
headerShown: true,
|
||||
headerBackTitleVisible: false,
|
||||
headerShadowVisible: false,
|
||||
headerLeft: () => <BackButton inCustomHeader />
|
||||
headerLeft: () => <BackButton inCustomHeader testID="header-back-button" />
|
||||
};
|
||||
|
||||
const showHeader: Object = {
|
||||
|
||||
@@ -258,58 +258,7 @@ describe( "ObsDetails", () => {
|
||||
// );
|
||||
} );
|
||||
|
||||
describe( "viewing own observation", ( ) => {
|
||||
async function expectEditAndNotMenu( ) {
|
||||
const editLabelText = t( "Edit" );
|
||||
const editButton = await screen.findByLabelText( editLabelText );
|
||||
expect( editButton ).toBeTruthy( );
|
||||
const kebabMenuLabelText = t( "Observation-options" );
|
||||
const kebabMenu = screen.queryByLabelText( kebabMenuLabelText );
|
||||
expect( kebabMenu ).toBeFalsy( );
|
||||
}
|
||||
|
||||
it( "should show the edit button and not the menu", async ( ) => {
|
||||
const mockOwnObservation = factory( "LocalObservation", { user: mockUser } );
|
||||
jest.spyOn( useLocalObservation, "default" ).mockImplementation( () => mockOwnObservation );
|
||||
jest.spyOn( useCurrentUser, "default" ).mockImplementation( () => mockOwnObservation.user );
|
||||
renderObsDetails( );
|
||||
expect( mockOwnObservation.user.id ).toEqual( mockUser.id );
|
||||
await expectEditAndNotMenu( );
|
||||
} );
|
||||
|
||||
it(
|
||||
"should show the edit button and not the menu when the observation has never been uploaded",
|
||||
async ( ) => {
|
||||
const observation = factory( "LocalObservation" );
|
||||
jest.spyOn( useLocalObservation, "default" )
|
||||
.mockImplementation( () => observation );
|
||||
jest.spyOn( useCurrentUser, "default" ).mockImplementation( () => observation.user );
|
||||
renderObsDetails( );
|
||||
// An unuploaded observation *should* be the only situation where an
|
||||
// observation has no user, b/c a user can make observations before
|
||||
// signing in
|
||||
expect( observation.user ).toBeFalsy( );
|
||||
await expectEditAndNotMenu( );
|
||||
}
|
||||
);
|
||||
} );
|
||||
|
||||
describe( "viewing someone else's observation", ( ) => {
|
||||
it( "should show the menu and not the edit button", async ( ) => {
|
||||
expect( mockObservation.user.id ).not.toEqual( mockUser.id );
|
||||
renderObsDetails( );
|
||||
jest.spyOn( useLocalObservation, "default" ).mockImplementation( () => mockObservation );
|
||||
jest.spyOn( useCurrentUser, "default" ).mockImplementation( () => null );
|
||||
renderObsDetails( );
|
||||
expect( await screen.findByTestId( `ObsDetails.${mockObservation.uuid}` ) ).toBeTruthy( );
|
||||
const kebabMenuLabelText = t( "Observation-options" );
|
||||
const kebabMenu = await screen.findByLabelText( kebabMenuLabelText );
|
||||
expect( kebabMenu ).toBeTruthy( );
|
||||
const editLabelText = t( "Edit" );
|
||||
const editButton = screen.queryByLabelText( editLabelText );
|
||||
expect( editButton ).toBeFalsy( );
|
||||
} );
|
||||
|
||||
it( "should agree with another user's identification when agree button pressed", async ( ) => {
|
||||
const firstIdentification = factory( "RemoteIdentification", {
|
||||
taxon: factory( "RemoteTaxon", {
|
||||
|
||||
@@ -1,63 +0,0 @@
|
||||
import { fireEvent, screen } from "@testing-library/react-native";
|
||||
import ObsDetailsHeader from "components/ObsDetails/ObsDetailsHeader.tsx";
|
||||
import i18next from "i18next";
|
||||
import React from "react";
|
||||
import factory from "tests/factory";
|
||||
import { renderComponent } from "tests/helpers/render";
|
||||
|
||||
jest.mock( "react-native/Libraries/Share/Share", () => ( {
|
||||
share: jest.fn( () => Promise.resolve( "mockResolve" ) )
|
||||
} ) );
|
||||
|
||||
jest.mock( "react-native/Libraries/Utilities/Platform", ( ) => ( {
|
||||
OS: "ios",
|
||||
select: jest.fn( )
|
||||
} ) );
|
||||
|
||||
describe( "ObsDetailsHeader", () => {
|
||||
it( "shows options menu when viewing someone else's observation", async ( ) => {
|
||||
renderComponent(
|
||||
<ObsDetailsHeader
|
||||
observation={factory( "RemoteObservation" )}
|
||||
belongsToCurrentUser={false}
|
||||
/>
|
||||
);
|
||||
const anchorButton = screen.getByLabelText( i18next.t( "Observation-options" ) );
|
||||
expect( anchorButton ).toBeTruthy( );
|
||||
fireEvent.press( anchorButton );
|
||||
const shareButton = await screen.findByTestId( "MenuItem.Share" );
|
||||
expect( shareButton ).toBeTruthy( );
|
||||
const enableNotificationsButton = await screen.findByTestId( "MenuItem.EnableNotifications" );
|
||||
expect( enableNotificationsButton ).toBeTruthy( );
|
||||
} );
|
||||
|
||||
it( "shows ignore notification button in options menu when subscribed to obs", async ( ) => {
|
||||
renderComponent(
|
||||
<ObsDetailsHeader
|
||||
observation={factory( "RemoteObservation" )}
|
||||
belongsToCurrentUser={false}
|
||||
subscriptions={[{ id: 324810661, user_id: 6280741 }]}
|
||||
/>
|
||||
);
|
||||
const anchorButton = screen.getByLabelText( i18next.t( "Observation-options" ) );
|
||||
expect( anchorButton ).toBeTruthy( );
|
||||
fireEvent.press( anchorButton );
|
||||
const shareButton = await screen.findByTestId( "MenuItem.Share" );
|
||||
expect( shareButton ).toBeTruthy( );
|
||||
const ignoreNotificationsButton = await screen.findByTestId( "MenuItem.IgnoreNotifications" );
|
||||
expect( ignoreNotificationsButton ).toBeTruthy( );
|
||||
} );
|
||||
|
||||
it( "does not show options menu when observation belongs to current user", ( ) => {
|
||||
renderComponent(
|
||||
<ObsDetailsHeader
|
||||
observation={factory( "RemoteObservation" )}
|
||||
belongsToCurrentUser
|
||||
/>
|
||||
);
|
||||
const editButton = screen.getByTestId( "ObsDetail.editButton" );
|
||||
expect( editButton ).toBeVisible( );
|
||||
const anchorButton = screen.queryByLabelText( i18next.t( "Observation-options" ) );
|
||||
expect( anchorButton ).toBeFalsy( );
|
||||
} );
|
||||
} );
|
||||
Reference in New Issue
Block a user