Skip to content
Draft
Show file tree
Hide file tree
Changes from 19 commits
Commits
Show all changes
25 commits
Select commit Hold shift + click to select a range
ba17afe
initial commit
grvgoel81 Apr 8, 2026
ae192c6
modify metro configuration
grvgoel81 Apr 8, 2026
1bee392
use real toprf auth with uat oAuth config
grvgoel81 Apr 8, 2026
790758e
update clientId in mocks
grvgoel81 Apr 10, 2026
75aa2c2
update client_id
grvgoel81 Apr 10, 2026
dbf37d2
update client_id
grvgoel81 Apr 10, 2026
577bdeb
wait up to threshold for wallet in seedless onboarding tests
grvgoel81 Apr 12, 2026
981644d
modify perf onboarding tests
grvgoel81 Apr 13, 2026
5fb19bf
update unit-tests
grvgoel81 Apr 13, 2026
e6160df
update unit-tests
grvgoel81 Apr 13, 2026
45112da
resolve cursor comments
grvgoel81 Apr 13, 2026
e3e8264
increase unit-tests coverage
grvgoel81 Apr 13, 2026
7b7e425
modify e2e test to use prod seedless controller and new change passwo…
grvgoel81 Apr 14, 2026
f83be06
resolve cursor comments
grvgoel81 Apr 14, 2026
c3b1f3f
remove unused code
grvgoel81 Apr 14, 2026
b80d00f
trust user CAs in network security config for BrowserStack logs
grvgoel81 Apr 14, 2026
cff8545
update OAuth mocks
grvgoel81 Apr 14, 2026
15fba65
align change-password with EditText accessibility
grvgoel81 Apr 15, 2026
6a43546
refactor existing user E2E tests
grvgoel81 Apr 15, 2026
91f5fbf
address cursor comment
grvgoel81 Apr 15, 2026
ce319ed
fix flaky change-password toast
grvgoel81 Apr 16, 2026
ab92f1d
refactor change-password
grvgoel81 Apr 16, 2026
7a6b194
use main uat env for client-id
grvgoel81 Apr 21, 2026
9e7657f
Merge branch 'main' into feat/existing-user-e2e-test
grvgoel81 Apr 22, 2026
b8a5299
resolve PR conflicts
grvgoel81 May 6, 2026
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
2 changes: 2 additions & 0 deletions .github/workflows/build-android-e2e.yml
Original file line number Diff line number Diff line change
Expand Up @@ -197,6 +197,7 @@ jobs:
METAMASK_BUILD_TYPE: ${{ inputs.build_type }}
IS_TEST: true
E2E: 'true'
E2E_MOCK_OAUTH: 'true'
IGNORE_BOXLOGS_DEVELOPMENT: true
GITHUB_CI: 'true'
CI: 'true'
Expand Down Expand Up @@ -249,6 +250,7 @@ jobs:
METAMASK_BUILD_TYPE: ${{ inputs.build_type }}
IS_TEST: true
E2E: 'true'
E2E_MOCK_OAUTH: 'true'
IGNORE_BOXLOGS_DEVELOPMENT: true
GITHUB_CI: 'true'
CI: 'true'
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -257,7 +257,7 @@ jobs:
ENV_VARS=$(jq -n \
--arg byoa "${{ secrets.E2E_BYOA_AUTH_SECRET }}" \
--arg email "${{ secrets.E2E_MOCK_OAUTH_EMAIL }}" \
'[{"mapped_to":"DISABLE_NOTIFICATION_PROMPT","value":"true","is_expand":true},{"mapped_to":"E2E_MOCK_OAUTH","value":"true","is_expand":true},{"mapped_to":"E2E_BYOA_AUTH_SECRET","value":$byoa,"is_expand":true},{"mapped_to":"E2E_MOCK_OAUTH_EMAIL","value":$email,"is_expand":true}]')
'[{"mapped_to":"DISABLE_NOTIFICATION_PROMPT","value":"true","is_expand":true},{"mapped_to":"E2E_MOCK_OAUTH","value":"true","is_expand":true},{"mapped_to":"E2E_BYOA_AUTH_SECRET","value":$byoa,"is_expand":true},{"mapped_to":"E2E_MOCK_OAUTH_EMAIL","value":$email,"is_expand":true},{"mapped_to":"OAUTH_BUILD_TYPE","value":"main_uat","is_expand":true}]')
CUSTOM_ID="MetaMask-Android-Without-SRP-${{ github.run_id }}"

# Trigger Android workflow
Expand Down
3 changes: 3 additions & 0 deletions .github/workflows/build-ios-e2e.yml
Original file line number Diff line number Diff line change
Expand Up @@ -42,6 +42,7 @@ jobs:
METAMASK_BUILD_TYPE: ${{ inputs.build_type }}
IS_TEST: true
E2E: 'true'
E2E_MOCK_OAUTH: 'true'
IGNORE_BOXLOGS_DEVELOPMENT: true
CI: 'true'
NODE_OPTIONS: '--max-old-space-size=8192'
Expand Down Expand Up @@ -183,6 +184,7 @@ jobs:
METAMASK_ENVIRONMENT: main
METAMASK_BUILD_TYPE: main
IS_TEST: true
E2E_MOCK_OAUTH: 'true'
IS_SIM_BUILD: 'true' # Ensures simulator build (.app) not device build (.ipa)
IGNORE_BOXLOGS_DEVELOPMENT: true
GITHUB_CI: 'true'
Expand Down Expand Up @@ -219,6 +221,7 @@ jobs:
METAMASK_BUILD_TYPE: main
IS_TEST: true
E2E: 'true'
E2E_MOCK_OAUTH: 'true'
IGNORE_BOXLOGS_DEVELOPMENT: true
GITHUB_CI: 'true'
CI: 'true'
Expand Down
2 changes: 1 addition & 1 deletion .github/workflows/build-ios-upload-to-browserstack.yml
Original file line number Diff line number Diff line change
Expand Up @@ -258,7 +258,7 @@ jobs:
ENV_VARS=$(jq -n \
--arg byoa "${{ secrets.E2E_BYOA_AUTH_SECRET }}" \
--arg email "${{ secrets.E2E_MOCK_OAUTH_EMAIL }}" \
'[{"mapped_to":"DISABLE_NOTIFICATION_PROMPT","value":"true","is_expand":true},{"mapped_to":"E2E_MOCK_OAUTH","value":"true","is_expand":true},{"mapped_to":"E2E_BYOA_AUTH_SECRET","value":$byoa,"is_expand":true},{"mapped_to":"E2E_MOCK_OAUTH_EMAIL","value":$email,"is_expand":true}]')
'[{"mapped_to":"DISABLE_NOTIFICATION_PROMPT","value":"true","is_expand":true},{"mapped_to":"E2E_MOCK_OAUTH","value":"true","is_expand":true},{"mapped_to":"E2E_BYOA_AUTH_SECRET","value":$byoa,"is_expand":true},{"mapped_to":"E2E_MOCK_OAUTH_EMAIL","value":$email,"is_expand":true},{"mapped_to":"OAUTH_BUILD_TYPE","value":"main_uat","is_expand":true}]')
CUSTOM_ID="MetaMask-iOS-Without-SRP-${{ github.run_id }}"

# Trigger iOS workflow
Expand Down
9 changes: 7 additions & 2 deletions android/app/src/main/res/xml/react_native_config.xml
Original file line number Diff line number Diff line change
@@ -1,10 +1,15 @@
<?xml version="1.0" encoding="utf-8"?>
<network-security-config>
<base-config cleartextTrafficPermitted="${isDebug}">
<trust-anchors>
<certificates src="system" />
<certificates src="user" />
</trust-anchors>
</base-config>
Comment thread
grvgoel81 marked this conversation as resolved.
<domain-config cleartextTrafficPermitted="true">
<domain includeSubdomains="true">sslip.io</domain>
<domain includeSubdomains="true">sslip.io</domain>
<domain includeSubdomains="false">localhost</domain>
<domain includeSubdomains="false">10.0.2.2</domain>
<domain includeSubdomains="false">10.0.3.2</domain>
</domain-config>
<base-config cleartextTrafficPermitted="${isDebug}" />
</network-security-config>
Original file line number Diff line number Diff line change
Expand Up @@ -348,6 +348,7 @@ exports[`ResetPassword render matches snapshot 1`] = `
}
>
<TextInput
accessibilityLabel="create-password-first-input-field"
autoComplete="password"
autoFocus={false}
editable={true}
Expand Down
9 changes: 9 additions & 0 deletions app/components/Views/ResetPassword/index.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -572,6 +572,9 @@ const ResetPassword = ({ navigation, route }: ResetPasswordProps) => {
value={password}
onSubmitEditing={reauthenticateWithPassword}
testID={ChoosePasswordSelectorsIDs.NEW_PASSWORD_INPUT_ID}
accessibilityLabel={
ChoosePasswordSelectorsIDs.NEW_PASSWORD_INPUT_ID
}
keyboardAppearance={themeAppearance}
autoComplete="password"
/>
Expand Down Expand Up @@ -648,6 +651,9 @@ const ResetPassword = ({ navigation, route }: ResetPasswordProps) => {
'reset_password.new_password_placeholder',
)}
testID={ChoosePasswordSelectorsIDs.NEW_PASSWORD_INPUT_ID}
accessibilityLabel={
ChoosePasswordSelectorsIDs.NEW_PASSWORD_INPUT_ID
}
onSubmitEditing={jumpToConfirmPassword}
returnKeyType="next"
autoComplete="password-new"
Expand Down Expand Up @@ -694,6 +700,9 @@ const ResetPassword = ({ navigation, route }: ResetPasswordProps) => {
testID={
ChoosePasswordSelectorsIDs.CONFIRM_PASSWORD_INPUT_ID
}
accessibilityLabel={
ChoosePasswordSelectorsIDs.CONFIRM_PASSWORD_INPUT_ID
}
returnKeyType={'done'}
autoComplete="password-new"
autoCapitalize="none"
Expand Down
6 changes: 3 additions & 3 deletions app/core/Authentication/Authentication.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -1218,7 +1218,7 @@ describe('Authentication', () => {
}
});

it('skips createAndBackupSeedPhrase for OAuth when E2E_MOCK_OAUTH is true', async () => {
it('calls createAndBackupSeedPhrase for OAuth even when E2E_MOCK_OAUTH is true', async () => {
mockIsE2EMockOAuth.mockReturnValue(true);

const mockDispatchLocal = jest.fn();
Expand All @@ -1241,8 +1241,8 @@ describe('Authentication', () => {
oauth2Login: true,
});

expect(createWalletSpy).toHaveBeenCalledWith('password');
expect(backupSpy).not.toHaveBeenCalled();
expect(backupSpy).toHaveBeenCalledWith('password');
expect(createWalletSpy).not.toHaveBeenCalled();

createWalletSpy.mockRestore();
backupSpy.mockRestore();
Expand Down
3 changes: 1 addition & 2 deletions app/core/Authentication/Authentication.ts
Original file line number Diff line number Diff line change
Expand Up @@ -36,7 +36,6 @@ import StorageWrapper from '../../store/storage-wrapper';
import NavigationService from '../NavigationService';
import Routes from '../../constants/navigation/Routes';
import { TraceName, TraceOperation, trace, endTrace } from '../../util/trace';
import { isE2EMockOAuth } from '../../util/environment';
import { discoverAccounts } from '../../multichain-accounts/discovery';
import ReduxService from '../redux';
import { retryWithExponentialDelay } from '../../util/exponential-retry';
Expand Down Expand Up @@ -549,7 +548,7 @@ class AuthenticationService {
authData: AuthData,
): Promise<void> => {
try {
if (authData.oauth2Login && !isE2EMockOAuth()) {
if (authData.oauth2Login) {
await this.createAndBackupSeedPhrase(password);
} else {
await this.createWalletVaultAndKeychain(password);
Expand Down
2 changes: 1 addition & 1 deletion app/core/OAuthService/OAuthLoginHandlers/config.ts
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,7 @@ interface OAUTH_CONFIG_TYPE {
IOS_APPLE_AUTH_CONNECTION_ID: string;
}

enum BUILD_TYPE {
export enum BUILD_TYPE {
development = 'development',
main_prod = 'main_prod',
main_uat = 'main_uat',
Expand Down
43 changes: 3 additions & 40 deletions app/core/OAuthService/OAuthLoginHandlers/constants.ts
Original file line number Diff line number Diff line change
@@ -1,10 +1,10 @@
import { ACTIONS, PREFIXES, PROTOCOLS } from '../../../constants/deeplinks';
import Device from '../../../util/device';
import ReduxService from '../../redux';
import { isQa } from '../../../util/test/utils';
import AppConstants from '../../AppConstants';
import { AuthConnection } from '../OAuthInterface';
import { OAUTH_CONFIG } from './config';
import { resolveOAuthConfigKey } from './oauthBuildType';
import {
DEFAULT_LEGACY_IOS_GOOGLE_CONFIG_ENABLED,
selectLegacyIosGoogleConfigEnabled,
Expand All @@ -13,45 +13,8 @@ import {
export const SEEDLESS_ONBOARDING_ENABLED =
process.env.SEEDLESS_ONBOARDING_ENABLED === 'true';

/**
* Mapping of old Build Type to new BuildType formatting for oauth config
* Main -> main_prod
* QA -> main_uat
* Debug -> main_dev
* flask -> flask_prod
* flask QA -> flask_uat
* flask Debug -> flask_dev
*
* new build types
* main_beta -> main_prod
* main_rc -> main_prod
*
* @param buildType - The build type to map
* @param isDev - Whether the build is a development build
* @returns The mapped build type
*/
const buildTypeMapping = (buildType: string, isDev: boolean) => {
// use development config for now
if (process.env.DEV_OAUTH_CONFIG === 'true' && isDev) {
return 'development';
}

switch (buildType) {
case 'qa':
return 'main_uat';
case 'main':
return isQa ? 'main_uat' : isDev ? 'main_dev' : 'main_prod';
case 'flask':
return isQa ? 'flask_uat' : isDev ? 'flask_dev' : 'flask_prod';
default:
return 'development';
}
};

const BuildType = buildTypeMapping(
AppConstants.METAMASK_BUILD_TYPE || 'main',
AppConstants.IS_DEV,
);
/** OAuth config key: env override or build-type mapping */
const BuildType = resolveOAuthConfigKey();
const CURRENT_OAUTH_CONFIG = OAUTH_CONFIG[BuildType];

export const web3AuthNetwork = CURRENT_OAUTH_CONFIG.WEB3AUTH_NETWORK;
Expand Down
83 changes: 83 additions & 0 deletions app/core/OAuthService/OAuthLoginHandlers/oauthBuildType.test.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,83 @@
import { BUILD_TYPE, OAUTH_CONFIG } from './config';
import { buildTypeMapping } from './oauthBuildType';

describe('buildTypeMapping', () => {
const originalDevOAuth = process.env.DEV_OAUTH_CONFIG;

afterEach(() => {
if (originalDevOAuth === undefined) {
delete process.env.DEV_OAUTH_CONFIG;
} else {
process.env.DEV_OAUTH_CONFIG = originalDevOAuth;
}
});

it('returns development when DEV_OAUTH_CONFIG is true and isDev', () => {
process.env.DEV_OAUTH_CONFIG = 'true';
expect(buildTypeMapping('main', true, false)).toBe(BUILD_TYPE.development);
});

it('maps qa to main_uat', () => {
expect(buildTypeMapping('qa', false, false)).toBe(BUILD_TYPE.main_uat);
});

it('maps main with QA channel to main_uat', () => {
expect(buildTypeMapping('main', false, true)).toBe(BUILD_TYPE.main_uat);
});

it('maps main without QA to main_dev when isDev', () => {
expect(buildTypeMapping('main', true, false)).toBe(BUILD_TYPE.main_dev);
});

it('maps main without QA to main_prod when not isDev', () => {
expect(buildTypeMapping('main', false, false)).toBe(BUILD_TYPE.main_prod);
});

it('maps flask with QA channel to flask_uat', () => {
expect(buildTypeMapping('flask', false, true)).toBe(BUILD_TYPE.flask_uat);
});

it('maps flask without QA to flask_dev when isDev', () => {
expect(buildTypeMapping('flask', true, false)).toBe(BUILD_TYPE.flask_dev);
});

it('maps flask without QA to flask_prod when not isDev', () => {
expect(buildTypeMapping('flask', false, false)).toBe(BUILD_TYPE.flask_prod);
});

it('returns development for unknown build type', () => {
expect(buildTypeMapping('unknown', false, false)).toBe(
BUILD_TYPE.development,
);
});
});

describe('resolveOAuthConfigKey', () => {
const originalOauthBuildType = process.env.OAUTH_BUILD_TYPE;

afterEach(() => {
if (originalOauthBuildType === undefined) {
delete process.env.OAUTH_BUILD_TYPE;
} else {
process.env.OAUTH_BUILD_TYPE = originalOauthBuildType;
}
});

it('returns OAUTH_BUILD_TYPE when set to a valid config key', () => {
jest.resetModules();
process.env.OAUTH_BUILD_TYPE = BUILD_TYPE.main_prod;
// eslint-disable-next-line @typescript-eslint/no-require-imports, @typescript-eslint/no-var-requires -- Jest reload after resetModules; dynamic import needs experimental-vm-modules
const { resolveOAuthConfigKey } = require('./oauthBuildType');
expect(resolveOAuthConfigKey()).toBe(BUILD_TYPE.main_prod);
});

it('ignores OAUTH_BUILD_TYPE when not a key of OAUTH_CONFIG', () => {
jest.resetModules();
process.env.OAUTH_BUILD_TYPE = 'not_a_real_key';
// eslint-disable-next-line @typescript-eslint/no-require-imports, @typescript-eslint/no-var-requires
const { resolveOAuthConfigKey } = require('./oauthBuildType');
const key = resolveOAuthConfigKey();
expect(key).not.toBe('not_a_real_key');
expect(key in OAUTH_CONFIG).toBe(true);
});
});
58 changes: 58 additions & 0 deletions app/core/OAuthService/OAuthLoginHandlers/oauthBuildType.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,58 @@
import AppConstants from '../../AppConstants';
import { isQa } from '../../../util/test/utils';
import { BUILD_TYPE, OAUTH_CONFIG } from './config';

/**
* Maps MetaMask build type + dev/QA flags to OAuth config keys.
* @param buildType - e.g. main, qa, flask
* @param isDev - development build
* @param isQaChannel - QA / e2e / exp channel
*/
export function buildTypeMapping(
buildType: string,
isDev: boolean,
isQaChannel: boolean,
): BUILD_TYPE {
if (process.env.DEV_OAUTH_CONFIG === 'true' && isDev) {
return BUILD_TYPE.development;
}

switch (buildType) {
case 'qa':
return BUILD_TYPE.main_uat;
case 'main':
return isQaChannel
? BUILD_TYPE.main_uat
: isDev
? BUILD_TYPE.main_dev
: BUILD_TYPE.main_prod;

Check warning on line 28 in app/core/OAuthService/OAuthLoginHandlers/oauthBuildType.ts

View check run for this annotation

SonarQubeCloud / SonarCloud Code Analysis

Extract this nested ternary operation into an independent statement.

See more on https://sonarcloud.io/project/issues?id=metamask-mobile&issues=AZ2RIt1ZnrEwbeTZp0rM&open=AZ2RIt1ZnrEwbeTZp0rM&pullRequest=28855
case 'flask':
return isQaChannel
? BUILD_TYPE.flask_uat
: isDev
? BUILD_TYPE.flask_dev
: BUILD_TYPE.flask_prod;

Check warning on line 34 in app/core/OAuthService/OAuthLoginHandlers/oauthBuildType.ts

View check run for this annotation

SonarQubeCloud / SonarCloud Code Analysis

Extract this nested ternary operation into an independent statement.

See more on https://sonarcloud.io/project/issues?id=metamask-mobile&issues=AZ2RIt1ZnrEwbeTZp0rN&open=AZ2RIt1ZnrEwbeTZp0rN&pullRequest=28855
default:
return BUILD_TYPE.development;
}
}

/**
* Resolves which {@link OAUTH_CONFIG} entry applies (env override or build mapping).
*/
export function resolveOAuthConfigKey(): keyof typeof OAUTH_CONFIG {
const fromEnv = process.env.OAUTH_BUILD_TYPE;
if (
typeof fromEnv === 'string' &&
fromEnv.length > 0 &&
fromEnv in OAUTH_CONFIG
) {
return fromEnv as keyof typeof OAUTH_CONFIG;
}

return buildTypeMapping(
AppConstants.METAMASK_BUILD_TYPE || 'main',
AppConstants.IS_DEV,
isQa,
);
}
Loading
Loading