Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
3 changes: 2 additions & 1 deletion .travis.yml
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
language: php

php:
- 5.3
- 5.4
- 5.5

Expand All @@ -10,6 +11,6 @@ before_script:
- java -jar selenium-server-standalone-2.35.0.jar -port 4444 >/dev/null 2>&1 &
- cd test/integration/
- mkdir tests/_log

- php codecept.phar build

script: php codecept.phar run -d
102 changes: 66 additions & 36 deletions module/VisualCeption.php
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@

/**
* Class VisualCeption
*
* @copyright Copyright (c) 2014 G+J Digital Products GmbH
* @license MIT license, http://www.opensource.org/licenses/mit-license.php
* @package Codeception\Module
Expand Down Expand Up @@ -42,8 +43,61 @@ public function _before (\Codeception\TestCase $test)
$this->test = $test;
}

private function getDeviation ($identifier, $elementID)
{
$coords = $this->getCoordinates($elementID);
$this->createScreenshot($identifier, $coords);

$compareResult = $this->compare($identifier);

unlink($this->getScreenshotPath($identifier));

$deviation = round($compareResult[1] * 100, 2);
$this->debug("The deviation between the images is ". $deviation . " percent");
return array ("deviation" => $deviation, "deviationImage" => $compareResult[0]);
}

/**
* Compare the reference image with a current screenshot, identified by their indentifier name
* and their element ID.
*
* @param string $identifier identifies your test object
* @param string $elementID DOM ID of the element, which should be screenshotted
*/
public function dontSeeVisualChanges ($identifier, $elementID = null)
{
$deviationResult = $this->getDeviation($identifier, $elementID);
if (! is_null($deviationResult["deviationImage"])) {
if ($deviationResult["deviation"] > $this->maximumDeviation) {
$compareScreenshotPath = $this->getDeviationScreenshotPath($identifier);
$deviationResult["deviationImage"]->writeImage($compareScreenshotPath);
$this->assertTrue(false, "The deviation of the taken screenshot is too high (" . $deviationResult["deviation"] . "%).\nSee $compareScreenshotPath for a deviation screenshot.");
}
}
}

/**
* Compare the reference image with a current screenshot, identified by their indentifier name
* and their element ID.
*
* @param string $identifier identifies your test object
* @param string $elementID DOM ID of the element, which should be screenshotted
*/
public function seeVisualChanges ($identifier, $elementID = null)
{
$deviationResult = $this->getDeviation($identifier, $elementID);
if (! is_null($deviationResult["deviationImage"])) {
if ($deviationResult["deviation"] <= $this->maximumDeviation) {
$compareScreenshotPath = $this->getDeviationScreenshotPath($identifier);
$deviationResult["deviationImage"]->writeImage($compareScreenshotPath);
$this->assertTrue(false, "The deviation of the taken screenshot is too low (" . $deviationResult["deviation"] . "%).\nSee $compareScreenshotPath for a deviation screenshot.");
}
}
}

/**
* Initialize the module and read the config. Throws a runtime exception, if the
* Initialize the module and read the config.
* Throws a runtime exception, if the
* reference image dir is not set in the config
*
* @throws \RuntimeException
Expand All @@ -67,7 +121,8 @@ private function init ()
}

/**
* Find the position and proportion of a DOM element, specified by it's ID. The method inject the
* Find the position and proportion of a DOM element, specified by it's ID.
* The method inject the
* JQuery Framework and uses the "noConflict"-mode to get the width, height and offset params.
*
* @param $elementId DOM ID of the element, which should be screenshotted
Expand All @@ -80,7 +135,7 @@ private function getCoordinates ($elementId)
$elementId = 'body';
}

$jQueryString = file_get_contents(__DIR__."/jquery.js");
$jQueryString = file_get_contents(__DIR__ . "/jquery.js");
$webDriver->executeScript($jQueryString);
$webDriver->executeScript('jQuery.noConflict();');

Expand Down Expand Up @@ -118,12 +173,11 @@ private function getScreenshotPath ($identifier)
$debugDir = \Codeception\Configuration::logDir() . 'debug/tmp/';
if (! is_dir($debugDir)) {
$created = mkdir($debugDir, 0777, true);
if( $created ) {
$this->debug("Creating directory: $debugDir");
}else{
if ($created) {
$this->debug("Creating directory: $debugDir");
} else {
throw new \RuntimeException("Unable to create temporary screenshot dir ($debugDir)");
}

}
return $debugDir . $this->getScreenshotName($identifier);
}
Expand Down Expand Up @@ -157,40 +211,15 @@ private function createScreenshot ($identifier, array $coords)
$webDriver->takeScreenshot($screenshotPath);

$screenShotImage = new \Imagick();
$screenShotImage->readImage( $screenshotPath );
$screenShotImage->cropImage( $coords['width'], $coords['height'], $coords['offset_x'], $coords['offset_y'] );
$screenShotImage->writeImage( $elementPath );
$screenShotImage->readImage($screenshotPath);
$screenShotImage->cropImage($coords['width'], $coords['height'], $coords['offset_x'], $coords['offset_y']);
$screenShotImage->writeImage($elementPath);

unlink($screenshotPath);

return $elementPath;
}

/**
* Compare the reference image with a current screenshot, identified by their indentifier name
* and their element ID
*
* @param string $identifier identifies your test object
* @param string $elementID DOM ID of the element, which should be screenshotted
*/
public function compareScreenshot ($identifier, $elementID = null)
{
$coords = $this->getCoordinates($elementID);
$this->createScreenshot($identifier, $coords);

$compareResult = $this->compare($identifier);

unlink($this->getScreenshotPath($identifier));

$deviation = round($compareResult[1] * 100, 2);

if ($deviation > $this->maximumDeviation) {
$compareScreenshotPath = $this->getDeviationScreenshotPath($identifier);
$compareResult[0]->writeImage($compareScreenshotPath);
$this->assertTrue(false, "The deviation of the taken screenshot is too high (".$deviation."%).\nSee $compareScreenshotPath for a deviation screenshot.");
}
}

/**
* Returns the image path including the filename of a deviation image
*
Expand All @@ -204,7 +233,8 @@ private function getDeviationScreenshotPath ($identifier)
}

/**
* Compare two images by its identifiers. If the reference image doesn't exists
* Compare two images by its identifiers.
* If the reference image doesn't exists
* the image is copied to the reference path.
*
* @param $identifier identifies your test object
Expand Down
11 changes: 8 additions & 3 deletions readme.md
Original file line number Diff line number Diff line change
@@ -1,6 +1,8 @@
# VisualCeption
Visual regression tests integrated in [Codeception](http://codeception.com/).

[![Build Status](https://travis-ci.org/DigitalProducts/codeception-module-visualception.svg?branch=master)](https://travis-ci.org/DigitalProducts/codeception-module-visualception)

This module can be used to compare the current representation of a website element with an expeted. It was written on the shoulders of codeception and integrates in a very easy way.

**Example**
Expand Down Expand Up @@ -52,20 +54,23 @@ VisualCeption:

## Usage

VisualCeption is really easy to use. There is only one method that will be added to your WebGuy <code>compareScreenshot</code>. This will be used to name the screenshot and identify the elements that has to be screenshot.
VisualCeption is really easy to use. There are only two method that will be added to your WebGuy <code>seeVisualChanges</code> and <code>dontSeeVisualChanges</code>.

```php
$I->compareScreenshot( "uniqueIdentifier", "elementId" );
$I->seeVisualChanges( "uniqueIdentifier1", "elementId1" );
$I->dontSeeVisualChanges( "uniqueIdentifier2", "elementId2" );
```

* **uniqueIdentifier** For comparing the images it is important to have a stable name. This is the corresponding name.
* **elementId** It is possible to only compare a special div container. The element id can be passed. *You can use all locators that can be used in jQuery*.

**Example Usage**
```php
$I->compareScreenshot( "subNavigation", "#subNav" );
$I->seeVisualChanges( "subNavigation", "#subNav" );
```

If you need more information about the test run please use the command line debug option (-d).

## Restriction

VisualCeption uses the WebDriver module for making the screenshots. As a consequence we are not able to take screenshots via google chrome as the chromedriver does not allow full page screenshots.
21 changes: 16 additions & 5 deletions test/integration/tests/acceptance/TimeComparisonCest.php
Original file line number Diff line number Diff line change
Expand Up @@ -6,13 +6,24 @@ class TimeComparisonCest
/**
* Coparing a div that renders the current time
*/
public function compareTimeString (WebGuy $I, $scenario)
public function seeVisualChanges (WebGuy $I, $scenario)
{
$I->amOnPage("/VisualCeption/time.php");
$I->compareScreenshot("the-time", "#thetime");
$I->amOnPage("/VisualCeption/seeVisualChanges.php");
$I->seeVisualChanges("block", "#theblock");

// the test has to be called twice for comparison on the travis server
$I->amOnPage("/VisualCeption/time.php");
$I->compareScreenshot("the-time", "#thetime");
$I->amOnPage("/VisualCeption/seeVisualChanges.php");
$I->seeVisualChanges("block", "#theblock");
}

public function dontSeeVisualChanges (WebGuy $I, $scenario)
{
$I->amOnPage("/VisualCeption/dontSeeVisualChanges.php");
$I->dontSeeVisualChanges("block", "#theblock");

// the test has to be called twice for comparison on the travis server
$I->amOnPage("/VisualCeption/dontSeeVisualChanges.php");
$I->dontSeeVisualChanges("block", "#theblock");
}

}