Skip to content

Fix: Jest Setup File Not Working — setupFilesAfterFramework Not Running or Globals Not Applied

FixDevs ·

Quick Answer

How to fix Jest setup file issues — setupFilesAfterFramework vs setupFiles, global mocks not applying, @testing-library/jest-dom matchers, module mocking in setup, and TypeScript setup files.

The Problem

Jest setup file code doesn’t run before tests:

// jest.setup.js
global.fetch = jest.fn();  // Should mock fetch globally

// test file
test('fetch is mocked', () => {
  expect(fetch).toBeDefined();  // ReferenceError: fetch is not defined
});

Or @testing-library/jest-dom matchers aren’t available:

// test file
expect(element).toBeInTheDocument();
// TypeError: expect(...).toBeInTheDocument is not a function

Or a module mock defined in the setup file doesn’t apply to test files:

// jest.setup.js
jest.mock('axios');  // Should mock axios in all tests

// test file
import axios from 'axios';
test('axios is mocked', () => {
  expect(jest.isMockFunction(axios.get)).toBe(true);  // false — not mocked
});

Why This Happens

Jest has two separate setup mechanisms with different timing and scope:

  • setupFiles — runs before the test framework (Jest/Jasmine) is installed. Use for polyfills and environment setup. Does NOT have access to jest globals like jest.fn() or expect.
  • setupFilesAfterFramework — the correct spelling is setupFilesAfterFramework. Runs after the framework is installed, so jest, expect, and matchers are available. This is where you add custom matchers, global mocks, and @testing-library/jest-dom.
  • Typo in config keysetupFilesAfterFramework vs setupTestFrameworkScriptFile (old Jest) vs setupFilesAfterFramework — a single typo means the file is silently ignored.
  • jest.mock() in setup files — module mocks registered with jest.mock() in setup files apply to the setup file’s module scope, not automatically to all test files.

Fix 1: Use the Correct Config Keys

// jest.config.js
module.exports = {
  // Runs BEFORE the test framework — no jest.fn(), no expect
  // Use for: polyfills, global variable setup, environment patches
  setupFiles: [
    './jest.polyfills.js',      // e.g., TextEncoder, crypto polyfills
    './jest.env-setup.js',
  ],

  // Runs AFTER the framework — jest.fn(), expect, and custom matchers available
  // Use for: custom matchers, global mocks, testing-library setup
  setupFilesAfterFramework: [
    './jest.setup.js',
  ],

  testEnvironment: 'jsdom',  // 'node' for Node.js, 'jsdom' for browser-like
};

Note: In older versions of Jest (≤26), the key was setupTestFrameworkScriptFile (singular, deprecated). From Jest 27+, use setupFilesAfterFramework (plural).

TypeScript config:

// jest.config.ts
import type { Config } from 'jest';

const config: Config = {
  setupFilesAfterFramework: ['./jest.setup.ts'],
  testEnvironment: 'jsdom',
  transform: {
    '^.+\\.(ts|tsx)$': ['ts-jest', { tsconfig: './tsconfig.test.json' }],
  },
};

export default config;

Fix 2: Set Up @testing-library/jest-dom

npm install --save-dev @testing-library/jest-dom
// jest.setup.js
import '@testing-library/jest-dom';
// Or: require('@testing-library/jest-dom');

// Now all jest-dom matchers are available in all tests:
// toBeInTheDocument, toHaveTextContent, toBeVisible, toBeDisabled, etc.
// jest.config.js
module.exports = {
  setupFilesAfterFramework: ['./jest.setup.js'],
  // Or use the shorthand (testing-library provides a jest-dom setup file)
  setupFilesAfterFramework: ['@testing-library/jest-dom'],
};

TypeScript — add type declarations:

// jest.setup.ts
import '@testing-library/jest-dom';
// tsconfig.json — include jest-dom types
{
  "compilerOptions": {
    "types": ["jest", "@testing-library/jest-dom"]
  }
}

Fix 3: Global Mocks in Setup Files

For mocks that should apply to every test file, use setupFiles or setupFilesAfterFramework:

// jest.setup.js — global mocks available in all tests

// Mock fetch (not available in jsdom by default)
global.fetch = jest.fn();

// Reset all mocks before each test
beforeEach(() => {
  jest.clearAllMocks();
  // Or: jest.resetAllMocks() — also resets mock implementations
  // Or: jest.restoreAllMocks() — also restores spies
});

// Mock browser APIs not available in jsdom
global.ResizeObserver = jest.fn().mockImplementation(() => ({
  observe: jest.fn(),
  unobserve: jest.fn(),
  disconnect: jest.fn(),
}));

global.IntersectionObserver = jest.fn().mockImplementation(() => ({
  observe: jest.fn(),
  unobserve: jest.fn(),
  disconnect: jest.fn(),
  root: null,
  rootMargin: '',
  thresholds: [],
}));

// Mock matchMedia (not in jsdom)
Object.defineProperty(window, 'matchMedia', {
  writable: true,
  value: jest.fn().mockImplementation(query => ({
    matches: false,
    media: query,
    onchange: null,
    addListener: jest.fn(),
    removeListener: jest.fn(),
    addEventListener: jest.fn(),
    removeEventListener: jest.fn(),
    dispatchEvent: jest.fn(),
  })),
});

// Mock localStorage
const localStorageMock = (() => {
  let store: Record<string, string> = {};
  return {
    getItem: jest.fn((key: string) => store[key] ?? null),
    setItem: jest.fn((key: string, value: string) => { store[key] = value; }),
    removeItem: jest.fn((key: string) => { delete store[key]; }),
    clear: jest.fn(() => { store = {}; }),
  };
})();

Object.defineProperty(window, 'localStorage', { value: localStorageMock });

Fix 4: Module Mocks with mocks Directory

For automatic module mocking across all tests, use the __mocks__ directory:

project/
  __mocks__/
    axios.js          ← Auto-mocked for 'axios'
    ../utils/api.js   ← Manual mock for '../utils/api' (relative to __mocks__)
  src/
    __mocks__/
      myModule.js     ← Mock for './myModule' when used in src/
  node_modules/
    axios/
// __mocks__/axios.js — manual mock for the axios package
const axios = {
  get: jest.fn(() => Promise.resolve({ data: {} })),
  post: jest.fn(() => Promise.resolve({ data: {} })),
  put: jest.fn(() => Promise.resolve({ data: {} })),
  delete: jest.fn(() => Promise.resolve({ data: {} })),
  create: jest.fn(function() { return this; }),
  defaults: { headers: { common: {} } },
  interceptors: {
    request: { use: jest.fn(), eject: jest.fn() },
    response: { use: jest.fn(), eject: jest.fn() },
  },
};

module.exports = axios;
module.exports.default = axios;
// In test files — call jest.mock('axios') to activate the __mocks__/axios.js
import axios from 'axios';
jest.mock('axios');  // Uses __mocks__/axios.js automatically

test('uses mock axios', async () => {
  axios.get.mockResolvedValueOnce({ data: { id: 1, name: 'Alice' } });
  const result = await fetchUser(1);
  expect(result.name).toBe('Alice');
});

For user modules (not node_modules), mock must be explicit or automatic:

// src/__mocks__/api.ts
export const getUser = jest.fn();
export const createUser = jest.fn();

// In test — manual mock is used when jest.mock() is called
jest.mock('../api');  // Uses src/__mocks__/api.ts

Fix 5: Environment-Specific Setup

Different test environments (node vs browser) need different setups:

// jest.config.js — multiple projects with different environments
module.exports = {
  projects: [
    {
      displayName: 'dom',
      testEnvironment: 'jsdom',
      testMatch: ['**/*.browser.test.{ts,tsx}', '**/components/**/*.test.{ts,tsx}'],
      setupFilesAfterFramework: ['./jest.setup.browser.js'],
    },
    {
      displayName: 'node',
      testEnvironment: 'node',
      testMatch: ['**/*.test.ts', '!**/*.browser.test.ts'],
      setupFilesAfterFramework: ['./jest.setup.node.js'],
    },
  ],
};
// jest.setup.browser.js
import '@testing-library/jest-dom';
import { server } from './src/mocks/server';

beforeAll(() => server.listen({ onUnhandledRequest: 'error' }));
afterEach(() => server.resetHandlers());
afterAll(() => server.close());
// jest.setup.node.js
// No DOM setup needed for node tests
process.env.NODE_ENV = 'test';
process.env.DATABASE_URL = 'postgresql://localhost:5432/testdb';

Fix 6: Verify Setup File Is Running

Add debug output to confirm the setup file actually executes:

// jest.setup.js
console.log('✓ Jest setup file loaded');

// Verify environment
console.log('Environment:', process.env.NODE_ENV);
console.log('Test environment:', process.env.JEST_WORKER_ID);
# Run with verbose output to see setup file execution
npx jest --verbose

# Run a single test to debug setup
npx jest path/to/test.test.js --verbose

# Show all console output (not silenced)
npx jest --verbose --no-coverage 2>&1

Check configuration is being read:

# Print the resolved Jest config
npx jest --showConfig | grep -A5 "setupFilesAfterFramework"

# Verify the setup file path resolves correctly
node -e "console.log(require.resolve('./jest.setup.js'))"

Still Not Working?

ESM vs CommonJS conflict — if your project uses ES modules ("type": "module" in package.json) but your setup file uses require(), it fails. Use import syntax in setup files and configure transform in jest.config.

jest.config.js vs package.json "jest" conflict — Jest reads configuration from one source. If you have both jest.config.js and a "jest" key in package.json, jest.config.js takes precedence. Remove the duplicate.

Setup file path is relative to jest.config.js locationsetupFilesAfterFramework: ['./jest.setup.js'] resolves relative to where jest.config.js lives (usually the project root), not the test file. Use <rootDir>/jest.setup.js for explicit root-relative paths:

setupFilesAfterFramework: ['<rootDir>/jest.setup.js'],

For related Jest issues, see Fix: Jest Module Mock Not Working and Fix: Jest Async Test Timeout.

F

FixDevs

Solo developer based in Japan. Every solution is cross-referenced with official documentation and tested before publishing.

Was this article helpful?

Related Articles