6
6
package com .assertthat .selenium_shutterbug .utils .web ;
7
7
8
8
import com .assertthat .selenium_shutterbug .utils .file .FileUtil ;
9
+ import com .github .zafarkhaja .semver .Version ;
9
10
import com .google .common .collect .ImmutableMap ;
10
11
import org .openqa .selenium .Dimension ;
11
12
import org .openqa .selenium .JavascriptExecutor ;
15
16
import org .openqa .selenium .WebDriver ;
16
17
import org .openqa .selenium .WebElement ;
17
18
import org .openqa .selenium .chrome .ChromeDriver ;
19
+ import org .openqa .selenium .firefox .FirefoxDriver ;
18
20
import org .openqa .selenium .remote .CommandInfo ;
19
21
import org .openqa .selenium .remote .HttpCommandExecutor ;
20
22
import org .openqa .selenium .remote .RemoteWebDriver ;
@@ -112,9 +114,13 @@ public BufferedImage takeScreenshotEntirePage() {
112
114
113
115
if (driver instanceof ChromeDriver ) {
114
116
return takeScreenshotEntirePageUsingChromeCommand ();
117
+ } else if (driver instanceof FirefoxDriver ) {
118
+ return takeScreenshotEntirePageUsingGeckoDriver ();
115
119
} else if (driver instanceof RemoteWebDriver ) {
116
120
if (((RemoteWebDriver ) driver ).getCapabilities ().getBrowserName ().equals ("chrome" )) {
117
121
return takeScreenshotEntirePageUsingChromeCommand ();
122
+ } else if (((RemoteWebDriver ) driver ).getCapabilities ().getBrowserName ().equals ("firefox" )) {
123
+ return takeScreenshotEntirePageUsingGeckoDriver ();
118
124
}
119
125
}
120
126
return takeScreenshotEntirePageDefault ();
@@ -158,14 +164,7 @@ public BufferedImage takeScreenshotEntirePageUsingChromeCommand() {
158
164
Object devicePixelRatio = executeJsScript (DEVICE_PIXEL_RATIO );
159
165
this .devicePixelRatio = devicePixelRatio instanceof Double ? (Double ) devicePixelRatio : (Long ) devicePixelRatio * 1.0 ;
160
166
161
- try {
162
- CommandInfo cmd = new CommandInfo ("/session/:sessionId/chromium/send_command_and_get_result" , HttpMethod .POST );
163
- Method defineCommand = HttpCommandExecutor .class .getDeclaredMethod ("defineCommand" , String .class , CommandInfo .class );
164
- defineCommand .setAccessible (true );
165
- defineCommand .invoke (((RemoteWebDriver ) this .driver ).getCommandExecutor (), "sendCommand" , cmd );
166
- } catch (InvocationTargetException | IllegalAccessException | NoSuchMethodException e ) {
167
- throw new RuntimeException (e );
168
- }
167
+ defineCustomCommand ("sendCommand" , new CommandInfo ("/session/:sessionId/chromium/send_command_and_get_result" , HttpMethod .POST ));
169
168
170
169
int verticalIterations = (int ) Math .ceil (((double ) this .getDocHeight ()) / this .getViewportHeight ());
171
170
for (int j = 0 ; j < verticalIterations ; j ++) {
@@ -176,15 +175,27 @@ public BufferedImage takeScreenshotEntirePageUsingChromeCommand() {
176
175
this .sendCommand ("Emulation.setDeviceMetricsOverride" , metrics );
177
176
Object result = this .sendCommand ("Page.captureScreenshot" , ImmutableMap .of ("format" , "png" , "fromSurface" , true ));
178
177
this .sendCommand ("Emulation.clearDeviceMetricsOverride" , ImmutableMap .of ());
179
- String base64EncodedPng = (String ) ((Map <String , ?>) result ).get ("data" );
180
- InputStream in = new ByteArrayInputStream (OutputType .BYTES .convertFromBase64Png (base64EncodedPng ));
181
- BufferedImage bImageFromConvert ;
182
- try {
183
- bImageFromConvert = ImageIO .read (in );
184
- } catch (IOException e ) {
185
- throw new RuntimeException ("Error while converting results from bytes to BufferedImage" );
178
+ return decodeBase64EncodedPng ((String ) ((Map <String , ?>) result ).get ("data" ));
179
+ }
180
+
181
+ public BufferedImage takeScreenshotEntirePageUsingGeckoDriver () {
182
+ // Check geckodriver version (>= 0.24.0 is requried)
183
+ String version = (String ) ((RemoteWebDriver ) driver ).getCapabilities ().getCapability ("moz:geckodriverVersion" );
184
+ if (version == null || Version .valueOf (version ).satisfies (">=0.24.0" )) {
185
+ return takeScreenshotEntirePageDefault ();
186
186
}
187
- return bImageFromConvert ;
187
+ defineCustomCommand ("mozFullPageScreenshot" , new CommandInfo ("/session/:sessionId/moz/screenshot/full" , HttpMethod .GET ));
188
+ Object result = this .executeCustomCommand ("mozFullPageScreenshot" );
189
+ String base64EncodedPng ;
190
+ if (result instanceof String ) {
191
+ base64EncodedPng = (String ) result ;
192
+ } else if (result instanceof byte []) {
193
+ base64EncodedPng = new String ((byte []) result );
194
+ } else {
195
+ throw new RuntimeException (String .format ("Unexpected result for /moz/screenshot/full command: %s" ,
196
+ result == null ? "null" : result .getClass ().getName () + "instance" ));
197
+ }
198
+ return decodeBase64EncodedPng (base64EncodedPng );
188
199
}
189
200
190
201
public WebDriver getUnderlyingDriver () {
@@ -258,4 +269,36 @@ public Object evaluate(String script) {
258
269
Object result = ((Map <String , ?>) response ).get ("result" );
259
270
return ((Map <String , ?>) result ).get ("value" );
260
271
}
272
+
273
+ public Object executeCustomCommand (String commandName ) {
274
+ try {
275
+ Method execute = RemoteWebDriver .class .getDeclaredMethod ("execute" , String .class );
276
+ execute .setAccessible (true );
277
+ Response res = (Response ) execute .invoke (this .driver , commandName );
278
+ return res .getValue ();
279
+ } catch (NoSuchMethodException | InvocationTargetException | IllegalAccessException e ) {
280
+ throw new RuntimeException (e );
281
+ }
282
+ }
283
+
284
+ private void defineCustomCommand (String name , CommandInfo info ) {
285
+ try {
286
+ Method defineCommand = HttpCommandExecutor .class .getDeclaredMethod ("defineCommand" , String .class , CommandInfo .class );
287
+ defineCommand .setAccessible (true );
288
+ defineCommand .invoke (((RemoteWebDriver ) this .driver ).getCommandExecutor (), name , info );
289
+ } catch (InvocationTargetException | IllegalAccessException | NoSuchMethodException e ) {
290
+ throw new RuntimeException (e );
291
+ }
292
+ }
293
+
294
+ private BufferedImage decodeBase64EncodedPng (String base64EncodedPng ) {
295
+ InputStream in = new ByteArrayInputStream (OutputType .BYTES .convertFromBase64Png (base64EncodedPng ));
296
+ BufferedImage bImageFromConvert ;
297
+ try {
298
+ bImageFromConvert = ImageIO .read (in );
299
+ } catch (IOException e ) {
300
+ throw new RuntimeException ("Error while converting results from bytes to BufferedImage" );
301
+ }
302
+ return bImageFromConvert ;
303
+ }
261
304
}
0 commit comments