1- <?php
2- namespace Codeception \Module ;
3-
4- class VisualCeption extends \Codeception \Module
5- {
6-
7- private $ referenceImageDir ;
8-
9- private $ maximumDeviation = 0 ;
10-
11- public function __construct ($ config )
12- {
13- $ result = parent ::__construct ($ config );
14- $ this ->init ();
15- return $ result ;
16- }
17-
18- public function _before (\Codeception \TestCase $ test )
19- {
20- $ this ->test = $ test ;
21- }
22-
23- private function init ()
24- {
25- if (array_key_exists ('maximumDeviation ' , $ this ->config )) {
26- $ this ->maximumDeviation = $ this ->config ["maximumDeviation " ];
27- }
28-
29- if (array_key_exists ('referenceImageDir ' , $ this ->config )) {
30- $ this ->referenceImageDir = $ this ->config ["referenceImageDir " ];
31- } else {
32- throw new \RuntimeException ("Reference image dir was not set, but is mandatory. " );
33- }
34-
35- if (! is_dir ($ this ->referenceImageDir )) {
36- mkdir ($ this ->referenceImageDir , 0666 );
37- }
38- }
39-
40- private function getCoordinates ($ elementId )
41- {
42- $ webDriver = $ this ->getModule ("WebDriver " )->webDriver ;
43- if (is_null ($ elementId )) {
44- $ elementId = 'body ' ;
45- }
46- $ imageCoords = array ();
47- $ imageCoords ['offset_x ' ] = (string ) $ webDriver ->executeScript ('var element = $( " ' . $ elementId . '" );var offset = element.offset();return offset.left; ' );
48- $ imageCoords ['offset_y ' ] = (string ) $ webDriver ->executeScript ('var element = $( " ' . $ elementId . '" );var offset = element.offset();return offset.top; ' );
49- $ imageCoords ['width ' ] = (string ) $ webDriver ->executeScript ('var element = $( " ' . $ elementId . '" );return element.width(); ' );
50- $ imageCoords ['height ' ] = (string ) $ webDriver ->executeScript ('var element = $( " ' . $ elementId . '" );return element.height(); ' );
51-
52- return $ imageCoords ;
53- }
54-
55- private function getScreenshotName ($ identifier )
56- {
57- $ caseName = str_replace ('Cept.php ' , '' , $ this ->test ->getFileName ());
58- return $ caseName . $ identifier . "-element.png " ;
59- }
60-
61- private function getScreenshotPath ($ identifier )
62- {
63- $ debugDir = \Codeception \Configuration::logDir () . 'debug/tmp/ ' ;
64- if (! is_dir ($ debugDir )) {
65- mkdir ($ debugDir , 0666 );
66- }
67- return $ debugDir . $ this ->getScreenshotName ($ identifier );
68- }
69-
70- private function getExpectedScreenshotPath ($ identifier )
71- {
72- return $ this ->referenceImageDir . $ this ->getScreenshotName ($ identifier );
73- }
74-
75- private function createScreenshot ($ identifier , $ coords )
76- {
77- $ webDriverModule = $ this ->getModule ("WebDriver " );
78- $ webDriver = $ webDriverModule ->webDriver ;
79-
80- $ screenshotPath = \Codeception \Configuration::logDir () . 'debug/ ' . "fullscreenshot.tmp.png " ;
81- $ elementPath = $ this ->getScreenshotPath ($ identifier );
82-
83- $ webDriver ->takeScreenshot ($ screenshotPath );
84-
85- $ screenshotImage = imagecreatefrompng ($ screenshotPath );
86- $ elementImage = \imagecreatetruecolor ($ coords ['width ' ], $ coords ['height ' ]);
87-
88- list ($ current_width , $ current_height ) = \getimagesize ($ screenshotPath );
89- imagecopy ($ elementImage , $ screenshotImage , 0 , 0 , $ coords ['offset_x ' ], $ coords ['offset_y ' ], $ current_width , $ current_height );
90-
91- $ result = \imagepng ($ elementImage , $ elementPath , 0 );
92-
93- unlink ($ screenshotPath );
94-
95- return $ elementPath ;
96- }
97-
98- public function compareScreenshot ($ identifier , $ elementID = null )
99- {
100- $ coords = $ this ->getCoordinates ($ elementID );
101- $ currentImagePath = $ this ->createScreenshot ($ identifier , $ coords );
102-
103- $ compareResult = $ this ->compare ($ identifier );
104-
105- unlink ($ this ->getScreenshotPath ($ identifier ));
106-
107- $ this ->debug ($ compareResult );
108-
109- if ($ compareResult [1 ] > $ this ->maximumDeviation ) {
110- $ compareScreenshotPath = $ this ->getDeviationScreenshotPath ($ identifier );
111- $ compareResult [0 ]->writeImage ($ compareScreenshotPath );
112- $ this ->assertTrue (false , "The deviation of the taken screenshot is too high. See $ compareScreenshotPath for a deviation screenshot. " );
113- }
114- }
115-
116- private function getDeviationScreenshotPath ($ identifier )
117- {
118- $ debugDir = \Codeception \Configuration::logDir () . 'debug/ ' ;
119- return $ debugDir . 'compare. ' . $ this ->getScreenshotName ($ identifier );
120- }
121-
122- private function compare ($ identifier )
123- {
124- $ currentImagePath = $ this ->getScreenshotPath ($ identifier );
125- $ expectedImagePath = $ this ->getExpectedScreenshotPath ($ identifier );
126-
127- if (! file_exists ($ expectedImagePath )) {
128- copy ($ currentImagePath , $ expectedImagePath );
129- return array (null ,0 );
130- } else {
131- return $ this ->compareImages ($ expectedImagePath , $ currentImagePath );
132- }
133- }
134-
135- private function compareImages ($ image1 , $ image2 )
136- {
137- $ imagick1 = new \Imagick ($ image1 );
138- $ imagick2 = new \Imagick ($ image2 );
139-
140- $ result = $ imagick1 ->compareImages ($ imagick2 , \Imagick::METRIC_MEANSQUAREERROR );
141- $ result [0 ]->setImageFormat ("png " );
142-
143- $ this ->debug ($ result );
144-
145- return $ result ;
146- }
147- }
1+ <<<<<<< HEAD
2+ <?php
3+
4+ namespace Codeception \Module ;
5+
6+ class VisualCeption extends \Codeception \Module
7+ {
8+
9+ private $ referenceImageDir ;
10+
11+ private $ maximumDeviation = 0 ;
12+
13+ public function __construct ($ config )
14+ {
15+ $ result = parent ::__construct ($ config );
16+ $ this ->init ();
17+ return $ result ;
18+ }
19+
20+ public function _before (\Codeception \TestCase $ test )
21+ {
22+ $ this ->test = $ test ;
23+ }
24+
25+ private function init ()
26+ {
27+ if (array_key_exists ('maximumDeviation ' , $ this ->config )) {
28+ $ this ->maximumDeviation = $ this ->config ["maximumDeviation " ];
29+ }
30+
31+ if (array_key_exists ('referenceImageDir ' , $ this ->config )) {
32+ $ this ->referenceImageDir = $ this ->config ["referenceImageDir " ];
33+ } else {
34+ throw new \RuntimeException ("Reference image dir was not set, but is mandatory. " );
35+ }
36+
37+ if (! is_dir ($ this ->referenceImageDir )) {
38+ mkdir ($ this ->referenceImageDir , 0666 );
39+ }
40+ }
41+
42+ private function getCoordinates ($ elementId )
43+ {
44+ $ webDriver = $ this ->getModule ("WebDriver " )->webDriver ;
45+ if (is_null ($ elementId )) {
46+ $ elementId = 'body ' ;
47+ }
48+
49+ $ jQueryString = file_get_contents (__DIR__ ."/jquery.js " );
50+ $ webDriver ->executeScript ($ jQueryString );
51+ $ webDriver ->executeScript ('jQuery.noConflict(); ' );
52+
53+ $ imageCoords = array ();
54+ $ imageCoords ['offset_x ' ] = (string ) $ webDriver ->executeScript ('var element = jQuery( " ' . $ elementId . '" );var offset = element.offset();return offset.left; ' );
55+ $ imageCoords ['offset_y ' ] = (string ) $ webDriver ->executeScript ('var element = jQuery( " ' . $ elementId . '" );var offset = element.offset();return offset.top; ' );
56+ $ imageCoords ['width ' ] = (string ) $ webDriver ->executeScript ('var element = jQuery( " ' . $ elementId . '" );return element.width(); ' );
57+ $ imageCoords ['height ' ] = (string ) $ webDriver ->executeScript ('var element = jQuery( " ' . $ elementId . '" );return element.height(); ' );
58+
59+ return $ imageCoords ;
60+ }
61+
62+ private function getScreenshotName ($ identifier )
63+ {
64+ $ caseName = str_replace ('Cept.php ' , '' , $ this ->test ->getFileName ());
65+ return $ caseName . $ identifier . "-element.png " ;
66+ }
67+
68+ private function getScreenshotPath ($ identifier )
69+ {
70+ $ debugDir = \Codeception \Configuration::logDir () . 'debug/tmp/ ' ;
71+ if (! is_dir ($ debugDir )) {
72+ mkdir ($ debugDir , 0666 );
73+ }
74+ return $ debugDir . $ this ->getScreenshotName ($ identifier );
75+ }
76+
77+ private function getExpectedScreenshotPath ($ identifier )
78+ {
79+ return $ this ->referenceImageDir . $ this ->getScreenshotName ($ identifier );
80+ }
81+
82+ private function createScreenshot ($ identifier , $ coords )
83+ {
84+ $ webDriverModule = $ this ->getModule ("WebDriver " );
85+ $ webDriver = $ webDriverModule ->webDriver ;
86+
87+ $ screenshotPath = \Codeception \Configuration::logDir () . 'debug/ ' . "fullscreenshot.tmp.png " ;
88+ $ elementPath = $ this ->getScreenshotPath ($ identifier );
89+
90+ $ webDriver ->takeScreenshot ($ screenshotPath );
91+
92+ $ screenshotImage = imagecreatefrompng ($ screenshotPath );
93+ $ elementImage =\imagecreatetruecolor ($ coords ['width ' ], $ coords ['height ' ]);
94+
95+ list ($ current_width , $ current_height ) =\getimagesize ($ screenshotPath );
96+ imagecopy ($ elementImage , $ screenshotImage , 0 , 0 , $ coords ['offset_x ' ], $ coords ['offset_y ' ], $ current_width , $ current_height );
97+
98+ $ result =\imagepng ($ elementImage , $ elementPath , 0 );
99+
100+ unlink ($ screenshotPath );
101+
102+ return $ elementPath ;
103+ }
104+
105+ public function compareScreenshot ($ identifier , $ elementID = null )
106+ {
107+ $ coords = $ this ->getCoordinates ($ elementID );
108+ $ currentImagePath = $ this ->createScreenshot ($ identifier , $ coords );
109+
110+ $ compareResult = $ this ->compare ($ identifier );
111+
112+ unlink ($ this ->getScreenshotPath ($ identifier ));
113+
114+ $ this ->debug ($ compareResult );
115+
116+ $ deviation = round ($ compareResult [1 ] * 100 , 2 );
117+
118+ if ($ deviation > $ this ->maximumDeviation ) {
119+ $ compareScreenshotPath = $ this ->getDeviationScreenshotPath ($ identifier );
120+ $ compareResult [0 ]->writeImage ($ compareScreenshotPath );
121+ $ this ->assertTrue (false , "The deviation of the taken screenshot is too high ( " .$ deviation ."%). \nSee $ compareScreenshotPath for a deviation screenshot. " );
122+ }
123+ }
124+
125+ private function getDeviationScreenshotPath ($ identifier )
126+ {
127+ $ debugDir = \Codeception \Configuration::logDir () . 'debug/ ' ;
128+ return $ debugDir . 'compare. ' . $ this ->getScreenshotName ($ identifier );
129+ }
130+
131+ private function compare ($ identifier )
132+ {
133+ $ currentImagePath = $ this ->getScreenshotPath ($ identifier );
134+ $ expectedImagePath = $ this ->getExpectedScreenshotPath ($ identifier );
135+
136+ if (! file_exists ($ expectedImagePath )) {
137+ copy ($ currentImagePath , $ expectedImagePath );
138+ return array (null , 0 );
139+ } else {
140+ return $ this ->compareImages ($ expectedImagePath , $ currentImagePath );
141+ }
142+ }
143+
144+ private function compareImages ($ image1 , $ image2 )
145+ {
146+ $ imagick1 = new \Imagick ($ image1 );
147+ $ imagick2 = new \Imagick ($ image2 );
148+
149+ $ result = $ imagick1 ->compareImages ($ imagick2 , \Imagick::METRIC_MEANSQUAREERROR );
150+ $ result [0 ]->setImageFormat ("png " );
151+
152+ $ this ->debug ($ result );
153+
154+ return $ result ;
155+ }
156+ }
0 commit comments