Skip to content

Commit

Permalink
#929@minor: Adds support for disabling the simulation of rendering wh…
Browse files Browse the repository at this point in the history
…en calculating computed style. The rendering process converts units such as rem, em and cm to pixels, but it is very limited.
  • Loading branch information
capricorn86 committed May 22, 2023
1 parent 2c62156 commit 9de3ce1
Show file tree
Hide file tree
Showing 8 changed files with 76 additions and 6 deletions.
5 changes: 5 additions & 0 deletions packages/happy-dom/README.md
Expand Up @@ -258,6 +258,7 @@ const window = new Window({
disableJavaScriptEvaluation: true,
disableCSSFileLoading: true,
disableIframePageLoading: true,
disableComputedStyleRendering: true,
enableFileSystemHttpRequests: true,
device: {
mediaType: 'print',
Expand All @@ -276,6 +277,7 @@ window.happyDOM.settings.disableJavaScriptFileLoading = true;
window.happyDOM.settings.disableJavaScriptEvaluation = true;
window.happyDOM.settings.disableCSSFileLoading = true;
window.happyDOM.settings.disableIframePageLoading = true;
window.happyDOM.settings.disableComputedStyleRendering = true;
window.happyDOM.settings.enableFileSystemHttpRequests = true;
window.happyDOM.settings.device.mediaType = 'print';
window.happyDOM.settings.device.prefersColorScheme = 'dark';
Expand All @@ -297,6 +299,9 @@ Set it to "true" to disable CSS file loading in HTMLLinkElement. Defaults to "fa
Set it to "true" to disable page loading in HTMLIFrameElement. Defaults to "false".
**disableComputedStyleRendering**
Set it to "true" to disable the simulation of rendering when calculating computed style. The rendering process will convert values such as "rem", "em", "cm" etc. to pixels. However, it is currently very limited and will therefore not give the same result as the browser. Defaults to "false".
**enableFileSystemHttpRequests**
Set it to "true" to enable file system HTTP requests using XMLHttpRequest. Defaults to "false".
Expand Down
Expand Up @@ -232,7 +232,7 @@ export default class CSSStyleDeclarationElementStyle {
parentFontSize,

// TODO: Only "font-size" is supported when using percentage values. Add support for other properties.
parentSize: name === 'font-size' ? parentFontSize : 0
parentSize: name === 'font-size' ? parentFontSize : null
});
}
}
Expand Down Expand Up @@ -335,8 +335,12 @@ export default class CSSStyleDeclarationElementStyle {
value: string;
rootFontSize: string | number;
parentFontSize: string | number;
parentSize: string | number;
parentSize: string | number | null;
}): string {
if (this.element.ownerDocument.defaultView.happyDOM.settings.disableComputedStyleRendering) {
return options.value;
}

const regexp = new RegExp(CSS_MEASUREMENT_REGEXP);
let newValue = options.value;
let match;
Expand Down
2 changes: 1 addition & 1 deletion packages/happy-dom/src/match-media/MediaQueryItem.ts
Expand Up @@ -313,7 +313,7 @@ export default class MediaQueryItem {
* @returns Value in pixels.
*/
private toPixels(value: string): number | null {
if (value.endsWith('em')) {
if (!this.ownerWindow.happyDOM.settings.disableComputedStyleRendering && value.endsWith('em')) {
this.rootFontSize =
this.rootFontSize ||
parseFloat(
Expand Down
1 change: 1 addition & 0 deletions packages/happy-dom/src/window/IHappyDOMOptions.ts
Expand Up @@ -10,6 +10,7 @@ export default interface IHappyDOMOptions {
disableJavaScriptFileLoading?: boolean;
disableCSSFileLoading?: boolean;
disableIframePageLoading?: boolean;
disableComputedStyleRendering?: boolean;
enableFileSystemHttpRequests?: boolean;
device?: {
prefersColorScheme?: string;
Expand Down
1 change: 1 addition & 0 deletions packages/happy-dom/src/window/IHappyDOMSettings.ts
Expand Up @@ -6,6 +6,7 @@ export default interface IHappyDOMSettings {
disableJavaScriptFileLoading: boolean;
disableCSSFileLoading: boolean;
disableIframePageLoading: boolean;
disableComputedStyleRendering: boolean;
enableFileSystemHttpRequests: boolean;
device: {
prefersColorScheme: string;
Expand Down
1 change: 1 addition & 0 deletions packages/happy-dom/src/window/Window.ts
Expand Up @@ -177,6 +177,7 @@ export default class Window extends EventTarget implements IWindow {
disableJavaScriptFileLoading: false,
disableCSSFileLoading: false,
disableIframePageLoading: false,
disableComputedStyleRendering: false,
enableFileSystemHttpRequests: false,
device: {
prefersColorScheme: 'light',
Expand Down
20 changes: 20 additions & 0 deletions packages/happy-dom/test/match-media/MediaQueryList.test.ts
Expand Up @@ -485,6 +485,26 @@ describe('MediaQueryList', () => {
}).matches
).toBe(true);
});

it('Handles disabling computed style rendering with Window.happyDOM.settings.disableComputedStyleRendering.', () => {
window.document.documentElement.style.fontSize = '10px';

expect(
new MediaQueryList({ ownerWindow: window, media: `(max-width: ${1023 / 10}rem)` }).matches
).toBe(false);
expect(
new MediaQueryList({ ownerWindow: window, media: `(max-width: ${1024 / 10}rem)` }).matches
).toBe(true);

window.happyDOM.settings.disableComputedStyleRendering = true;

expect(
new MediaQueryList({ ownerWindow: window, media: `(max-width: ${1023 / 16}rem)` }).matches
).toBe(false);
expect(
new MediaQueryList({ ownerWindow: window, media: `(max-width: ${1024 / 16}rem)` }).matches
).toBe(true);
});
});

describe('addEventListener()', () => {
Expand Down
44 changes: 41 additions & 3 deletions packages/happy-dom/test/window/Window.test.ts
Expand Up @@ -436,7 +436,7 @@ describe('Window', () => {
expect(computedStyle.height).toBe('150px');
});

it('Returns a CSSStyleDeclaration object with computed styles containing "%" measurement values converted to pixels.', () => {
it('Returns a CSSStyleDeclaration object with computed styles containing "%" measurement values that have not been converted, as it is not supported yet.', () => {
const parent = <IHTMLElement>document.createElement('div');
const element = <IHTMLElement>document.createElement('span');
const computedStyle = window.getComputedStyle(element);
Expand All @@ -457,7 +457,7 @@ describe('Window', () => {

elementStyle.innerHTML = `
span {
width: 100%;
width: 80%;
height: 10em;
}
`;
Expand All @@ -468,10 +468,48 @@ describe('Window', () => {
document.body.appendChild(parentStyle);
document.body.appendChild(parent);

expect(computedStyle.width).toBe('0px');
expect(computedStyle.width).toBe('80%');
expect(computedStyle.height).toBe('150px');
});

it('Returns a CSSStyleDeclaration object with computed styles containing "rem" and "em" measurement values that has not been converted to pixels if Window.happyDOM.settings.disableComputedStyleRendering is set to "true".', () => {
const parent = <IHTMLElement>document.createElement('div');
const element = <IHTMLElement>document.createElement('span');
const computedStyle = window.getComputedStyle(element);
const parentStyle = document.createElement('style');
const elementStyle = document.createElement('style');

window.happyDOM.setInnerWidth(1024);

parentStyle.innerHTML = `
html {
font-size: 10px;
}
div {
font-size: 1.5rem;
}
`;

elementStyle.innerHTML = `
span {
width: 10rem;
height: 10em;
}
`;

parent.appendChild(elementStyle);
parent.appendChild(element);

document.body.appendChild(parentStyle);
document.body.appendChild(parent);

window.happyDOM.settings.disableComputedStyleRendering = true;

expect(computedStyle.width).toBe('10rem');
expect(computedStyle.height).toBe('10em');
});

for (const measurement of [
{ value: '100vw', result: '1024px' },
{ value: '100vh', result: '768px' },
Expand Down

0 comments on commit 9de3ce1

Please sign in to comment.