Jest Environment Emitter
jest-environment-emit is a utility package for Jest that overcomes the limitation of having only one test environment per project. It provides a mechanism to add multiple event handlers to any Jest test environment, acting similarly to multiple test reporters. The package offers `WithEmitter`, a higher-order function to wrap custom environments, and pre-wrapped `TestEnvironment` classes for `jest-environment-node` and `jest-environment-jsdom` via subpath exports. Currently at version 1.2.0, released in June 2025, the package maintains a steady release cadence, frequently addressing compatibility with new Jest versions (e.g., Jest 30 support in v1.2.0) and refining import/export mechanisms for robust ESM and CJS interoperability. Its primary differentiator is enabling modular, composable event-driven logic within the Jest testing lifecycle, which is otherwise restricted to a single environment definition. It ships with full TypeScript types, enhancing developer experience.
Common errors
-
TypeError: (0, jest_environment_emit_1.TestEnvironment) is not a constructor
cause Attempting to import `TestEnvironment` directly from the main `jest-environment-emit` package, which only exports `WithEmitter` by default.fixUse the correct subpath import for the desired environment, e.g., `import { TestEnvironment } from 'jest-environment-emit/node';`. -
Jest: `testEnvironment` must be a path to a Node module. Error: Cannot find module 'jest-environment-emit'
cause The package `jest-environment-emit` or its specific subpath export is not correctly resolved by Node/Jest.fixEnsure `jest-environment-emit` is installed. If using a specific subpath (e.g., `jest-environment-emit/node`), verify the path is correct and accessible from your Jest configuration file. This often happens if the package isn't in `node_modules` or a symlink is broken. -
TypeError: Cannot read properties of undefined (reading 'on') at subscription (my-listener.js)
cause The `context.testEvents` object within your event listener function is `undefined` because the listener function was not called by `jest-environment-emit`.fixVerify that your listener module is correctly listed in `testEnvironmentOptions.eventListeners` in your Jest config and that it exports the listener function as a `default` export.
Warnings
- breaking Version 1.2.0 introduced support for Jest 30. While this is a feature, environments relying on older Jest versions or custom Jest configurations might require updates to ensure full compatibility. Always verify your Jest setup when upgrading.
- gotcha Incorrect subpath imports for built-in environments. Trying to `import { TestEnvironment } from 'jest-environment-emit'` will fail as the main export is `WithEmitter`.
- gotcha Earlier versions (prior to 1.0.8) could have listeners that were not resilient to errors, potentially causing entire test runs to fail if an individual listener threw an unhandled exception.
- gotcha Versions prior to 1.0.3/1.0.5 had issues with ESM/CJS export collisions and quirky import patterns, potentially leading to 'undefined' imports or incorrect module resolution, especially in mixed environments.
Install
-
npm install jest-environment-emit -
yarn add jest-environment-emit -
pnpm add jest-environment-emit
Imports
- WithEmitter
const WithEmitter = require('jest-environment-emit').WithEmitter;import { WithEmitter } from 'jest-environment-emit'; - TestEnvironment (Node)
import { TestEnvironment } from 'jest-environment-emit';import { TestEnvironment } from 'jest-environment-emit/node'; - TestEnvironment (JSDOM)
import { TestEnvironment } from 'jest-environment-emit';import { TestEnvironment } from 'jest-environment-emit/jsdom'; - EnvironmentListenerFn
import type { EnvironmentListenerFn } from 'jest-environment-emit';
Quickstart
/** @type {import('jest').Config} */
module.exports = {
testEnvironment: 'jest-environment-emit/node',
testEnvironmentOptions: {
eventListeners: [
'./jest-setup-listener.js',
['./jest-parametrized-listener.js', { some: 'options', token: process.env.API_TOKEN ?? '' }],
]
},
};
// jest-setup-listener.js
/** @type {import('jest-environment-emit').EnvironmentListenerFn} */
const setupListener = function (context, options) {
context.testEvents
.on('test_environment_setup', async ({ env }) => {
console.log('Test environment setup initiated!');
env.global.__MY_CUSTOM_GLOBAL__ = 'initialized from listener';
})
.on('test_start', ({ event, state }) => {
console.log(`Starting test: ${event.test.name}`);
})
.on('test_environment_teardown', async ({ env }) => {
console.log('Test environment teardown completed!');
delete env.global.__MY_CUSTOM_GLOBAL__;
});
};
export default setupListener;