Closed bavaria95 closed 6 years ago
Setting marionette
capability as a pytest argument (to empty string, due to the fact that it considers all passed arguments as strings and python will consider empty string as False) helped me:
--capability marionette ''
This was in fact a bug before, as the default has been to use Marionette since Selenium 3 was released, and meant that you would have inconsistent behaviour between local browsers and those running against a remote server. To use the plugin against old Firefox versions with the legacy driver, you can either set the marionette
capability to an empty string on the command line, which evaluates as Falsy (as you have), or you can set it to False using the capabilities
fixture:
@pytest.fixture
def capabilities(capabilities):
capabilities['marionette'] = False
return capabilities
My recommendation would be to run your tests against a modern version of Firefox, which requires the geckodriver binary to be available in your path. There's some documentation on this here.
@davehunt Selenium is running as a separate docker container, thus it's remote)
@bavaria95 then it would depend on the version of Selenium running. Marionette has been enabled by default since 3.0. The official docker images from Selenium also come with geckodriver binary installed.
@davehunt hi, a collegue of @bavaria95 here, so we are running pytest-selenium on a container, and selenium on another, but for some reason it's looking for the binary on the pytest-selenium container instead of trying to connect to the selenium one (as it did before, and as it does when settting marionette to False
).
Maybe there's something else we have to specify to force it to connect to the remote selenium?
@david-caro okay, that does sound like a bug.. let me take a look
@bavaria95 @david-caro could you provide a full traceback? I can't see why pytest-selenium or selenium would be looking for geckodriver when specifying a remote driver, and a trace would help me to identify what code is failing.
request = <SubRequest 'driver' for <Function 'test_advisors_typehead'>>
driver_class = <class 'selenium.webdriver.firefox.webdriver.WebDriver'>
driver_kwargs = {'capabilities': {'acceptInsecureCerts': True, 'browserName': 'firefox', 'marionette': True}, 'firefox_options': <sele...ox.options.Options object at 0x975e7d0>, 'log_path': '/tmp/pytest-of-root/pytest-0/test_advisors_typehead0/driver.log'}
@pytest.yield_fixture
def driver(request, driver_class, driver_kwargs):
"""Returns a WebDriver instance based on options and capabilities"""
> driver = driver_class(**driver_kwargs)
/virtualenv/lib/python2.7/site-packages/pytest_selenium/pytest_selenium.py:128:
_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _
/virtualenv/lib/python2.7/site-packages/selenium/webdriver/firefox/webdriver.py:144: in __init__
self.service.start()
_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _
self = <selenium.webdriver.firefox.service.Service object at 0x975e390>
def start(self):
"""
Starts the Service.
:Exceptions:
- WebDriverException : Raised either when it can't start the service
or when it can't connect to the service
"""
try:
cmd = [self.path]
cmd.extend(self.command_line_args())
self.process = subprocess.Popen(cmd, env=self.env,
close_fds=platform.system() != 'Windows',
stdout=self.log_file, stderr=self.log_file)
except TypeError:
raise
except OSError as err:
if err.errno == errno.ENOENT:
raise WebDriverException(
"'%s' executable needs to be in PATH. %s" % (
> os.path.basename(self.path), self.start_error_message)
E WebDriverException: Message: 'geckodriver' executable needs to be in PATH.
/virtualenv/lib/python2.7/site-packages/selenium/webdriver/common/service.py:81: WebDriverException
Okay, you have selenium.webdriver.firefox.webdriver.WebDriver
where you should have selenium.webdriver.remote.webdriver.WebDriver
.. What are you command line options? Could you also provide the pytest header from the console?
@bavaria95 I've noticed https://github.com/inspirehep/inspire-next/blob/1595d6707e7cb6499dafb0ff9fa769874e6db446/docker-compose.test.yml#L109 which specifies --driver=Firefox
, which should perhaps be --driver=Remote
?
py.test --driver Remote --host selenium --port 4444 --capability browserName firefox --html=selenium-report.html tests/acceptance
============================= test session starts ==============================
platform linux2 -- Python 2.7.5, pytest-3.2.5, py-1.5.2, pluggy-0.4.0 -- /virtualenv/bin/python
cachedir: .cache
driver: Firefox
sensitiveurl: .*
metadata: {'Python': '2.7.5', 'Driver': 'Firefox', 'Capabilities': {'browserName': 'firefox'}, 'Server': 'selenium:4444', 'Base URL': '', 'Platform': 'Linux-4.11.8-300.fc26.x86_64-x86_64-with-centos-7.4.1708-Core', 'Plugins': {'base-url': '1.4.1', 'cov': '2.5.1', 'variables': '1.7.0', 'selenium': '1.11.2', 'html': '1.16.0', 'metadata': '1.5.0', 'flake8': '0.9.1'}, 'Packages': {'py': '1.5.2', 'pytest': '3.2.5', 'pluggy': '0.4.0'}}
rootdir: /code, inifile: pytest.ini
plugins: variables-1.7.0, selenium-1.11.2, metadata-1.5.0, html-1.16.0, flake8-0.9.1, cov-2.5.1, base-url-1.4.1
hmm.. there's clearly something odd because driver: Firefox
in the pytest header should be driver: Remote
based on those command line arguments. I'll keep digging.
@bavaria95 is this something I can attempt to replicate? I've cloned https://github.com/inspirehep/inspire-next/ and was able to run the tests using:
docker-compose pull
docker-compose -f docker-compose.deps.yml run --rm pip
docker-compose run --rm web scripts/recreate_records
docker-compose -f docker-compose.test.yml run --rm acceptance
The tests ran, with the following pytest header showing the correct driver:
============================= test session starts ==============================
platform linux2 -- Python 2.7.5, pytest-3.2.5, py-1.5.2, pluggy-0.4.0
driver: Remote
sensitiveurl: .*
metadata: {'Python': '2.7.5', 'Driver': 'Remote', 'Capabilities': {'browserName': 'firefox'}, 'Server': 'selenium:4444', 'Base URL': '', 'Platform': 'Linux-4.9.49-moby-x86_64-with-centos-7.4.1708-Core', 'Plugins': {'base-url': '1.4.1', 'cov': '2.5.1', 'variables': '1.7.0', 'selenium': '1.11.2', 'html': '1.16.0', 'metadata': '1.5.0', 'flake8': '0.9.1'}, 'Packages': {'py': '1.5.2', 'pytest': '3.2.5', 'pluggy': '0.4.0'}}
rootdir: /code, inifile: pytest.ini
plugins: variables-1.7.0, selenium-1.11.2, metadata-1.5.0, html-1.16.0, flake8-0.9.1, cov-2.5.1, base-url-1.4.1
The first time I ran I had tests failing due to elements not being found, and another time I had connection timeouts. I did not see the geckodriver issue, however I did when I ran docker-compose -f docker-compose.test.yml run --rm visible-acceptance
, which specified a driver of Firefox.
I just following the instructions again (I think I missed the docker-compose -f docker-compose.deps.yml run --rm assets
step originally, and the 'acceptance' tests are now passing for me.
@davehunt
Okay, there is my bad, actually in the code I was using --driver Firefox
. And it makes sense why it doesn't work (after changing to --driver Remote
it works without setting up marionette to False).
Buuut, the question is, how was it working before with the same driver? Right now I made some tests with my older image (before library update) and my new image (after library update).
Looks like:
+ stdbuf -o 0 py.test -s -vv --driver Firefox --host selenium --port 4444 --capability browserName firefox --html=selenium-report.html --junitxml=output.xml tests/acceptance
Coverage.py warning: --include is ignored because --source is set (include-ignored)
============================= test session starts ==============================
platform linux2 -- Python 2.7.5, pytest-3.2.3, py-1.4.34, pluggy-0.4.0 -- /virtualenv/bin/python
cachedir: .cache
driver: Firefox
sensitiveurl: .*
metadata: {'Python': '2.7.5', 'Driver': 'Firefox', 'Capabilities': {'browserName': 'firefox'}, 'Server': 'selenium:4444', 'Base URL': '', 'Platform': 'Linux-4.11.8-300.fc26.x86_64-x86_64-with-centos-7.4.1708-Core', 'Plugins': {'base-url': '1.4.1', 'cov': '2.5.1', 'variables': '1.7.0', 'selenium': '1.11.1', 'html': '1.16.0', 'metadata': '1.5.0', 'flake8': '0.9.1'}, 'Packages': {'py': '1.4.34', 'pytest': '3.2.3', 'pluggy': '0.4.0'}}
rootdir: /code, inifile: pytest.ini
plugins: variables-1.7.0, selenium-1.11.1, metadata-1.5.0, html-1.16.0, flake8-0.9.1, cov-2.5.1, base-url-1.4.1
collected 23 items
tests/acceptance/conftest.py PASSED
tests/acceptance/authors/test_authors_new_form.py PASSED
tests/acceptance/authors/test_authors_new_form.py::test_institutions_typeahead Processed 0 records
All migration tasks have been completed.
PASSED
+ stdbuf -o 0 py.test -s -vv --driver Firefox --host selenium --port 4444 --capability browserName firefox --html=selenium-report.html --junitxml=output.xml tests/acceptance
Coverage.py warning: --include is ignored because --source is set (include-ignored)
============================= test session starts ==============================
platform linux2 -- Python 2.7.5, pytest-3.2.3, py-1.4.34, pluggy-0.4.0 -- /virtualenv/bin/python
cachedir: .cache
driver: Firefox
sensitiveurl: .*
metadata: {'Python': '2.7.5', 'Driver': 'Firefox', 'Capabilities': {'browserName': 'firefox'}, 'Server': 'selenium:4444', 'Base URL': '', 'Platform': 'Linux-4.11.8-300.fc26.x86_64-x86_64-with-centos-7.4.1708-Core', 'Plugins': {'base-url': '1.4.1', 'cov': '2.5.1', 'variables': '1.7.0', 'selenium': '1.11.2', 'html': '1.16.0', 'metadata': '1.5.0', 'flake8': '0.9.1'}, 'Packages': {'py': '1.4.34', 'pytest': '3.2.3', 'pluggy': '0.4.0'}}
rootdir: /code, inifile: pytest.ini
plugins: variables-1.7.0, selenium-1.11.2, metadata-1.5.0, html-1.16.0, flake8-0.9.1, cov-2.5.1, base-url-1.4.1
collected 23 items
tests/acceptance/conftest.py PASSED
tests/acceptance/authors/test_authors_new_form.py PASSED
tests/acceptance/authors/test_authors_new_form.py::test_institutions_typeahead Processed 0 records
All migration tasks have been completed.
ERROR
tests/acceptance/authors/test_authors_new_form.py::test_experiments_typehead ERROR
This was because before version 1.11.2 the capabilities were empty by default, meaning the marionette capability was not present and legacy Firefox was used. This was fixed so that the appropriate defaults were set according to the Selenium client, and therefore marionette and modern Firefox are used. See https://github.com/pytest-dev/pytest-selenium/commit/0773c93a54f3218d960f4b11b026f2b58a918922#diff-88a7aec9c2361f634a0f93e317ffa663R44 for the specific change.
I'd suggest this is a welcome issue to discover, as it suggests your tests are running on an old version of Firefox, which most likely does not represent your user base. It should be trivial to update Firefox and install geckodriver onto this image to resolve you current issue.
Also note that when using --driver Firefox
the --host
and --port
arguments are no necessary, and might add confusion. Please let me know if there's anything else I can help with.
Great, thanks. I think this one can be closed then. @david-caro, perhaps we can try upgrading firefox version for tests, right?
In case it's helpful, here's where the official Selenium images install Firefox and geckodriver: https://github.com/SeleniumHQ/docker-selenium/blob/master/NodeFirefox/Dockerfile#L10-L35
Closing this, as it seems to not be an issue with the plugin.
After update of pytest-selenium to 1.11.2 (https://github.com/pytest-dev/pytest-selenium/commit/0773c93a54f3218d960f4b11b026f2b58a918922 to be more precise) my selenium tests stopped working (using Firefox). I started to receive
WebDriverException: Message: 'geckodriver' executable needs to be in PATH.
error. Debugging has shown thatcapabilities
now are getting set to{'acceptInsecureCerts': True, 'browserName': 'firefox', 'marionette': True}
, instead of{'browserName': 'firefox'}
, which was the case before the update (now it takes them from selenium'sDesiredCapabilities
)