const testFileExtension = 'ts?(x)'; // Reassure runs only the performance tests, matched by the `.perf-test` suffix / `__perf__` folder (or the `.perf-local` suffix for local benchmarks), // which it passes to Jest as `--testMatch`. We detect that from the test-runner argv so we can leave // `performance` real for perf runs only: enabling Jest's modern fake timers globally also fakes // `performance`, and React's Scheduler captures that (frozen) clock once at module load, which zeroes // every React Profiler render duration — and thus every Reassure `[render]` measurement. const isPerfTestRun = process.argv.some((arg) => /perf-(test|local)|__perf__/.test(arg)); // With `--coverage`, Jest also instruments every file matched by `collectCoverageFrom` that no test loaded, so // untested files show up at 0%. Under `--shard=N/M` each shard would repeat that pass over all of `src/**` // (~7k files, 10-60s per shard). Only the first shard emits the untested files, the others report just what // their tests load. Codecov unions the per-shard reports, so the merged totals are unchanged. const shardMatch = process.argv.map((arg) => /^--shard=(\d+)\/\d+$/.exec(arg)).find(Boolean); const emitsUntestedFiles = !shardMatch || shardMatch[1] === '1'; module.exports = { preset: 'jest-expo', resolver: '/jest/resolver.ts', collectCoverageFrom: emitsUntestedFiles ? ['/src/**/*.{ts,tsx,js,jsx}', '!/src/**/__mocks__/**', '!/src/**/tests/**', '!**/*.d.ts'] : undefined, // Keeps the instrumented set identical to `collectCoverageFrom` above on the shards that skip it. coveragePathIgnorePatterns: ['/node_modules/', '/(?!src/)', '/__mocks__/', '/src/.*/tests/', '\\.d\\.ts$'], testMatch: [ `/tests/ui/**/*.${testFileExtension}`, `/tests/unit/**/*.${testFileExtension}`, `/tests/actions/**/*.${testFileExtension}`, `/tests/navigation/**/*.${testFileExtension}`, `/?(*.)+(spec|test).${testFileExtension}`, ], transform: { // OXC + esbuild is native and stays fast without TurboFan, where Babel was measured as // roughly half of each Reassure measure job. The transformer sends test files, mocks and // node_modules to babel-jest itself, so `jest.mock` is still hoisted there. '^.+\\.[jt]sx?$': '/config/babel/oxcJestTransformer.js', '^.+\\.svg?$': 'jest-transformer-svg', }, transformIgnorePatterns: [ '/node_modules/(?!.*(react-native|expo|react-navigation|uuid|@shopify\/flash-list).*/)', // Prevent Babel from transforming worklets in this file so they are treated as normal functions, otherwise FormatSelectionUtilsTest won't run. '/node_modules/@expensify/react-native-live-markdown/lib/commonjs/parseExpensiMark.js', ], // tests/tooling/ covers .github/ and scripts/ and runs under `bun test` instead (see the `test:bun` npm // script), so those files import `bun:test` rather than Jest's globals. They aren't in testMatch above, and // this keeps them out even if a future testMatch entry broadens to all of tests/. testPathIgnorePatterns: ['/node_modules', '/tests/tooling/'], // .worktrees/ and .claude/worktrees/ hold parallel git worktrees a developer may check out locally. // Each one carries its own modules/hybrid-app/package.json, which trips // jest-haste-map's "duplicate package name" assertion. Skip them entirely. modulePathIgnorePatterns: ['/.worktrees/', '/.claude/worktrees/'], globals: { __DEV__: true, WebSocket: {}, // Build-time define from config/rsbuild/rsbuild.common.ts. SkiaWebChart reads it when mounting CanvasKit. __CANVASKIT_WASM_URL__: '/canvaskit-test.wasm', }, fakeTimers: { enableGlobally: true, // `nextTick` is never faked because Onyx notifies its subscribers on process.nextTick. // `performance` is left real only for perf runs (see isPerfTestRun above). doNotFake: isPerfTestRun ? ['nextTick', 'performance'] : ['nextTick'], }, testEnvironment: 'jsdom', setupFiles: ['/jest/setup.ts', './node_modules/@react-native-google-signin/google-signin/jest/build/setup.js'], setupFilesAfterEnv: ['/jest/setupAfterEnv.ts', '/tests/perf-test/setupAfterEnv.ts'], // Restarts a worker between suites once it holds this much memory, so long-lived CI workers don't get OOM killed. workerIdleMemoryLimit: '2GB', cacheDirectory: '/.jest-cache', coverageReporters: ['json', 'lcov', 'text-summary'], moduleNameMapper: { '\\.(lottie)$': '/__mocks__/fileMock.ts', '^@lottiefiles/dotlottie-react$': '/__mocks__/@lottiefiles/dotlottie-react.tsx', '^group-ib-fp$': '/__mocks__/group-ib-fp.ts', '^parse-imports-exports$': '/node_modules/parse-imports-exports/index.cjs', }, };