Skip to content
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 scroll position for cdp events #7559

Merged
merged 3 commits into from
Mar 15, 2023
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 3 additions & 1 deletion src/client/automation/move.ts
Original file line number Diff line number Diff line change
Expand Up @@ -217,7 +217,9 @@ export default class MoveAutomation {
const events: any[] = [];

await mouseMoveStep(mouseMoveOptions, nativeMethods.dateNow, async currPosition => {
events.push(this.proxylessInput?.createMouseMoveEvent(currPosition));
const moveEvent = await this.proxylessInput?.createMouseMoveEvent(currPosition);

events.push(moveEvent);

return nextTick();
});
Expand Down
5 changes: 2 additions & 3 deletions src/client/automation/playback/click/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,6 @@ import delay from '../../../core/utils/delay';
import { utils, Promise } from '../../deps/hammerhead';
import { createMouseClickStrategy, MouseClickStrategy } from './browser-click-strategy';
import ProxylessInput from '../../../../proxyless/client/input';
import AxisValues from '../../../core/utils/values/axis-values';
import { setCaretPosition } from '../../utils/utils';
import { DispatchEventFn } from '../../../../proxyless/client/types';

Expand All @@ -23,8 +22,8 @@ export default class ClickAutomation extends VisibleElementAutomation {
private modifiers: Modifiers;
public strategy: MouseClickStrategy;

protected constructor (element: HTMLElement, clickOptions: ClickOptions, win: Window, cursor: Cursor, dispatchProxylessEventFn?: DispatchEventFn, leftTopPoint?: AxisValues<number>) {
super(element, clickOptions, win, cursor, dispatchProxylessEventFn, leftTopPoint);
protected constructor (element: HTMLElement, clickOptions: ClickOptions, win: Window, cursor: Cursor, dispatchProxylessEventFn?: DispatchEventFn) {
super(element, clickOptions, win, cursor, dispatchProxylessEventFn);

this.modifiers = clickOptions.modifiers;
this.strategy = createMouseClickStrategy(this.element, clickOptions.caretPos);
Expand Down
4 changes: 2 additions & 2 deletions src/client/automation/playback/hover.js
Original file line number Diff line number Diff line change
Expand Up @@ -3,8 +3,8 @@ import cursor from '../cursor';


export default class HoverAutomation extends VisibleElementAutomation {
constructor (element, hoverOptions, dispatchProxylessEventFn, leftTopPoint) {
super(element, hoverOptions, window, cursor, dispatchProxylessEventFn, leftTopPoint);
constructor (element, hoverOptions, dispatchProxylessEventFn) {
super(element, hoverOptions, window, cursor, dispatchProxylessEventFn);
}

run (useStrictElementCheck) {
Expand Down
4 changes: 2 additions & 2 deletions src/client/automation/types.d.ts
Original file line number Diff line number Diff line change
@@ -1,10 +1,10 @@
import { ActionCommandBase } from '../../test-run/commands/base';
import EventEmitter from '../core/utils/event-emitter';
import AxisValues, { AxisValuesData } from '../core/utils/values/axis-values';
import { AxisValuesData } from '../core/utils/values/axis-values';
import { DispatchEventFn } from '../../proxyless/client/types';

export interface AutomationHandler {
create: (cmd: ActionCommandBase, elements: any[], dispatchProxylessEventFn?: DispatchEventFn, leftTopPoint?: AxisValues<number>) => Automation;
create: (cmd: ActionCommandBase, elements: any[], dispatchProxylessEventFn?: DispatchEventFn) => Automation;
ensureElsProps?: (elements: any[]) => void;
ensureCmdArgs?: (cmd: ActionCommandBase) => void;
additionalSelectorProps?: string[];
Expand Down
4 changes: 2 additions & 2 deletions src/client/automation/visible-element-automation.ts
Original file line number Diff line number Diff line change
Expand Up @@ -101,7 +101,7 @@ export default class VisibleElementAutomation extends SharedEventEmitter {
protected readonly options: OffsetOptions;
protected readonly proxylessInput: ProxylessInput | null;

protected constructor (element: HTMLElement, offsetOptions: OffsetOptions, win: Window, cursor: Cursor, dispatchProxylessEventFn?: DispatchEventFn, topLeftPoint?: AxisValues<number>) {
protected constructor (element: HTMLElement, offsetOptions: OffsetOptions, win: Window, cursor: Cursor, dispatchProxylessEventFn?: DispatchEventFn) {
super();

this.TARGET_ELEMENT_FOUND_EVENT = 'automation|target-element-found-event';
Expand All @@ -114,7 +114,7 @@ export default class VisibleElementAutomation extends SharedEventEmitter {
this.window = win;
this.cursor = cursor;

this.proxylessInput = dispatchProxylessEventFn ? new ProxylessInput(dispatchProxylessEventFn, topLeftPoint) : null;
this.proxylessInput = dispatchProxylessEventFn ? new ProxylessInput(dispatchProxylessEventFn) : null;

// NOTE: only for legacy API
this._ensureWindowAndCursorForLegacyTests(this);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -39,7 +39,6 @@ import {
import COMMAND_TYPE from '../../../../test-run/commands/type';
import { ActionCommandBase } from '../../../../test-run/commands/base';
import { Automation } from '../../../automation/types';
import AxisValues from '../../../core/utils/values/axis-values';
import { DispatchEventFn } from '../../../../proxyless/client/types';


Expand All @@ -66,11 +65,11 @@ ActionExecutor.ACTIONS_HANDLERS[COMMAND_TYPE.pressKey] = {
};

ActionExecutor.ACTIONS_HANDLERS[COMMAND_TYPE.click] = {
create: (command, elements, dispatchProxylessEventFn?: DispatchEventFn, leftTopPoint?: AxisValues<number>) => {
create: (command, elements, dispatchProxylessEventFn?: DispatchEventFn) => {
if (/option|optgroup/.test(domUtils.getTagName(elements[0])))
return new SelectChildClickAutomation(elements[0], command.options);

return new ClickAutomation(elements[0], command.options, window, cursor, dispatchProxylessEventFn, leftTopPoint);
return new ClickAutomation(elements[0], command.options, window, cursor, dispatchProxylessEventFn);
},
};

Expand All @@ -83,8 +82,8 @@ ActionExecutor.ACTIONS_HANDLERS[COMMAND_TYPE.doubleClick] = {
};

ActionExecutor.ACTIONS_HANDLERS[COMMAND_TYPE.hover] = {
create: (command, elements, dispatchProxylessEventFn?: DispatchEventFn, leftTopPoint?: AxisValues<number>) => {
return new HoverAutomation(elements[0], command.options, dispatchProxylessEventFn, leftTopPoint);
create: (command, elements, dispatchProxylessEventFn?: DispatchEventFn) => {
return new HoverAutomation(elements[0], command.options, dispatchProxylessEventFn);
},
};

Expand Down
4 changes: 1 addition & 3 deletions src/client/driver/command-executors/action-executor/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,6 @@ import { Automation, AutomationHandler } from '../../../automation/types';
import { nativeMethods, Promise } from '../../deps/hammerhead';
import { getOffsetOptions } from '../../../core/utils/offsets';
import { TEST_RUN_ERRORS } from '../../../../errors/types';
import AxisValues from '../../../core/utils/values/axis-values';
import { DispatchEventFn } from '../../../../proxyless/client/types';

const MAX_DELAY_AFTER_EXECUTION = 2000;
Expand All @@ -22,7 +21,6 @@ interface ActionExecutorOptions {
testSpeed: number;
executeSelectorFn: ExecuteSelectorFn<HTMLElement>;
dispatchProxylessEventFn: DispatchEventFn;
leftTopPoint: AxisValues<number>;
}

export default class ActionExecutor extends EventEmitter {
Expand Down Expand Up @@ -140,7 +138,7 @@ export default class ActionExecutor extends EventEmitter {
if (!handler)
throw new Error(`There is no handler for the "${this._command.type}" command.`);

return handler.create(this._command, this._elements, this._options.dispatchProxylessEventFn, this._options.leftTopPoint);
return handler.create(this._command, this._elements, this._options.dispatchProxylessEventFn);
}

private _runAction (strictElementCheck: boolean): Promise<void> {
Expand Down
27 changes: 2 additions & 25 deletions src/client/driver/driver-link/iframe/child.js
Original file line number Diff line number Diff line change
Expand Up @@ -27,8 +27,6 @@ import {
} from '../timeouts';

import sendConfirmationMessage from '../send-confirmation-message';
import { getBordersWidthFloat, getElementPaddingFloat } from '../../../core/utils/style';


export default class ChildIframeDriverLink {
constructor (driverWindow, driverId, dispatchProxylessEventUrls) {
Expand Down Expand Up @@ -92,20 +90,6 @@ export default class ChildIframeDriverLink {
});
}

_getLeftTopPoint (proxyless) {
if (!proxyless)
return null;

const rect = this.driverIframe.getBoundingClientRect();
const borders = getBordersWidthFloat(this.driverIframe);
const paddings = getElementPaddingFloat(this.driverIframe);

return {
x: rect.left + borders.left + paddings.left,
y: rect.top + borders.top + paddings.top,
};
}

sendConfirmationMessage (requestMsgId) {
sendConfirmationMessage({
requestMsgId,
Expand All @@ -114,20 +98,13 @@ export default class ChildIframeDriverLink {
});
}

executeCommand (command, testSpeed, proxyless, leftTopPoint) {
executeCommand (command, testSpeed) {
// NOTE: We should check if the iframe is visible and exists before executing the next
// command, because the iframe might be hidden or removed since the previous command.
return this
._ensureIframe()
.then(() => {
const currentLeftTopPoint = this._getLeftTopPoint(proxyless);

if (leftTopPoint) {
currentLeftTopPoint.x += leftTopPoint.x;
currentLeftTopPoint.y += leftTopPoint.y;
}

const msg = new ExecuteCommandMessage(command, testSpeed, currentLeftTopPoint);
const msg = new ExecuteCommandMessage(command, testSpeed);

return Promise.all([
sendMessageToDriver(msg, this.driverWindow, this.iframeAvailabilityTimeout, CurrentIframeIsNotLoadedError),
Expand Down
7 changes: 3 additions & 4 deletions src/client/driver/driver-link/messages.js
Original file line number Diff line number Diff line change
Expand Up @@ -84,12 +84,11 @@ export class CommandExecutedMessage extends InterDriverMessage {
}

export class ExecuteCommandMessage extends InterDriverMessage {
constructor (command, testSpeed, leftTopPoint) {
constructor (command, testSpeed) {
super(TYPE.executeCommand);

this.command = command;
this.testSpeed = testSpeed;
this.leftTopPoint = leftTopPoint;
this.command = command;
this.testSpeed = testSpeed;
}
}

Expand Down
3 changes: 1 addition & 2 deletions src/client/driver/driver.js
Original file line number Diff line number Diff line change
Expand Up @@ -941,7 +941,7 @@ export default class Driver extends serviceUtils.EventEmitter {
.then(() => {
this.contextStorage.setItem(this.EXECUTING_IN_IFRAME_FLAG, true);

return this.activeChildIframeDriverLink.executeCommand(command, this.speed, this.options.proxyless, this.leftTopPoint);
return this.activeChildIframeDriverLink.executeCommand(command, this.speed, this.options.proxyless);
})
.then(status => this._onCommandExecutedInIframe(status))
.catch(err => this._onCommandExecutedInIframe(new DriverStatus({
Expand Down Expand Up @@ -1194,7 +1194,6 @@ export default class Driver extends serviceUtils.EventEmitter {
globalSelectorTimeout: this.options.selectorTimeout,
testSpeed: this.speed,
executeSelectorFn: executeSelectorCb,
leftTopPoint: this.leftTopPoint,
dispatchProxylessEventFn: this.createDispatchProxylessEventFunctions(),
});

Expand Down
6 changes: 1 addition & 5 deletions src/client/driver/iframe-driver.js
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,6 @@ import {
StopInternalFromFrameMessage,
TYPE as MESSAGE_TYPE,
} from './driver-link/messages';
import AxisValues from '../core/utils/values/axis-values';

const messageSandbox = eventSandbox.message;

Expand All @@ -29,8 +28,6 @@ export default class IframeDriver extends Driver {
this.parentDriverLink = new ParentIframeDriverLink(window.parent);

this._initParentDriverListening();

this.leftTopPoint = new AxisValues(0, 0);
}

// Errors handling
Expand Down Expand Up @@ -70,8 +67,7 @@ export default class IframeDriver extends Driver {
this.lastParentDriverMessageId = msg.id;

this.readyPromise.then(() => {
this.speed = msg.testSpeed;
this.leftTopPoint = msg.leftTopPoint;
this.speed = msg.testSpeed;

this.parentDriverLink.sendConfirmationMessage(msg.id);
this._onCommand(msg.command);
Expand Down
67 changes: 62 additions & 5 deletions src/proxyless/client/event-descriptor.ts
Original file line number Diff line number Diff line change
@@ -1,15 +1,70 @@
import { EventType } from '../types';
import { SimulatedKeyInfo } from './key-press/utils';
// @ts-ignore
import { utils } from '../../client/core/deps/hammerhead';
import { utils, eventSandbox } from '../../client/core/deps/hammerhead';
import { calculateKeyModifiersValue, calculateMouseButtonValue } from './utils';
import AxisValues from '../../client/core/utils/values/axis-values';
import { AxisValuesData } from '../../client/core/utils/values/axis-values';
import sendRequestToFrame from '../../client/core/utils/send-request-to-frame';
import { findIframeByWindow } from '../../client/core/utils/dom';
import { getBordersWidthFloat, getElementPaddingFloat } from '../../client/core/utils/style';

const messageSandbox = eventSandbox.message;

const MOUSE_EVENT_OPTIONS = {
clickCount: 1,
button: 'left',
};

const CALCULATE_TOP_LEFT_POINT_REQUEST_CMD = 'proxyless|calculate-top-left-point|request';
const CALCULATE_TOP_LEFT_POINT_RESPONSE_CMD = 'proxyless|calculate-top-left-point|response';

function getLeftTopPoint (driverIframe: any): AxisValuesData<number> {
const rect = driverIframe.getBoundingClientRect();
const borders = getBordersWidthFloat(driverIframe);
const paddings = getElementPaddingFloat(driverIframe);

return {
x: rect.left + borders.left + paddings.left,
y: rect.top + borders.top + paddings.top,
};
}

// Setup cross-iframe interaction
messageSandbox.on(messageSandbox.SERVICE_MSG_RECEIVED_EVENT, async (e:any) => {
if (e.message.cmd === CALCULATE_TOP_LEFT_POINT_REQUEST_CMD) {
const iframeWin = e.source;

const { x, y } = await calculateIFrameTopLeftPoint();

const iframe = findIframeByWindow(iframeWin);
const topLeftPoint = getLeftTopPoint(iframe);

const responseMsg = {
cmd: CALCULATE_TOP_LEFT_POINT_RESPONSE_CMD,
topLeftPoint: {
x: topLeftPoint.x + x,
y: topLeftPoint.y + y,
},
};

messageSandbox.sendServiceMsg(responseMsg, iframeWin);
}
});

async function calculateIFrameTopLeftPoint (): Promise<AxisValuesData<number>> {
if (window !== window.parent) {
const msg: any = {
cmd: CALCULATE_TOP_LEFT_POINT_REQUEST_CMD,
};

const { topLeftPoint } = await sendRequestToFrame(msg, CALCULATE_TOP_LEFT_POINT_RESPONSE_CMD, window.parent);

return topLeftPoint;
}

return { x: 0, y: 0 };
}

export default class CDPEventDescriptor {
private static _getKeyDownEventText (options: SimulatedKeyInfo): any {
if (options.isNewLine)
Expand Down Expand Up @@ -42,10 +97,12 @@ export default class CDPEventDescriptor {
};
}

public static createMouseEventOptions (type: string, options: any, leftTopPoint: AxisValues<number>): any {
public static async createMouseEventOptions (type: string, options: any): Promise<any> {
const { x, y } = await calculateIFrameTopLeftPoint();

return utils.extend({
x: options.options.clientX + leftTopPoint.x,
y: options.options.clientY + leftTopPoint.y,
x: options.options.clientX + x,
y: options.options.clientY + y,
modifiers: calculateKeyModifiersValue(options.options),
button: calculateMouseButtonValue(options.options),
type,
Expand Down
22 changes: 9 additions & 13 deletions src/proxyless/client/input.ts
Original file line number Diff line number Diff line change
@@ -1,26 +1,23 @@
import { EventType } from '../types';
import AxisValues, { AxisValuesData } from '../../client/core/utils/values/axis-values';
import { AxisValuesData } from '../../client/core/utils/values/axis-values';
import { SimulatedKeyInfo } from './key-press/utils';
import { DispatchEventFn } from './types';
import CDPEventDescriptor from './event-descriptor';

export default class ProxylessInput {

private readonly _dispatchEventFn: DispatchEventFn;
private readonly _leftTopPoint: AxisValues<number>;
constructor (dispatchEventFn: DispatchEventFn, leftTopPoint?: AxisValues<number>) {
constructor (dispatchEventFn: DispatchEventFn) {
this._dispatchEventFn = dispatchEventFn;
this._leftTopPoint = leftTopPoint || new AxisValues<number>(0, 0);
}

public mouseDown (options: any): Promise<void> {
const eventOptions = CDPEventDescriptor.createMouseEventOptions('mousePressed', options, this._leftTopPoint);
public async mouseDown (options: any): Promise<void> {
const eventOptions = await CDPEventDescriptor.createMouseEventOptions('mousePressed', options);

return this._dispatchEventFn.single(EventType.Mouse, eventOptions);
}

public mouseUp (options: any): Promise<void> {
const eventOptions = CDPEventDescriptor.createMouseEventOptions('mouseReleased', options, this._leftTopPoint);
public async mouseUp (options: any): Promise<void> {
const eventOptions = await CDPEventDescriptor.createMouseEventOptions('mouseReleased', options);

return this._dispatchEventFn.single(EventType.Mouse, eventOptions);
}
Expand All @@ -40,15 +37,14 @@ export default class ProxylessInput {
return this._dispatchEventFn.sequence(eventSequence);
}

public createMouseMoveEvent (currPosition: AxisValuesData<number>): any {
const options = CDPEventDescriptor.createMouseEventOptions('mouseMoved', {
public async createMouseMoveEvent (currPosition: AxisValuesData<number>): Promise<any> {
const options = await CDPEventDescriptor.createMouseEventOptions('mouseMoved', {
options: {
clientX: currPosition.x,
clientY: currPosition.y,
button: 'none',
},
// @ts-ignore
}, this._leftTopPoint);
});

return {
type: EventType.Mouse,
Expand Down
Loading