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