Skip to content

Commit 644f2fd

Browse files
committed
Merge branch 'wsun/create-runway-rc-ios-workflow' into release/test-runway-rc-ios-workflow
2 parents 93bd6ad + 9298e1c commit 644f2fd

750 files changed

Lines changed: 21357 additions & 7247 deletions

File tree

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

.agents/skills/component-view-test/SKILL.md

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -56,6 +56,7 @@ tests/component-view/
5656
├── mocks.ts ← Engine + native mocks (import this first, always)
5757
├── render.tsx ← renderComponentViewScreen, renderScreenWithRoutes
5858
├── stateFixture.ts ← StateFixtureBuilder (createStateFixture)
59+
├── platform.ts ← describeForPlatforms, itForPlatforms (run per iOS/Android)
5960
├── api-mocking/ ← HTTP API mocks (nock) — extensible, one file per feature
6061
├── presets/ ← initialState<Feature>() builders — one file per feature area
6162
└── renderers/ ← render<Feature>View() functions — one file per feature area

.agents/skills/component-view-test/references/writing-tests.md

Lines changed: 32 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -195,6 +195,38 @@ const defaultBridgeWithTokens = (overrides?: Record<string, unknown>) => {
195195

196196
Then each test only specifies its delta from this baseline.
197197

198+
### describe / it and platform (iOS + Android)
199+
200+
Import from `tests/component-view/platform`. All helpers accept an optional **filter** (3rd arg): `'ios'` | `'android'` | `['ios','android']` | `{ only: 'ios' }` | `{ skip: ['android'] }`. Env: `TEST_OS=ios` or `TEST_OS=android` to run only one OS.
201+
202+
| Helper | Use |
203+
| ----------------------------------------------------------------------- | ------------------------------------------------------------------------------------------------------------- |
204+
| `describeForPlatforms(name, define, filter?)` | One describe per OS. Inside, `define({ os })`; use `it()` or `itForPlatforms()` — each runs once per that OS. |
205+
| `itForPlatforms(name, (ctx) => {}, filter?)` | One `it` per OS. Callback receives `{ os }`. |
206+
| `itOnlyForPlatforms(name, fn, filter?)` | Same as `itForPlatforms` but registers `it.only`. |
207+
| `itEach(table)(name, (row) => {}, filter?)` | One `it` per table row × per OS. Use `$key` in name to interpolate row fields. |
208+
| `describeEach(table)(name, (row) => { it('...', () => {}); }, filter?)` | One describe per row × per OS. Use `$key` in name. |
209+
| `getTargetPlatforms(filter?)` | Returns `['ios','android']` (or filtered list) for custom loops. |
210+
211+
Example — `itEach` (each case runs on iOS and Android):
212+
213+
```typescript
214+
import { itEach } from '../../../../../../tests/component-view/platform';
215+
216+
const cases = [
217+
{ name: 'renders empty', amount: '0' },
218+
{ name: 'displays fiat', amount: '1' },
219+
];
220+
itEach(cases)('$name', ({ amount }) => {
221+
const { findByDisplayValue } = renderDefault({
222+
bridge: { sourceAmount: amount },
223+
});
224+
expect(findByDisplayValue(amount)).toBeOnTheScreen();
225+
});
226+
```
227+
228+
Jest modifiers (`it.only`, `it.skip`, `describe.only`, `describe.skip`) work as usual inside these blocks.
229+
198230
### Minimal template
199231

200232
```typescript

.agents/skills/e2e-test/SKILL.md

Lines changed: 13 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,8 @@ name: e2e-test
33
description:
44
Add and fix Detox E2E tests (smoke and regression) for MetaMask Mobile using
55
withFixtures, Page Objects, and tests/framework. Use when creating a new spec,
6-
fixing a failing E2E test, or adding page objects and selectors.
6+
fixing a failing E2E test, adding page objects and selectors, or adding
7+
MetaMetrics analytics expectations (analyticsExpectations).
78
---
89

910
# E2E Test Builder — Skill
@@ -44,6 +45,10 @@ Task → What do you need?
4445
│ → Open references/mocking.md (testSpecificMock, setupRemoteFeatureFlagsMock, setupMockRequest)
4546
│ → When writing the spec: open references/writing-tests.md
4647
48+
├─ MetaMetrics / Segment analytics assertions (`analyticsExpectations` on `withFixtures`)
49+
│ → Open [tests/docs/analytics-e2e.md](../../../tests/docs/analytics-e2e.md) (config shape, teardown order, presets under `tests/helpers/analytics/expectations/`, `runAnalyticsExpectations`)
50+
│ → When wiring a spec: still follow references/writing-tests.md for `withFixtures` usage
51+
4752
└─ Run tests, debug failures, or self-review
4853
→ Open references/running-tests.md (build check, detox commands, common failures, retry patterns)
4954
```
@@ -84,9 +89,10 @@ Step 5 → Iterate (fix → lint → run) until green
8489

8590
Documentation is split by **action**. Open only the reference that matches what you are doing.
8691

87-
| Action | File | When to open it |
88-
| --------------------------------------------- | ---------------------------------------------------------- | ------------------------------------------------------------------------------------------------- |
89-
| **Writing or updating a spec** | [references/writing-tests.md](references/writing-tests.md) | New spec file, spec structure, FixtureBuilder patterns, smoke/regression templates. |
90-
| **Page Objects and selectors** | [references/page-objects.md](references/page-objects.md) | Create or update POM classes, selector/testId conventions, Matchers/Gestures/Assertions API. |
91-
| **API and feature flag mocking** | [references/mocking.md](references/mocking.md) | testSpecificMock, setupRemoteFeatureFlagsMock, setupMockRequest, shared mock files. |
92-
| **Running tests, debugging, fixing failures** | [references/running-tests.md](references/running-tests.md) | Build check, detox run commands, lint/tsc, common failures table, retry patterns, iteration loop. |
92+
| Action | File | When to open it |
93+
| --------------------------------------------- | ------------------------------------------------------------------- | ------------------------------------------------------------------------------------------------------------------ |
94+
| **Writing or updating a spec** | [references/writing-tests.md](references/writing-tests.md) | New spec file, spec structure, FixtureBuilder patterns, smoke/regression templates. |
95+
| **Page Objects and selectors** | [references/page-objects.md](references/page-objects.md) | Create or update POM classes, selector/testId conventions, Matchers/Gestures/Assertions API. |
96+
| **API and feature flag mocking** | [references/mocking.md](references/mocking.md) | testSpecificMock, setupRemoteFeatureFlagsMock, setupMockRequest, shared mock files. |
97+
| **MetaMetrics / analytics expectations** | [tests/docs/analytics-e2e.md](../../../tests/docs/analytics-e2e.md) | `analyticsExpectations` on `withFixtures`, declarative checks, presets in `tests/helpers/analytics/expectations/`. |
98+
| **Running tests, debugging, fixing failures** | [references/running-tests.md](references/running-tests.md) | Build check, detox run commands, lint/tsc, common failures table, retry patterns, iteration loop. |

.cursor/rules/deeplink-handler-guidelines.mdc

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -12,6 +12,8 @@ This guide walks you through adding new deeplink handlers to MetaMask Mobile. Fo
1212

1313
## Quick Reference
1414

15+
The **`deposit` deeplink** (`metamask://deposit`, `/deposit`) is **deprecated** and not handled; do not add handlers under Ramp Deposit `deeplink/` for it.
16+
1517
| File | Purpose |
1618
|------|---------|
1719
| `app/constants/deeplinks.ts` | Define action constants |

.depcheckrc.yml

Lines changed: 7 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -47,6 +47,13 @@ ignores:
4747
- '@metamask/perps-controller'
4848
# Used in scripts/repack for CI optimization
4949
- '@expo/repack-app'
50+
51+
# ESLint plugins, resolvers, parsers, configuration, etc.
52+
- 'eslint-config-prettier'
53+
- 'eslint-import-resolver-typescript'
54+
- 'eslint-plugin-prettier'
55+
- 'eslint-plugin-react-native'
56+
5057
# Note: Everything below this line should be removed after investigation
5158
# TODO: Investigate each dependency to see whether it's used
5259

@@ -63,9 +70,6 @@ ignores:
6370
- 'babel-core'
6471
- 'babel-loader'
6572
- 'chromedriver'
66-
- 'eslint-config-prettier'
67-
- 'eslint-plugin-prettier'
68-
- 'eslint-plugin-react-native'
6973
- 'execa'
7074
- 'jetifier'
7175
- 'metro-react-native-babel-preset'

.eslintrc.js

Lines changed: 92 additions & 22 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
/* eslint-disable import/no-commonjs */
1+
/* eslint-disable import-x/no-commonjs */
22
module.exports = {
33
root: true,
44
parser: '@typescript-eslint/parser',
@@ -9,7 +9,7 @@ module.exports = {
99
'@react-native',
1010
'eslint:recommended',
1111
// '@metamask/eslint-config', // TODO: Enable when ready
12-
'plugin:import/warnings',
12+
'plugin:import-x/warnings',
1313
'plugin:react/recommended',
1414
],
1515
// ESLint can find the plugin without the `eslint-plugin-` prefix. Ex. `eslint-plugin-react-compiler` -> `react-compiler`
@@ -51,6 +51,65 @@ module.exports = {
5151
allow: ['Text'],
5252
},
5353
],
54+
55+
// These rule modifications are removing changes to our shared ESLint config made after
56+
// version v9. This is a temporary measure to get us to ESLint v9 compatible versions,
57+
// at which point we can restore the intended rules and use error suppression instead.
58+
//
59+
// TODO: Remove these modifications after the ESLint v9 update
60+
'@typescript-eslint/await-thenable': 'off',
61+
'@typescript-eslint/consistent-type-imports': 'off',
62+
'@typescript-eslint/consistent-type-exports': 'off',
63+
'@typescript-eslint/explicit-function-return-type': 'off',
64+
'@typescript-eslint/naming-convention': 'off',
65+
'@typescript-eslint/no-base-to-string': 'off',
66+
'@typescript-eslint/no-duplicate-type-constituents': 'off',
67+
'@typescript-eslint/no-empty-object-type': 'off',
68+
'@typescript-eslint/no-floating-promises': 'off',
69+
'@typescript-eslint/no-implied-eval': 'off',
70+
'@typescript-eslint/no-misused-promises': 'off',
71+
'@typescript-eslint/no-redundant-type-constituents': 'off',
72+
'@typescript-eslint/no-throw-literal': 'off',
73+
'@typescript-eslint/no-unnecessary-type-assertion': 'off',
74+
'@typescript-eslint/no-unnecessary-type-arguments': 'off',
75+
'@typescript-eslint/no-unsafe-enum-comparison': 'off',
76+
'@typescript-eslint/no-unnecessary-boolean-literal-compare': 'off',
77+
'@typescript-eslint/no-unused-vars': 'off',
78+
'@typescript-eslint/no-wrapper-object-types': 'off',
79+
'@typescript-eslint/only-throw-error': 'off',
80+
'@typescript-eslint/prefer-enum-initializers': 'off',
81+
'@typescript-eslint/prefer-includes': 'off',
82+
'@typescript-eslint/prefer-nullish-coalescing': 'off',
83+
'@typescript-eslint/prefer-optional-chain': 'off',
84+
'@typescript-eslint/prefer-promise-reject-errors': 'off',
85+
'@typescript-eslint/prefer-readonly': 'off',
86+
'@typescript-eslint/prefer-reduce-type-parameter': 'off',
87+
'@typescript-eslint/prefer-string-starts-ends-with': 'off',
88+
'@typescript-eslint/promise-function-async': 'off',
89+
'@typescript-eslint/restrict-plus-operands': 'off',
90+
'@typescript-eslint/restrict-template-expressions': 'off',
91+
'@typescript-eslint/switch-exhaustiveness-check': 'off',
92+
'@typescript-eslint/unbound-method': 'off',
93+
'no-restricted-syntax': [
94+
'error',
95+
{
96+
selector: 'WithStatement',
97+
message: 'With statements are not allowed',
98+
},
99+
{
100+
selector: 'SequenceExpression',
101+
message: 'Sequence expressions are not allowed',
102+
},
103+
// {
104+
// selector: "BinaryExpression[operator='in']",
105+
// message: 'The "in" operator is not allowed',
106+
// },
107+
// {
108+
// selector:
109+
// "PropertyDefinition[accessibility='private'], MethodDefinition[accessibility='private'], TSParameterProperty[accessibility='private']",
110+
// message: 'Use a hash name instead.',
111+
// },
112+
],
54113
},
55114
},
56115
{
@@ -86,8 +145,8 @@ module.exports = {
86145
},
87146
rules: {
88147
'no-console': 'off',
89-
'import/no-commonjs': 'off',
90-
'import/no-nodejs-modules': 'off',
148+
'import-x/no-commonjs': 'off',
149+
'import-x/no-nodejs-modules': 'off',
91150
},
92151
},
93152
{
@@ -98,8 +157,8 @@ module.exports = {
98157
],
99158
rules: {
100159
'no-console': 'off',
101-
'import/no-commonjs': 'off',
102-
'import/no-nodejs-modules': 'off',
160+
'import-x/no-commonjs': 'off',
161+
'import-x/no-nodejs-modules': 'off',
103162
},
104163
},
105164
{
@@ -361,10 +420,13 @@ module.exports = {
361420
'@typescript-eslint/no-floating-promises': 'error',
362421
'@typescript-eslint/restrict-template-expressions': 'error',
363422

364-
// === Import rules (using 'import' plugin, not 'import-x') ===
365-
'import/consistent-type-specifier-style': ['error', 'prefer-top-level'],
366-
'import/no-named-as-default': 'error',
367-
'import/order': [
423+
// === Import rules ===
424+
'import-x/consistent-type-specifier-style': [
425+
'error',
426+
'prefer-top-level',
427+
],
428+
'import-x/no-named-as-default': 'error',
429+
'import-x/order': [
368430
'error',
369431
{
370432
groups: [
@@ -441,10 +503,10 @@ module.exports = {
441503
},
442504

443505
settings: {
444-
'import/resolver': {
506+
'import-x/resolver': {
445507
typescript: {}, // this loads <rootdir>/tsconfig.json to eslint
446508
},
447-
'import/internal-regex': '^@metamask/perps-controller',
509+
'import-x/internal-regex': '^@metamask/perps-controller',
448510
},
449511

450512
rules: {
@@ -466,7 +528,7 @@ module.exports = {
466528
'no-bitwise': 'off',
467529
'class-methods-use-this': 'off',
468530
'eol-last': 'warn',
469-
'import/no-named-as-default': 'off',
531+
'import-x/no-named-as-default': 'off',
470532
'no-invalid-this': 'off',
471533
'no-new': 'off',
472534
'react/jsx-handler-names': 'off',
@@ -477,14 +539,14 @@ module.exports = {
477539
'arrow-body-style': 'error',
478540
'dot-notation': 'error',
479541
eqeqeq: 'error',
480-
'import/no-amd': 'error',
481-
'import/no-commonjs': 'error',
482-
'import/no-duplicates': 'error',
483-
'import/no-extraneous-dependencies': ['error', { packageDir: ['./'] }],
484-
'import/no-mutable-exports': 'error',
485-
'import/no-namespace': 'error',
486-
'import/no-nodejs-modules': 'error',
487-
'import/prefer-default-export': 'off',
542+
'import-x/no-amd': 'error',
543+
'import-x/no-commonjs': 'error',
544+
'import-x/no-duplicates': 'error',
545+
'import-x/no-extraneous-dependencies': ['error', { packageDir: ['./'] }],
546+
'import-x/no-mutable-exports': 'error',
547+
'import-x/no-namespace': 'error',
548+
'import-x/no-nodejs-modules': 'error',
549+
'import-x/prefer-default-export': 'off',
488550
'no-alert': 'error',
489551
'no-constant-condition': [
490552
'error',
@@ -532,7 +594,7 @@ module.exports = {
532594
'prefer-const': 'error',
533595
'prefer-rest-params': 'error',
534596
'prefer-spread': 'error',
535-
'import/no-unresolved': 'error',
597+
'import-x/no-unresolved': 'error',
536598
'eslint-comments/no-unlimited-disable': 'off',
537599
'eslint-comments/no-unused-disable': 'off',
538600
'react-native/no-color-literals': 'error',
@@ -559,6 +621,14 @@ module.exports = {
559621
'react/prefer-es6-class': 'error',
560622
'@metamask/design-tokens/color-no-hex': 'warn',
561623
radix: 'off',
624+
625+
// These rule modifications are removing changes to our shared ESLint config made after
626+
// version v9. This is a temporary measure to get us to ESLint v9 compatible versions,
627+
// at which point we can restore the intended rules and use error suppression instead.
628+
//
629+
// TODO: Remove these modifications after the ESLint v9 update
630+
'react-hooks/rules-of-hooks': 'off',
631+
'no-loss-of-precision': 'off',
562632
},
563633

564634
ignorePatterns: ['wdio.conf.js', 'app/util/termsOfUse/termsOfUseContent.ts'],

.github/CODEOWNERS

Lines changed: 5 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -47,6 +47,7 @@ scripts/build.sh @MetaMask/mobile-pla
4747
fingerprint.config.js @MetaMask/mobile-platform
4848
builds.yml @MetaMask/mobile-platform
4949
.github/workflows/push-eas-update.yml @MetaMask/mobile-admins
50+
.github/workflows/upload-to-testflight.yml @MetaMask/mobile-admins
5051
scripts/update-expo-channel.js @MetaMask/mobile-admins
5152
certs/certificate.pem @MetaMask/mobile-admins
5253
ios/fastlane/ @MetaMask/mobile-admins
@@ -121,8 +122,10 @@ app/components/Views/AccountSelector @MetaMask/accounts-e
121122
**/multichainAccounts/** @MetaMask/accounts-engineers
122123

123124
# Swaps Team
124-
app/components/UI/Swaps @MetaMask/swaps-engineers
125-
app/components/UI/Bridge @MetaMask/swaps-engineers
125+
app/components/UI/Swaps @MetaMask/swaps-engineers
126+
app/components/UI/Bridge @MetaMask/swaps-engineers
127+
app/core/Engine/controllers/bridge-controller @MetaMask/swaps-engineers
128+
app/core/Engine/controllers/bridge-status-controller @MetaMask/swaps-engineers
126129

127130
# Notifications Team
128131
app/components/Views/Notifications @MetaMask/notifications

0 commit comments

Comments
 (0)