Skip to content

Commit

Permalink
Merge pull request #1100 from ckhampus/task/1099-add-document-current…
Browse files Browse the repository at this point in the history
…-script

#1099@minor: Add support for currentScript.
  • Loading branch information
capricorn86 authored Sep 30, 2023
2 parents 9ea682c + d959f1b commit b8f3ab6
Show file tree
Hide file tree
Showing 7 changed files with 56 additions and 8 deletions.
10 changes: 10 additions & 0 deletions packages/happy-dom/src/nodes/document/Document.ts
Original file line number Diff line number Diff line change
Expand Up @@ -68,6 +68,7 @@ export default class Document extends Node implements IDocument {
public readonly _readyStateManager: DocumentReadyStateManager;
public readonly _children: IHTMLCollection<IElement> = new HTMLCollection<IElement>();
public _activeElement: IHTMLElement = null;
public _currentScript: IHTMLScriptElement = null;

// Used as an unique identifier which is updated whenever the DOM gets modified.
public _cacheID = 0;
Expand Down Expand Up @@ -501,6 +502,15 @@ export default class Document extends Node implements IDocument {
return true;
}

/**
* Gets the currently executing script element.
*
* @returns the currently executing script element.
*/
public get currentScript(): IHTMLScriptElement {
return this._currentScript;
}

/**
* Inserts a set of Node objects or DOMString objects after the last child of the ParentNode. DOMString objects are inserted as equivalent Text nodes.
*
Expand Down
1 change: 1 addition & 0 deletions packages/happy-dom/src/nodes/document/IDocument.ts
Original file line number Diff line number Diff line change
Expand Up @@ -47,6 +47,7 @@ export default interface IDocument extends IParentNode {
readonly hidden: boolean;
readonly links: IHTMLCollection<IHTMLElement>;
readonly referrer: string;
readonly currentScript: IHTMLScriptElement;
cookie: string;
title: string;

Expand Down
9 changes: 8 additions & 1 deletion packages/happy-dom/src/nodes/element/Element.ts
Original file line number Diff line number Diff line change
Expand Up @@ -31,6 +31,7 @@ import EventPhaseEnum from '../../event/EventPhaseEnum.js';
import CSSStyleDeclaration from '../../css/declaration/CSSStyleDeclaration.js';
import DocumentFragment from '../document-fragment/DocumentFragment.js';
import ElementNamedNodeMap from './ElementNamedNodeMap.js';
import WindowErrorUtility from '../../window/WindowErrorUtility.js';

/**
* Element.
Expand Down Expand Up @@ -931,7 +932,13 @@ export default class Element extends Node implements IElement {
const attribute = this.getAttribute('on' + event.type);

if (attribute && !event._immediatePropagationStopped) {
this.ownerDocument.defaultView.eval(attribute);
if (this.ownerDocument.defaultView.happyDOM.settings.disableErrorCapturing) {
this.ownerDocument.defaultView.eval(attribute);
} else {
WindowErrorUtility.captureError(this.ownerDocument.defaultView, () =>
this.ownerDocument.defaultView.eval(attribute)
);
}
}
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -189,13 +189,17 @@ export default class HTMLScriptElement extends HTMLElement implements IHTMLScrip
type === 'application/x-javascript' ||
type.startsWith('text/javascript'))
) {
this.ownerDocument['_currentScript'] = this;

if (this.ownerDocument.defaultView.happyDOM.settings.disableErrorCapturing) {
this.ownerDocument.defaultView.eval(textContent);
} else {
WindowErrorUtility.captureError(this.ownerDocument.defaultView, () =>
this.ownerDocument.defaultView.eval(textContent)
);
}

this.ownerDocument['_currentScript'] = null;
}
}
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -56,13 +56,15 @@ export default class HTMLScriptElementUtility {
throw error;
}
} else {
element.ownerDocument['_currentScript'] = element;
if (element.ownerDocument.defaultView.happyDOM.settings.disableErrorCapturing) {
element.ownerDocument.defaultView.eval(code);
} else {
WindowErrorUtility.captureError(element.ownerDocument.defaultView, () =>
element.ownerDocument.defaultView.eval(code)
);
}
element.ownerDocument['_currentScript'] = null;
element.dispatchEvent(new Event('load'));
}
} else {
Expand All @@ -81,13 +83,15 @@ export default class HTMLScriptElementUtility {
throw error;
}
} else {
element.ownerDocument['_currentScript'] = element;
if (element.ownerDocument.defaultView.happyDOM.settings.disableErrorCapturing) {
element.ownerDocument.defaultView.eval(code);
} else {
WindowErrorUtility.captureError(element.ownerDocument.defaultView, () =>
element.ownerDocument.defaultView.eval(code)
);
}
element.ownerDocument['_currentScript'] = null;
element.dispatchEvent(new Event('load'));
}
}
Expand Down
23 changes: 20 additions & 3 deletions packages/happy-dom/test/nodes/document/Document.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -36,6 +36,7 @@ import ProcessingInstruction from '../../../src/nodes/processing-instruction/Pro
import DOMException from '../../../src/exception/DOMException.js';
import { beforeEach, afterEach, describe, it, expect, vi } from 'vitest';
import IRequestInit from '../../../src/fetch/types/IRequestInit.js';
import IShadowRoot from '../../../src/nodes/shadow-root/IShadowRoot.js';

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

Expand Down Expand Up @@ -277,7 +278,7 @@ describe('Document', () => {
it('Returns and sets title.', () => {
document.title = 'test title';
expect(document.title).toBe('test title');
const title = document.head.querySelector('title');
const title = <Element>document.head.querySelector('title');
expect(title.textContent).toBe('test title');
document.title = 'new title';
expect(document.title).toBe('new title');
Expand Down Expand Up @@ -405,7 +406,7 @@ describe('Document', () => {
}

public connectedCallback(): void {
this.shadowRoot.innerHTML = `
(<IShadowRoot>this.shadowRoot).innerHTML = `
<div>
<custom-element-b></custom-element-b>
</div>
Expand All @@ -419,7 +420,7 @@ describe('Document', () => {
}

public connectedCallback(): void {
this.shadowRoot.innerHTML = `
(<IShadowRoot>this.shadowRoot).innerHTML = `
<div>
<button tabindex="0"></button>
</div>
Expand Down Expand Up @@ -1290,4 +1291,20 @@ describe('Document', () => {
}
});
});

describe('currentScript', () => {
it('Returns the currently executing script element.', () => {
expect(document.currentScript).toBe(null);
const script1 = document.createElement('script');
script1.textContent = 'window.test = document.currentScript;';
document.body.appendChild(script1);
expect(window['test']).toBe(script1);
expect(document.currentScript).toBe(null);
const script2 = document.createElement('script');
script2.textContent = 'window.test = document.currentScript;';
document.body.appendChild(script2);
expect(window['test']).toBe(script2);
expect(document.currentScript).toBe(null);
});
});
});
Original file line number Diff line number Diff line change
Expand Up @@ -141,17 +141,18 @@ describe('HTMLScriptElement', () => {
describe('set isConnected()', () => {
it('Evaluates the text content as code when appended to an element that is connected to the document.', () => {
const element = <IHTMLScriptElement>document.createElement('script');
element.text = 'globalThis.test = "test";';
element.text = 'globalThis.test = "test";globalThis.currentScript = document.currentScript;';
document.body.appendChild(element);
expect(window['test']).toBe('test');
expect(window['currentScript']).toBe(element);
});

it('Evaluates the text content as code when inserted before an element that is connected to the document.', () => {
const element = <IHTMLScriptElement>document.createElement('script');
const div1 = document.createElement('div');
const div2 = document.createElement('div');

element.text = 'globalThis.test = "test";';
element.text = 'globalThis.test = "test";globalThis.currentScript = document.currentScript;';

div1.appendChild(element);

Expand All @@ -160,6 +161,7 @@ describe('HTMLScriptElement', () => {
document.body.appendChild(element);

expect(window['test']).toBe('test');
expect(window['currentScript']).toBe(element);
});

it('Loads external script asynchronously.', async () => {
Expand All @@ -169,7 +171,8 @@ describe('HTMLScriptElement', () => {
vi.spyOn(window, 'fetch').mockImplementation((url: IRequestInfo) => {
fetchedURL = <string>url;
return Promise.resolve(<IResponse>{
text: async () => 'globalThis.test = "test";',
text: async () =>
'globalThis.test = "test";globalThis.currentScript = document.currentScript;',
ok: true
});
});
Expand All @@ -188,6 +191,7 @@ describe('HTMLScriptElement', () => {
expect((<Event>(<unknown>loadEvent)).target).toBe(script);
expect(fetchedURL).toBe('path/to/script/');
expect(window['test']).toBe('test');
expect(window['currentScript']).toBe(script);
});

it('Triggers error event when loading external script asynchronously.', async () => {
Expand Down Expand Up @@ -228,7 +232,7 @@ describe('HTMLScriptElement', () => {
(document: IDocument, url: string) => {
fetchedDocument = document;
fetchedURL = url;
return 'globalThis.test = "test";';
return 'globalThis.test = "test";globalThis.currentScript = document.currentScript;';
}
);

Expand All @@ -244,6 +248,7 @@ describe('HTMLScriptElement', () => {
expect(fetchedDocument).toBe(document);
expect(fetchedURL).toBe('path/to/script/');
expect(window['test']).toBe('test');
expect(window['currentScript']).toBe(script);
});

it('Triggers error event when loading external script synchronously with relative URL.', () => {
Expand Down

0 comments on commit b8f3ab6

Please sign in to comment.