Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
21 changes: 1 addition & 20 deletions .github/workflows/build-android-e2e.yml
Original file line number Diff line number Diff line change
Expand Up @@ -9,9 +9,6 @@ on:
apk-uploaded:
description: 'Whether the APK was successfully uploaded'
value: ${{ jobs.build-android-apks.outputs.apk-uploaded }}
aab-uploaded:
description: 'Whether the AAB was successfully uploaded'
value: ${{ jobs.build-android-apks.outputs.aab-uploaded }}
inputs:
build_type:
description: 'The type of build to perform'
Expand All @@ -32,17 +29,15 @@ on:
jobs:
build-android-apks:
name: Build Android E2E APKs
runs-on: ghcr.io/cirruslabs/ubuntu-runner-amd64:24.04-xl # Bumped from lg to xl to prevent Daemon disappearance issue (Daemon OOM issue in CI)
runs-on: ghcr.io/cirruslabs/ubuntu-runner-amd64:24.04-lg # lg runner: 16 vCPUs, 48GB RAM
timeout-minutes: 40
env:
GRADLE_USER_HOME: /home/admin/_work/.gradle
CACHE_GENERATION: v1 # Increment this to bust the cache (v1, v2, v3, etc.)
outputs:
apk-uploaded: ${{ steps.upload-apk.outcome == 'success' }}
aab-uploaded: ${{ steps.upload-aab.outcome == 'success' }}
apk-target-path: ${{ steps.determine-target-paths.outputs.apk-target-path }}
test-apk-target-path: ${{ steps.determine-target-paths.outputs.test-apk-target-path }}
aab-target-path: ${{ steps.determine-target-paths.outputs.aab-target-path }}
artifact_name: ${{ steps.determine-target-paths.outputs.artifact_name }}

steps:
Expand Down Expand Up @@ -88,14 +83,12 @@ jobs:
{
echo "apk-target-path=android/app/build/outputs/apk/flask/release"
echo "test-apk-target-path=android/app/build/outputs/apk/androidTest/flask/release"
echo "aab-target-path=android/app/build/outputs/bundle/flaskRelease"
echo "artifact_name=app-flask-release"
} >> "$GITHUB_OUTPUT"
elif [[ "${{ inputs.build_type }}" == "main" ]]; then
{
echo "apk-target-path=android/app/build/outputs/apk/prod/release"
echo "test-apk-target-path=android/app/build/outputs/apk/androidTest/prod/release"
echo "aab-target-path=android/app/build/outputs/bundle/prodRelease"
echo "artifact_name=app-prod-release"
} >> "$GITHUB_OUTPUT"
else
Expand All @@ -110,7 +103,6 @@ jobs:
path: |
${{ steps.determine-target-paths.outputs.apk-target-path }}/${{ steps.determine-target-paths.outputs.artifact_name }}.apk
${{ steps.determine-target-paths.outputs.test-apk-target-path }}/${{ steps.determine-target-paths.outputs.artifact_name }}-androidTest.apk
${{ steps.determine-target-paths.outputs.aab-target-path }}/${{ steps.determine-target-paths.outputs.artifact_name }}.aab
# Include Gradle properties in key to force rebuild when properties change
# Keep the `hashFiles` call for Gradle config in-sync with these steps:
# - "Cache Gradle dependencies"
Expand Down Expand Up @@ -241,7 +233,6 @@ jobs:
path: |
${{ steps.determine-target-paths.outputs.apk-target-path }}/${{ steps.determine-target-paths.outputs.artifact_name }}.apk
${{ steps.determine-target-paths.outputs.test-apk-target-path }}/${{ steps.determine-target-paths.outputs.artifact_name }}-androidTest.apk
${{ steps.determine-target-paths.outputs.aab-target-path }}/${{ steps.determine-target-paths.outputs.artifact_name }}.aab
# Keep the `hashFiles` call for Gradle config in-sync with these steps:
# - "Check and restore cached APKs if Fingerprint is found"
# - "Cache Gradle dependencies"
Expand All @@ -264,13 +255,3 @@ jobs:
path: ${{ steps.determine-target-paths.outputs.test-apk-target-path }}/${{ steps.determine-target-paths.outputs.artifact_name }}-androidTest.apk
retention-days: 7
if-no-files-found: error

- name: Upload Android AAB
id: upload-aab
uses: actions/upload-artifact@v4
with:
name: ${{ inputs.build_type }}-${{ inputs.metamask_environment }}-release.aab
path: ${{ steps.determine-target-paths.outputs.aab-target-path }}/${{ steps.determine-target-paths.outputs.artifact_name }}.aab
retention-days: 7
if-no-files-found: warn
continue-on-error: true
4 changes: 0 additions & 4 deletions .github/workflows/run-e2e-workflow.yml
Original file line number Diff line number Diff line change
Expand Up @@ -56,7 +56,6 @@ jobs:
outputs:
apk-target-path: ${{ steps.determine-target-paths.outputs.apk-target-path }}
test-apk-target-path: ${{ steps.determine-target-paths.outputs.test-apk-target-path }}
aab-target-path: ${{ steps.determine-target-paths.outputs.aab-target-path }}

env:
PREBUILT_IOS_APP_PATH: artifacts/MetaMask.app
Expand Down Expand Up @@ -131,14 +130,12 @@ jobs:
{
echo "apk-target-path=android/app/build/outputs/apk/flask/release"
echo "test-apk-target-path=android/app/build/outputs/apk/androidTest/flask/release"
echo "aab-target-path=android/app/build/outputs/bundle/flaskRelease"
echo "artifact_name=app-flask-release"
} >> "$GITHUB_OUTPUT"
elif [[ "${{ inputs.build_type }}" == "main" ]]; then
{
echo "apk-target-path=android/app/build/outputs/apk/prod/release"
echo "test-apk-target-path=android/app/build/outputs/apk/androidTest/prod/release"
echo "aab-target-path=android/app/build/outputs/bundle/prodRelease"
echo "artifact_name=app-prod-release"
} >> "$GITHUB_OUTPUT"
else
Expand All @@ -152,7 +149,6 @@ jobs:
echo "🏗 Setting up Android artifacts from build job..."
mkdir -p ${{ steps.determine-target-paths.outputs.apk-target-path }}
mkdir -p ${{ steps.determine-target-paths.outputs.test-apk-target-path }}
mkdir -p ${{ steps.determine-target-paths.outputs.aab-target-path }}

- name: Download Android build artifacts
if: ${{ inputs.platform == 'android' }}
Expand Down
14 changes: 7 additions & 7 deletions android/gradle.properties.github
Original file line number Diff line number Diff line change
@@ -1,16 +1,16 @@
# GitHub Actions-specific Gradle settings
# Optimized for E2E builds on GitHub Actions runners

# JVM configuration - balanced settings to avoid OOM while maintaining performance
# Using 16GB heap to leave room for parallel workers and native memory
org.gradle.jvmargs=-Xmx16g -XX:MaxMetaspaceSize=1g -XX:+UseG1GC -XX:G1HeapRegionSize=16m -XX:+UseStringDeduplication -XX:+OptimizeStringConcat
# JVM configuration - tuned for 48GB runner to avoid OOM while maintaining performance
# Heap: 12GB to leave room for Node.js/Metro and native memory
# ExitOnOutOfMemoryError: fail-fast on OOM for CI
org.gradle.jvmargs=-Xmx12g -Xms4g -XX:MaxMetaspaceSize=1g -XX:+UseG1GC -XX:G1HeapRegionSize=16m -XX:+UseStringDeduplication -XX:MaxGCPauseMillis=500 -XX:+ExitOnOutOfMemoryError -Dfile.encoding=UTF-8

# Enable performance optimizations but limit parallelism to prevent OOM
org.gradle.parallel=true
org.gradle.configureondemand=true
org.gradle.caching=true
org.gradle.daemon=true
org.gradle.workers.max=6
org.gradle.daemon=false
org.gradle.workers.max=2
org.gradle.vfs.watch=false

# CI-specific optimizations - enabled for GitHub Actions
Expand Down Expand Up @@ -54,4 +54,4 @@ hermesEnabled=true
android.disableResourceValidation=true

# Use legacy packaging to compress native libraries in the resulting APK.
expo.useLegacyPackaging=false
expo.useLegacyPackaging=false
69 changes: 67 additions & 2 deletions app/components/Nav/Main/MainNavigator.js
Original file line number Diff line number Diff line change
Expand Up @@ -1080,10 +1080,43 @@ const MainNavigator = () => {
component={NotificationsModeView}
/>
<Stack.Screen name={Routes.QR_TAB_SWITCHER} component={QRTabSwitcher} />
<Stack.Screen name="NftDetails" component={NftDetailsModeView} />
<Stack.Screen
name="NftDetails"
component={NftDetailsModeView}
options={{
animationEnabled: true,
cardStyleInterpolator: ({ current, layouts }) => ({
cardStyle: {
transform: [
{
translateX: current.progress.interpolate({
inputRange: [0, 1],
outputRange: [layouts.screen.width, 0],
}),
},
],
},
}),
}}
/>
<Stack.Screen
name="NftDetailsFullImage"
component={NftDetailsFullImageModeView}
options={{
animationEnabled: true,
cardStyleInterpolator: ({ current, layouts }) => ({
cardStyle: {
transform: [
{
translateX: current.progress.interpolate({
inputRange: [0, 1],
outputRange: [layouts.screen.width, 0],
}),
},
],
},
}),
}}
/>
<Stack.Screen
name={Routes.WALLET.NFTS_FULL_VIEW}
Expand All @@ -1108,7 +1141,26 @@ const MainNavigator = () => {
component={BridgeModalStack}
options={clearStackNavigatorOptions}
/>
<Stack.Screen name="StakeScreens" component={StakeScreenStack} />
<Stack.Screen
name="StakeScreens"
component={StakeScreenStack}
options={{
headerShown: false,
animationEnabled: true,
cardStyleInterpolator: ({ current, layouts }) => ({
cardStyle: {
transform: [
{
translateX: current.progress.interpolate({
inputRange: [0, 1],
outputRange: [layouts.screen.width, 0],
}),
},
],
},
}),
}}
/>
<Stack.Screen name={Routes.EARN.ROOT} component={EarnScreenStack} />
<Stack.Screen
name={Routes.EARN.MODALS.ROOT}
Expand Down Expand Up @@ -1257,6 +1309,19 @@ const MainNavigator = () => {
component={DeFiProtocolPositionDetails}
options={{
headerShown: true,
animationEnabled: true,
cardStyleInterpolator: ({ current, layouts }) => ({
cardStyle: {
transform: [
{
translateX: current.progress.interpolate({
inputRange: [0, 1],
outputRange: [layouts.screen.width, 0],
}),
},
],
},
}),
}}
/>
{
Expand Down
21 changes: 21 additions & 0 deletions app/components/Nav/Main/__snapshots__/MainNavigator.test.tsx.snap
Original file line number Diff line number Diff line change
Expand Up @@ -131,10 +131,22 @@ exports[`MainNavigator matches rendered snapshot 1`] = `
<Screen
component={[Function]}
name="NftDetails"
options={
{
"animationEnabled": true,
"cardStyleInterpolator": [Function],
}
}
/>
<Screen
component={[Function]}
name="NftDetailsFullImage"
options={
{
"animationEnabled": true,
"cardStyleInterpolator": [Function],
}
}
/>
<Screen
component={[Function]}
Expand Down Expand Up @@ -184,6 +196,13 @@ exports[`MainNavigator matches rendered snapshot 1`] = `
<Screen
component={[Function]}
name="StakeScreens"
options={
{
"animationEnabled": true,
"cardStyleInterpolator": [Function],
"headerShown": false,
}
}
/>
<Screen
component={[Function]}
Expand Down Expand Up @@ -265,6 +284,8 @@ exports[`MainNavigator matches rendered snapshot 1`] = `
name="DeFiProtocolPositionDetails"
options={
{
"animationEnabled": true,
"cardStyleInterpolator": [Function],
"headerShown": true,
}
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -28,7 +28,7 @@ function getInitRequestMock(): jest.Mocked<
requestMock.getController.mockImplementation((name: string) => {
if (name === 'NftController') {
return {
addNft: jest.fn(),
addNfts: jest.fn(),
state: {},
};
}
Expand All @@ -52,7 +52,7 @@ describe('NftDetectionControllerInit', () => {
expect(controllerMock).toHaveBeenCalledWith({
messenger: expect.any(Object),
disabled: false,
addNft: expect.any(Function),
addNfts: expect.any(Function),
getNftState: expect.any(Function),
});
});
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -20,7 +20,7 @@ export const nftDetectionControllerInit: ControllerInitFunction<
const controller = new NftDetectionController({
messenger: controllerMessenger,
disabled: false,
addNft: nftController.addNft.bind(nftController),
addNfts: nftController.addNfts.bind(nftController),
getNftState: () => nftController.state,
});

Expand Down
68 changes: 68 additions & 0 deletions appwright/tests/performance/login/perps-add-funds.spec.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,68 @@
import { test } from '../../../fixtures/performance-test.js';

import TimerHelper from '../../../utils/TimersHelper.js';
import LoginScreen from '../../../../wdio/screen-objects/LoginScreen.js';
import WalletMainScreen from '../../../../wdio/screen-objects/WalletMainScreen.js';
import TabBarModal from '../../../../wdio/screen-objects/Modals/TabBarModal.js';
import WalletActionModal from '../../../../wdio/screen-objects/Modals/WalletActionModal.js';
import PerpsTutorialScreen from '../../../../wdio/screen-objects/PerpsTutorialScreen.js';
import PerpsMarketListView from '../../../../wdio/screen-objects/PerpsMarketListView.js';
import PerpsTabView from '../../../../wdio/screen-objects/PerpsTabView.js';
import PerpsDepositScreen from '../../../../wdio/screen-objects/PerpsDepositScreen.js';
import { login } from '../../../utils/Flows.js';

async function screensSetup(device) {
const screens = [
LoginScreen,
WalletMainScreen,
TabBarModal,
WalletActionModal,
PerpsTutorialScreen,
PerpsMarketListView,
PerpsTabView,
PerpsDepositScreen,
];
screens.forEach((screen) => {
screen.device = device;
});
}

/* Scenario 5: Perps add funds */
test('Perps add funds', async ({ device, performanceTracker }, testInfo) => {
test.setTimeout(10 * 60 * 1000); // 10 minutes

const selectPerpsMainScreenTimer = new TimerHelper(
'Select Perps Main Screen',
);
const openAddFundsTimer = new TimerHelper('Open Add Funds');
const getQuoteTimer = new TimerHelper('Get Quote');
await screensSetup(device);

await login(device);
await TabBarModal.tapActionButton();

// Open Perps Main Screen
selectPerpsMainScreenTimer.start();
await WalletActionModal.tapPerpsButton();
selectPerpsMainScreenTimer.stop();
performanceTracker.addTimer(selectPerpsMainScreenTimer);

// Skip tutorial
await PerpsTutorialScreen.tapSkip();

// Open Add Funds flow
openAddFundsTimer.start();
await PerpsTutorialScreen.tapAddFunds();
await PerpsDepositScreen.isAmountInputVisible();
openAddFundsTimer.stop();
performanceTracker.addTimer(openAddFundsTimer);

// Get quote
getQuoteTimer.start();
await PerpsDepositScreen.fillUsdAmount(5);
await PerpsDepositScreen.isAddFundsVisible();
await PerpsDepositScreen.isTotalVisible();
getQuoteTimer.stop();
performanceTracker.addTimer(getQuoteTimer);
await performanceTracker.attachToTest(testInfo);
});
Loading
Loading