Commit f923f78
authored
chore: improve unit test CI performance via shared deps cache and Jest cache (#28419)
---
## **Description**
If we start to see OOM failures (exit code 137, "JavaScript heap out of
memory") after this change, the first thing to try would be lowering
--max_old_space_size from 20480 to something more realistic like 8192,
which forces Node's GC to be more aggressive rather than hoarding memory
until the OS kills the process.
<!--
Write a short description of the changes included in this pull request,
also include relevant motivation and context. Have in mind the following
questions:
1. What is the reason for the change?
2. What is the improvement/solution?
-->
Unit tests in CI were taking **~18+ minutes** due to several avoidable
bottlenecks. This PR addresses three root causes without requiring paid
infrastructure:
**Problems fixed:**
1. **Redundant dependency installation** — Each of 10 unit test shards,
2 component-view test shards, and the coverage merge job independently
ran `yarn install --immutable` + `yarn setup:github-ci --node` (~3–5 min
each), totalling 13 redundant installs per CI run.
2. **Jest transform cache disabled** — `cache: false` in
`jest.config.js` forced every shard to re-parse and re-transform all
~3,060 test files through `babel-jest` from scratch on every run.
3. **Low parallelism within shards** — `maxWorkers: '20%'` on a 4-vCPU
`ubuntu-latest` runner meant Jest used ~1 worker per shard, leaving 3
cores idle.
**Changes:**
- New `prepare-unit-test-deps` CI job runs `yarn install` +
`setup:github-ci --node` once and caches `node_modules` via
`actions/cache`. All downstream jobs restore from this cache (~30s)
instead of installing independently.
- Jest transform cache persisted across CI runs via `actions/cache`,
keyed on `yarn.lock` + `babel.config.tests.js`. Transforms are only
redone when dependencies or transform config change.
- `cache: false` → `cache: true` in `jest.config.js`, with a
configurable `cacheDirectory` via `JEST_CACHE_DIRECTORY` env var so CI
controls the cache path.
- `maxWorkers` changed from `'20%'` (always) to `'50%'` in CI / `'20%'`
locally, utilizing ~2 workers on the 4-core runner instead of ~1.
**Expected impact (warm cache):**
| Metric | Before | After |
|---|---|---|
| Setup time per shard | ~3–5 min | ~30s |
| Transform time per shard | Full rebuild every run | Cached |
| Jest workers per shard | ~1 | ~2 |
| **Estimated wall-clock time** | **~18+ min** | **~8–12 min** |
## **Changelog**
CHANGELOG entry: null
## **Related issues**
Fixes:
## **Manual testing steps**
N/A
## **Screenshots/Recordings**
### **Before**
<img width="1079" height="381" alt="image"
src="https://github.com/user-attachments/assets/4d2a32f5-6ab0-410d-838e-b902172567a2"
/>
N/A
### **After**
<img width="976" height="318" alt="image"
src="https://github.com/user-attachments/assets/25655008-6956-49b7-8a4f-db1bf72ea12c"
/>
N/A
## **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
- [x] I've documented my code using [JSDoc](https://jsdoc.app/) format
if applicable
- [x] 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**
- [x] I've manually tested the PR (e.g. pull and build branch, run the
app, test code being changed).
- [x] 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.
<!-- Generated with the help of the pr-description AI skill -->
Made with [Cursor](https://cursor.com)
<!-- CURSOR_SUMMARY -->
---
> [!NOTE]
> **Medium Risk**
> Changes CI test execution by introducing cross-job workspace caching
and enabling Jest caching, which could cause flaky runs or cache-miss
failures if the cache keys/paths are incorrect. No production runtime
code is affected.
>
> **Overview**
> Improves CI test performance by introducing a new
`prepare-unit-test-deps` job that installs once and caches a prepared
workspace (`node_modules`, `.yarn`, and generated terms-of-use content)
for all unit-test shards, component-view shards, and the coverage merge
job.
>
> Enables and persists Jest’s transform cache across CI runs (shared
`JEST_CACHE_DIRECTORY` at `/tmp/jest_rs` with an `actions/cache` key
based on `yarn.lock` and `babel.config.tests.js`) and increases Jest
parallelism in CI by setting `maxWorkers` to `50%` when `process.env.CI`
is set.
>
> <sup>Reviewed by [Cursor Bugbot](https://cursor.com/bugbot) for commit
cafd2e6. Bugbot is set up for automated
code reviews on this repo. Configure
[here](https://www.cursor.com/dashboard/bugbot).</sup>
<!-- /CURSOR_SUMMARY -->1 parent bfc8e9a commit f923f78
2 files changed
Lines changed: 70 additions & 29 deletions
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
| |||
259 | 259 | | |
260 | 260 | | |
261 | 261 | | |
262 | | - | |
263 | | - | |
| 262 | + | |
| 263 | + | |
| 264 | + | |
| 265 | + | |
264 | 266 | | |
265 | 267 | | |
266 | 268 | | |
267 | 269 | | |
268 | | - | |
269 | | - | |
270 | | - | |
271 | 270 | | |
272 | 271 | | |
273 | 272 | | |
| |||
283 | 282 | | |
284 | 283 | | |
285 | 284 | | |
| 285 | + | |
| 286 | + | |
| 287 | + | |
| 288 | + | |
| 289 | + | |
| 290 | + | |
| 291 | + | |
| 292 | + | |
| 293 | + | |
| 294 | + | |
| 295 | + | |
| 296 | + | |
| 297 | + | |
| 298 | + | |
| 299 | + | |
| 300 | + | |
| 301 | + | |
| 302 | + | |
| 303 | + | |
| 304 | + | |
| 305 | + | |
| 306 | + | |
| 307 | + | |
| 308 | + | |
| 309 | + | |
| 310 | + | |
| 311 | + | |
| 312 | + | |
| 313 | + | |
| 314 | + | |
| 315 | + | |
| 316 | + | |
| 317 | + | |
| 318 | + | |
| 319 | + | |
| 320 | + | |
| 321 | + | |
| 322 | + | |
| 323 | + | |
| 324 | + | |
286 | 325 | | |
287 | 326 | | |
288 | 327 | | |
289 | 328 | | |
290 | 329 | | |
291 | 330 | | |
292 | 331 | | |
| 332 | + | |
293 | 333 | | |
294 | 334 | | |
295 | 335 | | |
| |||
317 | 357 | | |
318 | 358 | | |
319 | 359 | | |
320 | | - | |
| 360 | + | |
321 | 361 | | |
322 | 362 | | |
323 | 363 | | |
324 | 364 | | |
325 | 365 | | |
326 | 366 | | |
327 | | - | |
328 | | - | |
329 | | - | |
330 | | - | |
331 | | - | |
332 | | - | |
333 | | - | |
334 | | - | |
335 | | - | |
336 | | - | |
| 367 | + | |
| 368 | + | |
| 369 | + | |
| 370 | + | |
| 371 | + | |
| 372 | + | |
| 373 | + | |
| 374 | + | |
| 375 | + | |
337 | 376 | | |
338 | 377 | | |
339 | 378 | | |
| |||
428 | 467 | | |
429 | 468 | | |
430 | 469 | | |
| 470 | + | |
431 | 471 | | |
432 | 472 | | |
433 | 473 | | |
| |||
436 | 476 | | |
437 | 477 | | |
438 | 478 | | |
439 | | - | |
440 | | - | |
441 | | - | |
442 | | - | |
443 | | - | |
444 | | - | |
445 | | - | |
446 | | - | |
447 | | - | |
448 | | - | |
| 479 | + | |
| 480 | + | |
| 481 | + | |
| 482 | + | |
| 483 | + | |
| 484 | + | |
| 485 | + | |
| 486 | + | |
| 487 | + | |
449 | 488 | | |
450 | 489 | | |
451 | 490 | | |
| |||
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
| |||
60 | 60 | | |
61 | 61 | | |
62 | 62 | | |
63 | | - | |
| 63 | + | |
64 | 64 | | |
65 | 65 | | |
66 | 66 | | |
| |||
89 | 89 | | |
90 | 90 | | |
91 | 91 | | |
92 | | - | |
93 | | - | |
| 92 | + | |
| 93 | + | |
| 94 | + | |
| 95 | + | |
94 | 96 | | |
95 | 97 | | |
96 | 98 | | |
| |||
0 commit comments