Skip to content

Commit

Permalink
fix: [1706] Add an error for invalid characters in set attribute as well
Browse files Browse the repository at this point in the history
  • Loading branch information
OlaviSau committed Jan 30, 2025
1 parent 3ac521e commit 8492df9
Show file tree
Hide file tree
Showing 4 changed files with 79 additions and 0 deletions.
10 changes: 10 additions & 0 deletions packages/happy-dom/src/nodes/element/Element.ts
Original file line number Diff line number Diff line change
Expand Up @@ -33,6 +33,9 @@ import NodeFactory from '../NodeFactory.js';
import HTMLSerializer from '../../html-serializer/HTMLSerializer.js';
import HTMLParser from '../../html-parser/HTMLParser.js';
import IScrollToOptions from '../../window/IScrollToOptions.js';
import { AttributeUtility } from '../../utilities/AttributeUtility.js';
import DOMException from '../../exception/DOMException.js';
import DOMExceptionNameEnum from '../../exception/DOMExceptionNameEnum.js';

type InsertAdjacentPosition = 'beforebegin' | 'afterbegin' | 'beforeend' | 'afterend';

Expand Down Expand Up @@ -669,6 +672,13 @@ export default class Element
* @param value Value.
*/
public setAttribute(name: string, value: string): void {
if (AttributeUtility.isValidAttributeName(name)) {
throw new DOMException(
`Uncaught InvalidCharacterError: Failed to execute 'setAttribute' on 'Element': '${name}' is not a valid attribute name.`,
DOMExceptionNameEnum.invalidCharacterError
);
}
name = String(name);
const namespaceURI = this[PropertySymbol.namespaceURI];
// TODO: Is it correct to check for namespaceURI === NamespaceURI.svg?
const attribute =
Expand Down
15 changes: 15 additions & 0 deletions packages/happy-dom/src/utilities/AttributeUtility.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
const INVALID_CHARACTER_REGEX =
/[\x00-\x1F\x7F\x80-\x9F "\'><=\/\uFDD0-\uFDEF\uFFFE\uFFFF\u1FFFE\u1FFFF\u2FFFE\u2FFFF\u3FFFE\u3FFFF\u4FFFE\u4FFFF\u5FFFE\u5FFFF\u6FFFE\u6FFFF\u7FFFE\u7FFFF\u8FFFE\u8FFFF\u9FFFE\u9FFFF\uAFFFE\uAFFFF\uBFFFE\uBFFFF\uCFFFE\uCFFFF\uDFFFE\uDFFFF\uEFFFE\uEFFFF\uFFFFE\uFFFFF\u10FFFE\u10FFFF]/;

/**
* Attribute utility
*/
export class AttributeUtility {
/**
*
* @param name the attribute name
*/
public static isValidAttributeName(name: unknown): boolean {
return INVALID_CHARACTER_REGEX.test(String(name));
}
}
49 changes: 49 additions & 0 deletions packages/happy-dom/test/nodes/element/Element.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,7 @@ import NodeList from '../../../src/nodes/node/NodeList.js';
import Event from '../../../src/event/Event.js';
import { beforeEach, afterEach, describe, it, expect, vi } from 'vitest';
import * as PropertySymbol from '../../../src/PropertySymbol.js';
import DOMExceptionNameEnum from '../../../lib/exception/DOMExceptionNameEnum';

const NAMESPACE_URI = 'https://test.test';

Expand Down Expand Up @@ -1566,6 +1567,54 @@ describe('Element', () => {
expect(element.attributes['key2'].ownerElement === element).toBe(true);
expect(element.attributes['key2'].ownerDocument === document).toBe(true);
});

it('Throws an error when given an invalid character in the attribute name', () => {
try {
element.setAttribute('☺', '1');
} catch (error) {
expect(error.name).toBe(DOMExceptionNameEnum.invalidCharacterError);
}
try {
element.setAttribute('=', '1');
} catch (error) {
expect(error.name).toBe(DOMExceptionNameEnum.invalidCharacterError);
}
try {
element.setAttribute(' ', '1');
} catch (error) {
expect(error.name).toBe(DOMExceptionNameEnum.invalidCharacterError);
}
try {
element.setAttribute('"', '1');
} catch (error) {
expect(error.name).toBe(DOMExceptionNameEnum.invalidCharacterError);
}
try {
element.setAttribute(`'`, '1');
} catch (error) {
expect(error.name).toBe(DOMExceptionNameEnum.invalidCharacterError);
}
try {
element.setAttribute(`>`, '1');
} catch (error) {
expect(error.name).toBe(DOMExceptionNameEnum.invalidCharacterError);
}
try {
element.setAttribute(`\/`, '1');
} catch (error) {
expect(error.name).toBe(DOMExceptionNameEnum.invalidCharacterError);
}
try {
element.setAttribute(`\u007F`, '1'); // control character delete
} catch (error) {
expect(error.name).toBe(DOMExceptionNameEnum.invalidCharacterError);
}
try {
element.setAttribute(`\u9FFFE`, '1'); // control character delete
} catch (error) {
expect(error.name).toBe(DOMExceptionNameEnum.invalidCharacterError);
}
});
});

describe('setAttributeNS()', () => {
Expand Down
5 changes: 5 additions & 0 deletions packages/happy-dom/test/nodes/element/NamedNodeMap.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -129,6 +129,11 @@ describe('NamedNodeMap', () => {
expect(element.getAttribute('key')).toBe('value1');
expect(element.getAttributeNS('namespace', 'key')).toBe('value2');
});

it('Converts no string keys to strings', () => {
element.setAttribute(undefined, 'value1');
expect(element.getAttribute(undefined)).toBe('value1');
});
});

describe('setNamedItemNS()', () => {
Expand Down

0 comments on commit 8492df9

Please sign in to comment.