happy-dom 8.5.0 → 8.7.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.

Potentially problematic release.


This version of happy-dom might be problematic. Click here for more details.

Files changed (67) hide show
  1. package/README.md +11 -1
  2. package/lib/config/ElementTag.d.ts +2 -1
  3. package/lib/config/ElementTag.js +2 -1
  4. package/lib/config/ElementTag.js.map +1 -1
  5. package/lib/config/NonImplemenetedElementClasses.js +0 -1
  6. package/lib/config/NonImplemenetedElementClasses.js.map +1 -1
  7. package/lib/event/EventTarget.d.ts +7 -1
  8. package/lib/event/EventTarget.js +13 -2
  9. package/lib/event/EventTarget.js.map +1 -1
  10. package/lib/event/IEventListenerOptions.d.ts +6 -0
  11. package/lib/event/IEventListenerOptions.js +3 -0
  12. package/lib/event/IEventListenerOptions.js.map +1 -0
  13. package/lib/event/IMessagePort.d.ts +23 -0
  14. package/lib/event/IMessagePort.js +3 -0
  15. package/lib/event/IMessagePort.js.map +1 -0
  16. package/lib/event/MessagePort.d.ts +24 -0
  17. package/lib/event/MessagePort.js +36 -0
  18. package/lib/event/MessagePort.js.map +1 -0
  19. package/lib/event/events/IMessageEventInit.d.ts +10 -0
  20. package/lib/event/events/IMessageEventInit.js +3 -0
  21. package/lib/event/events/IMessageEventInit.js.map +1 -0
  22. package/lib/event/events/MessageEvent.d.ts +23 -0
  23. package/lib/event/events/MessageEvent.js +34 -0
  24. package/lib/event/events/MessageEvent.js.map +1 -0
  25. package/lib/index.d.ts +3 -1
  26. package/lib/index.js +3 -1
  27. package/lib/index.js.map +1 -1
  28. package/lib/nodes/html-iframe-element/HTMLIFrameElement.d.ts +126 -0
  29. package/lib/nodes/html-iframe-element/HTMLIFrameElement.js +246 -0
  30. package/lib/nodes/html-iframe-element/HTMLIFrameElement.js.map +1 -0
  31. package/lib/nodes/html-iframe-element/IFrameCrossOriginWindow.d.ts +29 -0
  32. package/lib/nodes/html-iframe-element/IFrameCrossOriginWindow.js +47 -0
  33. package/lib/nodes/html-iframe-element/IFrameCrossOriginWindow.js.map +1 -0
  34. package/lib/nodes/html-iframe-element/IHTMLIFrameElement.d.ts +24 -0
  35. package/lib/nodes/html-iframe-element/IHTMLIFrameElement.js +3 -0
  36. package/lib/nodes/html-iframe-element/IHTMLIFrameElement.js.map +1 -0
  37. package/lib/nodes/html-link-element/HTMLLinkElement.js +2 -1
  38. package/lib/nodes/html-link-element/HTMLLinkElement.js.map +1 -1
  39. package/lib/nodes/html-script-element/HTMLScriptElement.js +1 -1
  40. package/lib/nodes/html-script-element/HTMLScriptElement.js.map +1 -1
  41. package/lib/window/IHappyDOMOptions.d.ts +15 -0
  42. package/lib/window/IHappyDOMOptions.js +3 -0
  43. package/lib/window/IHappyDOMOptions.js.map +1 -0
  44. package/lib/window/IHappyDOMSettings.d.ts +1 -0
  45. package/lib/window/IWindow.d.ts +13 -0
  46. package/lib/window/Window.d.ts +17 -7
  47. package/lib/window/Window.js +33 -0
  48. package/lib/window/Window.js.map +1 -1
  49. package/package.json +1 -1
  50. package/src/config/ElementTag.ts +2 -1
  51. package/src/config/NonImplemenetedElementClasses.ts +0 -1
  52. package/src/event/EventTarget.ts +24 -2
  53. package/src/event/IEventListenerOptions.ts +8 -0
  54. package/src/event/IMessagePort.ts +26 -0
  55. package/src/event/MessagePort.ts +33 -0
  56. package/src/event/events/IMessageEventInit.ts +11 -0
  57. package/src/event/events/MessageEvent.ts +32 -0
  58. package/src/index.ts +4 -0
  59. package/src/nodes/html-iframe-element/HTMLIFrameElement.ts +266 -0
  60. package/src/nodes/html-iframe-element/IFrameCrossOriginWindow.ts +60 -0
  61. package/src/nodes/html-iframe-element/IHTMLIFrameElement.ts +27 -0
  62. package/src/nodes/html-link-element/HTMLLinkElement.ts +2 -1
  63. package/src/nodes/html-script-element/HTMLScriptElement.ts +2 -2
  64. package/src/window/IHappyDOMOptions.ts +15 -0
  65. package/src/window/IHappyDOMSettings.ts +1 -0
  66. package/src/window/IWindow.ts +14 -0
  67. package/src/window/Window.ts +46 -7
@@ -0,0 +1,60 @@
1
+ import EventTarget from '../../event/EventTarget';
2
+ import IWindow from '../../window/IWindow';
3
+ import DOMException from '../../exception/DOMException';
4
+ import DOMExceptionNameEnum from '../../exception/DOMExceptionNameEnum';
5
+ import Location from '../../location/Location';
6
+
7
+ /**
8
+ * Browser window with limited access due to CORS restrictions in iframes.
9
+ */
10
+ export default class IFrameCrossOriginWindow extends EventTarget {
11
+ public readonly self = this;
12
+ public readonly window = this;
13
+ public readonly parent: IWindow;
14
+ public readonly top: IWindow;
15
+ public readonly location: Location;
16
+
17
+ private _targetWindow: IWindow;
18
+
19
+ /**
20
+ * Constructor.
21
+ *
22
+ * @param parent Parent window.
23
+ * @param target Target window.
24
+ */
25
+ constructor(parent: IWindow, target: IWindow) {
26
+ super();
27
+
28
+ this.parent = parent;
29
+ this.top = parent;
30
+ this.location = <Location>new Proxy(
31
+ {},
32
+ {
33
+ get: () => {
34
+ throw new DOMException(
35
+ `Blocked a frame with origin "${this.parent.location.origin}" from accessing a cross-origin frame.`,
36
+ DOMExceptionNameEnum.securityError
37
+ );
38
+ },
39
+ set: () => {
40
+ throw new DOMException(
41
+ `Blocked a frame with origin "${this.parent.location.origin}" from accessing a cross-origin frame.`,
42
+ DOMExceptionNameEnum.securityError
43
+ );
44
+ }
45
+ }
46
+ );
47
+ this._targetWindow = target;
48
+ }
49
+
50
+ /**
51
+ * Safely enables cross-origin communication between Window objects; e.g., between a page and a pop-up that it spawned, or between a page and an iframe embedded within it.
52
+ *
53
+ * @param message Message.
54
+ * @param [targetOrigin=*] Target origin.
55
+ * @param transfer Transfer. Not implemented.
56
+ */
57
+ public postMessage(message: unknown, targetOrigin = '*', transfer?: unknown[]): void {
58
+ this._targetWindow.postMessage(message, targetOrigin, transfer);
59
+ }
60
+ }
@@ -0,0 +1,27 @@
1
+ import Event from '../../event/Event';
2
+ import IWindow from '../../window/IWindow';
3
+ import IDocument from '../document/IDocument';
4
+ import IHTMLElement from '../html-element/IHTMLElement';
5
+ import IFrameCrossOriginWindow from './IFrameCrossOriginWindow';
6
+
7
+ /**
8
+ * HTML Iframe Element.
9
+ *
10
+ * Reference:
11
+ * https://developer.mozilla.org/en-US/docs/Web/API/HTMLIFrameElement.
12
+ */
13
+ export default interface IHTMLIFrameElement extends IHTMLElement {
14
+ src: string | null;
15
+ allow: string | null;
16
+ height: string | null;
17
+ width: string | null;
18
+ name: string | null;
19
+ sandbox: string | null;
20
+ srcdoc: string | null;
21
+ readonly contentDocument: IDocument | null;
22
+ readonly contentWindow: IWindow | IFrameCrossOriginWindow | null;
23
+
24
+ // Events
25
+ onload: (event: Event) => void | null;
26
+ onerror: (event: Event) => void | null;
27
+ }
@@ -250,13 +250,14 @@ export default class HTMLLinkElement extends HTMLElement implements IHTMLLinkEle
250
250
  /**
251
251
  * @override
252
252
  */
253
- public _connectToNode(parentNode: INode = null): void {
253
+ public override _connectToNode(parentNode: INode = null): void {
254
254
  const isConnected = this.isConnected;
255
255
  const isParentConnected = parentNode ? parentNode.isConnected : false;
256
256
 
257
257
  super._connectToNode(parentNode);
258
258
 
259
259
  if (
260
+ isParentConnected &&
260
261
  isConnected !== isParentConnected &&
261
262
  this._evaluateCSS &&
262
263
  !this.ownerDocument.defaultView.happyDOM.settings.disableCSSFileLoading
@@ -182,13 +182,13 @@ export default class HTMLScriptElement extends HTMLElement implements IHTMLScrip
182
182
  /**
183
183
  * @override
184
184
  */
185
- public _connectToNode(parentNode: INode = null): void {
185
+ public override _connectToNode(parentNode: INode = null): void {
186
186
  const isConnected = this.isConnected;
187
187
  const isParentConnected = parentNode ? parentNode.isConnected : false;
188
188
 
189
189
  super._connectToNode(parentNode);
190
190
 
191
- if (isConnected !== isParentConnected && this._evaluateScript) {
191
+ if (isParentConnected && isConnected !== isParentConnected && this._evaluateScript) {
192
192
  const src = this.getAttributeNS(null, 'src');
193
193
 
194
194
  if (src !== null) {
@@ -0,0 +1,15 @@
1
+ /**
2
+ * Happy DOM options.
3
+ */
4
+ export default interface IHappyDOMOptions {
5
+ innerWidth?: number;
6
+ innerHeight?: number;
7
+ url?: string;
8
+ settings?: {
9
+ disableJavaScriptEvaluation?: boolean;
10
+ disableJavaScriptFileLoading?: boolean;
11
+ disableCSSFileLoading?: boolean;
12
+ disableIframePageLoading?: boolean;
13
+ enableFileSystemHttpRequests?: boolean;
14
+ };
15
+ }
@@ -5,5 +5,6 @@ export default interface IHappyDOMSettings {
5
5
  disableJavaScriptEvaluation: boolean;
6
6
  disableJavaScriptFileLoading: boolean;
7
7
  disableCSSFileLoading: boolean;
8
+ disableIframePageLoading: boolean;
8
9
  enableFileSystemHttpRequests: boolean;
9
10
  }
@@ -24,6 +24,7 @@ import HTMLMediaElement from '../nodes/html-media-element/HTMLMediaElement';
24
24
  import HTMLAudioElement from '../nodes/html-audio-element/HTMLAudioElement';
25
25
  import HTMLVideoElement from '../nodes/html-video-element/HTMLVideoElement';
26
26
  import HTMLBaseElement from '../nodes/html-base-element/HTMLBaseElement';
27
+ import HTMLIFrameElement from '../nodes/html-iframe-element/HTMLIFrameElement';
27
28
  import SVGSVGElement from '../nodes/svg-element/SVGSVGElement';
28
29
  import SVGElement from '../nodes/svg-element/SVGElement';
29
30
  import HTMLScriptElement from '../nodes/html-script-element/HTMLScriptElement';
@@ -73,6 +74,8 @@ import InputEvent from '../event/events/InputEvent';
73
74
  import UIEvent from '../event/UIEvent';
74
75
  import ErrorEvent from '../event/events/ErrorEvent';
75
76
  import StorageEvent from '../event/events/StorageEvent';
77
+ import MessageEvent from '../event/events/MessageEvent';
78
+ import MessagePort from '../event/MessagePort';
76
79
  import Screen from '../screen/Screen';
77
80
  import AsyncTaskManager from '../async-task-manager/AsyncTaskManager';
78
81
  import Storage from '../storage/Storage';
@@ -142,6 +145,7 @@ export default interface IWindow extends IEventTarget, NodeJS.Global {
142
145
  readonly HTMLAudioElement: typeof HTMLAudioElement;
143
146
  readonly HTMLVideoElement: typeof HTMLVideoElement;
144
147
  readonly HTMLBaseElement: typeof HTMLBaseElement;
148
+ readonly HTMLIFrameElement: typeof HTMLIFrameElement;
145
149
  readonly HTMLDialogElement: typeof HTMLDialogElement;
146
150
  readonly Attr: typeof Attr;
147
151
  readonly NamedNodeMap: typeof NamedNodeMap;
@@ -175,6 +179,8 @@ export default interface IWindow extends IEventTarget, NodeJS.Global {
175
179
  readonly InputEvent: typeof InputEvent;
176
180
  readonly ErrorEvent: typeof ErrorEvent;
177
181
  readonly StorageEvent: typeof StorageEvent;
182
+ readonly MessageEvent: typeof MessageEvent;
183
+ readonly MessagePort: typeof MessagePort;
178
184
  readonly ProgressEvent: typeof ProgressEvent;
179
185
  readonly MediaQueryListEvent: typeof MediaQueryListEvent;
180
186
  readonly EventTarget: typeof EventTarget;
@@ -374,4 +380,12 @@ export default interface IWindow extends IEventTarget, NodeJS.Global {
374
380
  * @returns An ASCII string containing decoded data from encodedData.
375
381
  */
376
382
  atob(data: unknown): string;
383
+
384
+ /**
385
+ * Safely enables cross-origin communication between Window objects; e.g., between a page and a pop-up that it spawned, or between a page and an iframe embedded within it.
386
+ *
387
+ * @param message Message.
388
+ * @param listener Listener.
389
+ */
390
+ postMessage(message: unknown, targetOrigin?: string, transfer?: unknown[]): void;
377
391
  }
@@ -25,6 +25,7 @@ import HTMLMediaElement from '../nodes/html-media-element/HTMLMediaElement';
25
25
  import HTMLAudioElement from '../nodes/html-audio-element/HTMLAudioElement';
26
26
  import HTMLVideoElement from '../nodes/html-video-element/HTMLVideoElement';
27
27
  import HTMLBaseElement from '../nodes/html-base-element/HTMLBaseElement';
28
+ import HTMLIFrameElement from '../nodes/html-iframe-element/HTMLIFrameElement';
28
29
  import HTMLDialogElement from '../nodes/html-dialog-element/HTMLDialogElement';
29
30
  import SVGSVGElement from '../nodes/svg-element/SVGSVGElement';
30
31
  import SVGElement from '../nodes/svg-element/SVGElement';
@@ -39,9 +40,11 @@ import Event from '../event/Event';
39
40
  import CustomEvent from '../event/events/CustomEvent';
40
41
  import AnimationEvent from '../event/events/AnimationEvent';
41
42
  import KeyboardEvent from '../event/events/KeyboardEvent';
43
+ import MessageEvent from '../event/events/MessageEvent';
42
44
  import ProgressEvent from '../event/events/ProgressEvent';
43
45
  import MediaQueryListEvent from '../event/events/MediaQueryListEvent';
44
46
  import EventTarget from '../event/EventTarget';
47
+ import MessagePort from '../event/MessagePort';
45
48
  import { URL, URLSearchParams } from 'url';
46
49
  import Location from '../location/Location';
47
50
  import NonImplementedEventTypes from '../event/NonImplementedEventTypes';
@@ -115,9 +118,10 @@ import Attr from '../nodes/attr/Attr';
115
118
  import NamedNodeMap from '../named-node-map/NamedNodeMap';
116
119
  import IElement from '../nodes/element/IElement';
117
120
  import ProcessingInstruction from '../nodes/processing-instruction/ProcessingInstruction';
118
- import IHappyDOMSettings from './IHappyDOMSettings';
119
121
  import RequestInfo from '../fetch/RequestInfo';
120
122
  import FileList from '../nodes/html-input-element/FileList';
123
+ import DOMExceptionNameEnum from '../exception/DOMExceptionNameEnum';
124
+ import IHappyDOMOptions from './IHappyDOMOptions';
121
125
 
122
126
  const ORIGINAL_SET_TIMEOUT = setTimeout;
123
127
  const ORIGINAL_CLEAR_TIMEOUT = clearTimeout;
@@ -159,6 +163,7 @@ export default class Window extends EventTarget implements IWindow {
159
163
  disableJavaScriptEvaluation: false,
160
164
  disableJavaScriptFileLoading: false,
161
165
  disableCSSFileLoading: false,
166
+ disableIframePageLoading: false,
162
167
  enableFileSystemHttpRequests: false
163
168
  }
164
169
  };
@@ -183,6 +188,7 @@ export default class Window extends EventTarget implements IWindow {
183
188
  public readonly HTMLAudioElement = HTMLAudioElement;
184
189
  public readonly HTMLVideoElement = HTMLVideoElement;
185
190
  public readonly HTMLBaseElement = HTMLBaseElement;
191
+ public readonly HTMLIFrameElement = HTMLIFrameElement;
186
192
  public readonly HTMLDialogElement = HTMLDialogElement;
187
193
  public readonly Attr = Attr;
188
194
  public readonly NamedNodeMap = NamedNodeMap;
@@ -208,6 +214,7 @@ export default class Window extends EventTarget implements IWindow {
208
214
  public readonly CustomEvent = CustomEvent;
209
215
  public readonly AnimationEvent = AnimationEvent;
210
216
  public readonly KeyboardEvent = KeyboardEvent;
217
+ public readonly MessageEvent = MessageEvent;
211
218
  public readonly MouseEvent = MouseEvent;
212
219
  public readonly PointerEvent = PointerEvent;
213
220
  public readonly FocusEvent = FocusEvent;
@@ -218,6 +225,7 @@ export default class Window extends EventTarget implements IWindow {
218
225
  public readonly ProgressEvent = ProgressEvent;
219
226
  public readonly MediaQueryListEvent = MediaQueryListEvent;
220
227
  public readonly EventTarget = EventTarget;
228
+ public readonly MessagePort = MessagePort;
221
229
  public readonly DataTransfer = DataTransfer;
222
230
  public readonly DataTransferItem = DataTransferItem;
223
231
  public readonly DataTransferItemList = DataTransferItemList;
@@ -370,12 +378,7 @@ export default class Window extends EventTarget implements IWindow {
370
378
  * @param [options.url] URL.
371
379
  * @param [options.settings] Settings.
372
380
  */
373
- constructor(options?: {
374
- innerWidth?: number;
375
- innerHeight?: number;
376
- url?: string;
377
- settings?: IHappyDOMSettings;
378
- }) {
381
+ constructor(options?: IHappyDOMOptions) {
379
382
  super();
380
383
 
381
384
  this.customElements = new CustomElementRegistry();
@@ -732,6 +735,42 @@ export default class Window extends EventTarget implements IWindow {
732
735
  return Base64.atob(data);
733
736
  }
734
737
 
738
+ /**
739
+ * Safely enables cross-origin communication between Window objects; e.g., between a page and a pop-up that it spawned, or between a page and an iframe embedded within it.
740
+ *
741
+ * @param message Message.
742
+ * @param [targetOrigin=*] Target origin.
743
+ * @param _transfer Transfer. Not implemented.
744
+ */
745
+ public postMessage(message: unknown, targetOrigin = '*', _transfer?: unknown[]): void {
746
+ // TODO: Implement transfer.
747
+
748
+ if (targetOrigin && targetOrigin !== '*' && this.location.origin !== targetOrigin) {
749
+ throw new DOMException(
750
+ `Failed to execute 'postMessage' on 'Window': The target origin provided ('${targetOrigin}') does not match the recipient window\'s origin ('${this.location.origin}').`,
751
+ DOMExceptionNameEnum.securityError
752
+ );
753
+ }
754
+
755
+ try {
756
+ JSON.stringify(message);
757
+ } catch (error) {
758
+ throw new DOMException(
759
+ `Failed to execute 'postMessage' on 'Window': The provided message cannot be serialized.`,
760
+ DOMExceptionNameEnum.invalidStateError
761
+ );
762
+ }
763
+
764
+ this.dispatchEvent(
765
+ new MessageEvent('message', {
766
+ data: message,
767
+ origin: this.parent.location.origin,
768
+ source: this.parent,
769
+ lastEventId: ''
770
+ })
771
+ );
772
+ }
773
+
735
774
  /**
736
775
  * Setup of VM context.
737
776
  */