Skip to content

Commit

Permalink
#1223@patch: Relax MutationsObserver.observe check for options ar…
Browse files Browse the repository at this point in the history
…gument. Throw `TypeError` instead of `DOMException` when validation fails.
  • Loading branch information
romansp committed Jan 18, 2024
1 parent 3a98235 commit 9279da5
Show file tree
Hide file tree
Showing 2 changed files with 47 additions and 3 deletions.
42 changes: 39 additions & 3 deletions packages/happy-dom/src/mutation-observer/MutationObserver.ts
Original file line number Diff line number Diff line change
@@ -1,4 +1,3 @@
import DOMException from '../exception/DOMException.js';
import * as PropertySymbol from '../PropertySymbol.js';
import INode from '../nodes/node/INode.js';
import Node from '../nodes/node/Node.js';
Expand Down Expand Up @@ -34,13 +33,50 @@ export default class MutationObserver {
*/
public observe(target: INode, options: IMutationObserverInit): void {
if (!target) {
throw new DOMException(
throw new TypeError(
`Failed to execute 'observe' on 'MutationObserver': The first parameter "target" should be of type "Node".`
);
}

if (options && (options.attributeFilter || options.attributeOldValue)) {
if (options.attributes === undefined) {
options = Object.assign({}, options, {
attributes: true,
attributeFilter: options.attributeFilter,
attributeOldValue: options.attributeOldValue
});
}

if (!options.attributes && options.attributeOldValue) {
throw new TypeError(
`Failed to execute 'observe' on 'MutationObserver': The options object may only set 'attributeOldValue' to true when 'attributes' is true or not present.`
);
}

if (!options.attributes && options.attributeFilter) {
throw new TypeError(
`Failed to execute 'observe' on 'MutationObserver': The options object may only set 'attributeFilter' when 'attributes' is true or not present.`
);
}
}

if (options && !options.characterData && options.characterDataOldValue) {
if (options.characterData === undefined) {
options = Object.assign({}, options, {
characterData: true,
characterDataOldValue: options.characterDataOldValue
});
}

if (!options.characterData && options.characterDataOldValue) {
throw new TypeError(
`Failed to execute 'observe' on 'MutationObserver': The options object may only set 'characterDataOldValue' to true when 'characterData' is true or not present.`
);
}
}

if (!options || (!options.childList && !options.attributes && !options.characterData)) {
throw new DOMException(
throw new TypeError(
`Failed to execute 'observe' on 'MutationObserver': The options object must set at least one of 'attributes', 'characterData', or 'childList' to true.`
);
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -49,13 +49,21 @@ describe('MutationObserver', () => {
it('Allows to omit "attributes" if "attributeOldValue" or "attributeFilter" is specified.', async () => {
const div = document.createElement('div');
const observer = new MutationObserver(() => {});
expect(() => observer.observe(div, { attributes: false, attributeOldValue: true })).toThrow();
expect(() =>
observer.observe(div, { attributes: false, attributeFilter: ['style', 'class'] })
).toThrow();

expect(() => observer.observe(div, { attributeOldValue: true })).not.toThrow();
expect(() => observer.observe(div, { attributeFilter: ['style', 'class'] })).not.toThrow();
});

it('Allows to omit "characterData" if "characterDataOldValue" is specified.', async () => {
const text = document.createTextNode('old');
const observer = new MutationObserver(() => {});
expect(() =>
observer.observe(text, { characterData: false, characterDataOldValue: true })
).toThrow();
expect(() => observer.observe(text, { characterDataOldValue: true })).not.toThrow();
});

Expand Down

0 comments on commit 9279da5

Please sign in to comment.