Skip to content

Commit

Permalink
fix(waitForSelector): use raf polling instead of mutation (#2047)
Browse files Browse the repository at this point in the history
MutationObserver does not work with mutations in the shadow, so we cannot use it for selectors that pierce shadows.
  • Loading branch information
dgozman committed Apr 30, 2020
1 parent 9f62f29 commit 4afd391
Show file tree
Hide file tree
Showing 3 changed files with 37 additions and 3 deletions.
5 changes: 2 additions & 3 deletions src/selectors.ts
Original file line number Diff line number Diff line change
Expand Up @@ -145,8 +145,7 @@ export class Selectors {
_waitForSelectorTask(selector: string, waitFor: 'attached' | 'detached' | 'visible' | 'hidden', deadline: number): { world: 'main' | 'utility', task: (context: dom.FrameExecutionContext) => Promise<js.JSHandle> } {
const parsed = this._parseSelector(selector);
const task = async (context: dom.FrameExecutionContext) => context.evaluateHandleInternal(({ evaluator, parsed, waitFor, timeout }) => {
const polling = (waitFor === 'attached' || waitFor === 'detached') ? 'mutation' : 'raf';
return evaluator.injected.poll(polling, timeout, () => {
return evaluator.injected.poll('raf', timeout, () => {
const element = evaluator.querySelector(parsed, document);
switch (waitFor) {
case 'attached':
Expand All @@ -166,7 +165,7 @@ export class Selectors {
_dispatchEventTask(selector: string, type: string, eventInit: Object, deadline: number): (context: dom.FrameExecutionContext) => Promise<js.JSHandle> {
const parsed = this._parseSelector(selector);
const task = async (context: dom.FrameExecutionContext) => context.evaluateHandleInternal(({ evaluator, parsed, type, eventInit, timeout }) => {
return evaluator.injected.poll('mutation', timeout, () => {
return evaluator.injected.poll('raf', timeout, () => {
const element = evaluator.querySelector(parsed, document);
if (element)
evaluator.injected.dispatchEvent(element, type, eventInit);
Expand Down
18 changes: 18 additions & 0 deletions test/dispatchevent.spec.js
Original file line number Diff line number Diff line change
Expand Up @@ -79,6 +79,24 @@ describe('Page.dispatchEvent(click)', function() {
await page.dispatchEvent('button', 'click');
expect(await page.evaluate(() => window.clicked)).toBeTruthy();
});
it('should dispatch click when node is added in shadow dom', async({page, server}) => {
await page.goto(server.EMPTY_PAGE);
const watchdog = page.dispatchEvent('span', 'click');
await page.evaluate(() => {
const div = document.createElement('div');
div.attachShadow({mode: 'open'});
document.body.appendChild(div);
});
await page.evaluate(() => new Promise(f => setTimeout(f, 100)));
await page.evaluate(() => {
const span = document.createElement('span');
span.textContent = 'Hello from shadow';
span.addEventListener('click', () => window.clicked = true);
document.querySelector('div').shadowRoot.appendChild(span);
});
await watchdog;
expect(await page.evaluate(() => window.clicked)).toBe(true);
});
});

describe('Page.dispatchEvent(drag)', function() {
Expand Down
17 changes: 17 additions & 0 deletions test/waittask.spec.js
Original file line number Diff line number Diff line change
Expand Up @@ -192,6 +192,23 @@ describe('Frame.waitForSelector', function() {
const tagName = await eHandle.getProperty('tagName').then(e => e.jsonValue());
expect(tagName).toBe('DIV');
});
it('should resolve promise when node is added in shadow dom', async({page, server}) => {
await page.goto(server.EMPTY_PAGE);
const watchdog = page.waitForSelector('span');
await page.evaluate(() => {
const div = document.createElement('div');
div.attachShadow({mode: 'open'});
document.body.appendChild(div);
});
await page.evaluate(() => new Promise(f => setTimeout(f, 100)));
await page.evaluate(() => {
const span = document.createElement('span');
span.textContent = 'Hello from shadow';
document.querySelector('div').shadowRoot.appendChild(span);
});
const handle = await watchdog;
expect(await handle.evaluate(e => e.textContent)).toBe('Hello from shadow');
});
it('should work when node is added through innerHTML', async({page, server}) => {
await page.goto(server.EMPTY_PAGE);
const watchdog = page.waitForSelector('h3 div');
Expand Down

0 comments on commit 4afd391

Please sign in to comment.