Skip to content

Commit

Permalink
chore: [#1101] Continues on implementation
Browse files Browse the repository at this point in the history
  • Loading branch information
capricorn86 committed Mar 5, 2024
1 parent 6e64250 commit a215170
Show file tree
Hide file tree
Showing 8 changed files with 117 additions and 40 deletions.
63 changes: 55 additions & 8 deletions packages/happy-dom/src/nodes/document/Document.ts
Original file line number Diff line number Diff line change
Expand Up @@ -48,6 +48,7 @@ import NodeFactory from '../NodeFactory.js';
import { URL } from 'url';
import IElementTagNameMap from '../../config/IElementTagNameMap.js';
import ISVGElementTagNameMap from '../../config/ISVGElementTagNameMap.js';
import ISVGElement from '../svg-element/ISVGElement.js';

const PROCESSING_INSTRUCTION_TARGET_REGEXP = /^[a-z][a-z0-9-]+$/;

Expand Down Expand Up @@ -637,6 +638,26 @@ export default class Document extends Node implements IDocument {
return ParentNodeUtility.getElementsByClassName(this, className);
}

/**
* Returns an elements by tag name.
*
* @param tagName Tag name.
* @returns Matching element.
*/
public getElementsByTagName<K extends keyof IElementTagNameMap>(
tagName: K
): IHTMLCollection<IElementTagNameMap[K]>;

/**
* Returns an elements by tag name.
*
* @param tagName Tag name.
* @returns Matching element.
*/
public getElementsByTagName<K extends keyof ISVGElementTagNameMap>(
tagName: K
): IHTMLCollection<ISVGElementTagNameMap[K]>;

/**
* Returns an elements by tag name.
*
Expand All @@ -647,6 +668,30 @@ export default class Document extends Node implements IDocument {
return ParentNodeUtility.getElementsByTagName(this, tagName);
}

/**
* Returns an elements by tag name and namespace.
*
* @param namespaceURI Namespace URI.
* @param tagName Tag name.
* @returns Matching element.
*/
public getElementsByTagNameNS<K extends keyof IElementTagNameMap>(
namespaceURI: 'http://www.w3.org/1999/xhtml',
tagName: K
): IHTMLCollection<IElementTagNameMap[K]>;

/**
* Returns an elements by tag name and namespace.
*
* @param namespaceURI Namespace URI.
* @param tagName Tag name.
* @returns Matching element.
*/
public getElementsByTagNameNS<K extends keyof ISVGElementTagNameMap>(
namespaceURI: 'http://www.w3.org/2000/svg',
tagName: K
): IHTMLCollection<ISVGElementTagNameMap[K]>;

/**
* Returns an elements by tag name and namespace.
*
Expand Down Expand Up @@ -883,8 +928,10 @@ export default class Document extends Node implements IDocument {
public createElement<E extends keyof IElementTagNameMap, S extends keyof ISVGElementTagNameMap>(
qualifiedName: E | S | string,
options?: { is?: string }
): IElementTagNameMap[E] | ISVGElementTagNameMap[S] | IElement {
return this.createElementNS(NamespaceURI.html, qualifiedName, options);
): IElementTagNameMap[E] | ISVGElementTagNameMap[S] | IHTMLElement {
return <IElementTagNameMap[E] | ISVGElementTagNameMap[S] | IHTMLElement>(
this.createElementNS(NamespaceURI.html, qualifiedName, options)
);
}

/**
Expand All @@ -900,7 +947,7 @@ export default class Document extends Node implements IDocument {
namespaceURI: string,
qualifiedName: E | S | string,
options?: { is?: string }
): IElementTagNameMap[E] | ISVGElementTagNameMap[S] | IElement {
): IElementTagNameMap[E] | ISVGElementTagNameMap[S] | IHTMLElement {
qualifiedName = String(qualifiedName);

if (!qualifiedName) {
Expand All @@ -911,7 +958,7 @@ export default class Document extends Node implements IDocument {

// SVG element
if (namespaceURI === NamespaceURI.svg) {
const element = NodeFactory.createNode<IElement>(
const element = NodeFactory.createNode<ISVGElement>(
this,
qualifiedName === 'svg'
? this[PropertySymbol.ownerWindow].SVGSVGElement
Expand All @@ -921,7 +968,7 @@ export default class Document extends Node implements IDocument {
element[PropertySymbol.localName] = qualifiedName;
element[PropertySymbol.namespaceURI] = namespaceURI;
element[PropertySymbol.isValue] = options && options.is ? String(options.is) : null;
return element;
return <ISVGElementTagNameMap[S]>element;
}

// Custom HTML element
Expand All @@ -931,7 +978,7 @@ export default class Document extends Node implements IDocument {
];

if (customElement) {
const element = NodeFactory.createNode<IElement>(this, customElement.elementClass);
const element = NodeFactory.createNode<IHTMLElement>(this, customElement.elementClass);
element[PropertySymbol.tagName] = qualifiedName.toUpperCase();
element[PropertySymbol.localName] = qualifiedName;
element[PropertySymbol.namespaceURI] = namespaceURI;
Expand All @@ -951,7 +998,7 @@ export default class Document extends Node implements IDocument {
element[PropertySymbol.namespaceURI] = namespaceURI;
element[PropertySymbol.isValue] = options && options.is ? String(options.is) : null;

return element;
return <IElementTagNameMap[E]>element;
}

// Unknown HTML element
Expand All @@ -968,7 +1015,7 @@ export default class Document extends Node implements IDocument {
element[PropertySymbol.namespaceURI] = namespaceURI;
element[PropertySymbol.isValue] = options && options.is ? String(options.is) : null;

return element;
return <IHTMLElement>element;
}

/* eslint-enable jsdoc/valid-types */
Expand Down
9 changes: 5 additions & 4 deletions packages/happy-dom/src/nodes/document/IDocument.ts
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,6 @@ import IAttr from '../attr/IAttr.js';
import IDocumentType from '../document-type/IDocumentType.js';
import IParentNode from '../parent-node/IParentNode.js';
import INode from '../node/INode.js';
import ICharacterData from '../character-data/ICharacterData.js';
import IDocumentFragment from '../document-fragment/IDocumentFragment.js';
import Selection from '../../selection/Selection.js';
import IHTMLCollection from '../element/IHTMLCollection.js';
Expand All @@ -25,6 +24,8 @@ import IProcessingInstruction from '../processing-instruction/IProcessingInstruc
import VisibilityStateEnum from './VisibilityStateEnum.js';
import IElementTagNameMap from '../../config/IElementTagNameMap.js';
import ISVGElementTagNameMap from '../../config/ISVGElementTagNameMap.js';
import IText from '../text/IText.js';
import IComment from '../comment/IComment.js';

/**
* Document.
Expand Down Expand Up @@ -217,7 +218,7 @@ export default interface IDocument extends IParentNode {
options?: { is: string }
): IElementTagNameMap[K];
createElementNS<K extends keyof ISVGElementTagNameMap>(
namespaceURI: '"http://www.w3.org/2000/svg"',
namespaceURI: 'http://www.w3.org/2000/svg',
qualifiedName: K,
options?: { is: string }
): ISVGElementTagNameMap[K];
Expand All @@ -233,15 +234,15 @@ export default interface IDocument extends IParentNode {
* @param data Text data.
* @returns Text node.
*/
createTextNode(data?: string): ICharacterData;
createTextNode(data?: string): IText;

/**
* Creates a comment node.
*
* @param data Text data.
* @returns Text node.
*/
createComment(data?: string): ICharacterData;
createComment(data?: string): IComment;

/**
* Creates a document fragment.
Expand Down
14 changes: 14 additions & 0 deletions packages/happy-dom/src/nodes/parent-node/IParentNode.ts
Original file line number Diff line number Diff line change
Expand Up @@ -73,6 +73,12 @@ export default interface IParentNode extends INode {
* @param tagName Tag name.
* @returns Matching element.
*/
getElementsByTagName<K extends keyof IElementTagNameMap>(
tagName: K
): IHTMLCollection<IElementTagNameMap[K]>;
getElementsByTagName<K extends keyof ISVGElementTagNameMap>(
tagName: K
): IHTMLCollection<ISVGElementTagNameMap[K]>;
getElementsByTagName(tagName: string): IHTMLCollection<IElement>;

/**
Expand All @@ -82,6 +88,14 @@ export default interface IParentNode extends INode {
* @param tagName Tag name.
* @returns Matching element.
*/
getElementsByTagNameNS<K extends keyof IElementTagNameMap>(
namespaceURI: 'http://www.w3.org/1999/xhtml',
tagName: K
): IHTMLCollection<IElementTagNameMap[K]>;
getElementsByTagNameNS<K extends keyof ISVGElementTagNameMap>(
namespaceURI: 'http://www.w3.org/2000/svg',
tagName: K
): IHTMLCollection<ISVGElementTagNameMap[K]>;
getElementsByTagNameNS(namespaceURI: string, tagName: string): IHTMLCollection<IElement>;

/**
Expand Down
26 changes: 20 additions & 6 deletions packages/happy-dom/src/nodes/parent-node/ParentNodeUtility.ts
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,8 @@ import INode from '../node/INode.js';
import HTMLCollection from '../element/HTMLCollection.js';
import DocumentFragment from '../document-fragment/DocumentFragment.js';
import NamespaceURI from '../../config/NamespaceURI.js';
import IElementTagNameMap from '../../config/IElementTagNameMap.js';
import ISVGElementTagNameMap from '../../config/ISVGElementTagNameMap.js';

/**
* Parent node utility.
Expand Down Expand Up @@ -107,10 +109,16 @@ export default class ParentNodeUtility {
* @param tagName Tag name.
* @returns Matching element.
*/
public static getElementsByTagName(
public static getElementsByTagName<
E extends keyof IElementTagNameMap,
S extends keyof ISVGElementTagNameMap
>(
parentNode: IElement | IDocumentFragment | IDocument,
tagName: string
): IHTMLCollection<IElement> {
tagName: E | S | string
):
| IHTMLCollection<IElementTagNameMap[E]>
| IHTMLCollection<ISVGElementTagNameMap[S]>
| IHTMLCollection<IElement> {
const upperTagName = tagName.toUpperCase();
const includeAll = tagName === '*';
let matches = new HTMLCollection<IElement>();
Expand All @@ -135,11 +143,17 @@ export default class ParentNodeUtility {
* @param tagName Tag name.
* @returns Matching element.
*/
public static getElementsByTagNameNS(
public static getElementsByTagNameNS<
E extends keyof IElementTagNameMap,
S extends keyof ISVGElementTagNameMap
>(
parentNode: IElement | IDocumentFragment | IDocument,
namespaceURI: string,
tagName: string
): IHTMLCollection<IElement> {
tagName: E | S | string
):
| IHTMLCollection<IElementTagNameMap[E]>
| IHTMLCollection<ISVGElementTagNameMap[S]>
| IHTMLCollection<IElement> {
// When the namespace is HTML, the tag name is case-insensitive.
const formattedTagName = namespaceURI === NamespaceURI.html ? tagName.toUpperCase() : tagName;
const includeAll = tagName === '*';
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,7 @@ describe('CSSStyleDeclaration', () => {
beforeEach(() => {
window = new Window();
document = window.document;
element = <IHTMLElement>document.createElement('div');
element = document.createElement('div');
});

describe(`get {number}()`, () => {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,7 @@ describe('CSSStyleDeclarationElementStyle', () => {
beforeEach(() => {
window = new Window();
document = window.document;
element = <IHTMLElement>document.createElement('div');
element = document.createElement('div');
});

describe('getElementStyle()', () => {
Expand Down
27 changes: 14 additions & 13 deletions packages/happy-dom/test/form-data/FormData.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@ import IWindow from '../../src/window/IWindow.js';
import IDocument from '../../src/nodes/document/IDocument.js';
import IHTMLFormElement from '../../src/nodes/html-form-element/IHTMLFormElement.js';
import IHTMLInputElement from '../../src/nodes/html-input-element/IHTMLInputElement.js';
import IHTMLButtonElement from '../../src/nodes/html-button-element/IHTMLButtonElement.js';
import File from '../../src/file/File.js';
import { beforeEach, describe, it, expect } from 'vitest';

Expand All @@ -17,20 +18,20 @@ describe('FormData', () => {

describe('constructor', () => {
it('Supports sending in an HTMLFormElement to the contructor.', () => {
const form = <IHTMLFormElement>document.createElement('form');
const form = document.createElement('form');
const file = new File([Buffer.from('fileContent')], 'file.txt', { type: 'text/plain' });
const textInput = <IHTMLInputElement>document.createElement('input');
const hiddenInput = <IHTMLInputElement>document.createElement('input');
const hiddenInput2 = <IHTMLInputElement>document.createElement('input');
const fileInput = <IHTMLInputElement>document.createElement('input');
const radioInput1 = <IHTMLInputElement>document.createElement('input');
const radioInput2 = <IHTMLInputElement>document.createElement('input');
const checkboxInput1 = <IHTMLInputElement>document.createElement('input');
const checkboxInput2 = <IHTMLInputElement>document.createElement('input');
const button1 = <IHTMLInputElement>document.createElement('button');
const button2 = <IHTMLInputElement>document.createElement('input');
const button3 = <IHTMLInputElement>document.createElement('button');
const button4 = <IHTMLInputElement>document.createElement('input');
const textInput = document.createElement('input');
const hiddenInput = document.createElement('input');
const hiddenInput2 = document.createElement('input');
const fileInput = document.createElement('input');
const radioInput1 = document.createElement('input');
const radioInput2 = document.createElement('input');
const checkboxInput1 = document.createElement('input');
const checkboxInput2 = document.createElement('input');
const button1 = document.createElement('button');
const button2 = document.createElement('input');
const button3 = document.createElement('button');
const button4 = document.createElement('input');

textInput.type = 'text';
textInput.name = 'textInput';
Expand Down
14 changes: 7 additions & 7 deletions packages/happy-dom/test/nodes/document/Document.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -339,7 +339,7 @@ describe('Document', () => {
'body { background-color: red }\ndiv { background-color: green }'
);
const style = document.createElement('style');
const link = <IHTMLLinkElement>document.createElement('link');
const link = document.createElement('link');
let fetchedUrl: string | null = null;

link.rel = 'stylesheet';
Expand Down Expand Up @@ -378,8 +378,8 @@ describe('Document', () => {

describe('get activeElement()', () => {
it('Returns the currently active element.', () => {
const div = <IHTMLElement>document.createElement('div');
const span = <IHTMLElement>document.createElement('span');
const div = document.createElement('div');
const span = document.createElement('span');

document.appendChild(div);
document.appendChild(span);
Expand All @@ -400,7 +400,7 @@ describe('Document', () => {
});

it('Unsets the active element when it gets disconnected.', () => {
const div = <IHTMLElement>document.createElement('div');
const div = document.createElement('div');

document.appendChild(div);

Expand Down Expand Up @@ -578,7 +578,7 @@ describe('Document', () => {
vi.spyOn(QuerySelector, 'querySelectorAll').mockImplementation((parentNode, selector) => {
expect(parentNode === document).toBe(true);
expect(selector).toEqual(expectedSelector);
return <INodeList<IElement>>[element];
return <INodeList<IHTMLElement>>[element];
});

const result = document.querySelectorAll(expectedSelector);
Expand Down Expand Up @@ -612,7 +612,7 @@ describe('Document', () => {
(parentNode, requestedClassName) => {
expect(parentNode === document).toBe(true);
expect(requestedClassName).toEqual(className);
return <IHTMLCollection<IElement>>[element];
return <IHTMLCollection<IHTMLElement>>[element];
}
);

Expand All @@ -631,7 +631,7 @@ describe('Document', () => {
(parentNode, requestedTagName) => {
expect(parentNode === document).toBe(true);
expect(requestedTagName).toEqual(tagName);
return <IHTMLCollection<IElement>>[element];
return <IHTMLCollection<IHTMLElement>>[element];
}
);

Expand Down

0 comments on commit a215170

Please sign in to comment.