---
description: Critical rules for avoiding out-of-memory issues in tests, specifically preventing nested require() calls that cause pipeline failures
version: 1.0.0
status: active
owners:
  - team: mobile-identity
  - team: platform-infrastructure
lastUpdated: 2025-01-12
specId: test-memory-optimization
importanceScore: 100
importanceJustification: Prevents catastrophic pipeline failures due to out-of-memory errors caused by nested require() calls, especially with react-native modules in test environments.
contextUsageNote: If this file is used to add in-context notes, include a single italicized line stating what specific information was used from this file in sentence case.
---

# Test Memory Optimization Rules

## Critical: Never Nest require() Calls

### The Problem

Nested `require('react-native')` calls within tests cause **out-of-memory (OOM) errors** in CI/CD pipelines. This happens because:

1. **Module Resolution Loops**: Each nested require can trigger additional module resolution and initialization
2. **Memory Accumulation**: React Native modules are large and complex; nested requires multiply memory usage
3. **Test Environment Overhead**: Jest/Vitest test runners already load modules; nested requires create duplicate module instances
4. **Hermes Parser Issues**: Nested requires can trigger WASM memory issues with hermes-parser

### The Rule

**NEVER create nested `require('react-native')` calls within test files or test setup files.**

### Examples of FORBIDDEN Patterns

#### ❌ FORBIDDEN: Nested require in test files
```typescript
// BAD - This will cause OOM issues
describe('MyComponent', () => {
  beforeEach(() => {
    const RN = require('react-native');
    const Component = require('./MyComponent');
    // Component internally does: require('react-native') again
    // This creates nested requires = OOM
  });
});
```

#### ❌ FORBIDDEN: require() inside module that's required in tests
```typescript
// BAD - If this module is required in tests, it creates nested requires
// app/src/utils/myUtil.ts
export function myFunction() {
  const RN = require('react-native'); // Nested if called from test
  return RN.Platform.OS;
}
```

#### ❌ FORBIDDEN: Dynamic requires in test hooks
```typescript
// BAD - Dynamic requires in beforeEach/afterEach create nested requires
beforeEach(() => {
  jest.resetModules();
  const RN = require('react-native'); // First require
  const service = require('@/utils/service'); // May internally require RN again
});
```

### Examples of CORRECT Patterns

#### ✅ CORRECT: Use ES6 imports at top level
```typescript
// GOOD - Single import at top level
import { Platform } from 'react-native';

describe('MyComponent', () => {
  it('should work', () => {
    expect(Platform.OS).toBe('ios');
  });
});
```

**Key Rule**: Use `import` statements, not `require()`. React Native is already mocked in setup files (`jest.setup.js` for Jest, `tests/setup.ts` for Vitest), so imports work correctly.

## React Native Module Handling in Tests

### Jest Setup Pattern (app/jest.setup.js)

The project uses a custom require override in `jest.setup.js` to handle React Native mocks:

```javascript
// This is OK - it's in setup file, runs once
const Module = require('module');
const originalRequire = Module.prototype.require;
Module.prototype.require = function (id) {
  if (id === 'react-native') {
    const RN = originalRequire.apply(this, arguments);
    // Add mocks if needed
    return RN;
  }
  return originalRequire.apply(this, arguments);
};
```

**Key Point**: This override runs ONCE during test setup. Tests should NOT create additional require() calls that would trigger this override multiple times.

### Vitest Setup Pattern (packages/mobile-sdk-alpha/tests/setup.ts)

Vitest uses `vi.mock()` to mock React Native:

```typescript
// This is OK - runs once during setup
vi.mock('react-native', () => ({
  Platform: { OS: 'web' },
  // ... other mocks
}));
```

**Key Point**: Tests should use `import` statements, not `require()`, after mocks are set up.

## Best Practices

1. **Always use ES6 `import` statements** - Never use `require('react')` or `require('react-native')` in test files
2. **Put all imports at the top of the file** - No dynamic imports in hooks
3. **Avoid `jest.resetModules()`** - Only use when absolutely necessary for module initialization tests
4. **Use setup file mocks** - React Native is already mocked in `jest.setup.js` (Jest) or `tests/setup.ts` (Vitest)

## Automated Enforcement

The project has multiple layers of protection against nested require() patterns:

### 1. ESLint Rule (app/.eslintrc.cjs)

ESLint will fail on `require('react')` and `require('react-native')` in test files:

```javascript
'no-restricted-syntax': [
  'error',
  {
    selector: "CallExpression[callee.name='require'][arguments.0.value='react']",
    message: "Do not use require('react') in tests..."
  },
  {
    selector: "CallExpression[callee.name='require'][arguments.0.value='react-native']",
    message: "Do not use require('react-native') in tests..."
  }
]
```

Run `yarn lint` to check for violations.

### 2. Validation Script (app/scripts/check-test-requires.cjs)

Automated script to detect nested require patterns:

```bash
node scripts/check-test-requires.cjs
```

This script:
- Scans all test files for `require('react')` and `require('react-native')`
- Reports exact file locations and line numbers
- Exits with error code 1 if issues found

### 3. CI Fast-Fail Check

GitHub Actions runs the validation script before tests:

```yaml
- name: Check for nested require() in tests
  run: node scripts/check-test-requires.cjs
  working-directory: ./app
```

This prevents wasting CI time on tests that will OOM.

## Quick Checklist

Before committing test changes:
- [ ] No `require('react')` calls in test files (use `import React from 'react'` instead)
- [ ] No `require('react-native')` calls in test files (use `import { ... } from 'react-native'` instead)
- [ ] All imports at top of file (not in hooks or jest.mock() factories)
- [ ] Run validation: `node scripts/check-test-requires.cjs`
- [ ] Run lint: `yarn lint`

## Detection

**Signs of nested require issues**: CI OOM errors, test timeouts, memory spikes, "Call stack size exceeded" errors, tests hiding actual failures

**Fix**:
1. Search for `require('react')` and `require('react-native')` in tests
2. Replace with `import` statements at the top of the file
3. Run `node scripts/check-test-requires.cjs` to verify

## Related Files

- `app/.eslintrc.cjs` - ESLint rules blocking nested requires
- `app/scripts/check-test-requires.cjs` - Validation script
- `.github/workflows/mobile-ci.yml` - CI enforcement
- `app/jest.setup.js` - Jest setup with React Native mocks
- `packages/mobile-sdk-alpha/tests/setup.ts` - Vitest setup with React Native mocks
- `app/jest.config.cjs` - Jest configuration
- `packages/mobile-sdk-alpha/vitest.config.ts` - Vitest configuration

$END$
