Firefox started by Selenium ignores the display created by pyvirtualdisplay

firefox, python, pyvirtualdisplay, selenium

Solution

Solution

Move your creation of the `FirefoxBinary` object inside the context managed by `pyvirtualdisplay.Display`:

from selenium import webdriver
from selenium.webdriver.firefox.webdriver import FirefoxBinary
import pyvirtualdisplay

with pyvirtualdisplay.Display(visible=True):
    if True:  # Set to False to use Chrome...
        binary = FirefoxBinary()
        driver = webdriver.Firefox(None, binary)
    else:
        driver = webdriver.Chrome()

    driver.get("http://www.google.com")
    driver.quit()

Explanation

The problem is what happens behind the scenes. The environment variable named `DISPLAY` is what determines where Firefox and Chrome will connect to. It is not set in the way you'd expect it to be set.

Here is what happens with your code:

You create an instance of `FirefoxBinary`. If you read the source code, you'll see that when an object of this class is created it makes a copy of `os.environ` (the environment).

You create a display with `pyvirtualdisplay.Display` and use it as a context manager. As you enter the context, the display alters `os.environ` so that as long as the context is in effect, the `DISPLAY` environment variable is set so that X clients will connect to the new display instead of what `DISPLAY` was before the context came into effect.

You create your driver. When you use Chrome, everything is fine because Chrome will get its `DISPLAY` variable from the modified environment. However, when you use Firefox, it will use the `DISPLAY` environment from the environment that was copied in the first step. This environment contains a value of `DISPLAY` which is prior to the alteration described in the previous step, so it does not connect to the new display you created.

Problem

I start a display with `pyvirtualdisplay` before creating my `WebDriver` instance. If I use Chrome, it works without any problem: Chrome shows up in the Xephyr instance that `pyvirtualdisplay` creates. However, when I use Firefox, the Xephyr instance appears but Firefox shows up outside of it. Here is code that fully reproduces the problem: ``` from selenium import webdriver from selenium.webdriver.firefox.webdriver import FirefoxBinary import pyvirtualdisplay binary = FirefoxBinary() with pyvirtualdisplay.Display(visible=True): if True: # Set to False to use Chrome... driver = webdriver.Firefox(None, binary) else: driver = webdriver.Chrome() driver.get("http://www.google.com") driver.quit() ``` The code above is a minimal version of code that is more complex (which explains the seemingly useless `FirefoxBinary()`).

Original source