Running UI Automation Tests in the cloud or on dedicated self hosted Linux servers with minimal resources, will help you to save some costs when you have multiple tests running in parallel on several Linux servers. It is recommended to keep it lean and use Linux server distributions without graphical user interface, and to execute your test cases with a “Headless” state in Chrome.
Headless test automation execution simulates the actual actions as they were preformed on an actual browser, but it doesn’t require any GUI. By running tests in a Headless mode you will also notice much faster performance – tests that run in a headless mode run 2 to 10 times faster than running in a normal mode browser. The reason is simple – In a Headless mode the time it takes to load the JavaScript, CSS and render the HTML are much lower since it is not starting up a browser GUI.
In addition, you might want to continue developing while simultaneously running a 10 minute UI test suite script on your machine, without having the browser pop up every 5 seconds. With a script running in a Headless mode you can do just that – Run the script from the command line and continue developing, instead of being stuck watching your screen for the next 10 minutes.
For this article I’m going to use CentOS as my Linux server, even though the same goal can be achieved on most Linux environments.
📍 If you are looking for a single Python Package for Android, iOS and Web Testing – there is also an easy open source solution provided by TestProject. With a single executable, zero configurations, and familiar Selenium APIs, you can develop and execute robust Python tests and get automatic HTML test reports as a bonus! All you need is: pip install testproject-python-sdk
. Simply follow this Github link to learn more about it, or read through this great tutorial to get started.
Firstly, you will need Python and Selenium on your Linux machine:
pip is the package management system for Python.
yum install python27 yum install python-pip pip install -U selenium
So, how would you run UI Automation Tests in a Headless mode?
These are the 2 ways to tackle this issue (If you want to use Firefox webdriver, you only have to use the first option):
- PyVirtualDisplay.
- Chrome headless flag (in chrome_options).
Note: If your website has SSL errors, ignoring certificate errors does not work very well with chromedriver. I would suggest using Firefox instead. This line of code won’t help:
chrome_options.add_argument('--ignore-certificate-errors')
PyVirtualDisplay is a Python wrapper for Xvfb, Xephyr and Xvnc. You must have Xvfb installed on your Linux machine as well as the PyVirtualDisplay library:
yum install Xvfb pip install PyVirtualDisplay
Xvfb (X virtual framebuffer) is a display server implementing the X11 display server protocol. Xvfb executes all graphical operations using the virtual memory without showing any screen output, unlike other display servers. In addition, Xvfb does not require the machine to have a screen, graphics adapter or input device. The only requirement is a network layer.
Default display should be :1
You can check this with the command:
env | grep DISPLAY
You should make sure your proxy settings (if required) are configured correctly, since incorrect configured proxies can cause ChromeDriver to not work properly. Since ChromeDriver takes the proxy settings from the env variable, you can set or unset the proxies as you wish (Remove them if you’re running tests on local machines):
unset http_proxy unset https_proxy
Or:
export http_proxy=10.0.x.x export https_proxy=10.0.x.x
You could also add the proxy settings via chrome_options or desired_capabilities for Firefox:
# Firefox: myProxy = "10.0.x.x:yyyy" proxy = Proxy({ 'proxyType': ProxyType.MANUAL, 'httpProxy': myProxy, 'ftpProxy': myProxy, 'sslProxy': myProxy, 'noProxy': '' }) driver = webdriver.Firefox(proxy=proxy) # Chrome: myProxy = "10.0.x.x:yyyy" chrome_options = webdriver.ChromeOptions() chrome_options.add_argument('--proxy-server=%s' % myProxy )
Update chrome to its latest version to be compatible with the latest ChromeDriver binary.
Use this command:
yum update google-chrome
Download ChromeDriver and copy to your folder of choice:
cd /home/dev wget https://chromedriver.storage.googleapis.com/2.35/chromedriver_linux64.zip unzip chromedriver_linux64.zip
And run your script of choice:
from selenium import webdriver # Option 1 - with ChromeOptions chrome_options = webdriver.ChromeOptions() chrome_options.add_argument('--headless') chrome_options.add_argument('--no-sandbox') # required when running as root user. otherwise you would get no sandbox errors. driver = webdriver.Chrome(driver_path='/home/dev/chromedriver', chrome_options=chrome_options, service_args=['--verbose', '--log-path=/tmp/chromedriver.log']) # Option 2 - with pyvirtualdisplay from pyvirtualdisplay import Display display = Display(visible=0, size=(1024, 768)) display.start() driver = webdriver.Chrome(driver_path='/home/dev/chromedriver', service_args=['--verbose', '--log-path=/tmp/chromedriver.log']) # Log path added via service_args to see errors if something goes wrong (always a good idea - many of the errors I encountered were described in the logs) # And now you can add your website / app testing functionality: driver.get('https://python.org') print(driver.title) # driver.click...
Add the code to a test.py file, and run it:
python test.py
What is your experience running remote Linux servers with Chrome Headless? Please share in the comments below!
This was so helpful thank you for sharing!!
I did find that with using chromedriver 2.38 on OS X the section for
driver = webdriver.Chrome(driver_path=’/home/dev/chromedriver’, chrome_options=chrome_options,
service_args=[‘–verbose’, ‘–log-path=/tmp/chromedriver.log’])
worked with executalble_path
driver = webdriver.Chrome(executable_path=’/home/dev/chromedriver’, chrome_options=chrome_options,
service_args=[‘–verbose’, ‘–log-path=/tmp/chromedriver.log’])
Hello
I am using Python 3.6.8 and while testing the provided solution in Option 1 found an issue: the option `driver_path` does not exist. I looked up the webdriver class file for chrome and turns out it is called `executable_path`. Changing this fixed the issue.
Cheers \m/