diff --git a/packages/happy-dom/src/nodes/element/Element.ts b/packages/happy-dom/src/nodes/element/Element.ts index 8a34c7eae..f835b92f3 100644 --- a/packages/happy-dom/src/nodes/element/Element.ts +++ b/packages/happy-dom/src/nodes/element/Element.ts @@ -14,14 +14,13 @@ import XMLSerializer from '../../xml-serializer/XMLSerializer'; import ChildNodeUtility from '../child-node/ChildNodeUtility'; import ParentNodeUtility from '../parent-node/ParentNodeUtility'; import NonDocumentChildNodeUtility from '../child-node/NonDocumentChildNodeUtility'; -import IElement from './IElement'; +import IElement, { TInsertAdjacentPositions } from './IElement'; import DOMException from '../../exception/DOMException'; import IShadowRoot from '../shadow-root/IShadowRoot'; import INode from '../node/INode'; import IDocument from '../document/IDocument'; import IHTMLCollection from './IHTMLCollection'; import INodeList from '../node/INodeList'; -import { TInsertAdjacentPositions } from './IElement'; import IText from '../text/IText'; import IDOMRectList from './IDOMRectList'; import DOMRectListFactory from './DOMRectListFactory'; @@ -255,7 +254,21 @@ export default class Element extends Node implements IElement { * @returns Attributes. */ public get attributes(): INamedNodeMap { - return Object.assign(new NamedNodeMap(this), Object.values(this._attributes), this._attributes); + const nodeMap = new NamedNodeMap(this); + return new Proxy(nodeMap, { + get: (target, name) => { + if (name in target && typeof target[name] === 'function') { + return (...args) => target[name](...args); + } + + return ( + target[name] || + (typeof name === 'string' || typeof name === 'number' + ? this._attributes[name] + : undefined) + ); + } + }); } /** @@ -404,7 +417,8 @@ export default class Element extends Node implements IElement { } /** - * The Node.replaceWith() method replaces this Node in the children list of its parent with a set of Node or DOMString objects. + * The Node.replaceWith() method replaces this Node in the children list of its parent with a set of Node or + * DOMString objects. * * @param nodes List of Node or DOMString. */ @@ -413,7 +427,8 @@ export default class Element extends Node implements IElement { } /** - * Inserts a set of Node or DOMString objects in the children list of this ChildNode's parent, just before this ChildNode. DOMString objects are inserted as equivalent Text nodes. + * Inserts a set of Node or DOMString objects in the children list of this ChildNode's parent, just before this + * ChildNode. DOMString objects are inserted as equivalent Text nodes. * * @param nodes List of Node or DOMString. */ @@ -422,7 +437,8 @@ export default class Element extends Node implements IElement { } /** - * Inserts a set of Node or DOMString objects in the children list of this ChildNode's parent, just after this ChildNode. DOMString objects are inserted as equivalent Text nodes. + * Inserts a set of Node or DOMString objects in the children list of this ChildNode's parent, just after this + * ChildNode. DOMString objects are inserted as equivalent Text nodes. * * @param nodes List of Node or DOMString. */ @@ -431,7 +447,8 @@ export default class Element extends Node implements IElement { } /** - * Inserts a set of Node objects or DOMString objects after the last child of the ParentNode. DOMString objects are inserted as equivalent Text nodes. + * Inserts a set of Node objects or DOMString objects after the last child of the ParentNode. DOMString objects are + * inserted as equivalent Text nodes. * * @param nodes List of Node or DOMString. */ @@ -440,7 +457,8 @@ export default class Element extends Node implements IElement { } /** - * Inserts a set of Node objects or DOMString objects before the first child of the ParentNode. DOMString objects are inserted as equivalent Text nodes. + * Inserts a set of Node objects or DOMString objects before the first child of the ParentNode. DOMString objects are + * inserted as equivalent Text nodes. * * @param nodes List of Node or DOMString. */ @@ -564,7 +582,8 @@ export default class Element extends Node implements IElement { * Returns `true` if attribute name is eventually present, and `false` otherwise. * * @param name A DOMString specifying the name of the attribute to be toggled. - * @param force A boolean value to determine whether the attribute should be added or removed, no matter whether the attribute is present or not at the moment. + * @param force A boolean value to determine whether the attribute should be added or removed, no matter whether the + * attribute is present or not at the moment. */ public toggleAttribute(name: string, force?: boolean): boolean { name = name.toLowerCase(); @@ -727,7 +746,8 @@ export default class Element extends Node implements IElement { } /** - * Traverses the Element and its parents (heading toward the document root) until it finds a node that matches the provided selector string. + * Traverses the Element and its parents (heading toward the document root) until it finds a node that matches the + * provided selector string. * * @param selector Selector. * @returns Closest matching element.