Skip to content

Commit

Permalink
Should find element with not-integer offset (closes DevExpress#2080)
Browse files Browse the repository at this point in the history
  • Loading branch information
AlexKamaev committed Aug 22, 2018
1 parent 5522e04 commit ef5c8b6
Show file tree
Hide file tree
Showing 5 changed files with 128 additions and 23 deletions.
40 changes: 21 additions & 19 deletions src/client/automation/playback/visible-element-automation.js
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,8 @@ import ScrollAutomation from './scroll';
import MoveAutomation from './move';
import { MoveOptions, ScrollOptions } from '../../../test-run/commands/options';

var extend = hammerhead.utils.extend;
const extend = hammerhead.utils.extend;
const browserUtils = hammerhead.utils.browser;

class ElementState {
constructor ({ element = null, clientPoint = null, screenPoint = null, isTarget = false, inMoving = false }) {
Expand All @@ -35,66 +36,67 @@ export default class VisibleElementAutomation extends serviceUtils.EventEmitter
}

_getElementForEvent (eventArgs) {
var { x, y } = eventArgs.point;
var expectedElement = positionUtils.containsOffset(this.element, this.options.offsetX, this.options.offsetY) ? this.element : null;
const { x, y } = eventArgs.point;
const expectedElement = positionUtils.containsOffset(this.element, this.options.offsetX, this.options.offsetY) ? this.element : null;

return getElementFromPoint(x, y, expectedElement).then(({ element }) => element);
}

_moveToElement () {
var moveOptions = new MoveOptions(extend({ skipScrolling: true }, this.options), false);
var moveAutomation = new MoveAutomation(this.element, moveOptions);
const moveOptions = new MoveOptions(extend({ skipScrolling: true }, this.options), false);
const moveAutomation = new MoveAutomation(this.element, moveOptions);

return moveAutomation
.run()
.then(() => delay(this.automationSettings.mouseActionStepDelay));
}

_scrollToElement () {
var scrollAutomation = new ScrollAutomation(this.element, new ScrollOptions(this.options));
const scrollAutomation = new ScrollAutomation(this.element, new ScrollOptions(this.options));

return scrollAutomation
.run()
.then(() => delay(this.automationSettings.mouseActionStepDelay));
}

_wrapAction (action) {
var offsetX = this.options.offsetX;
var offsetY = this.options.offsetY;
var screenPointBeforeAction = getAutomationPoint(this.element, offsetX, offsetY);
var clientPositionBeforeAction = positionUtils.getClientPosition(this.element);
const roundFn = browserUtils.isFirefox ? Math.ceil : Math.round;
const offsetX = this.options.offsetX;
const offsetY = this.options.offsetY;
const screenPointBeforeAction = getAutomationPoint(this.element, offsetX, offsetY, roundFn);
const clientPositionBeforeAction = positionUtils.getClientPosition(this.element);

return action()
.then(() => {
var screenPointAfterAction = getAutomationPoint(this.element, offsetX, offsetY);
var clientPositionAfterAction = positionUtils.getClientPosition(this.element);
var clientPoint = screenPointToClient(this.element, screenPointAfterAction);
var expectedElement = positionUtils.containsOffset(this.element, offsetX, offsetY) ? this.element : null;
const screenPointAfterAction = getAutomationPoint(this.element, offsetX, offsetY, roundFn);
const clientPositionAfterAction = positionUtils.getClientPosition(this.element);
const clientPoint = screenPointToClient(this.element, screenPointAfterAction);
const expectedElement = positionUtils.containsOffset(this.element, offsetX, offsetY) ? this.element : null;

return getElementFromPoint(clientPoint.x, clientPoint.y, expectedElement)
.then(({ element, corrected }) => {
var foundElement = element;
const foundElement = element;

if (!foundElement)
return new ElementState({});

var isTarget = !expectedElement || corrected || foundElement === this.element;
let isTarget = !expectedElement || corrected || foundElement === this.element;

if (!isTarget) {
// NOTE: perform an operation with searching in dom only if necessary
isTarget = arrayUtils.indexOf(domUtils.getParents(foundElement), this.element) > -1;
}

var offsetPositionChanged = screenPointBeforeAction.x !== screenPointAfterAction.x ||
const offsetPositionChanged = screenPointBeforeAction.x !== screenPointAfterAction.x ||
screenPointBeforeAction.y !== screenPointAfterAction.y;
var clientPositionChanged = clientPositionBeforeAction.x !== clientPositionAfterAction.x ||
const clientPositionChanged = clientPositionBeforeAction.x !== clientPositionAfterAction.x ||
clientPositionBeforeAction.y !== clientPositionAfterAction.y;

// NOTE: We consider the element moved if its offset position and client position
// are changed both. If only client position was changed it means the page was
// scrolled and the element keeps its position on the page. If only offset position was
// changed it means the element is fixed on the page (it can be implemented via script).
var targetElementIsMoving = offsetPositionChanged && clientPositionChanged;
const targetElementIsMoving = offsetPositionChanged && clientPositionChanged;

return new ElementState({
element,
Expand Down
8 changes: 4 additions & 4 deletions src/client/automation/utils/get-automation-point.js
Original file line number Diff line number Diff line change
@@ -1,9 +1,9 @@
import { positionUtils } from '../deps/testcafe-core';

export default function getAutomationPoint (element, offsetX, offsetY) {
var elementOffset = positionUtils.getOffsetPosition(element);
var left = element === document.documentElement ? 0 : elementOffset.left;
var top = element === document.documentElement ? 0 : elementOffset.top;
export default function getAutomationPoint (element, offsetX, offsetY, roundFn) {
const elementOffset = positionUtils.getOffsetPosition(element, roundFn);
const left = element === document.documentElement ? 0 : elementOffset.left;
const top = element === document.documentElement ? 0 : elementOffset.top;

return {
x: left + offsetX,
Expand Down
83 changes: 83 additions & 0 deletions test/functional/fixtures/regression/gh-2080/pages/index.html
Original file line number Diff line number Diff line change
@@ -0,0 +1,83 @@
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Title</title>
<style>
#parent {
width: 100px;
height: 100px;
background-color: red;
margin: 100px;
position: relative;
}

.child {
width: 10px;
height: 10px;
background-color: blue;
position: absolute;
}

#child1 {
top: 5.1px;
left: 5.1px;
}

#child2 {
top: 25.3px;
left: 25.3px;
}

#child3 {
top: 45.5px;
left: 45.5px;
}

#child4 {
top: 65.7px;
left: 65.7px;
}

.leaf {
width: 1px;
height: 1px;
background-color: white;
position: absolute;
top: 0;
left: 0;
}
</style>
</head>
<body>
<div id="parent">
<div id="child1" class="child">
<div id="leaf1" class="leaf"></div>
</div>

<div id="child2" class="child">
<div id="leaf2" class="leaf"></div>
</div>

<div id="child3" class="child">
<div id="leaf3" class="leaf"></div>
</div>

<div id="child4" class="child">
<div id="leaf4" class="leaf"></div>
</div>
</div>

<div id="result"></div>
<script>
function log(e) {
document.querySelector('#result').innerHTML += e.currentTarget.id + ' ';
}

var divs = document.querySelectorAll('div');

for (var i = 0; i < divs.length; i++)
divs[i].addEventListener('click', log);
</script>
</body>
</html>
5 changes: 5 additions & 0 deletions test/functional/fixtures/regression/gh-2080/test.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
describe('[Regression](GH-2080)', function () {
it('Should find element with not-integer offset', function () {
return runTests('testcafe-fixtures/index.js');
});
});
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
import { Selector } from 'testcafe';

fixture `GH-2080 - Should find element with not-integer offset`
.page `http://localhost:3000/fixtures/regression/gh-2080/pages/index.html`;

const result = Selector('#result');

test('Click on elements with not-integer offsets', async t => {
await t
.click('#child1', { offsetX: 0, offsetY: 0 })
.click('#child2', { offsetX: 0, offsetY: 0 })
.click('#child3', { offsetX: 0, offsetY: 0 })
.click('#child4', { offsetX: 0, offsetY: 0 })
.expect(result.innerText).contains('leaf1 child1 parent leaf2 child2 parent leaf3 child3 parent leaf4 child4 parent');
});

0 comments on commit ef5c8b6

Please sign in to comment.