Skip to content

Commit

Permalink
#468@minor: Adds support for Event.composedPath().
Browse files Browse the repository at this point in the history
  • Loading branch information
davidortnercybercom committed May 10, 2022
1 parent ae900ea commit e92a7aa
Show file tree
Hide file tree
Showing 2 changed files with 138 additions and 1 deletion.
36 changes: 35 additions & 1 deletion packages/happy-dom/src/event/Event.ts
@@ -1,8 +1,12 @@
import IEventInit from './IEventInit';
import EventTarget from './EventTarget';
import INode from '../nodes/node/INode';
import IWindow from '../window/IWindow';
import IShadowRoot from '../nodes/shadow-root/IShadowRoot';
import IEventTarget from './IEventTarget';

/**
*
* Event.
*/
export default class Event {
public composed = false;
Expand Down Expand Up @@ -31,6 +35,36 @@ export default class Event {
}
}

/**
* Returns composed path.
*
* @returns Composed path.
*/
public composedPath(): IEventTarget[] {
if (!this.target) {
return [];
}

const composedPath = [];
let eventTarget: INode | IShadowRoot | IWindow = <INode | IShadowRoot>(<unknown>this.target);

while (eventTarget) {
composedPath.push(eventTarget);

if (this.bubbles) {
if (this.composed && (<IShadowRoot>eventTarget).host) {
eventTarget = (<IShadowRoot>eventTarget).host;
} else if ((<INode>(<unknown>this.target)).ownerDocument === eventTarget) {
eventTarget = (<INode>(<unknown>this.target)).ownerDocument.defaultView;
} else {
eventTarget = (<INode>(<unknown>eventTarget)).parentNode || null;
}
}
}

return composedPath;
}

/**
* Init event.
*
Expand Down
103 changes: 103 additions & 0 deletions packages/happy-dom/test/event/Event.test.ts
@@ -0,0 +1,103 @@
import IWindow from '../../src/window/IWindow';
import Window from '../../src/window/Window';
import IDocument from '../../src/nodes/document/IDocument';
import Event from '../../src/event/Event';
import CustomElement from '../CustomElement';

describe('Event', () => {
let window: IWindow;
let document: IDocument;

beforeEach(() => {
window = new Window();
document = window.document;

window.customElements.define('custom-element', CustomElement);
});

describe('composedPath()', () => {
it('Returns a composed path.', () => {
const div = document.createElement('div');
const span = document.createElement('span');
let composedPath = null;

div.appendChild(span);
document.body.appendChild(div);

div.addEventListener('click', (event: Event) => {
composedPath = event.composedPath();
});

span.dispatchEvent(
new Event('click', {
bubbles: true
})
);

expect(composedPath).toEqual([
span,
div,
document.body,
document.documentElement,
document,
window
]);
});

it('Goes through shadow roots if composed is set to "true".', () => {
const div = document.createElement('div');
const customELement = document.createElement('custom-element');
let composedPath = null;

div.appendChild(customELement);

document.body.appendChild(div);

div.addEventListener('click', (event: Event) => {
composedPath = event.composedPath();
});

customELement.shadowRoot.children[1].children[0].dispatchEvent(
new Event('click', {
bubbles: true,
composed: true
})
);

expect(composedPath).toEqual([
customELement.shadowRoot.children[1].children[0],
customELement.shadowRoot.children[1],
customELement.shadowRoot,
customELement,
div,
document.body,
document.documentElement,
document,
window
]);
});

it('Does not go through shadow roots if composed is set to "false".', () => {
const customELement = document.createElement('custom-element');
let composedPath = null;

document.body.appendChild(customELement);

customELement.shadowRoot.children[1].addEventListener('click', (event: Event) => {
composedPath = event.composedPath();
});

customELement.shadowRoot.children[1].children[0].dispatchEvent(
new Event('click', {
bubbles: true
})
);

expect(composedPath).toEqual([
customELement.shadowRoot.children[1].children[0],
customELement.shadowRoot.children[1],
customELement.shadowRoot
]);
});
});
});

0 comments on commit e92a7aa

Please sign in to comment.