-
Notifications
You must be signed in to change notification settings - Fork 3.7k
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
fix(chromium): drag and drop works in chromium #6207
Conversation
src/server/chromium/crDragDrop.ts
Outdated
return false; | ||
await this._page._mainFrameSession._client.send('Input.dispatchDragEvent', { | ||
type: 'dragCancel', | ||
x: 0, |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Should we store last drag position to pass here?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Reasonable! I was going based off of Firefox, which has (0,0) for the position on all dragend
events. But Chromium does report the position of dragend
.
src/server/chromium/crDragDrop.ts
Outdated
}); | ||
}).toString(), true, undefined, 'utility'); | ||
// don't resolve on errors. This could be replaced by Promise.any after Node v15 | ||
dragSignalPromises.push(promise.catch(e => new Promise(() => {}))); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Why not resolve on errors? What if we have just a single frame and is has just navigated under our feet? We'll stall forever.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
It doesn't stall because these are used with Promise.race
fe2b625
to
3a1bb81
Compare
3a1bb81
to
1d1c0d8
Compare
Ready for review! |
tests/page/page-drag.spec.ts
Outdated
it.skip(({ isAndroid }) => isAndroid); | ||
it.fixme(({ browserName }) => browserName === 'chromium'); | ||
it.skip(({isAndroid}) => isAndroid); | ||
it.skip(({isChromium, browserMajorVersion}) => isChromium && browserMajorVersion < 91); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I was under impression that we are waiting for the stable to pick up the protocol changes.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
There is a try-catch in the code.
await page.goto(server.PREFIX + '/frames/one-frame.html'); | ||
await page.mouse.move(30, 30); | ||
await page.mouse.down(); | ||
await page.mouse.move(60, 60); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Let's do a mouseup just in case.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Done. Added an event tracker as well.
src/server/chromium/crDragDrop.ts
Outdated
dragSignalPromises.push(promise.catch(() => false)); | ||
} | ||
// make sure that all previous evaluate expressions hit the renderer | ||
await this._crPage._page.mainFrame().evaluateExpression('1', false, undefined, 'utility').catch(() => {}); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
You have to do this for all oopifs, I guess.
src/server/chromium/crDragDrop.ts
Outdated
|
||
const dragSignalPromises: Promise<boolean>[] = []; | ||
for (const frame of this._crPage._page.frames()) { | ||
const promise = frame.evaluateExpression((function() { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I think you need something like nonStallingRawEvaluateInExistingMainContext
her (there is such a function) to avoid stalling mouse move because some frame is perpetually navigating.
fa05b58
to
a4f5a8f
Compare
a4f5a8f
to
23e0794
Compare
it.skip(({ isAndroid }) => isAndroid); | ||
it.fixme(({ browserName }) => browserName === 'chromium'); | ||
it.skip(({isAndroid}) => isAndroid); | ||
it.skip(({browserName, browserMajorVersion}) => browserName === 'chromium' && browserMajorVersion < 91); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
91 is current stable, we can drop the version check
}); | ||
} | ||
|
||
async down(x: number, y: number, button: types.MouseButton, buttons: Set<types.MouseButton>, modifiers: Set<types.KeyboardModifier>, clickCount: number): Promise<void> { | ||
if (this._dragManager.isDragging()) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Shouldn't it be drop? If I do left button down, drag and then right button click (while holding left button) it will paste the selection.
return frame.evaluateExpression((() => window.__didStartDrag).toString(), true, undefined, 'utility').catch(() => false); | ||
}))).some(x => x); | ||
this._dragState = expectingDrag ? (await dragInterceptedPromise).data : null; | ||
client.off('Input.dragIntercepted', onDragIntercepted!); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Consider removing 'mousemove' listeners too
src/server/chromium/crDragDrop.ts
Outdated
await client.send('Input.setInterceptDrags', {enabled: true}); | ||
} catch { | ||
// If Input.setInterceptDrags is not supported, just do a regular move. | ||
// This can be removed once Input.setInterceptDrags lands into Chromium Stable. |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This will be needed for quite a while for Electron, right? Let's update the comment.
src/server/chromium/crDragDrop.ts
Outdated
const dragInterceptedPromise = new Promise<Protocol.Input.dragInterceptedPayload>(x => onDragIntercepted = x); | ||
|
||
await Promise.all(this._crPage._page.frames().map(async frame => { | ||
await frame.evaluateExpression((function() { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I still think that awaiting all frames when some oopif could be perpetually navigating is going to stall. Did we figure out the solution?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I'll go add a test
23e0794
to
774af59
Compare
774af59
to
2a79043
Compare
What is the correct way to implement this functionality from within a playwright test? |
How use that from tests? |
Today you can just do |
Waiting for #6203 to percolate to the cdn. But this all works locally.
Fixes #1094