Skip to content

Commit

Permalink
feat(jest-environment): Support configuration of happy-dom with testE…
Browse files Browse the repository at this point in the history
…nvironmentOptions
  • Loading branch information
Codex- committed Mar 11, 2024
1 parent 1bd9020 commit ff9b0ed
Show file tree
Hide file tree
Showing 2 changed files with 158 additions and 4 deletions.
153 changes: 153 additions & 0 deletions packages/jest-environment/src/configuration.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,153 @@
import type { Config } from '@jest/types';
import {
BrowserErrorCaptureEnum,
BrowserNavigationCrossOriginPolicyEnum,
type IWindow
} from 'happy-dom';

export function parseEnvironmentOptions(
testEnvironmentOptions: Config.ProjectConfig['testEnvironmentOptions'],
happyDOM: IWindow['happyDOM']
): void {
for (const [key, value] of Object.entries(testEnvironmentOptions)) {
switch (key) {
case 'disableJavaScriptEvaluation':
case 'disableJavaScriptFileLoading':
case 'disableCSSFileLoading':
case 'disableComputedStyleRendering': {
setValue('boolean', 'testEnvironmentOptions', happyDOM.settings, key, value);
break;
}
case 'errorCapture': {
const errorCaptureValidOptions: unknown[] = Object.values(BrowserErrorCaptureEnum);
setEnumValue(
errorCaptureValidOptions,
'testEnvironmentOptions',
happyDOM.settings,
key,
value
);
break;
}
case 'navigation': {
parseNavigationOptions(happyDOM, testEnvironmentOptions.navigation);
break;
}
case 'navigator': {
parseNavigatorOptions(happyDOM, testEnvironmentOptions.navigator);
break;
}
case 'device': {
parseDeviceOptions(happyDOM, testEnvironmentOptions.device);
break;
}
case 'url': {
if (typeof value !== 'string') {
throw new Error('testEnvironmentOptions.url must be a string');
}
happyDOM.setURL(value);
}
}
}
}

function parseNavigationOptions(happyDOM: IWindow['happyDOM'], options: unknown): void {
for (const [key, value] of Object.entries(options)) {
switch (key) {
case 'disableMainFrameNavigation':
case 'disableChildFrameNavigation':
case 'disableChildPageNavigation':
case 'disableFallbackToSetURL': {
setValue(
'boolean',
'testEnvironmentOptions.navigation',
happyDOM.settings.navigation,
key,
value
);
break;
}
case 'crossOriginPolicy': {
const browserNavigationCrossOriginPolicyOptions: unknown[] = Object.values(
BrowserNavigationCrossOriginPolicyEnum
);
setEnumValue(
browserNavigationCrossOriginPolicyOptions,
'testEnvironmentOptions.navigation',
happyDOM.settings.navigation,
key,
value
);
break;
}
}
}
}

function parseNavigatorOptions(happyDOM: IWindow['happyDOM'], options: unknown): void {
for (const [key, value] of Object.entries(options)) {
switch (key) {
case 'userAgent': {
setValue(
'string',
'testEnvironmentOptions.navigator',
happyDOM.settings.navigator,
key,
value
);
break;
}
case 'maxTouchPoints': {
setValue(
'number',
'testEnvironmentOptions.navigator',
happyDOM.settings.navigator,
key,
value
);
break;
}
}
}
}

function parseDeviceOptions(happyDOM: IWindow['happyDOM'], options: unknown): void {
for (const [key, value] of Object.entries(options)) {
switch (key) {
case 'prefersColorScheme': {
setValue('string', 'testEnvironmentOptions.device', happyDOM.settings.device, key, value);
break;
}
case 'mediaType': {
setValue('string', 'testEnvironmentOptions.device', happyDOM.settings.device, key, value);
break;
}
}
}
}

function setValue<T, U extends keyof T>(
type: 'string' | 'number' | 'boolean',
path: string,
target: T,
key: U,
value: unknown
): void {
if (typeof value !== type) {
throw new Error(`${path}.${key.toString()} must be a ${type}`);
}
target[key] = <T[U]>value;
}

function setEnumValue<T, U extends keyof T>(
enumValues: unknown[],
path: string,
target: T,
key: U,
value: unknown
): void {
if (!enumValues.includes(value)) {
throw new Error(`${path}.${key.toString()} must be one of ${enumValues.join(', ')}`);
}
target[key] = <T[U]>value;
}
9 changes: 5 additions & 4 deletions packages/jest-environment/src/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@ import { JestEnvironment, EnvironmentContext } from '@jest/environment';
import { Window, IWindow } from 'happy-dom';
import { Script } from 'vm';
import { Global, Config } from '@jest/types';
import { parseEnvironmentOptions } from './configuration';

/**
* Happy DOM Jest Environment.
Expand Down Expand Up @@ -69,10 +70,10 @@ export default class HappyDOMEnvironment implements JestEnvironment {
this.global.window['console'] = options.console;
}

if (projectConfig.testEnvironmentOptions['url']) {
this.window.happyDOM?.setURL(String(projectConfig.testEnvironmentOptions['url']));
} else {
this.window.happyDOM?.setURL('http://localhost/');
// Always set a default URL, override should the option be present in the environment options.
this.window.happyDOM?.setURL('http://localhost/');
if (projectConfig.testEnvironmentOptions && this.window.happyDOM) {
parseEnvironmentOptions(projectConfig.testEnvironmentOptions, this.window.happyDOM);
}

this.fakeTimers = new LegacyFakeTimers({
Expand Down

0 comments on commit ff9b0ed

Please sign in to comment.