66package com .assertthat .selenium_shutterbug .utils .web ;
77
88import com .assertthat .selenium_shutterbug .utils .file .FileUtil ;
9+ import com .google .common .collect .ImmutableMap ;
910import org .openqa .selenium .Dimension ;
1011import org .openqa .selenium .*;
1112import org .openqa .selenium .Point ;
13+ import org .openqa .selenium .chrome .ChromeDriver ;
14+ import org .openqa .selenium .remote .CommandInfo ;
15+ import org .openqa .selenium .remote .HttpCommandExecutor ;
16+ import org .openqa .selenium .remote .RemoteWebDriver ;
17+ import org .openqa .selenium .remote .Response ;
18+ import org .openqa .selenium .remote .http .HttpMethod ;
1219
1320import javax .imageio .ImageIO ;
1421import java .awt .*;
1522import java .awt .image .BufferedImage ;
23+ import java .io .ByteArrayInputStream ;
1624import java .io .File ;
1725import java .io .IOException ;
26+ import java .io .InputStream ;
27+ import java .lang .reflect .InvocationTargetException ;
28+ import java .lang .reflect .Method ;
1829import java .util .ArrayList ;
19-
20- import static java .lang .Math .toIntExact ;
30+ import java .util .Map ;
2131
2232/**
2333 * Created by Glib_Briia on 17/06/2016.
@@ -34,6 +44,7 @@ public class Browser {
3444 public static final String CURRENT_SCROLL_Y_JS = "js/get-current-scrollY.js" ;
3545 public static final String CURRENT_SCROLL_X_JS = "js/get-current-scrollX.js" ;
3646 public static final String DEVICE_PIXEL_RATIO = "js/get-device-pixel-ratio.js" ;
47+ public static final String ALL_METRICS = "js/all-metrics.js" ;
3748
3849 private WebDriver driver ;
3950 private int docHeight = -1 ;
@@ -50,7 +61,14 @@ public Browser(WebDriver driver, boolean useDevicePixelRatio) {
5061 this .devicePixelRatio = devicePixelRatio instanceof Double ? (Double )devicePixelRatio : (Long )devicePixelRatio *1.0 ;
5162 }
5263 }
53-
64+ public Browser (ChromeDriver driver ) throws InvocationTargetException , IllegalAccessException , NoSuchMethodException {
65+ this .driver = driver ;
66+ CommandInfo cmd = new CommandInfo ("/session/:sessionId/chromium/send_command_and_get_result" , HttpMethod .POST );
67+ Method defineCommand = HttpCommandExecutor .class .getDeclaredMethod ("defineCommand" , String .class , CommandInfo .class );
68+ defineCommand .setAccessible (true );
69+ defineCommand .invoke (driver .getCommandExecutor (), "sendCommand" , cmd );
70+ }
71+
5472 public Double getDevicePixelRatio () {
5573 return devicePixelRatio ;
5674 }
@@ -79,7 +97,7 @@ public BufferedImage takeScreenshot() {
7997 srcFile .delete ();
8098 }
8199 }
82-
100+
83101 }
84102
85103 public BufferedImage takeScreenshotEntirePage () {
@@ -90,12 +108,12 @@ public BufferedImage takeScreenshotEntirePage() {
90108 int _viewportWidth = this .getViewportWidth ();
91109 int _viewportHeight = this .getViewportHeight ();
92110 final int scrollBarMaxWidth = 40 ; // this is probably too high, but better to be safe than sorry
93-
111+
94112 if (_viewportWidth < _docWidth || (_viewportHeight < _docHeight && _viewportWidth - scrollBarMaxWidth < _docWidth ))
95113 _viewportHeight -=scrollBarMaxWidth ; // some space for a scrollbar
96114 if (_viewportHeight < _docHeight )
97115 _viewportWidth -=scrollBarMaxWidth ; // some space for a scrollbar
98-
116+
99117 int horizontalIterations = (int ) Math .ceil (((double ) _docWidth ) / _viewportWidth );
100118 int verticalIterations = (int ) Math .ceil (((double ) _docHeight ) / _viewportHeight );
101119 outer_loop :
@@ -115,6 +133,36 @@ public BufferedImage takeScreenshotEntirePage() {
115133 return combinedImage ;
116134 }
117135
136+ public BufferedImage takeScreenshotEntirePageUsingChromeCommand () {
137+ if (!(this .driver instanceof ChromeDriver ))
138+ throw new UnsupportedOperationException ("You must use Chrome driver for this operation" );
139+
140+ Browser driver ;
141+ try {
142+ driver = new Browser ((ChromeDriver ) this .driver );
143+ } catch (InvocationTargetException | IllegalAccessException | NoSuchMethodException e ) {
144+ throw new RuntimeException (e );
145+ }
146+
147+ int verticalIterations = (int ) Math .ceil (((double ) this .getDocHeight ()) / this .getViewportHeight ());
148+ for (int j = 0 ; j < verticalIterations ; j ++) {
149+ this .scrollTo (0 , j * this .getViewportHeight ());
150+ wait (scrollTimeout );
151+ }
152+ Object metrics = driver .evaluate (FileUtil .getJsScript (ALL_METRICS ));
153+ driver .sendCommand ("Emulation.setDeviceMetricsOverride" , metrics );
154+ Object result = driver .sendCommand ("Page.captureScreenshot" , ImmutableMap .of ("format" , "png" , "fromSurface" , true ));
155+ String base64EncodedPng = (String ) ((Map <String , ?>) result ).get ("data" );
156+ InputStream in = new ByteArrayInputStream (OutputType .BYTES .convertFromBase64Png (base64EncodedPng ));
157+ BufferedImage bImageFromConvert ;
158+ try {
159+ bImageFromConvert = ImageIO .read (in );
160+ } catch (IOException e ) {
161+ throw new RuntimeException ("Error while converting results from bytes to BufferedImage" );
162+ }
163+ return bImageFromConvert ;
164+ }
165+
118166 public BufferedImage takeScreenshotScrollHorizontally () {
119167 BufferedImage combinedImage = new BufferedImage (this .getDocWidth (), this .getViewportHeight (), BufferedImage .TYPE_INT_ARGB );
120168 Graphics2D g = combinedImage .createGraphics ();
@@ -198,4 +246,21 @@ public Object executeJsScript(String filePath, Object... arg) {
198246 JavascriptExecutor js = (JavascriptExecutor ) driver ;
199247 return js .executeScript (script , arg );
200248 }
249+
250+ public Object sendCommand (String cmd , Object params ) {
251+ try {
252+ Method execute = RemoteWebDriver .class .getDeclaredMethod ("execute" , String .class , Map .class );
253+ execute .setAccessible (true );
254+ Response res = (Response ) execute .invoke (driver , "sendCommand" , ImmutableMap .of ("cmd" , cmd , "params" , params ));
255+ return res .getValue ();
256+ } catch (NoSuchMethodException | InvocationTargetException | IllegalAccessException e ) {
257+ throw new RuntimeException (e );
258+ }
259+ }
260+
261+ public Object evaluate (String script ) {
262+ Object response = sendCommand ("Runtime.evaluate" , ImmutableMap .of ("returnByValue" , true , "expression" , script ));
263+ Object result = ((Map <String , ?>) response ).get ("result" );
264+ return ((Map <String , ?>) result ).get ("value" );
265+ }
201266}
0 commit comments