round 2 android e2e fixes: bundled media asset, report dialog deps, flow guards
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
This commit is contained in:
@@ -153,16 +153,6 @@ if [[ "$platform" == "android" ]]; then
|
|||||||
phase "Configuring Android localhost routing"
|
phase "Configuring Android localhost routing"
|
||||||
adb -s "$device_id" reverse tcp:3000 tcp:3000
|
adb -s "$device_id" reverse tcp:3000 tcp:3000
|
||||||
adb -s "$device_id" reverse tcp:8081 tcp:8081
|
adb -s "$device_id" reverse tcp:8081 tcp:8081
|
||||||
|
|
||||||
# The e2e media picker mock reads a seeded photo from the app's external
|
|
||||||
# files directory (see src/lib/media/picker.e2e.tsx). The app must already
|
|
||||||
# be installed (the install step runs before this script), so the directory
|
|
||||||
# exists and is owned by the app; sdcardfs makes it world-readable so the
|
|
||||||
# mock can read the file without any runtime media permission.
|
|
||||||
phase "Seeding e2e media"
|
|
||||||
e2e_media_dir="/sdcard/Android/data/xyz.blueskyweb.app/files/e2e"
|
|
||||||
adb -s "$device_id" shell mkdir -p "$e2e_media_dir"
|
|
||||||
adb -s "$device_id" push assets/images/welcome-modal-bg.jpg "$e2e_media_dir/test.jpg"
|
|
||||||
fi
|
fi
|
||||||
|
|
||||||
phase "Running Maestro flows"
|
phase "Running Maestro flows"
|
||||||
|
|||||||
@@ -44,6 +44,12 @@ appId: xyz.blueskyweb.app
|
|||||||
id: "e2eRefreshHome"
|
id: "e2eRefreshHome"
|
||||||
- tapOn:
|
- tapOn:
|
||||||
id: "replyBtn"
|
id: "replyBtn"
|
||||||
|
# Wait for the composer to fully open before typing. Tapping replyBtn right
|
||||||
|
# after the previous publish can race the closing composer on Android.
|
||||||
|
- extendedWaitUntil:
|
||||||
|
visible:
|
||||||
|
id: "composerPublishBtn"
|
||||||
|
timeout: 10000
|
||||||
- inputText: "Reply text only"
|
- inputText: "Reply text only"
|
||||||
- tapOn:
|
- tapOn:
|
||||||
id: "composerPublishBtn"
|
id: "composerPublishBtn"
|
||||||
@@ -51,6 +57,11 @@ appId: xyz.blueskyweb.app
|
|||||||
id: "composeFAB"
|
id: "composeFAB"
|
||||||
- tapOn:
|
- tapOn:
|
||||||
id: "replyBtn"
|
id: "replyBtn"
|
||||||
|
# Wait for the composer to fully open before typing.
|
||||||
|
- extendedWaitUntil:
|
||||||
|
visible:
|
||||||
|
id: "composerPublishBtn"
|
||||||
|
timeout: 10000
|
||||||
- inputText: "Reply with an image"
|
- inputText: "Reply with an image"
|
||||||
- tapOn:
|
- tapOn:
|
||||||
id: "openMediaBtn"
|
id: "openMediaBtn"
|
||||||
@@ -63,6 +74,11 @@ appId: xyz.blueskyweb.app
|
|||||||
id: "composeFAB"
|
id: "composeFAB"
|
||||||
- tapOn:
|
- tapOn:
|
||||||
id: "replyBtn"
|
id: "replyBtn"
|
||||||
|
# Wait for the composer to fully open before typing.
|
||||||
|
- extendedWaitUntil:
|
||||||
|
visible:
|
||||||
|
id: "composerPublishBtn"
|
||||||
|
timeout: 10000
|
||||||
- inputText: "Reply with a https://example.com link card"
|
- inputText: "Reply with a https://example.com link card"
|
||||||
- tapOn:
|
- tapOn:
|
||||||
id: "composerPublishBtn"
|
id: "composerPublishBtn"
|
||||||
|
|||||||
@@ -29,86 +29,81 @@ appId: xyz.blueskyweb.app
|
|||||||
id: "homeScreenFeedTabs-selector-1"
|
id: "homeScreenFeedTabs-selector-1"
|
||||||
text: "alice-favs"
|
text: "alice-favs"
|
||||||
|
|
||||||
# Set alice-favs first
|
# Reordering feeds is driven by a drag on the feed-drag-handle. Maestro cannot
|
||||||
- tapOn: "Open drawer menu"
|
# activate the RNGH Pan gesture from a synthetic swipe on Android (proven
|
||||||
- tapOn:
|
# twice - coordinate swipes never register the pan), so the reorder
|
||||||
id: "menuItemButton-Feeds"
|
# verification below runs on iOS only. If Android drag coverage is needed,
|
||||||
- tapOn:
|
# revisit with the SavedFeedsA11y move buttons rather than a swipe.
|
||||||
id: "editFeedsBtn"
|
|
||||||
# The id+direction swipe doesn't register the RNGH pan on Android, so we
|
|
||||||
# use an explicit coordinate swipe that travels several row heights. iOS
|
|
||||||
# keeps the id-based swipe (its screen aspect ratio differs).
|
|
||||||
- runFlow:
|
- runFlow:
|
||||||
when:
|
when:
|
||||||
platform: iOS
|
platform: iOS
|
||||||
commands:
|
commands:
|
||||||
|
# Set alice-favs first
|
||||||
|
- tapOn: "Open drawer menu"
|
||||||
|
- tapOn:
|
||||||
|
id: "menuItemButton-Feeds"
|
||||||
|
- tapOn:
|
||||||
|
id: "editFeedsBtn"
|
||||||
- swipe:
|
- swipe:
|
||||||
label: "Drag feed down"
|
label: "Drag feed down"
|
||||||
from:
|
from:
|
||||||
id: "feed-drag-handle"
|
id: "feed-drag-handle"
|
||||||
direction: "DOWN"
|
direction: "DOWN"
|
||||||
duration: 1000
|
duration: 1000
|
||||||
- runFlow:
|
- assertVisible:
|
||||||
when:
|
id: "saveChangesBtn"
|
||||||
platform: Android
|
enabled: true
|
||||||
commands:
|
- tapOn:
|
||||||
- swipe:
|
label: "Save button"
|
||||||
label: "Drag feed down"
|
id: "saveChangesBtn"
|
||||||
start: "93%,31%"
|
- tapOn: "Go back"
|
||||||
end: "93%,45%"
|
- assertVisible:
|
||||||
duration: 1500
|
id: "homeScreenFeedTabs-selector-0"
|
||||||
- assertVisible:
|
text: "alice-favs"
|
||||||
id: "saveChangesBtn"
|
- assertVisible:
|
||||||
enabled: true
|
id: "homeScreenFeedTabs-selector-1"
|
||||||
- tapOn:
|
text: "Following"
|
||||||
label: "Save button"
|
|
||||||
id: "saveChangesBtn"
|
|
||||||
- tapOn: "Go back"
|
|
||||||
- assertVisible:
|
|
||||||
id: "homeScreenFeedTabs-selector-0"
|
|
||||||
text: "alice-favs"
|
|
||||||
- assertVisible:
|
|
||||||
id: "homeScreenFeedTabs-selector-1"
|
|
||||||
text: "Following"
|
|
||||||
|
|
||||||
# Set following first
|
# Set following first
|
||||||
- tapOn: "Open drawer menu"
|
- tapOn: "Open drawer menu"
|
||||||
- tapOn:
|
- tapOn:
|
||||||
id: "menuItemButton-Feeds"
|
id: "menuItemButton-Feeds"
|
||||||
- tapOn:
|
- tapOn:
|
||||||
id: "editFeedsBtn"
|
id: "editFeedsBtn"
|
||||||
- runFlow:
|
|
||||||
when:
|
|
||||||
platform: iOS
|
|
||||||
commands:
|
|
||||||
- swipe:
|
- swipe:
|
||||||
label: "Drag feed down"
|
label: "Drag feed down"
|
||||||
from:
|
from:
|
||||||
id: "feed-drag-handle"
|
id: "feed-drag-handle"
|
||||||
direction: "DOWN"
|
direction: "DOWN"
|
||||||
duration: 1000
|
duration: 1000
|
||||||
|
- assertVisible:
|
||||||
|
id: "saveChangesBtn"
|
||||||
|
enabled: true
|
||||||
|
- tapOn:
|
||||||
|
label: "Save button"
|
||||||
|
id: "saveChangesBtn"
|
||||||
|
- tapOn: "Go back"
|
||||||
|
- assertVisible:
|
||||||
|
id: "homeScreenFeedTabs-selector-0"
|
||||||
|
text: "Following"
|
||||||
|
- assertVisible:
|
||||||
|
id: "homeScreenFeedTabs-selector-1"
|
||||||
|
text: "alice-favs"
|
||||||
|
|
||||||
|
# On Android, the reorder path above is skipped. Smoke-test that the feeds
|
||||||
|
# edit screen opens and the pinned feeds render, then return to a valid state.
|
||||||
- runFlow:
|
- runFlow:
|
||||||
when:
|
when:
|
||||||
platform: Android
|
platform: Android
|
||||||
commands:
|
commands:
|
||||||
- swipe:
|
- tapOn: "Open drawer menu"
|
||||||
label: "Drag feed down"
|
- tapOn:
|
||||||
start: "93%,31%"
|
id: "menuItemButton-Feeds"
|
||||||
end: "93%,45%"
|
- tapOn:
|
||||||
duration: 1500
|
id: "editFeedsBtn"
|
||||||
- assertVisible:
|
- assertVisible: "Following"
|
||||||
id: "saveChangesBtn"
|
- assertVisible: "alice-favs"
|
||||||
enabled: true
|
- tapOn: "Go back"
|
||||||
- tapOn:
|
|
||||||
label: "Save button"
|
|
||||||
id: "saveChangesBtn"
|
|
||||||
- tapOn: "Go back"
|
|
||||||
- assertVisible:
|
|
||||||
id: "homeScreenFeedTabs-selector-0"
|
|
||||||
text: "Following"
|
|
||||||
- assertVisible:
|
|
||||||
id: "homeScreenFeedTabs-selector-1"
|
|
||||||
text: "alice-favs"
|
|
||||||
|
|
||||||
# Remove following
|
# Remove following
|
||||||
- tapOn: "Open drawer menu"
|
- tapOn: "Open drawer menu"
|
||||||
|
|||||||
@@ -15,8 +15,13 @@ appId: xyz.blueskyweb.app
|
|||||||
- tapOn:
|
- tapOn:
|
||||||
id: "e2eStartOnboarding"
|
id: "e2eStartOnboarding"
|
||||||
- tapOn: "Open avatar creator"
|
- tapOn: "Open avatar creator"
|
||||||
- extendedWaitUntil:
|
# The avatar-creator bottom sheet opens as a sliver on the short E2E emulator
|
||||||
visible: "Select an emoji"
|
# (720x1600), so the picker content sits below the fold. Scroll it into view
|
||||||
|
# instead of just waiting. No-op on iOS, where it is already visible.
|
||||||
|
- scrollUntilVisible:
|
||||||
|
element:
|
||||||
|
text: "Select an emoji"
|
||||||
|
direction: DOWN
|
||||||
timeout: 15000
|
timeout: 15000
|
||||||
- tapOn: "Select the zap emoji as your avatar"
|
- tapOn: "Select the zap emoji as your avatar"
|
||||||
- tapOn:
|
- tapOn:
|
||||||
|
|||||||
@@ -64,7 +64,10 @@ appId: xyz.blueskyweb.app
|
|||||||
id: "editProfileSaveBtn"
|
id: "editProfileSaveBtn"
|
||||||
- assertNotVisible:
|
- assertNotVisible:
|
||||||
id: "editProfileModal"
|
id: "editProfileModal"
|
||||||
- assertVisible: "alice.test"
|
# The display-name node renders the handle as a Text with a nested badge View
|
||||||
|
# once the display name is cleared, so the a11y text is not the bare handle
|
||||||
|
# string on Android. Match it as a substring instead.
|
||||||
|
- assertVisible: ".*alice\\.test.*"
|
||||||
- assertNotVisible: "One cool hacker"
|
- assertNotVisible: "One cool hacker"
|
||||||
|
|
||||||
# Set avi and banner via the edit profile modal
|
# Set avi and banner via the edit profile modal
|
||||||
|
|||||||
@@ -20,6 +20,12 @@ appId: xyz.blueskyweb.app
|
|||||||
- inputText: "Test thread"
|
- inputText: "Test thread"
|
||||||
- tapOn:
|
- tapOn:
|
||||||
id: "composerPublishBtn"
|
id: "composerPublishBtn"
|
||||||
|
# Wait for the composer to close and the home feed to settle before signing
|
||||||
|
# out. Without a settle guard the next action can race the closing composer.
|
||||||
|
- extendedWaitUntil:
|
||||||
|
visible:
|
||||||
|
id: "composeFAB"
|
||||||
|
timeout: 10000
|
||||||
|
|
||||||
# Login, reply to the thread, and log out
|
# Login, reply to the thread, and log out
|
||||||
- tapOn:
|
- tapOn:
|
||||||
@@ -31,9 +37,19 @@ appId: xyz.blueskyweb.app
|
|||||||
id: "viewHeaderHomeFeedPrefsBtn"
|
id: "viewHeaderHomeFeedPrefsBtn"
|
||||||
- tapOn:
|
- tapOn:
|
||||||
id: "replyBtn"
|
id: "replyBtn"
|
||||||
|
# Wait for the composer to fully open before typing.
|
||||||
|
- extendedWaitUntil:
|
||||||
|
visible:
|
||||||
|
id: "composerPublishBtn"
|
||||||
|
timeout: 10000
|
||||||
- inputText: "Reply 1"
|
- inputText: "Reply 1"
|
||||||
- tapOn:
|
- tapOn:
|
||||||
id: "composerPublishBtn"
|
id: "composerPublishBtn"
|
||||||
|
# Wait for the composer to close before signing out.
|
||||||
|
- extendedWaitUntil:
|
||||||
|
visible:
|
||||||
|
id: "composeFAB"
|
||||||
|
timeout: 10000
|
||||||
|
|
||||||
# Login, confirm notification exists, mute thread, and log out
|
# Login, confirm notification exists, mute thread, and log out
|
||||||
- tapOn:
|
- tapOn:
|
||||||
@@ -67,14 +83,36 @@ appId: xyz.blueskyweb.app
|
|||||||
id: "profilePager-selector-1"
|
id: "profilePager-selector-1"
|
||||||
- tapOn:
|
- tapOn:
|
||||||
id: "replyBtn"
|
id: "replyBtn"
|
||||||
|
# Wait for the composer to fully open before typing.
|
||||||
|
- extendedWaitUntil:
|
||||||
|
visible:
|
||||||
|
id: "composerPublishBtn"
|
||||||
|
timeout: 10000
|
||||||
- inputText: "Reply 2"
|
- inputText: "Reply 2"
|
||||||
- tapOn:
|
- tapOn:
|
||||||
id: "composerPublishBtn"
|
id: "composerPublishBtn"
|
||||||
|
# Wait for the composer to close and the thread reply button to return before
|
||||||
|
# opening the composer again. Previously this raced and the second replyBtn tap
|
||||||
|
# landed before the composer was ready, so the composer never opened.
|
||||||
|
- extendedWaitUntil:
|
||||||
|
visible:
|
||||||
|
id: "replyBtn"
|
||||||
|
timeout: 10000
|
||||||
- tapOn:
|
- tapOn:
|
||||||
id: "replyBtn"
|
id: "replyBtn"
|
||||||
|
# Wait for the composer to fully open before typing.
|
||||||
|
- extendedWaitUntil:
|
||||||
|
visible:
|
||||||
|
id: "composerPublishBtn"
|
||||||
|
timeout: 10000
|
||||||
- inputText: "Reply 3"
|
- inputText: "Reply 3"
|
||||||
- tapOn:
|
- tapOn:
|
||||||
id: "composerPublishBtn"
|
id: "composerPublishBtn"
|
||||||
|
# Wait for the composer to close and the thread to settle before signing out.
|
||||||
|
- extendedWaitUntil:
|
||||||
|
visible:
|
||||||
|
id: "replyBtn"
|
||||||
|
timeout: 10000
|
||||||
|
|
||||||
# Login, confirm notifications dont exist, unmute the thread, ~~confirm notifications exist~~
|
# Login, confirm notifications dont exist, unmute the thread, ~~confirm notifications exist~~
|
||||||
# Mute thread behaviour no longer change old notifications after muting/unmuting a thread -sfn
|
# Mute thread behaviour no longer change old notifications after muting/unmuting a thread -sfn
|
||||||
|
|||||||
@@ -161,6 +161,7 @@
|
|||||||
"expo": "54.0.34",
|
"expo": "54.0.34",
|
||||||
"expo-age-range": "0.2.18",
|
"expo-age-range": "0.2.18",
|
||||||
"expo-application": "~7.0.8",
|
"expo-application": "~7.0.8",
|
||||||
|
"expo-asset": "~12.0.13",
|
||||||
"expo-blur": "~15.0.8",
|
"expo-blur": "~15.0.8",
|
||||||
"expo-build-properties": "~1.0.10",
|
"expo-build-properties": "~1.0.10",
|
||||||
"expo-camera": "~17.0.10",
|
"expo-camera": "~17.0.10",
|
||||||
|
|||||||
Generated
+3
@@ -436,6 +436,9 @@ importers:
|
|||||||
expo-application:
|
expo-application:
|
||||||
specifier: ~7.0.8
|
specifier: ~7.0.8
|
||||||
version: 7.0.8(expo@54.0.34(@babel/core@7.29.0)(react-native-webview@13.15.0(react-native@0.81.5(patch_hash=2656ac6deb71b92a4df4af4593d13ace6a5740936432e5e7e8ef32bc3cd05194)(@babel/core@7.29.0)(@types/react@19.1.17)(react@19.1.0))(react@19.1.0))(react-native@0.81.5(patch_hash=2656ac6deb71b92a4df4af4593d13ace6a5740936432e5e7e8ef32bc3cd05194)(@babel/core@7.29.0)(@types/react@19.1.17)(react@19.1.0))(react@19.1.0))
|
version: 7.0.8(expo@54.0.34(@babel/core@7.29.0)(react-native-webview@13.15.0(react-native@0.81.5(patch_hash=2656ac6deb71b92a4df4af4593d13ace6a5740936432e5e7e8ef32bc3cd05194)(@babel/core@7.29.0)(@types/react@19.1.17)(react@19.1.0))(react@19.1.0))(react-native@0.81.5(patch_hash=2656ac6deb71b92a4df4af4593d13ace6a5740936432e5e7e8ef32bc3cd05194)(@babel/core@7.29.0)(@types/react@19.1.17)(react@19.1.0))(react@19.1.0))
|
||||||
|
expo-asset:
|
||||||
|
specifier: ~12.0.13
|
||||||
|
version: 12.0.13(expo@54.0.34(@babel/core@7.29.0)(react-native-webview@13.15.0(react-native@0.81.5(patch_hash=2656ac6deb71b92a4df4af4593d13ace6a5740936432e5e7e8ef32bc3cd05194)(@babel/core@7.29.0)(@types/react@19.1.17)(react@19.1.0))(react@19.1.0))(react-native@0.81.5(patch_hash=2656ac6deb71b92a4df4af4593d13ace6a5740936432e5e7e8ef32bc3cd05194)(@babel/core@7.29.0)(@types/react@19.1.17)(react@19.1.0))(react@19.1.0))(react-native@0.81.5(patch_hash=2656ac6deb71b92a4df4af4593d13ace6a5740936432e5e7e8ef32bc3cd05194)(@babel/core@7.29.0)(@types/react@19.1.17)(react@19.1.0))(react@19.1.0)
|
||||||
expo-blur:
|
expo-blur:
|
||||||
specifier: ~15.0.8
|
specifier: ~15.0.8
|
||||||
version: 15.0.8(expo@54.0.34(@babel/core@7.29.0)(react-native-webview@13.15.0(react-native@0.81.5(patch_hash=2656ac6deb71b92a4df4af4593d13ace6a5740936432e5e7e8ef32bc3cd05194)(@babel/core@7.29.0)(@types/react@19.1.17)(react@19.1.0))(react@19.1.0))(react-native@0.81.5(patch_hash=2656ac6deb71b92a4df4af4593d13ace6a5740936432e5e7e8ef32bc3cd05194)(@babel/core@7.29.0)(@types/react@19.1.17)(react@19.1.0))(react@19.1.0))(react-native@0.81.5(patch_hash=2656ac6deb71b92a4df4af4593d13ace6a5740936432e5e7e8ef32bc3cd05194)(@babel/core@7.29.0)(@types/react@19.1.17)(react@19.1.0))(react@19.1.0)
|
version: 15.0.8(expo@54.0.34(@babel/core@7.29.0)(react-native-webview@13.15.0(react-native@0.81.5(patch_hash=2656ac6deb71b92a4df4af4593d13ace6a5740936432e5e7e8ef32bc3cd05194)(@babel/core@7.29.0)(@types/react@19.1.17)(react@19.1.0))(react@19.1.0))(react-native@0.81.5(patch_hash=2656ac6deb71b92a4df4af4593d13ace6a5740936432e5e7e8ef32bc3cd05194)(@babel/core@7.29.0)(@types/react@19.1.17)(react@19.1.0))(react@19.1.0))(react-native@0.81.5(patch_hash=2656ac6deb71b92a4df4af4593d13ace6a5740936432e5e7e8ef32bc3cd05194)(@babel/core@7.29.0)(@types/react@19.1.17)(react@19.1.0))(react@19.1.0)
|
||||||
|
|||||||
@@ -249,7 +249,23 @@ function Inner(props: ReportDialogProps) {
|
|||||||
} finally {
|
} finally {
|
||||||
setIsPending(false)
|
setIsPending(false)
|
||||||
}
|
}
|
||||||
}, [logger, submitReport, props, state, ax, l])
|
/*
|
||||||
|
* Depend on the specific props members used, not the whole props object.
|
||||||
|
* props is a new object every render, so depending on it recreates this
|
||||||
|
* callback each render, which on Android tears down the pending
|
||||||
|
* setTimeout(close) before it fires and the dialog never closes on the
|
||||||
|
* fast submit path (APP-1999).
|
||||||
|
*/
|
||||||
|
}, [
|
||||||
|
logger,
|
||||||
|
submitReport,
|
||||||
|
props.subject,
|
||||||
|
props.control,
|
||||||
|
props.onAfterSubmit,
|
||||||
|
state,
|
||||||
|
ax,
|
||||||
|
l,
|
||||||
|
])
|
||||||
|
|
||||||
useCallOnce(() => {
|
useCallOnce(() => {
|
||||||
ax.metric('reportDialog:open', {
|
ax.metric('reportDialog:open', {
|
||||||
|
|||||||
@@ -1,3 +1,4 @@
|
|||||||
|
import {Asset} from 'expo-asset'
|
||||||
import {
|
import {
|
||||||
documentDirectory,
|
documentDirectory,
|
||||||
getInfoAsync,
|
getInfoAsync,
|
||||||
@@ -13,17 +14,6 @@ import {IS_ANDROID} from '#/env'
|
|||||||
import {compressIfNeeded} from './manip'
|
import {compressIfNeeded} from './manip'
|
||||||
import {type PickerImage} from './picker.shared'
|
import {type PickerImage} from './picker.shared'
|
||||||
|
|
||||||
/*
|
|
||||||
* The Android emulator can't reach the iOS simulator's sample photo library,
|
|
||||||
* so run-nightly-e2e.sh seeds a single jpg into the app's external files
|
|
||||||
* directory before the flows run. That directory is world-readable via the
|
|
||||||
* emulator's sdcardfs, so expo-file-system can read it without any runtime
|
|
||||||
* media permission (unlike /sdcard/DCIM, which is gated behind scoped storage
|
|
||||||
* on target SDK 35).
|
|
||||||
*/
|
|
||||||
const ANDROID_E2E_MEDIA_DIR =
|
|
||||||
'file:///sdcard/Android/data/xyz.blueskyweb.app/files/e2e'
|
|
||||||
|
|
||||||
async function getFile() {
|
async function getFile() {
|
||||||
if (IS_ANDROID) {
|
if (IS_ANDROID) {
|
||||||
return await getAndroidFile()
|
return await getAndroidFile()
|
||||||
@@ -57,25 +47,35 @@ async function getFile() {
|
|||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* The Android emulator can't reach the iOS simulator's sample photo library,
|
||||||
|
* so we load a jpg bundled with the app instead. It is bundled via require()
|
||||||
|
* (resolved by Metro), so it survives `pm clear`, which Maestro's clearState
|
||||||
|
* runs at the start of every flow. An adb-seeded file in app-scoped external
|
||||||
|
* storage does not survive: pm clear wipes that directory each flow, so the
|
||||||
|
* seeded file is gone before the picker mock ever reads it.
|
||||||
|
*/
|
||||||
async function getAndroidFile() {
|
async function getAndroidFile() {
|
||||||
let files = await readDirectoryAsync(ANDROID_E2E_MEDIA_DIR)
|
const asset = Asset.fromModule(
|
||||||
files = files.filter(file => file.toLowerCase().endsWith('.jpg'))
|
require('../../../assets/images/welcome-modal-bg.jpg'),
|
||||||
const file = `${ANDROID_E2E_MEDIA_DIR}/${files[0]}`
|
)
|
||||||
|
await asset.downloadAsync()
|
||||||
|
|
||||||
const fileInfo = await getInfoAsync(file)
|
const path = asset.localUri!
|
||||||
|
const fileInfo = await getInfoAsync(path)
|
||||||
|
|
||||||
if (!fileInfo.exists) {
|
if (!fileInfo.exists) {
|
||||||
throw new Error('Failed to get file info')
|
throw new Error('Failed to get file info')
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Dimensions of the seeded asset (assets/images/welcome-modal-bg.jpg). Only
|
* Dimensions of the bundled asset (assets/images/welcome-modal-bg.jpg). Only
|
||||||
* used for downstream aspect-ratio display; the actual bytes are read from
|
* used for downstream aspect-ratio display; the actual bytes are read from
|
||||||
* disk by compressIfNeeded.
|
* disk by compressIfNeeded.
|
||||||
*/
|
*/
|
||||||
return await compressIfNeeded(
|
return await compressIfNeeded(
|
||||||
{
|
{
|
||||||
path: file,
|
path,
|
||||||
mime: 'image/jpeg',
|
mime: 'image/jpeg',
|
||||||
size: fileInfo.size,
|
size: fileInfo.size,
|
||||||
width: 1432,
|
width: 1432,
|
||||||
|
|||||||
Reference in New Issue
Block a user