Automated web application testing with PHP, Selenium and GitLab

Mar 19, 2021 by Thibault | 164 views

PHP GitLab

https://cylab.be/blog/134/automated-web-application-testing-with-php-selenium-and-gitlab

The easiest way to test that a web application is working correctly is to use a browser and manually go through the pages. If one wants to automate the testing process, there are conceptually two possible approaches: 1) using raw HTTP requests to simulate a browser or 2) using some library and code to drive an actual browser.

The first approach is used by tools like Symfony BrowserKit and Laravel BrowserKit Testing. It is usually light and fast but, as there is no real browser involved, it is not possible to test the execution of javascript or the result of CSS code.

The second approach is possible thanks to tools like Selenium. It allows to test the entire website, including javascript code, but is generally slower.

In this blog post we will show how to use Selenium with PHP code, and how to integrate with GitLab.

Selenium

The core component is the Selenium Server, a java server that allows to drive a real instance of a browser. The server supports most current browsers: Firefox, Chrome, Edge, Safari... It is generally accessible through port 4444.

The Remote WebDriver is the client part. It is a library that makes it easy to connect to the Selenium Server and drive the browser. The Remote WebDriver is implemented for various programming languages (PHP, Java, Python, Ruby, C#...).

The combination of the Remote WebDriver and the Selenium Server allows to run the client code on one machine, and the browser on another. It is thus possible to run the PHP test code on a Linux machine, to drive Safari installed on a Mac.

There selenium server can be installed manually, but the easiest way is to run a Docker container that contains the server and a web browser. Here is an example to run selenium with the Chrome browser:

docker run -d -p 4444:4444 --shm-size 2g selenium/standalone-chrome

PHP

Once the Selenium container is running, we can use PHP code to drive the Chrome browser.

First, we must install the Remote WebDriver library:

composer require php-webdriver/webdriver

And now we can use Selenium and Chrome:

<?php
// selenium.php
require_once __DIR__ . "/vendor/autoload.php";

use Facebook\WebDriver\Remote\DesiredCapabilities;
use Facebook\WebDriver\Remote\RemoteWebDriver;
use Facebook\WebDriver\WebDriverBy;

// we try to read Selenium URL from environment
// will be used when testing in GitLab
// ideally, we should use PHP dotenv
$selenium_url = getenv("SELENIUM_URL");
if ($selenium_url === false) {
    $selenium_url = "http://localhost:4444/wd/hub";
}

$capabilities = DesiredCapabilities::chrome();
$browser = RemoteWebDriver::create(
        $selenium_url,
        $capabilities);

// browse a URL
$browser->get("https://cylab.be");
echo $browser->getTitle() . "\n";

// take a screenshot of the page
$browser->takeScreenshot("/tmp/screenshot.png");

// find an element on the page and check content
$el1 = $browser->findElement(WebDriverBy::name("q"));
$el1 = $browser->findElement(WebDriverBy::className("container-fluid"));
echo $el1->getText() . "\n";

// find a form field and interact
$el2 = $browser->findElement(WebDriverBy::name("q"));
$el2->sendKeys("laravel");
$el2->submit();

$browser->quit();

Typically, you will want to find an element on the page. The WebDryverBy class provides static methods to find by:

  • id($id)
  • className($class)
  • cssSelector($selector)
  • tagName($tag)
  • linkText($text) or partialLinkText($text) (for links)
  • xpath($xpath)

https://php-webdriver.github.io/php-webdriver/1.3.0/Facebook/WebDriver/WebDriverBy.html

Once the element is found, you can using following methods to check the element or interact:

  • getText()
  • getId()
  • isDisplayed()
  • click()
  • sendKeys($keys) and submit()

https://php-webdriver.github.io/php-webdriver/1.3.0/Facebook/WebDriver/Remote/RemoteWebElement.html

GitLab

We can also use the Selenium container as a GitLab service, to run our tests at each push. Here is an example gitlab-ci.yml, with 2 jobs for testing against Chrome and Firefox:

test:chrome:
  image: cylab/php73
  services:
    - selenium/standalone-chrome
  script:
    - composer install
    - SELENIUM_URL="http://selenium-standalone-chrome:4444/wd/hub" php selenium.php

test:firefox:
  image: cylab/php73
  services:
    - selenium/standalone-firefox
  script:
    - composer install
    - SELENIUM_URL="http://selenium-standalone-firefox:4444/wd/hub" php selenium.php

In a real setup, this should take place as the last stage of your pipeline, after unit testing and deployment to the test environment...