Skip to content

Commit f3dc828

Browse files
twalpolebarancev
authored andcommitted
Check element corners and middle for clickability
Signed-off-by: Alexei Barantsev <[email protected]>
1 parent 918be03 commit f3dc828

File tree

3 files changed

+77
-17
lines changed

3 files changed

+77
-17
lines changed

common/src/web/click_tests/overlapping_elements.html

Lines changed: 15 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -5,17 +5,27 @@
55
<style>
66
#under {
77
position: absolute;
8-
top: 20;
9-
left: 20;
8+
top: 20px;
9+
left: 20px;
1010
width: 100px;
1111
height: 100px;
1212
background-color: white;
1313
}
1414

15+
#partially_under {
16+
position: absolute;
17+
top: 20px;
18+
left: 10px;
19+
width: 100px;
20+
height: 100px;
21+
background-color: blue;
22+
opacity: 0.5;
23+
}
24+
1525
#over {
1626
position: absolute;
17-
top: 20;
18-
left: 20;
27+
top: 20px;
28+
left: 20px;
1929
width: 100px;
2030
height: 100px;
2131
background-color: red;
@@ -30,6 +40,7 @@
3040
</head>
3141
<body id="body">
3242
<div id="under"><p id="contents">Hello</p></div>
43+
<div id="partially_under"><p id="other_contents">Hello</p></div>
3344
<div id="over"></div>
3445
<div id="log">
3546
<p>Log:<p>

javascript/firefox-driver/js/utils.js

Lines changed: 55 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -683,23 +683,65 @@ Utils.getClickablePoint = function(element) {
683683
element = element.wrappedJSObject ? element.wrappedJSObject : element;
684684
var rect = bot.dom.getClientRect(element);
685685

686-
if (element.getClientRects().length > 1) {
687-
for (var i = 0; i < element.getClientRects().length; i++) {
688-
var candidate = element.getClientRects()[i];
689-
if (candidate.width != 0 && candidate.height != 0) {
690-
return {
691-
x: (candidate.left - rect.left + Math.floor(candidate.width / 2)),
692-
y: (candidate.top - rect.top + Math.floor(candidate.height / 2))
693-
};
686+
var rects = goog.array.filter(element.getClientRects(), function(r) {
687+
return r.width !=0 && r.height != 0;
688+
});
689+
690+
if (rects.length > 0) {
691+
for (var i = 0; i < rects.length; i++) {
692+
var candidate = rects[i];
693+
if (clickable_point = findClickablePoint(candidate)){
694+
return clickable_point;
694695
}
695696
}
697+
rect = rects[0];
696698
}
697699

698-
// Fallback to the main rect
699-
return {
700-
x: (rect.width ? Math.floor(rect.width / 2) : 0),
701-
y: (rect.height ? Math.floor(rect.height / 2) : 0)
702-
};
700+
// Fallback to the main rect - expected to return a point so if no clickable point return middle
701+
return findClickablePoint(rect) || { x: Math.floor(rect.width/2), y: Math.floor(rect.height/2) };
702+
703+
function findClickablePoint(rect){
704+
var offsets = [
705+
{ x: Math.floor(rect.width/2), y: Math.floor(rect.height/2) },
706+
{ x: 0, y: 0 },
707+
{ x: rect.width, y: 0 },
708+
{ x: 0, y: rect.height },
709+
{ x: rect.width, y: rect.height}
710+
]
711+
712+
return goog.array.find(offsets, function(offset){
713+
return isClickableAt( { x: rect.left + offset.x, y: rect.top + offset.y } );
714+
})
715+
}
716+
717+
function isClickableAt(coord) {
718+
// get the outermost ancestor of the element. This will be either the document
719+
// or a shadow root.
720+
var owner = element;
721+
while (owner.parentNode) {
722+
owner = owner.parentNode;
723+
}
724+
725+
var elementAtPoint = owner.elementFromPoint(coord.x, coord.y);
726+
727+
// element may be huge, so coordinates are outside the viewport
728+
if (elementAtPoint === null) {
729+
return true;
730+
}
731+
732+
if (element == elementAtPoint) {
733+
return true;
734+
}
735+
736+
// allow clicks to element descendants
737+
var parentElemIter = elementAtPoint.parentNode;
738+
while (parentElemIter) {
739+
if (parentElemIter == element) {
740+
return true;
741+
}
742+
parentElemIter = parentElemIter.parentNode;
743+
}
744+
}
703745
};
704746

705747

rb/spec/integration/selenium/webdriver/element_spec.rb

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -40,6 +40,13 @@
4040
end
4141
end
4242

43+
compliant_on :browser => [:firefox] do
44+
it "should not raise if element is only partially covered" do
45+
driver.navigate.to url_for("click_tests/overlapping_elements.html")
46+
expect { driver.find_element(:id, "other_contents").click }.not_to raise_error
47+
end
48+
end
49+
4350
# Marionette BUG - AutomatedTester: "known bug with execute script"
4451
not_compliant_on :browser => :marionette do
4552
it "should submit" do

0 commit comments

Comments
 (0)