element.webkitMatchesSelector in phantomjs does not report ":focus" accurately
ryangreenberg opened this issue ยท 64 comments
ryangree...@gmail.com commented:
Which version of PhantomJS are you using? 1.4.1
What steps will reproduce the problem?
- Run the provided test script with the test HTML (below).
What is the expected output? What do you see instead?
I expect :focus to be true after triggering a focus event on an element. Instead it is false.Which operating system are you using? OS X 10.7.3
Did you use binary PhantomJS or did you compile it from source? Compiled.
Here is the output of my test script in Chrome, Safari, and PhantomJS:
Chrome
navigator.userAgent: Mozilla/5.0 (Macintosh; Intel Mac OS X 10_7_3) AppleWebKit/535.19 (KHTML, like Gecko) Chrome/18.0.1025.54 Safari/535.19
$('#some-input').is(':focus'): true
$input[0].webkitMatchesSelector(':focus'): true
$input[0] == document.activeElement: trueSafari
navigator.userAgent: Mozilla/5.0 (Macintosh; Intel Mac OS X 10_7_3) AppleWebKit/534.54.16 (KHTML, like Gecko) Version/5.1.4 Safari/534.54.16
$('#some-input').is(':focus'): true
$input[0].webkitMatchesSelector(':focus'): true
$input[0] == document.activeElement: truePhantomJS 1.4.1
navigator.userAgent: Mozilla/5.0 (Macintosh; PPC Mac OS X) AppleWebKit/534.34 (KHTML, like Gecko) PhantomJS/1.4.1 Safari/534.34
$('#some-input').is(':focus'): false
$input[0].webkitMatchesSelector(':focus'): false
$input[0] == document.activeElement: trueTest HTML
<!DOCTYPE html>
<html>
<head>
<title>:focus check</title>
<script src="http://code.jquery.com/jquery.js"></script>
<script>
$(function(){
console.log("navigator.userAgent: " + navigator.userAgent);// Simple case $input = $('#some-input'); $input.focus(); console.log("$('#some-input').is(':focus'): " + $('#some-input').is(':focus')); // Similar case $input.focus(); console.log("$input[0].webkitMatchesSelector(':focus'): " + $input[0].webkitMatchesSelector(':focus')); // When a native matchesSelector isn't available, jQuery uses: // // focus: function( elem ) { // return elem === elem.ownerDocument.activeElement; // } // // The input == document.activeElement, which suggests that the bug is in webkitMatchesSelector console.log("$input[0] == document.activeElement: " + ($input[0] == document.activeElement));
});
</script>
</head>
<body>
<form>
<input id="some-input">
</form>
</body>
</html>Test script:
var page = require('webpage').create();
page.onConsoleMessage = function(msg) { console.log(msg); };page.open('file:///' + phantom.libraryPath + '/focus_test.html', function (status) {
if (status !== 'success') {
console.log('Could not open URL');
}
phantom.exit();
});
Disclaimer:
This issue was migrated on 2013-03-15 from the project's former issue tracker on Google Code, Issue #427.
๐ 16 people had starred this issue at the time of migration.
ste...@brandwatch.com commented:
I can confirm this is an issue in 1.4.1, also in 1.5.0 as well
I'm working around by using "elem === elem.ownerDocument.activeElement" instead, but it's not pretty.
Seems to work fine in Chrome 17 and Safari 5.1.5 - I'm not sure if these are using more recent versions of webkit though
cur...@ram9.cc commented:
Please fix :D
philfreo@gmail.com commented:
Please fix!
philfreo@gmail.com commented:
// Patch $el.is(':focus') until PhantomJS supports it properly.
// https://code.google.com/p/phantomjs/issues/detail?id=427
var _jQuery_is = jQuery.fn.is;
jQuery.fn.is = function(s) {
if (s === ':focus') {
return this.get(0) === document.activeElement;
}
return _jQuery_is.apply(this, arguments);
};This workaround may help some (put this in your test runner code)
+1
+1
+1
+1
๐
Since this bug specifically mentions jQuery, I'll note that jQuery added a workaround for this WebKit bug in jQuery core 1.8.2: http://bugs.jquery.com/ticket/12492
Though this has been fixed in jQuery, I'm using Poltergeist (a PhantomJS driver for Capybara, which is a browser testing driver for Ruby) for a lot of integration testing. I'd like to be able to test whether an element has focus and it seems like the natural way to do that would be to use the :focus
selector. It would be great if this was fixed.
I'd also guess the cause of this is the same as #11432.
+1
+1
+1
+1
+1
If I want to get currently focused element, I have to mock implementation framework which is not a part of BDD principles. The same downside exists in HTMLUnit also.
+1
+1
Please fix it!
+1
+1
+1
Any progress on fixing this bug?
+1
Would be nice to test accessibly features but no can do without a :focus element or document.activeElement
+1
+1
+1
Still broken as of 1.9.8
+1
+1
Still broken in 1.9.8 :(
+1
+1
+1
+1
+1
+1
+1
This appears still to be an issue in 2.0, using the test case from the original report:
$ ./bin/phantomjs focus_test.js
navigator.userAgent: Mozilla/5.0 (Unknown; Linux x86_64) AppleWebKit/538.1 (KHTML, like Gecko) PhantomJS/2.0.0 (development) Safari/538.1
$('#some-input').is(':focus'): false
$input[0].webkitMatchesSelector(':focus'): false
$input[0] == document.activeElement: true
I presume the expectation is for all three test cases to report 'true'.
This is almost certainly a Webkit bug. Can anyone reproduce it in Safari, Chrome, or the web browser formerly known as Epiphany?
@zackw Interestingly I get the same/similar bugs when and only when using livereload. If I manually start the tests in Chrome they pass, but if they are started by a livereload as I change files they fail.
+1
+1
Just to say, I am still having this issue.
I have solved it by doing what has been said above;
assertEqual(true, element === document.activeElement);
+1
As @zackw pointed out, this bug is still present in PhantomJS 2.0. It is not merely an issue with the pseudo selector :focus
accessed through jQuery, but the page renders incorrectly, if any styles depend on :focus
(as documented by #11432). That means that it's impossible to use PhantomJS for testing pages that contain any logic that's dependent on focussed elements.
Here are two screenshots that demonstrate the issue:
Chrome
PhantomJS 2.0
Here's the protractor snippet used for these screenshots:
browser.get('http://s.codepen.io/rh/debug/epbQRm');
browser.driver.switchTo().activeElement().sendKeys('focus is here...');
return browser.takeScreenshot().then(...)
The content in the input proofs that the focus really is there in both cases.
I agree with @renehamburger. I don't see any workaround for testing styling.
And this is only a problem in phantomjs, not in Chrome. So it doesn't look like a webkit-problem.
+1
I agree with @renehamburger & @myplacedk. I don't see any workaround for testing styling.
I think the problem here is that in Webkit, the :focus
selector only matches elements if the document itself has focus--that is, if document.hasFocus()
returns true. You can test this yourself in Chrome:
setTimeout(
function(){
var e = document.createEvent('Event');
e.initEvent("focus", true, true);
document.getElementById('id-of-some-focusable-element').dispatchEvent(e);
console.log(document.querySelectorAll(':focus'));
},
2000
);
If you run this from the Chrome dev tools console, you'll see an empty array returned two seconds later. However, if you run it and then click inside the document within two seconds, the log will spit out the expected element.
While researching this, I found a jQuery patch from a few years ago made when someone using Selenium ran into the same issue; unfortunately that patch doesn't work for the current jQuery version but it pointed me in this direction.
So it would seem that the only fix would be to patch the Webkit that PhantomJS is using to not expect the document to be focused when querying :focus
, or to allow some way to "focus" the document in PhantomJS so that document.hasFocus()
returns true
.
+1
Good investigation @sgress454 ๐
It would be great to see this finally fixed!
+1
+1
+1
+1
Another possible patch (rude)
// it's for casperjs, but I think you will catch the idea
this.evaluate(function() { document.hasFocus = function() { return true } })
+1
@garex I tried something like that at one point without much luck -- I don't think the :focus
selector just relies on document.hasFocus()
returning true, but rather that whatever underlying conditions cause hasFocus()
to return true must be met in order for the :focus
selector to work.
+1
I experimented with this a bit using a 2.1 branch (master crashes for me).
First I tried to fix it in PhantomJS itself, but calling QWebFrame::setFocus()
on m_currentFrame
or any other frame in webpage.cpp does not have any effect.
Next I looked into WebKit sources, the :focus
pseudo class is checked here. SelectorChecker::matchesFocusPseudoClass
function calls SelectorChecker::isFrameFocused
which in turn calls FrameSelection::isFocusedAndActive. Changing FrameSelection::isFocusedAndActive
to always return true
fixes this issue although it feels like a hack, I don't know what a proper solution here would be.
P.S. I suggest owner of this repo to remove all junk +1 comments and block their authors.
Can someone check it with recently released 2.5 beta version? Thanks!
+1
@vitallium Where can I download a version of 2.5 that will work with Selenium/Nightwatch.js? What I downloaded from https://bitbucket.org/ariya/phantomjs/downloads/ wasn't recognized by Selenium.
+1
+1
+1
Due to our very limited maintenance capacity (see #14541 for more details), we need to prioritize our development focus on other tasks. Therefore, this issue will be automatically closed. In the future, if we see the need to attend to this issue again, then it will be reopened. Thank you for your contribution!