Skip to content

Commit 4afd391

Browse files
authored
fix(waitForSelector): use raf polling instead of mutation (#2047)
MutationObserver does not work with mutations in the shadow, so we cannot use it for selectors that pierce shadows.
1 parent 9f62f29 commit 4afd391

File tree

3 files changed

+37
-3
lines changed

3 files changed

+37
-3
lines changed

src/selectors.ts

Lines changed: 2 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -145,8 +145,7 @@ export class Selectors {
145145
_waitForSelectorTask(selector: string, waitFor: 'attached' | 'detached' | 'visible' | 'hidden', deadline: number): { world: 'main' | 'utility', task: (context: dom.FrameExecutionContext) => Promise<js.JSHandle> } {
146146
const parsed = this._parseSelector(selector);
147147
const task = async (context: dom.FrameExecutionContext) => context.evaluateHandleInternal(({ evaluator, parsed, waitFor, timeout }) => {
148-
const polling = (waitFor === 'attached' || waitFor === 'detached') ? 'mutation' : 'raf';
149-
return evaluator.injected.poll(polling, timeout, () => {
148+
return evaluator.injected.poll('raf', timeout, () => {
150149
const element = evaluator.querySelector(parsed, document);
151150
switch (waitFor) {
152151
case 'attached':
@@ -166,7 +165,7 @@ export class Selectors {
166165
_dispatchEventTask(selector: string, type: string, eventInit: Object, deadline: number): (context: dom.FrameExecutionContext) => Promise<js.JSHandle> {
167166
const parsed = this._parseSelector(selector);
168167
const task = async (context: dom.FrameExecutionContext) => context.evaluateHandleInternal(({ evaluator, parsed, type, eventInit, timeout }) => {
169-
return evaluator.injected.poll('mutation', timeout, () => {
168+
return evaluator.injected.poll('raf', timeout, () => {
170169
const element = evaluator.querySelector(parsed, document);
171170
if (element)
172171
evaluator.injected.dispatchEvent(element, type, eventInit);

test/dispatchevent.spec.js

Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -79,6 +79,24 @@ describe('Page.dispatchEvent(click)', function() {
7979
await page.dispatchEvent('button', 'click');
8080
expect(await page.evaluate(() => window.clicked)).toBeTruthy();
8181
});
82+
it('should dispatch click when node is added in shadow dom', async({page, server}) => {
83+
await page.goto(server.EMPTY_PAGE);
84+
const watchdog = page.dispatchEvent('span', 'click');
85+
await page.evaluate(() => {
86+
const div = document.createElement('div');
87+
div.attachShadow({mode: 'open'});
88+
document.body.appendChild(div);
89+
});
90+
await page.evaluate(() => new Promise(f => setTimeout(f, 100)));
91+
await page.evaluate(() => {
92+
const span = document.createElement('span');
93+
span.textContent = 'Hello from shadow';
94+
span.addEventListener('click', () => window.clicked = true);
95+
document.querySelector('div').shadowRoot.appendChild(span);
96+
});
97+
await watchdog;
98+
expect(await page.evaluate(() => window.clicked)).toBe(true);
99+
});
82100
});
83101

84102
describe('Page.dispatchEvent(drag)', function() {

test/waittask.spec.js

Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -192,6 +192,23 @@ describe('Frame.waitForSelector', function() {
192192
const tagName = await eHandle.getProperty('tagName').then(e => e.jsonValue());
193193
expect(tagName).toBe('DIV');
194194
});
195+
it('should resolve promise when node is added in shadow dom', async({page, server}) => {
196+
await page.goto(server.EMPTY_PAGE);
197+
const watchdog = page.waitForSelector('span');
198+
await page.evaluate(() => {
199+
const div = document.createElement('div');
200+
div.attachShadow({mode: 'open'});
201+
document.body.appendChild(div);
202+
});
203+
await page.evaluate(() => new Promise(f => setTimeout(f, 100)));
204+
await page.evaluate(() => {
205+
const span = document.createElement('span');
206+
span.textContent = 'Hello from shadow';
207+
document.querySelector('div').shadowRoot.appendChild(span);
208+
});
209+
const handle = await watchdog;
210+
expect(await handle.evaluate(e => e.textContent)).toBe('Hello from shadow');
211+
});
195212
it('should work when node is added through innerHTML', async({page, server}) => {
196213
await page.goto(server.EMPTY_PAGE);
197214
const watchdog = page.waitForSelector('h3 div');

0 commit comments

Comments
 (0)