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.
This commit is contained in:
parent
9f62f29946
commit
4afd39117a
|
|
@ -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> } {
|
_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 parsed = this._parseSelector(selector);
|
||||||
const task = async (context: dom.FrameExecutionContext) => context.evaluateHandleInternal(({ evaluator, parsed, waitFor, timeout }) => {
|
const task = async (context: dom.FrameExecutionContext) => context.evaluateHandleInternal(({ evaluator, parsed, waitFor, timeout }) => {
|
||||||
const polling = (waitFor === 'attached' || waitFor === 'detached') ? 'mutation' : 'raf';
|
return evaluator.injected.poll('raf', timeout, () => {
|
||||||
return evaluator.injected.poll(polling, timeout, () => {
|
|
||||||
const element = evaluator.querySelector(parsed, document);
|
const element = evaluator.querySelector(parsed, document);
|
||||||
switch (waitFor) {
|
switch (waitFor) {
|
||||||
case 'attached':
|
case 'attached':
|
||||||
|
|
@ -166,7 +165,7 @@ export class Selectors {
|
||||||
_dispatchEventTask(selector: string, type: string, eventInit: Object, deadline: number): (context: dom.FrameExecutionContext) => Promise<js.JSHandle> {
|
_dispatchEventTask(selector: string, type: string, eventInit: Object, deadline: number): (context: dom.FrameExecutionContext) => Promise<js.JSHandle> {
|
||||||
const parsed = this._parseSelector(selector);
|
const parsed = this._parseSelector(selector);
|
||||||
const task = async (context: dom.FrameExecutionContext) => context.evaluateHandleInternal(({ evaluator, parsed, type, eventInit, timeout }) => {
|
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);
|
const element = evaluator.querySelector(parsed, document);
|
||||||
if (element)
|
if (element)
|
||||||
evaluator.injected.dispatchEvent(element, type, eventInit);
|
evaluator.injected.dispatchEvent(element, type, eventInit);
|
||||||
|
|
|
||||||
|
|
@ -79,6 +79,24 @@ describe('Page.dispatchEvent(click)', function() {
|
||||||
await page.dispatchEvent('button', 'click');
|
await page.dispatchEvent('button', 'click');
|
||||||
expect(await page.evaluate(() => window.clicked)).toBeTruthy();
|
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() {
|
describe('Page.dispatchEvent(drag)', function() {
|
||||||
|
|
|
||||||
|
|
@ -192,6 +192,23 @@ describe('Frame.waitForSelector', function() {
|
||||||
const tagName = await eHandle.getProperty('tagName').then(e => e.jsonValue());
|
const tagName = await eHandle.getProperty('tagName').then(e => e.jsonValue());
|
||||||
expect(tagName).toBe('DIV');
|
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}) => {
|
it('should work when node is added through innerHTML', async({page, server}) => {
|
||||||
await page.goto(server.EMPTY_PAGE);
|
await page.goto(server.EMPTY_PAGE);
|
||||||
const watchdog = page.waitForSelector('h3 div');
|
const watchdog = page.waitForSelector('h3 div');
|
||||||
|
|
|
||||||
Loading…
Reference in a new issue