Skip to content

Commit

Permalink
fix: [#1161] Implement DOMReact and DOMReactReadOnly interfaces
Browse files Browse the repository at this point in the history
  • Loading branch information
domakas committed Apr 12, 2024
1 parent c29f36c commit 41cb5f2
Show file tree
Hide file tree
Showing 6 changed files with 341 additions and 23 deletions.
2 changes: 2 additions & 0 deletions packages/happy-dom/src/index.ts
Expand Up @@ -70,6 +70,7 @@ import DocumentFragment from './nodes/document-fragment/DocumentFragment.js';
import DocumentType from './nodes/document-type/DocumentType.js';
import Document from './nodes/document/Document.js';
import DOMRect from './nodes/element/DOMRect.js';
import DOMRectReadOnly from './nodes/element/DOMRectReadOnly.js';
import Element from './nodes/element/Element.js';
import HTMLCollection from './nodes/element/HTMLCollection.js';
import HTMLAnchorElement from './nodes/html-anchor-element/HTMLAnchorElement.js';
Expand Down Expand Up @@ -211,6 +212,7 @@ export {
DOMException,
DOMParser,
DOMRect,
DOMRectReadOnly,
DataTransfer,
DataTransferItem,
DataTransferItemList,
Expand Down
62 changes: 39 additions & 23 deletions packages/happy-dom/src/nodes/element/DOMRect.ts
@@ -1,30 +1,46 @@
import DOMRectReadOnly, { IDOMRectInit } from './DOMRectReadOnly.js';

/* eslint-disable jsdoc/require-jsdoc */

/**
* Bounding rect object.
*
* @see https://developer.mozilla.org/en-US/docs/Web/API/DOMRect
*/
export default class DOMRect {
public x = 0;
public y = 0;
public width = 0;
public height = 0;
public top = 0;
public right = 0;
public bottom = 0;
public left = 0;

/**
* Constructor.
*
* @param [x] X position.
* @param [y] Y position.
* @param [width] Width.
* @param [height] Height.
*/
constructor(x?, y?, width?, height?) {
this.x = x || 0;
this.y = y || 0;
this.width = width || 0;
this.height = height || 0;
export default class DOMRect extends DOMRectReadOnly {
public set x(value: number) {
this._x = value;
}

public get x(): number {
return this._x;
}

public set y(value: number) {
this._y = value;
}

public get y(): number {
return this._y;
}

public set width(value: number) {
this._width = value;
}

public get width(): number {
return this._width;
}

public set height(value: number) {
this._height = value;
}

public get height(): number {
return this._height;
}

public static fromRect(other: IDOMRectInit): DOMRect {
return new DOMRect(other.x, other.y, other.width, other.height);
}
}
84 changes: 84 additions & 0 deletions packages/happy-dom/src/nodes/element/DOMRectReadOnly.ts
@@ -0,0 +1,84 @@
/* eslint-disable jsdoc/require-jsdoc */

/**
* Bounding rect readonly object.
*
* @see https://drafts.fxtf.org/geometry/#DOMRect
*/
export default class DOMRectReadOnly implements IDOMRectInit {
protected _x: number = 0;
protected _y: number = 0;
protected _width: number = 0;
protected _height: number = 0;

/**
* Constructor.
*
* @param [x] X position.
* @param [y] Y position.
* @param [width] Width.
* @param [height] Height.
*/
constructor(x?: number, y?: number, width?: number, height?: number) {
this._x = x || 0;
this._y = y || 0;
this._width = width || 0;
this._height = height || 0;
}

public get x(): number {
return this._x;
}

public get y(): number {
return this._y;
}

public get width(): number {
return this._width;
}

public get height(): number {
return this._height;
}

public get top(): number {
return Math.min(this._y, this._y + this._height);
}

public get right(): number {
return Math.max(this._x, this._x + this._width);
}

public get bottom(): number {
return Math.max(this._y, this._y + this._height);
}

public get left(): number {
return Math.min(this._x, this._x + this._width);
}

public toJSON(): object {
return {
x: this.x,
y: this.y,
width: this.width,
height: this.height,
top: this.top,
right: this.right,
bottom: this.bottom,
left: this.left
};
}

public static fromRect(other: IDOMRectInit): DOMRectReadOnly {
return new DOMRectReadOnly(other.x, other.y, other.width, other.height);
}
}

export interface IDOMRectInit {
readonly x: number;
readonly y: number;
readonly width: number;
readonly height: number;
}
2 changes: 2 additions & 0 deletions packages/happy-dom/src/window/BrowserWindow.ts
Expand Up @@ -97,6 +97,7 @@ import Plugin from '../navigator/Plugin.js';
import PluginArray from '../navigator/PluginArray.js';
import Fetch from '../fetch/Fetch.js';
import DOMRect from '../nodes/element/DOMRect.js';
import DOMRectReadOnly from '../nodes/element/DOMRectReadOnly.js';
import VMGlobalPropertyScript from './VMGlobalPropertyScript.js';
import VM from 'vm';
import { Buffer } from 'buffer';
Expand Down Expand Up @@ -372,6 +373,7 @@ export default class BrowserWindow extends EventTarget implements INodeJSGlobal
public readonly PluginArray = PluginArray;
public readonly FileList = FileList;
public readonly DOMRect = DOMRect;
public readonly DOMRectReadOnly = DOMRectReadOnly;
public readonly RadioNodeList = RadioNodeList;
public readonly ValidityState = ValidityState;
public readonly Headers = Headers;
Expand Down
123 changes: 123 additions & 0 deletions packages/happy-dom/test/nodes/element/DOMRect.test.ts
@@ -0,0 +1,123 @@
import { afterEach, describe, it, expect, vi } from 'vitest';
import DOMRect from '../../../src/nodes/element/DOMRect';

describe('DOMRect', () => {
afterEach(() => {
vi.restoreAllMocks();
});

describe('set x()', () => {
it('Sets rect x property.', () => {
const rect = new DOMRect(1, 2, 3, 4);
rect.x = 2;
expect(rect.x).toBe(2);
});
});

describe('get x()', () => {
it('Returns rect x property.', () => {
const rect = new DOMRect(1, 2, 3, 4);
expect(rect.x).toBe(1);
});
});

describe('set y()', () => {
it('Sets rect y property.', () => {
const rect = new DOMRect(1, 2, 3, 4);
rect.y = 3;
expect(rect.y).toBe(3);
});
});

describe('get y()', () => {
it('Returns rect y property.', () => {
const rect = new DOMRect(1, 2, 3, 4);
expect(rect.y).toBe(2);
});
});

describe('set width()', () => {
it('Sets rect y property.', () => {
const rect = new DOMRect(1, 2, 3, 4);
rect.width = 4;
expect(rect.width).toBe(4);
});
});

describe('get width()', () => {
it('Returns rect y property.', () => {
const rect = new DOMRect(1, 2, 3, 4);
expect(rect.width).toBe(3);
});
});

describe('set height()', () => {
it('Sets rect height property.', () => {
const rect = new DOMRect(1, 2, 3, 4);
rect.height = 5;
expect(rect.height).toBe(5);
});
});

describe('get height()', () => {
it('Returns rect height property.', () => {
const rect = new DOMRect(1, 2, 3, 4);
expect(rect.height).toBe(4);
});
});

describe('get top()', () => {
it('Returns rect top property.', () => {
const rect = new DOMRect(1, 2, 3, 4);
expect(rect.top).toBe(2);
});
});

describe('get right()', () => {
it('Returns rect right property.', () => {
const rect = new DOMRect(1, 2, 3, 4);
expect(rect.right).toBe(4);
});
});

describe('get bottom()', () => {
it('Returns rect bottom property.', () => {
const rect = new DOMRect(1, 2, 3, 4);
expect(rect.bottom).toBe(6);
});
});

describe('get left()', () => {
it('Returns rect left property.', () => {
const rect = new DOMRect(1, 2, 3, 4);
expect(rect.left).toBe(1);
});
});

describe('fromRect()', () => {
it('Creates DOMRect instance', () => {
const rect = DOMRect.fromRect({ x: 1, y: 2, width: 3, height: 4 });
expect(rect instanceof DOMRect).toBe(true);
expect(rect.x).toBe(1);
expect(rect.y).toBe(2);
expect(rect.width).toBe(3);
expect(rect.height).toBe(4);
});
});

describe('toJSON()', () => {
it('Returns rect as JSON.', () => {
const rect = new DOMRect(1, 2, 3, 4);
expect(rect.toJSON()).toEqual({
x: 1,
y: 2,
width: 3,
height: 4,
top: 2,
right: 4,
bottom: 6,
left: 1
});
});
});
});

0 comments on commit 41cb5f2

Please sign in to comment.