@happy-dom/jest-environment
Version:
Use Happy DOM as environment in Jest.
179 lines • 6.73 kB
JavaScript
;
/* eslint-disable filenames/match-exported */
var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
if (k2 === undefined) k2 = k;
var desc = Object.getOwnPropertyDescriptor(m, k);
if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
desc = { enumerable: true, get: function() { return m[k]; } };
}
Object.defineProperty(o, k2, desc);
}) : (function(o, m, k, k2) {
if (k2 === undefined) k2 = k;
o[k2] = m[k];
}));
var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) {
Object.defineProperty(o, "default", { enumerable: true, value: v });
}) : function(o, v) {
o["default"] = v;
});
var __importStar = (this && this.__importStar) || function (mod) {
if (mod && mod.__esModule) return mod;
var result = {};
if (mod != null) for (var k in mod) if (k !== "default" && Object.prototype.hasOwnProperty.call(mod, k)) __createBinding(result, mod, k);
__setModuleDefault(result, mod);
return result;
};
Object.defineProperty(exports, "__esModule", { value: true });
const JestUtil = __importStar(require("jest-util"));
const jest_mock_1 = require("jest-mock");
const fake_timers_1 = require("@jest/fake-timers");
const happy_dom_1 = require("happy-dom");
/**
* Happy DOM Jest Environment.
*/
class HappyDOMEnvironment {
fakeTimers = null;
fakeTimersModern = null;
window;
global;
moduleMocker;
/**
* jest-environment-jsdom" has the default set to ['browser']
* As changing this value would be a breaking change, we will keep it at ['node', 'node-addons'] until we do a major release
*
* @see https://stackoverflow.com/questions/72428323/jest-referenceerror-vue-is-not-defined
*/
customExportConditions = ['node', 'node-addons'];
_configuredExportConditions;
/**
* Constructor.
*
* @param config Jest config.
* @param config.globalConfig jest global config.
* @param config.projectConfig jest project config.
* @param options Options.
*/
constructor(config, options) {
let projectConfig;
let globals;
if (isJestConfigVersion29(config)) {
// Jest 29
globals = config.globals;
projectConfig = config;
}
else if (isJestConfigVersion28(config)) {
// Jest < 29
globals = config.projectConfig.globals;
projectConfig = config.projectConfig;
}
else {
throw new Error('Unsupported jest version.');
}
if ('customExportConditions' in projectConfig.testEnvironmentOptions) {
const { customExportConditions } = projectConfig.testEnvironmentOptions;
if (Array.isArray(customExportConditions) &&
customExportConditions.every((condition) => typeof condition === 'string')) {
this._configuredExportConditions = customExportConditions;
}
else {
throw new Error('Custom export conditions specified but they are not an array of strings');
}
}
// Initialize Window and Global
this.window = new happy_dom_1.Window({
url: 'http://localhost/',
...projectConfig.testEnvironmentOptions,
console: options.console || console,
settings: {
...projectConfig.testEnvironmentOptions?.settings,
errorCapture: happy_dom_1.BrowserErrorCaptureEnum.disabled
}
});
this.global = this.window;
this.moduleMocker = new jest_mock_1.ModuleMocker(this.window);
// Node's error-message stack size is limited to 10, but it's pretty useful to see more than that when a test fails.
this.global.Error.stackTraceLimit = 100;
// TODO: Remove this ASAP as it currently causes tests to run really slow.
this.global.Buffer = Buffer;
// Needed as Jest is using it
this.window['global'] = this.global;
JestUtil.installCommonGlobals(this.window, globals);
// For some reason Jest removes the global setImmediate, so we need to add it back.
this.global.setImmediate = global.setImmediate;
this.fakeTimers = new fake_timers_1.LegacyFakeTimers({
config: projectConfig,
global: this.window,
moduleMocker: this.moduleMocker,
timerConfig: {
idToRef: (id) => id,
refToId: (ref) => ref
}
});
this.fakeTimersModern = new fake_timers_1.ModernFakeTimers({
config: projectConfig,
global: this.window
});
// Jest is using the setTimeout function from Happy DOM internally for detecting when a test times out, but this causes window.happyDOM?.waitUntilComplete() and window.happyDOM?.abort() to not work as expected.
// Hopefully Jest can fix this in the future as this fix is not very pretty.
const happyDOMSetTimeout = this.global.setTimeout;
this.global.setTimeout = (...args) => {
if (new Error('stack').stack.includes('/jest-jasmine')) {
return global.setTimeout.call(global, ...args);
}
return happyDOMSetTimeout.call(this.global, ...args);
};
}
/**
* Respect any export conditions specified as options
* https://jestjs.io/docs/configuration#testenvironmentoptions-object
*/
exportConditions() {
return this._configuredExportConditions ?? this.customExportConditions;
}
/**
* Setup.
*
* @returns Promise.
*/
async setup() { }
/**
* Teardown.
*
* @returns Promise.
*/
async teardown() {
this.fakeTimers.dispose();
this.fakeTimersModern.dispose();
await this.global.happyDOM.abort();
this.global.close();
this.global = null;
this.moduleMocker = null;
this.fakeTimers = null;
this.fakeTimersModern = null;
}
/**
* Runs a script.
*
* @param script Script.
* @returns Result.
*/
runScript(script) {
return script.runInContext(this.global);
}
/**
* Returns the VM context.
*
* @returns Context.
*/
getVmContext() {
return this.global;
}
}
exports.default = HappyDOMEnvironment;
function isJestConfigVersion29(config) {
return Object.getOwnPropertyDescriptor(config, 'globals') !== undefined;
}
function isJestConfigVersion28(config) {
return Object.getOwnPropertyDescriptor(config, 'projectConfig') !== undefined;
}
//# sourceMappingURL=index.js.map