Skip to content

Commit 878c836

Browse files
release: 7.59.0 (#22226)
# 🚀 v7.59.0 Testing & Release Quality Process Hi Team, As part of our new **MetaMask Release Quality Process**, here’s a quick overview of the key processes, testing strategies, and milestones to ensure a smooth and high-quality deployment. --- ## 📋 Key Processes ### Testing Strategy - **Developer Teams:** Conduct regression and exploratory testing for your functional areas, including automated and manual tests for critical workflows. - **QA Team:** Focus on exploratory testing across the wallet, prioritize high-impact areas, and triage any Sentry errors found during testing. - **Customer Success Team:** Validate new functionalities and provide feedback to support release monitoring. ### GitHub Signoff - Each team must **sign off on the Release Candidate (RC)** via GitHub by the end of the validation timeline (**Tuesday EOD PT**). - Ensure all tests outlined in the Testing Plan are executed, and any identified issues are addressed. ### Issue Resolution - **Resolve all Release Blockers** (Sev0 and Sev1) by **Tuesday EOD PT**. - For unresolved blockers, PRs may be reverted, or feature flags disabled to maintain release quality and timelines. ### Cherry-Picking Criteria - Only **critical fixes** meeting outlined criteria will be cherry-picked. - Developers must ensure these fixes are thoroughly reviewed, tested, and merged by **Tuesday EOD PT**. --- ## 🗓️ Timeline and Milestones 1. **Today (Friday):** Begin Release Candidate validation. 2. **Tuesday EOD PT:** Finalize RC with all fixes and cherry-picks. 3. **Wednesday:** Buffer day for final checks. 4. **Thursday:** Submit release to app stores and begin rollout to 1% of users. 5. **Monday:** Scale deployment to 10%. 6. **Tuesday:** Full rollout to 100%. --- ## ✅ Signoff Checklist Each team is responsible for signing off via GitHub. Use the checkbox below to track signoff completion: # Team sign-off checklist - [x] Accounts Framework - [x] Assets - [x] Bots Team - [x] Card - [x] Confirmations - [x] Core Platform - [x] Design System - [x] Earn - [x] Mobile Platform - [x] Mobile UX - [x] Network Enablement - [x] New Networks - [x] Perps - [x] Predict - [x] Product Safety - [x] Ramp - [x] Rewards - [x] Swaps and Bridge - [x] Transactions - [x] Wallet Integrations - [x] Web3Auth This process is a major step forward in ensuring release stability and quality. Let’s stay aligned and make this release a success! 🚀 Feel free to reach out if you have questions or need clarification. Many thanks in advance # Reference - Testing plan sheet - https://docs.google.com/spreadsheets/d/1tsoodlAlyvEUpkkcNcbZ4PM9HuC9cEM80RZeoVv5OCQ/edit?gid=404070372#gid=404070372 <!-- CURSOR_SUMMARY --> --- > [!NOTE] > <sup>[Cursor Bugbot](https://cursor.com/dashboard?tab=bugbot) is generating a summary for commit 06788b7. Configure [here](https://cursor.com/dashboard?tab=bugbot).</sup> <!-- /CURSOR_SUMMARY -->
2 parents 52de212 + 06788b7 commit 878c836

File tree

1,940 files changed

+156016
-48182
lines changed

Some content is hidden

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

1,940 files changed

+156016
-48182
lines changed

.cursor/rules/BUGBOT.md

Lines changed: 174 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,174 @@
1+
# BUGBOT Rules
2+
3+
## Core Mission
4+
5+
Automated test quality enforcement and bug detection for MetaMask Mobile React Native codebase.
6+
7+
## Execution Protocol
8+
9+
### 1. Initial Setup
10+
11+
- **ALWAYS** load and reference `.cursor/rules/unit-testing-guidelines.mdc`
12+
- Verify test file naming pattern: `*.test.ts(x)` or `*.test.js(x)`
13+
- Check for proper Jest/React Native Testing Library imports
14+
15+
### 2. Automated Audits (Run in Order)
16+
17+
#### A. Quality Checklist Audit
18+
19+
Verify ALL items from the mandatory checklist:
20+
21+
- [ ] No "should" in any test name (ZERO tolerance)
22+
- [ ] All tests follow AAA pattern with blank line separation
23+
- [ ] Each test has ONE clear purpose
24+
- [ ] All code paths tested (happy path, edge cases, errors)
25+
- [ ] Test data is realistic (no `foo`, `bar`, `test123`)
26+
- [ ] Tests are independent (can run in any order)
27+
- [ ] Assertions are specific (no `toBeDefined`, use `toBeOnTheScreen`)
28+
- [ ] Test names are action-oriented and descriptive
29+
- [ ] No test duplication
30+
- [ ] Async operations wrapped in `act()` when triggering state updates
31+
- [ ] All external dependencies mocked
32+
33+
#### B. Code Coverage Audit
34+
35+
Report on:
36+
37+
- Line coverage percentage
38+
- Branch coverage percentage
39+
- Uncovered lines/branches (list specific line numbers)
40+
- Missing test scenarios for:
41+
- Error conditions
42+
- Edge cases (null, undefined, empty)
43+
- Boundary conditions
44+
- Different code paths (if/else, switch cases)
45+
46+
### 3. Rule Violation Detection
47+
48+
#### Test Naming Rules (CRITICAL)
49+
50+
- **FAIL** if ANY test contains "should"
51+
- **WARN** if using vague verbs: "handles", "manages", "processes"
52+
- **WARN** if using subjective outcomes: "correctly", "successfully", "properly"
53+
54+
#### Test Structure and Organization (MANDATORY)
55+
56+
- **FAIL** if missing AAA pattern separation
57+
- **FAIL** if testing multiple behaviors in one test
58+
- **WARN** if no helper functions for repeated test data
59+
60+
#### Mocking Rules (CRITICAL)
61+
62+
- **FAIL** if using `require` instead of ES6 imports
63+
- **FAIL** if using `any` type in TypeScript
64+
- **FAIL** if external dependencies not mocked
65+
- **WARN** if mock data unrealistic
66+
67+
#### Test Coverage (MANDATORY)
68+
69+
- **FAIL** if missing happy path tests
70+
- **FAIL** if missing error condition tests
71+
- **WARN** if missing edge case tests
72+
- **WARN** if branch coverage < 80%
73+
74+
#### Parameterized Tests
75+
76+
- **INFO** suggest parameterization for repetitive tests with different inputs
77+
78+
#### Async Testing and act() (CRITICAL)
79+
80+
- **FAIL** if async state updates not wrapped in `act()`
81+
- **FAIL** if seeing "terminated" or "SocketError" in test output
82+
- **WARN** if `onRefresh`, `onPress` with async handlers not using `act()`
83+
84+
#### Refactoring Support
85+
86+
- **INFO** suggest extracting helper functions for test setup
87+
- **INFO** suggest breaking down complex components for testability
88+
89+
### 4. Output Format
90+
91+
```
92+
🤖 BUGBOT Analysis Complete
93+
━━━━━━━━━━━━━━━━━━━━━━━━━━━
94+
95+
📊 Coverage Report:
96+
Lines: XX% | Branches: XX% | Functions: XX%
97+
98+
⚠️ Critical Violations (X found):
99+
- [FAIL] Test uses "should": line 42
100+
- [FAIL] Missing act() wrapper: line 87
101+
102+
⚡ Warnings (X found):
103+
- [WARN] Vague test name: line 23
104+
- [WARN] Missing edge case test for null input
105+
106+
✅ Passed Checks:
107+
- All tests follow AAA pattern
108+
- No `any` types used
109+
110+
💡 Suggestions:
111+
- Consider parameterized test for lines 45-67
112+
- Extract helper function for user creation (repeated 5 times)
113+
114+
📝 Action Items:
115+
1. Remove "should" from 3 test names
116+
2. Add act() wrapper to async onRefresh test
117+
3. Add test for empty array edge case
118+
```
119+
120+
### 5. Auto-fix Capabilities
121+
122+
When possible, suggest or apply fixes for:
123+
124+
- Test name corrections (remove "should", make action-oriented)
125+
- AAA pattern formatting (add blank lines)
126+
- act() wrapper additions
127+
- Mock setup boilerplate
128+
- Helper function extraction
129+
130+
### 6. Integration Points
131+
132+
- **Pre-commit**: Block commits with CRITICAL failures
133+
- **PR Review**: Add automated comments for violations
134+
- **CI Pipeline**: Fail builds on coverage drops or critical violations
135+
136+
### 7. Configuration
137+
138+
```yaml
139+
thresholds:
140+
line_coverage: 80
141+
branch_coverage: 75
142+
max_test_complexity: 20 # lines per test
143+
144+
rules:
145+
should_in_names: error
146+
aaa_pattern: error
147+
mock_externals: error
148+
async_act: error
149+
vague_names: warning
150+
edge_cases: warning
151+
```
152+
153+
## Quick Reference Commands
154+
155+
```bash
156+
# Run BUGBOT on specific file
157+
yarn bugbot app/components/MyComponent.test.tsx
158+
159+
# Run BUGBOT on all test files
160+
yarn bugbot:all
161+
162+
# Run with auto-fix
163+
yarn bugbot --fix
164+
165+
# Generate coverage report
166+
yarn test:unit:coverage
167+
```
168+
169+
## Exit Codes
170+
171+
- 0: All checks passed
172+
- 1: Critical violations found
173+
- 2: Coverage below threshold
174+
- 3: Test execution failed

.cursor/rules/general-coding-guidelines.mdc

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -32,7 +32,7 @@ ComponentName/
3232

3333
**Core**: `/docs/readme/` (architecture, testing, debugging, performance, environment, expo-environment, storybook, troubleshooting, expo-e2e-testing, reassure, release-build-profiler)
3434

35-
**Features**: `/docs/` (deeplinks, animations, tailwind, confirmations, confirmation-refactoring) • `app/component-library/README.md` • `e2e/MOCKING.md` • `CHANGELOG.md` • `app/core/{Analytics,Engine}/README.md` • `ppom/README.md`
35+
**Features**: `/docs/` (deeplinks, animations, tailwind, confirmations, confirmation-refactoring) • `app/component-library/README.md` • `e2e/MOCKING.md` • `CHANGELOG.md` • `app/core/{Analytics,Engine}/README.md`
3636

3737
**External**: [MetaMask Contributor Docs](https://github.com/MetaMask/contributor-docs) • [TypeScript Guidelines](https://github.com/MetaMask/contributor-docs/blob/main/docs/typescript.md) • [Unit Testing](https://github.com/MetaMask/contributor-docs/blob/main/docs/testing/unit-testing.md)
3838

@@ -44,4 +44,4 @@ ComponentName/
4444

4545
**Testing**: see .claude/commands/unit-test.md
4646

47-
**Forbidden**: ❌ npm/npx commands
47+
**Forbidden**: ❌ npm/npx commands

.cursor/rules/unit-testing-guidelines.mdc

Lines changed: 88 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -185,6 +185,92 @@ jest.setSystemTime(new Date('2024-01-01'));
185185

186186
- Avoid relying on global state or hardcoded values (e.g., dates) or mock it.
187187

188+
## Async Testing and act() - CRITICAL
189+
190+
**ALWAYS use `act()` when testing async operations that trigger React state updates.**
191+
192+
### When to Use act()
193+
194+
Use `act()` when you:
195+
- Call async functions via component props (e.g., `onRefresh`, `onPress` with async handlers)
196+
- Invoke functions that perform state updates asynchronously
197+
- Test pull-to-refresh or other async interactions
198+
199+
### Symptoms of Missing act()
200+
201+
Tests fail intermittently with:
202+
- `TypeError: terminated`
203+
- `SocketError: other side closed`
204+
- Warnings about state updates not being wrapped in act()
205+
206+
### Examples
207+
208+
```ts
209+
// ❌ WRONG - Causes flaky tests
210+
it('calls Logger.error when handleOnRefresh fails', async () => {
211+
const mockLoggerError = jest.spyOn(Logger, 'error');
212+
render(BankDetails);
213+
214+
// Async function called without act() - causes race condition
215+
screen
216+
.getByTestId('refresh-control-scrollview')
217+
.props.refreshControl.props.onRefresh();
218+
219+
await waitFor(() => {
220+
expect(mockLoggerError).toHaveBeenCalled();
221+
});
222+
});
223+
224+
// ✅ CORRECT - Properly handles async state updates
225+
it('calls Logger.error when handleOnRefresh fails', async () => {
226+
const mockLoggerError = jest.spyOn(Logger, 'error');
227+
render(BankDetails);
228+
229+
// Wrap async operation in act()
230+
await act(async () => {
231+
await screen
232+
.getByTestId('refresh-control-scrollview')
233+
.props.refreshControl.props.onRefresh();
234+
});
235+
236+
await waitFor(() => {
237+
expect(mockLoggerError).toHaveBeenCalled();
238+
});
239+
});
240+
```
241+
242+
### Common Patterns Requiring act()
243+
244+
```ts
245+
// RefreshControl callbacks
246+
await act(async () => {
247+
await refreshControl.props.onRefresh();
248+
});
249+
250+
// Async button press handlers
251+
await act(async () => {
252+
await button.props.onPress();
253+
});
254+
255+
// Any async callback that updates state
256+
await act(async () => {
257+
await component.props.onSomeAsyncAction();
258+
});
259+
```
260+
261+
### Why This Matters
262+
263+
Without `act()`:
264+
1. Async function starts executing
265+
2. Test continues and waits only for specific assertion
266+
3. Jest cleanup/termination happens while promises are still pending
267+
4. Results in "terminated" or "other side closed" errors
268+
269+
With `act()`:
270+
1. React Testing Library waits for all state updates
271+
2. All promises resolve before test proceeds
272+
3. Clean, deterministic test execution
273+
188274
# Reviewer Responsibilities
189275

190276
- Validate that tests fail when the code is broken (test the test).
@@ -215,6 +301,7 @@ Before submitting any test file, verify:
215301
- [ ] **Assertions are specific**
216302
- [ ] **Test names are descriptive**
217303
- [ ] **No test duplication**
304+
- [ ] **Async operations wrapped in act()** when they trigger state updates
218305

219306
# Common Mistakes to AVOID - CRITICAL
220307

@@ -226,6 +313,7 @@ Before submitting any test file, verify:
226313
- ❌ **Not following AAA pattern** - Always Arrange, Act, Assert
227314
- ❌ **Not testing edge cases** - Test null, undefined, empty values
228315
- ❌ **Using weak matchers** - Use specific assertions like `toBe()`, `toEqual()`
316+
- ❌ **Not wrapping async state updates in act()** - Causes flaky "terminated" errors
229317

230318
# Anti-patterns to Avoid
231319

.depcheckrc.yml

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -22,6 +22,8 @@ ignores:
2222
- 'reflect-metadata'
2323
# Husky is used for pre-commit hooks
2424
- 'husky'
25+
# Auto changelog tooling used in release scripts
26+
- '@metamask/auto-changelog'
2527
# Remove this once it's used in the project
2628
- 'rive-react-native'
2729
# Appwright will be used in a follow up PR. We will remove once PR is ready
@@ -68,6 +70,7 @@ ignores:
6870
- 'prettier-plugin-gherkin'
6971
- 'react-native-svg-asset-plugin'
7072
- 'regenerator-runtime'
73+
- 'prettier-2'
7174

7275
## Unused devDependencies to investigate
7376
- '@metamask/swappable-obj-proxy'

.detoxrc.js

Lines changed: 25 additions & 19 deletions
Original file line numberDiff line numberDiff line change
@@ -65,8 +65,12 @@ module.exports = {
6565
},
6666
'ios.sim.main.ci': {
6767
device: 'ios.simulator',
68-
app: 'ios.debug',
69-
}
68+
app: 'ios.main.release',
69+
},
70+
'ios.sim.flask.ci': {
71+
device: 'ios.simulator',
72+
app: 'ios.flask.release',
73+
},
7074
},
7175
devices: {
7276
'ios.simulator': {
@@ -110,42 +114,44 @@ module.exports = {
110114
'ios.main.release': {
111115
type: 'ios.app',
112116
binaryPath:
113-
'ios/build/Build/Products/Release-iphonesimulator/MetaMask.app',
114-
build: `yarn build:ios:main:e2e`,
117+
process.env.PREBUILT_IOS_APP_PATH || 'ios/build/Build/Products/Release-iphonesimulator/MetaMask.app',
118+
build: `export CONFIGURATION="Release" && yarn build:ios:main:e2e`,
115119
},
116120
'ios.flask.debug': {
117121
type: 'ios.app',
118122
binaryPath:
119-
'ios/build/Build/Products/Debug-iphonesimulator/MetaMask-Flask.app',
120-
build: 'yarn start:ios:e2e:flask',
123+
process.env.PREBUILT_IOS_APP_PATH || 'ios/build/Build/Products/Debug-iphonesimulator/MetaMask-Flask.app',
124+
build: 'export CONFIGURATION="Debug" && yarn build:ios:flask:e2e',
121125
},
122126
'ios.flask.release': {
123127
type: 'ios.app',
124128
binaryPath:
125-
'ios/build/Build/Products/Release-iphonesimulator/MetaMask-Flask.app',
126-
build: `yarn build:ios:flask:e2e`,
129+
process.env.PREBUILT_IOS_APP_PATH || 'ios/build/Build/Products/Release-iphonesimulator/MetaMask-Flask.app',
130+
build: `export CONFIGURATION="Release" && yarn build:ios:flask:e2e`,
127131
},
128132
'android.debug': {
129133
type: 'android.apk',
130134
binaryPath: process.env.PREBUILT_ANDROID_APK_PATH || 'android/app/build/outputs/apk/prod/debug/app-prod-debug.apk',
131-
testBinaryPath: process.env.PREBUILT_ANDROID_TEST_APK_PATH,
132-
build: 'yarn start:android:e2e',
135+
testBinaryPath: process.env.PREBUILT_ANDROID_TEST_APK_PATH || 'android/app/build/outputs/apk/androidTest/prod/debug/app-prod-debug-androidTest.apk',
136+
build: 'export CONFIGURATION="Debug" && yarn build:android:main:e2e',
133137
},
134-
'android.flask.debug': {
138+
'android.release': {
135139
type: 'android.apk',
136-
binaryPath: 'android/app/build/outputs/apk/flask/debug/app-flask-debug.apk',
137-
testBinaryPath: 'android/app/build/outputs/apk/androidTest/flask/debug/app-flask-debug-androidTest.apk',
138-
build: 'yarn start:android:e2e:flask',
140+
binaryPath: process.env.PREBUILT_ANDROID_APK_PATH || 'android/app/build/outputs/apk/prod/release/app-prod-release.apk',
141+
testBinaryPath: process.env.PREBUILT_ANDROID_TEST_APK_PATH || 'android/app/build/outputs/apk/androidTest/prod/release/app-prod-release-androidTest.apk',
142+
build: `export CONFIGURATION="Release" && yarn build:android:main:e2e`,
139143
},
140-
'android.release': {
144+
'android.flask.debug': {
141145
type: 'android.apk',
142-
binaryPath: 'android/app/build/outputs/apk/prod/release/app-prod-release.apk',
143-
build: `yarn build:android:main:e2e`,
146+
binaryPath: process.env.PREBUILT_ANDROID_APK_PATH || 'android/app/build/outputs/apk/flask/debug/app-flask-debug.apk',
147+
testBinaryPath: process.env.PREBUILT_ANDROID_TEST_APK_PATH || 'android/app/build/outputs/apk/androidTest/flask/debug/app-flask-debug-androidTest.apk',
148+
build: 'export CONFIGURATION="Debug" && yarn build:android:flask:e2e',
144149
},
145150
'android.flask.release': {
146151
type: 'android.apk',
147-
binaryPath: 'android/app/build/outputs/apk/flask/release/app-flask-release.apk',
148-
build: `yarn build:android:flask:e2e`,
152+
binaryPath: process.env.PREBUILT_ANDROID_APK_PATH || 'android/app/build/outputs/apk/flask/release/app-flask-release.apk',
153+
testBinaryPath: process.env.PREBUILT_ANDROID_TEST_APK_PATH || 'android/app/build/outputs/apk/androidTest/flask/release/app-flask-release-androidTest.apk',
154+
build: `export CONFIGURATION="Release" && yarn build:android:flask:e2e`,
149155
},
150156
},
151157
};

0 commit comments

Comments
 (0)