On this page

This quickstart will show you how to visually test web apps in Python using Selenium WebDriver and pytest. Visual testing can help you catch problems that traditional automation struggles to find.

After preparing your environment, this **three-step quickstart** should take **about 15 minutes** to complete.

Need extra help?

If you get stuck on this example, don't suffer in silence! Please [reach out to us](/content/contact/product-demo-request/index.html) to get things working. We can also help you get Applitools running in your own project.

## Step 1: Preparing your environment

You'll need a few things to run this quickstart:

1. An [Applitools account](https://auth.applitools.com/users/register), which you can register for free.
2. A recent version of [Python 3](https://www.python.org/downloads/).
3. A good Python editor like [Visual Studio Code](https://code.visualstudio.com/docs/languages/python) or [JetBrains PyCharm](https://www.jetbrains.com/pycharm/).
4. An up-to-date version of [Google Chrome](https://www.google.com/chrome/downloads/).
5. A corresponding version of [ChromeDriver](https://chromedriver.chromium.org/downloads).

Installing ChromeDriver

The major version numbers of Chrome and ChromeDriver must be the same. Otherwise, Selenium WebDriver may raise an exception when it is initialized. For example, Chrome v101 requires ChromeDriver v101. ChromeDriver must be installed into a directory covered by the system `PATH` variable. Follow the instructions on Selenium's [Install browser drivers](https://www.selenium.dev/documentation/webdriver/getting_started/install_drivers/#2-the-path-environment-variable) page. On macOS and Linux, the recommended location for the `chromedriver` executable is the `/usr/local/bin` directory. You can test that ChromeDriver is working by running the `chromedriver -v` command to print its version.

## Step 2: Getting your example project

### Downloading the example project

The example project is located at [https://github.com/applitools/example-selenium-python-pytest](https://github.com/applitools/example-selenium-python-pytest). Clone this repository to your local machine:

```text
git clone https://github.com/applitools/example-selenium-python-pytest.git
cd example-selenium-python-pytest
```

Don't have Git?

Instead of running `git clone`, you can [download the project as a ZIP file](https://github.com/applitools/example-selenium-python-pytest/archive/refs/heads/master.zip) and extract it.

### Installing the dependencies

The example project uses [pip](https://packaging.python.org/en/latest/eyes/installing-packages/) for package management. Run the following command (which works on any operating system):

```text
pip3 install -r requirements.txt
```

Adding Applitools to Another Python Project?

This example project already declares the Applitools Eyes SDK as a dependency. If you want to add the Applitools Eyes SDK into an existing Python environment, run the following commands:

```text
pip3 install eyes-selenium
```

### Deciding how to run tests

The test uses Selenium WebDriver to automate the browser. There are two places to run your Selenium WebDriver session:

1. On your _local machine_ (which is the default option)
2. On _Applitools Execution Cloud_

If you run WebDriver locally, then you need to set it up and manage it yourself. If you use Execution Cloud, then Applitools will manage WebDriver for you. It will also automatically heal broken locators and wait for elements to be ready. **If you would like to try Execution Cloud,** please [request access](/content/platform/execution-cloud/trial-request/index.html). The [docs for Execution Cloud](/content/docs/eyes/concepts/test-execution/execution-cloud/run-a-test/index.html) provide more information.

There are two ways to test the visual snapshots captured by the test:

1. Using _Applitools [Ultrafast Grid](/content/docs/eyes/concepts/test-execution/ultrafast-grid/index.html)_ for cross-browser testing in the cloud
2. Using _Applitools Classic runner_ on your local machine

### Walking through the code

All test setup and cleanup is handled by a set of pytest fixtures located at `tests/conftest.py`. The variables at the top control how tests will run:

- Set `USE_ULTRAFAST_GRID` to `True` to use Ultrafast Grid or `False` to use the Classic runner.
- Set `USE_EXECUTION_CLOUD` to `True` to use Execution Cloud or `False` to run WebDriver sessions locally.

```python
"""
This module provides fixtures for test setup.
You can use these fixtures for all tests in your suite.
You could also copy-paste this module into your own test project to provide Applitools setup for your tests.
"""

# --------------------------------------------------------------------------------
# Imports
# --------------------------------------------------------------------------------

import os
import pytest

from applitools.selenium import *
from applitools.selenium.runner import EyesRunner
from selenium.webdriver import Chrome, ChromeOptions, Remote

# --------------------------------------------------------------------------------
# Runner Settings
#   These could be set by environment variables or other input mechanisms.
#   They are hard-coded here to keep the example project simple.
# --------------------------------------------------------------------------------

USE_ULTRAFAST_GRID = True
USE_EXECUTION_CLOUD = False

# --------------------------------------------------------------------------------
# Session-Scope Fixtures
#   These fixtures run one time for the whole test suite.
#   Subsequent calls use the value cached from the first execution.
# --------------------------------------------------------------------------------

@pytest.fixture(scope='session')
def api_key():
  """
  Reads the Applitools API key from an environment variable.
  """
  return os.getenv('APPLITOOLS_API_KEY')

@pytest.fixture(scope='session')
def headless():
  """
  Reads the headless mode setting from an environment variable.
  Uses headless mode for Continuous Integration (CI) execution.
  Uses headed mode for local development.
  """
  h = os.getenv('HEADLESS', default='false')
  return h.lower() == 'true'

@pytest.fixture(scope='session')
def runner():
  """
  Creates the runner for either the Ultrafast Grid or the Classic runner (local execution).
  For UFG, concurrency refers to the number of visual checkpoints Applitools will perform in parallel.
  Warning: If you have a free account, then concurrency will be limited to 1.
  After the test suite finishes execution, closes the batch and report visual differences to the console.
  Note that it forces pytest to wait synchronously for all visual checkpoints to complete.
  """

if USE_ULTRAFAST_GRID:
    run = VisualGridRunner(RunnerOptions().test_concurrency(5))
  else:
    run = ClassicRunner()

yield run
  print(run.get_all_test_results(False))

@pytest.fixture(scope='session')
def batch_info():
  """
  Creates a new batch for tests.
  A batch is the collection of visual checkpoints for a test suite.
  Batches are displayed in the Eyes Test Manager, so use meaningful names.
  """

runner_name = "Ultrafast Grid" if USE_ULTRAFAST_GRID else "Classic runner"
  return BatchInfo(f"Example: Selenium Python pytest with the {runner_name}")

@pytest.fixture(scope='session')
def configuration(api_key: str, batch_info: BatchInfo):
  """
  Creates a configuration for Applitools Eyes to test 3 desktop browsers and 2 mobile devices.
  """

# Construct the object
  config = Configuration()

# Set the batch for the config.
  config.set_batch(batch_info)

# Set the Applitools API key so test results are uploaded to your account.
  # If you don't explicitly set the API key with this call,
  # then the SDK will automatically read the `APPLITOOLS_API_KEY` environment variable to fetch it.
  config.set_api_key(api_key)

# If running tests on the Ultrafast Grid, configure browsers.
  if USE_ULTRAFAST_GRID:

# Add 3 desktop browsers with different viewports for cross-browser testing in the Ultrafast Grid.
    # Other browsers are also available, like Edge and IE.
    config.add_browser(800, 600, BrowserType.CHROME)
    config.add_browser(1600, 1200, BrowserType.FIREFOX)
    config.add_browser(1024, 768, BrowserType.SAFARI)

# Add 2 mobile browsers with different orientations for cross-browser testing in the Ultrafast Grid.
    # Other mobile devices are available.
    config.add_browser(IosDeviceInfo(IosDeviceName.iPhone_11, ScreenOrientation.PORTRAIT))
    config.add_browser(ChromeEmulationInfo(DeviceName.Nexus_10, ScreenOrientation.LANDSCAPE))

# Return the configuration object
  return config

# --------------------------------------------------------------------------------
# Function-Scope Fixtures
#   These fixtures run one time before each test that calls them.
#   Returned values are not cached and reused across different tests.
# --------------------------------------------------------------------------------

@pytest.fixture(scope='function')
def webdriver(headless: bool):
  """
  Creates a WebDriver object for Chrome.
  After the test function finishes execution, quits the browser.
  """

options = ChromeOptions()
  options.add_argument("--headless=new")

if USE_EXECUTION_CLOUD:
    driver = Remote(
      command_executor=Eyes.get_execution_cloud_url(),
      options=options)
  else:
    driver = Chrome(options=options)

yield driver
  driver.quit()

@pytest.fixture(scope='function')
def eyes(
  runner: EyesRunner,
  configuration: Configuration,
  webdriver: Remote,
  request: pytest.FixtureRequest):
  """
  Creates the Applitools Eyes object connected to the runner and set its configuration.
  Then, opens Eyes to start visual testing before the test, and closes Eyes at the end of the test.

Opening Eyes requires 4 arguments:
    1. The WebDriver object to "watch".
    2. The name of the application under test.
       All tests for the same app should share the same app name.
       Set this name wisely: Applitools features rely on a shared app name across tests.
    3. The name of the test case for the given application.
       Additional unique characteristics of the test may also be specified as part of the test name,
       such as localization information ("Home Page - EN") or different user permissions ("Login by admin").
    4. The viewport size for the local browser.
       Eyes will resize the web browser to match the requested viewport size.
       This parameter is optional but encouraged in order to produce consistent results.
  """

eyes = Eyes(runner)
  eyes.set_configuration(configuration)

eyes.open(
    driver=webdriver,
    app_name='ACME Bank Web App',
    test_name=request.node.name,
    viewport_size=RectangleSize(1200, 600))

yield eyes
  eyes.close_async()
```

The project contains one visual test case, which is located at `tests/test_acme_bank.py`. `test_acme_bank` is a pytest test module that covers login behavior for the [ACME Bank demo web app](https://demo.applitools.com/). to execute the test across multiple browsers in Applitools Ultrafast Grid. With the Ultrafast Grid, you can specify different browser types, viewport sizes, and even mobile devices.

```python
from applitools.selenium import Eyes, Target
from selenium.webdriver import Chrome
from selenium.webdriver.common.by import By

def test_log_into_bank_account(webdriver: Chrome, eyes: Eyes) -> None:

# Load the login page.
  webdriver.get("https://demo.applitools.com")

# Verify the full login page loaded correctly.
  eyes.check(Target.window().fully().with_name("Login page"))

# Perform login.
  webdriver.find_element(By.ID, "username").send_keys("applibot")
  webdriver.find_element(By.ID, "password").send_keys("I<3VisualTests")
  webdriver.find_element(By.ID, "log-in").click()

# Verify the full main page loaded correctly.
  # This snapshot uses LAYOUT match level to avoid differences in closing time text.
  eyes.check(Target.window().fully().with_name("Main page").layout())
```

## Step 3: Running your tests

### Setting Applitools variables

Before running the visual test, you must [find your Applitools API key](/content/docs/eyes/getting-started/retrieve-api-key/index.html) and set it as an environment variable named `APPLITOOLS_API_KEY`. You may set it through your IDE (if applicable), or you may set it from the command line like this:

- macOS and Linux
- Windows

```text
export APPLITOOLS_API_KEY=<your-api-key>
```

```text
set APPLITOOLS_API_KEY=<your-api-key>
```

Having trouble with environment variables?

If you have trouble setting the `APPLITOOLS_API_KEY` environment variable, you can hard-code your API key like this:

```python
# Change the following line in the 'api_key' fixture:
# return os.getenv('APPLITOOLS_API_KEY')
return "<your-api-key>"
```

However, be warned: hard-coding secrets is poor practice. Do this only temporarily for debugging, and _never_ commit hard-coded secrets to version control.

You may also need to set your Applitools Eyes server. By default, tests will use the public Applitools Eyes server at [eyes.applitools.com](https://eyes.applitools.com/). However, if your team is using a [private Applitools Eyes server](https://help.applitools.com/hc/en-us/articles/360007189231-The-different-deployment-modes), you can target it by setting the `APPLITOOLS_SERVER_URL` environment variable. (If you are using a free Applitools account, then use the public server.)

### Launching visual tests

Run the following command to launch tests:

```text
python3 -m pytest -s -v tests
```

To run tests headlessly, set the `HEADLESS` environment variable to `true`.

After your tests run, you should see results in the [Eyes Test Manager](/content/docs/eyes/concepts/reviewing-tests/test-results-page/index.html). You can log into the Test Manager at [eyes.applitools.com](https://eyes.applitools.com/) or at the address for your private Applitools Eyes server.

When you run tests with the Applitools Ultrafast Grid, the tests will run one time on the local machine, and then they will upload snapshots to render on each target configuration in the cloud. The Test Manager will show a separate result for each rendering. When you run tests with the Applitools Classic runner, the Test Manager will show the one snapshot from your local machine.

You can also change the web page to inject visual bugs:

```python
# webdriver.get("https://demo.applitools.com")
webdriver.get("https://demo.applitools.com/index_v2.html")
```

If you rerun the tests, then they should yield "unresolved" results for you to review. Visual differences will be highlighted in magenta. It's up to you to accept (👍) or reject (👎) the changes. Applitools will remember your decisions for future analysis.

Need extra help?

Again, it's okay. If you get stuck on this example, don't suffer in silence! Please [reach out to us](/content/contact/product-demo-request/index.html) to get things working. We can also help you get Applitools running in your own project.

## Taking the next steps with Applitools

Congratulations on completing this quickstart! There's still so much to learn about visual testing with Applitools, but you're off to a great start.

### Resources for next steps:

1. [Setting match levels for visual checkpoints](/content/docs/eyes/concepts/best-practices/match-levels/index.html)
2. [Organizing Tests Into Batches](/content/docs/eyes/concepts/best-practices/batching/index.html)
3. [Run A/B Tests](/content/docs/eyes/concepts/best-practices/baseline-variations/index.html)

### You can also: [Request a demo](/content/contact/product-demo-request/index.html)
