Skip to content

Commit e84c09e

Browse files
test(card): replace hex test color suppressions with shared theme mocks (batch 1) (MetaMask#26955)
## **Description** This PR is Card-team batch 1 of the broader effort to remove hard-coded hex colors and `@metamask/design-tokens/color-no-hex` suppressions in tests. Reason for change: - Many tests were asserting or mocking hex values directly and suppressing lint. - The migration needs to be split into smaller, codeowner-aligned PRs to reduce review overhead and risk. Improvement/solution: - Replaced local hex theme mocks with shared theme sources (`mockTheme` / design tokens) in Card-owned test files. - Removed color-rule suppressions where no longer needed. - Updated one hook test to assert config behavior without hard-coding color literals. ## **Changelog** CHANGELOG entry: null ## **Related issues** Fixes: DSYS-507 ## **Manual testing steps** ```gherkin Feature: Card tests use shared theme values instead of hex suppressions Scenario: developer runs the updated Card test files Given the branch `chore/color-no-hex-card-batch-1` is checked out When the developer runs the targeted Jest commands Then all updated test suites pass without introducing new color-no-hex suppressions ``` Commands run: - `yarn jest app/components/UI/Card/components/AssetSelectionBottomSheet/AssetSelectionBottomSheet.test.tsx --runInBand --watchman=false --no-coverage` - `yarn jest app/components/UI/Card/components/DaimoPayModal/DaimoPayModal.test.tsx --runInBand --watchman=false --no-coverage` - `yarn jest app/components/UI/Card/components/Onboarding/ConfirmEmail.test.tsx --runInBand --watchman=false --no-coverage` - `yarn jest app/components/UI/Card/components/Onboarding/KYCFailed.test.tsx --runInBand --watchman=false --no-coverage` - `yarn jest app/components/UI/Card/components/Onboarding/KYCPending.test.tsx --runInBand --watchman=false --no-coverage` - `yarn jest app/components/UI/Card/hooks/useCardDetailsToken.test.ts --runInBand --watchman=false --no-coverage` - `yarn jest app/components/UI/Card/hooks/useSpendingLimit.test.ts --runInBand --watchman=false --no-coverage` ## **Screenshots/Recordings** ### **Before** N/A (test-only changes) ### **After** N/A (test-only changes) ## **Pre-merge author checklist** - [x] I've followed [MetaMask Contributor Docs](https://github.com/MetaMask/contributor-docs) and [MetaMask Mobile Coding Standards](https://github.com/MetaMask/metamask-mobile/blob/main/.github/guidelines/CODING_GUIDELINES.md). - [x] I've completed the PR template to the best of my ability - [x] I've included tests if applicable - [ ] I've documented my code using [JSDoc](https://jsdoc.app/) format if applicable - [ ] I've applied the right labels on the PR (see [labeling guidelines](https://github.com/MetaMask/metamask-mobile/blob/main/.github/guidelines/LABELING_GUIDELINES.md)). Not required for external contributors. ## **Pre-merge reviewer checklist** - [ ] I've manually tested the PR (e.g. pull and build branch, run the app, test code being changed). - [ ] I confirm that this PR addresses all acceptance criteria described in the ticket it closes and includes the necessary testing evidence such as recordings and or screenshots. <!-- CURSOR_SUMMARY --> --- > [!NOTE] > **Low Risk** > Low risk: changes are primarily test refactors and lint-rule scoping, plus a small styling token swap in `KYCFailed`. Main risk is inadvertent test brittleness or lint failures due to the stricter `color-no-hex` enforcement under `app/components/UI/Card`. > > **Overview** > Refactors Card-owned tests to stop hard-coding hex theme colors by switching mocks to the shared `util/theme` `mockTheme` (and design-tokens like `brandColor.white`), reducing the need for `@metamask/design-tokens/color-no-hex` suppressions. > > Tightens linting rollout by keeping `color-no-hex` disabled for tests globally but **re-enabling it for `app/components/UI/Card/**/*`**, and updates Card code/tests to comply (e.g., `KYCFailed` background now uses `brandColor.purple800`, and CSS constants for card-details/PIN token generation are exported and reused in tests). > > <sup>Written by [Cursor Bugbot](https://cursor.com/dashboard?tab=bugbot) for commit e732ec2. This will update automatically on new commits. Configure [here](https://cursor.com/dashboard?tab=bugbot).</sup> <!-- /CURSOR_SUMMARY -->
1 parent ec9230f commit e84c09e

20 files changed

Lines changed: 166 additions & 180 deletions

.eslintrc.js

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -105,11 +105,23 @@ module.exports = {
105105
},
106106
},
107107
{
108+
// Temporary rollout strategy:
109+
// Keep color-no-hex disabled for all tests by default, then re-enable it
110+
// for specific folders in small PR batches. Once migration is complete,
111+
// remove this override and enforce across all tests in:
112+
// - app/components/
113+
// - app/component-library/
108114
files: ['**/*.test.{js,ts,tsx}', '**/*.stories.{js,ts,tsx}'],
109115
rules: {
110116
'@metamask/design-tokens/color-no-hex': 'off',
111117
},
112118
},
119+
{
120+
files: ['app/components/UI/Card/**/*.{js,jsx,ts,tsx}'],
121+
rules: {
122+
'@metamask/design-tokens/color-no-hex': 'error',
123+
},
124+
},
113125
{
114126
files: [
115127
'app/components/UI/Name/**/*.{js,ts,tsx}',

app/components/UI/Card/Views/CardAuthentication/CardAuthentication.test.tsx

Lines changed: 16 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -53,17 +53,22 @@ jest.mock('../../hooks/useCardProviderAuthentication', () => ({
5353
})),
5454
}));
5555

56-
jest.mock('../../../../../util/theme', () => ({
57-
useTheme: () => ({
58-
colors: {
59-
background: { default: '#FFFFFF' },
60-
text: { primary: '#000000', alternative: '#666666' },
61-
primary: { default: '#037DD6' },
62-
error: { default: '#D73A49', muted: '#FEF2F2' },
63-
border: { default: '#E1E4E8' },
64-
},
65-
}),
66-
}));
56+
jest.mock('../../../../../util/theme', () => {
57+
const actual = jest.requireActual('../../../../../util/theme');
58+
return {
59+
...actual,
60+
useTheme: () => ({
61+
...actual.mockTheme,
62+
colors: {
63+
...actual.mockTheme.colors,
64+
text: {
65+
...actual.mockTheme.colors.text,
66+
primary: actual.mockTheme.colors.text.default,
67+
},
68+
},
69+
}),
70+
};
71+
});
6772

6873
jest.mock('../../../../../../locales/i18n', () => ({
6974
strings: (key: string) => {

app/components/UI/Card/Views/CardWelcome/CardWelcome.test.tsx

Lines changed: 7 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -51,9 +51,13 @@ jest.mock('../../../../../../locales/i18n', () => ({
5151

5252
jest.mock('../../../../../images/stacked-cards.png', () => 1);
5353

54-
jest.mock('../../../../../util/theme', () => ({
55-
useTheme: () => ({ colors: { background: { default: '#fff' } } }),
56-
}));
54+
jest.mock('../../../../../util/theme', () => {
55+
const actual = jest.requireActual('../../../../../util/theme');
56+
return {
57+
...actual,
58+
useTheme: () => actual.mockTheme,
59+
};
60+
});
5761

5862
const createTestStore = (initialState = {}) =>
5963
configureStore({

app/components/UI/Card/Views/Cashback/Cashback.test.tsx

Lines changed: 7 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -36,16 +36,13 @@ jest.mock('../../util/metrics', () => ({
3636
},
3737
}));
3838

39-
jest.mock('../../../../../util/theme', () => ({
40-
useTheme: jest.fn(() => ({
41-
colors: {
42-
icon: { default: '#000' },
43-
success: { default: '#00ff00' },
44-
error: { default: '#ff0000' },
45-
background: { default: '#fff' },
46-
},
47-
})),
48-
}));
39+
jest.mock('../../../../../util/theme', () => {
40+
const actual = jest.requireActual('../../../../../util/theme');
41+
return {
42+
...actual,
43+
useTheme: jest.fn(() => actual.mockTheme),
44+
};
45+
});
4946

5047
jest.mock('../../../../../../locales/i18n', () => ({
5148
strings: (key: string) => {

app/components/UI/Card/Views/SpendingLimit/SpendingLimit.test.tsx

Lines changed: 7 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -119,17 +119,13 @@ jest.mock('../../sdk', () => ({
119119
})),
120120
}));
121121

122-
jest.mock('../../../../../util/theme', () => ({
123-
useTheme: jest.fn(() => ({
124-
colors: {
125-
success: { default: '#00ff00', muted: '#00ff0033' },
126-
error: { default: '#ff0000', muted: '#ff000033' },
127-
background: { default: '#ffffff' },
128-
text: { default: '#000000' },
129-
border: { default: '#cccccc' },
130-
},
131-
})),
132-
}));
122+
jest.mock('../../../../../util/theme', () => {
123+
const actual = jest.requireActual('../../../../../util/theme');
124+
return {
125+
...actual,
126+
useTheme: jest.fn(() => actual.mockTheme),
127+
};
128+
});
133129

134130
const mockToastRef = {
135131
current: {

app/components/UI/Card/components/AddFundsBottomSheet/AddFundsBottomSheet.test.tsx

Lines changed: 7 additions & 21 deletions
Original file line numberDiff line numberDiff line change
@@ -51,27 +51,13 @@ jest.mock('../../../../../util/trace', () => ({
5151
},
5252
}));
5353

54-
jest.mock('../../../../../util/theme', () => ({
55-
useTheme: jest.fn(() => ({
56-
colors: {
57-
text: {
58-
alternative: '#666666',
59-
},
60-
},
61-
})),
62-
mockTheme: {
63-
colors: {
64-
background: {
65-
default: '#ffffff',
66-
},
67-
text: {
68-
default: '#000000',
69-
alternative: '#666666',
70-
},
71-
},
72-
themeAppearance: 'light',
73-
},
74-
}));
54+
jest.mock('../../../../../util/theme', () => {
55+
const { mockTheme } = jest.requireActual('../../../../../util/theme');
56+
return {
57+
useTheme: jest.fn(() => mockTheme),
58+
mockTheme,
59+
};
60+
});
7561

7662
jest.mock('./AddFundsBottomSheet.styles', () => ({
7763
createStyles: jest.fn(() => ({

app/components/UI/Card/components/AssetSelectionBottomSheet/AssetSelectionBottomSheet.test.tsx

Lines changed: 7 additions & 22 deletions
Original file line numberDiff line numberDiff line change
@@ -3,28 +3,13 @@ const mockNavigate = jest.fn();
33
const mockGoBack = jest.fn();
44

55
// Mock theme first to prevent component initialization errors
6-
jest.mock('../../../../../util/theme', () => ({
7-
useTheme: jest.fn(() => ({
8-
colors: {
9-
primary: { default: '#0376c9' },
10-
success: { default: '#28a745', muted: '#d4edda' },
11-
error: { default: '#d73a49', muted: '#f8d7da' },
12-
background: { default: '#ffffff' },
13-
text: { default: '#000000' },
14-
},
15-
themeAppearance: 'light',
16-
})),
17-
mockTheme: {
18-
colors: {
19-
primary: { default: '#0376c9' },
20-
success: { default: '#28a745', muted: '#d4edda' },
21-
error: { default: '#d73a49', muted: '#f8d7da' },
22-
background: { default: '#ffffff' },
23-
text: { default: '#000000' },
24-
},
25-
themeAppearance: 'light',
26-
},
27-
}));
6+
jest.mock('../../../../../util/theme', () => {
7+
const actual = jest.requireActual('../../../../../util/theme');
8+
return {
9+
...actual,
10+
useTheme: jest.fn(() => actual.mockTheme),
11+
};
12+
});
2813

2914
const mockUseParams = jest.fn();
3015
jest.mock('@react-navigation/native', () => ({

app/components/UI/Card/components/DaimoPayModal/DaimoPayModal.test.tsx

Lines changed: 7 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -114,10 +114,13 @@ jest.mock('../../../../../../locales/i18n', () => ({
114114
}));
115115

116116
jest.mock('@metamask/design-system-twrnc-preset', () => ({
117-
useTailwind: () => ({
118-
style: jest.fn(() => ({})),
119-
color: jest.fn(() => '#000'),
120-
}),
117+
useTailwind: () => {
118+
const { mockTheme } = jest.requireActual('../../../../../util/theme');
119+
return {
120+
style: jest.fn(() => ({})),
121+
color: jest.fn(() => mockTheme.colors.text.default),
122+
};
123+
},
121124
}));
122125

123126
jest.mock('../../../../../core/EntryScriptWeb3', () => ({

app/components/UI/Card/components/Onboarding/ConfirmEmail.test.tsx

Lines changed: 12 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -258,22 +258,19 @@ jest.mock('react-native-confirmation-code-field', () => {
258258
});
259259

260260
// Mock useStyles hook
261-
jest.mock('../../../../../component-library/hooks', () => ({
262-
useStyles: jest.fn(() => ({
263-
styles: {
264-
codeFieldRoot: {},
265-
cellRoot: {},
266-
focusCell: {},
267-
},
268-
theme: {
269-
colors: {
270-
text: {
271-
alternative: '#6a737d',
272-
},
261+
jest.mock('../../../../../component-library/hooks', () => {
262+
const { mockTheme } = jest.requireActual('../../../../../util/theme');
263+
return {
264+
useStyles: jest.fn(() => ({
265+
styles: {
266+
codeFieldRoot: {},
267+
cellRoot: {},
268+
focusCell: {},
273269
},
274-
},
275-
})),
276-
}));
270+
theme: mockTheme,
271+
})),
272+
};
273+
});
277274

278275
jest.mock('../../../../hooks/useAnalytics/useAnalytics', () => ({
279276
useAnalytics: jest.fn(),

app/components/UI/Card/components/Onboarding/KYCFailed.test.tsx

Lines changed: 8 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -198,11 +198,14 @@ jest.mock('../../../../../../locales/i18n', () => ({
198198
}));
199199

200200
// Mock styles/common
201-
jest.mock('../../../../../styles/common', () => ({
202-
colors: {
203-
white: '#FFFFFF',
204-
},
205-
}));
201+
jest.mock('../../../../../styles/common', () => {
202+
const { brandColor } = jest.requireActual('@metamask/design-tokens');
203+
return {
204+
colors: {
205+
white: brandColor.white,
206+
},
207+
};
208+
});
206209

207210
describe('KYCFailed Component', () => {
208211
const mockNavigate = jest.fn();

0 commit comments

Comments
 (0)