Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
#1799 implement full-size screenshots as a separate Selenide plugin
- Loading branch information
Showing
10 changed files
with
270 additions
and
0 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,14 @@ | ||
ext { | ||
artifactId = 'selenide-full-screenshot' | ||
} | ||
|
||
dependencies { | ||
api project(":statics") | ||
testImplementation project(':statics').sourceSets.test.output | ||
testImplementation project(':modules:core').sourceSets.test.output | ||
testImplementation("org.junit.jupiter:junit-jupiter-api:$junitVersion") | ||
testImplementation("org.junit.jupiter:junit-jupiter-engine:$junitVersion") | ||
testImplementation("org.junit.platform:junit-platform-suite-engine:1.8.2") | ||
} | ||
|
||
apply from: rootProject.file('gradle/publish-module.gradle') |
112 changes: 112 additions & 0 deletions
112
...-screenshot/src/main/java/com/codeborne/selenide/fullscreenshot/FullSizePhotographer.java
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,112 @@ | ||
package com.codeborne.selenide.fullscreenshot; | ||
|
||
import com.codeborne.selenide.Driver; | ||
import com.codeborne.selenide.impl.JavaScript; | ||
import com.codeborne.selenide.impl.Photographer; | ||
import com.codeborne.selenide.impl.WebdriverPhotographer; | ||
import com.github.bsideup.jabel.Desugar; | ||
import com.google.common.collect.ImmutableMap; | ||
import org.openqa.selenium.OutputType; | ||
import org.openqa.selenium.WebDriver; | ||
import org.openqa.selenium.WrapsDriver; | ||
import org.openqa.selenium.chromium.HasCdp; | ||
import org.openqa.selenium.devtools.DevTools; | ||
import org.openqa.selenium.devtools.HasDevTools; | ||
import org.openqa.selenium.devtools.v101.page.Page; | ||
import org.openqa.selenium.devtools.v101.page.model.Viewport; | ||
import org.openqa.selenium.firefox.HasFullPageScreenshot; | ||
import org.openqa.selenium.remote.Augmenter; | ||
import org.openqa.selenium.remote.RemoteWebDriver; | ||
|
||
import javax.annotation.CheckReturnValue; | ||
import javax.annotation.Nonnull; | ||
import javax.annotation.ParametersAreNonnullByDefault; | ||
import java.util.Map; | ||
import java.util.Optional; | ||
|
||
/** | ||
* Implementation of {@link Photographer} which can take full-size screenshots. | ||
* @since 6.7.0 | ||
*/ | ||
@ParametersAreNonnullByDefault | ||
public class FullSizePhotographer implements Photographer { | ||
private static final JavaScript js = new JavaScript("get-screen-size.js"); | ||
|
||
private final WebdriverPhotographer defaultImplementation; | ||
|
||
public FullSizePhotographer() { | ||
this(new WebdriverPhotographer()); | ||
} | ||
|
||
protected FullSizePhotographer(WebdriverPhotographer defaultImplementation) { | ||
this.defaultImplementation = defaultImplementation; | ||
} | ||
|
||
@Nonnull | ||
@Override | ||
@CheckReturnValue | ||
public <T> Optional<T> takeScreenshot(Driver driver, OutputType<T> outputType) { | ||
WebDriver wd = driver.getWebDriver(); | ||
if (wd instanceof WrapsDriver) { | ||
wd = ((WrapsDriver) wd).getWrappedDriver(); | ||
} | ||
if (wd instanceof HasFullPageScreenshot webDriver) { | ||
return Optional.of(webDriver.getFullPageScreenshotAs(outputType)); | ||
} | ||
if (wd instanceof HasCdp cdp) { | ||
Options options = getOptions(wd); | ||
Map<String, Object> captureScreenshotOptions = ImmutableMap.of( | ||
"clip", ImmutableMap.of( | ||
"x", 0, | ||
"y", 0, | ||
"width", options.fullWidth(), | ||
"height", options.fullHeight(), | ||
"scale", 1), | ||
"captureBeyondViewport", options.exceedViewport() | ||
); | ||
|
||
Map<String, Object> result = cdp.executeCdpCommand("Page.captureScreenshot", captureScreenshotOptions); | ||
|
||
String base64 = (String) result.get("data"); | ||
T screenshot = outputType.convertFromBase64Png(base64); | ||
return Optional.of(screenshot); | ||
} | ||
|
||
if (wd instanceof RemoteWebDriver remoteWebDriver) { | ||
WebDriver webDriver = new Augmenter().augment(remoteWebDriver); | ||
if (webDriver instanceof HasFullPageScreenshot smartWebDriver) { | ||
return Optional.of(smartWebDriver.getFullPageScreenshotAs(outputType)); | ||
} | ||
if (!(webDriver instanceof HasDevTools)) { | ||
return defaultImplementation.takeScreenshot(driver, outputType); | ||
} | ||
DevTools devTools = ((HasDevTools) webDriver).getDevTools(); | ||
devTools.createSession(); | ||
|
||
Options options = getOptions(remoteWebDriver); | ||
Viewport viewport = new Viewport(0, 0, options.fullWidth(), options.fullHeight(), 1); | ||
|
||
String base64 = devTools.send(Page.captureScreenshot( | ||
Optional.empty(), | ||
Optional.empty(), | ||
Optional.of(viewport), | ||
Optional.empty(), | ||
Optional.of(options.exceedViewport()) | ||
) | ||
); | ||
|
||
T screenshot = outputType.convertFromBase64Png(base64); | ||
return Optional.of(screenshot); | ||
} | ||
return Optional.empty(); | ||
} | ||
|
||
private Options getOptions(WebDriver webDriver) { | ||
Map<String, Object> size = js.execute(webDriver); | ||
return new Options((long) size.get("fullWidth"), (long) size.get("fullHeight"), (boolean) size.get("exceedViewport")); | ||
} | ||
|
||
@Desugar | ||
private record Options(long fullWidth, long fullHeight, boolean exceedViewport) { | ||
} | ||
} |
8 changes: 8 additions & 0 deletions
8
...les/full-screenshot/src/main/java/com/codeborne/selenide/fullscreenshot/package-info.java
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,8 @@ | ||
/** | ||
* Selenide plugin for taking full-size screenshots. | ||
* <p> | ||
* These screenshots cover the whole browser window which might be bigger than the area currently visible on the screen. | ||
* </p> | ||
* @since 6.7.0 | ||
*/ | ||
package com.codeborne.selenide.fullscreenshot; |
1 change: 1 addition & 0 deletions
1
...-screenshot/src/main/resources/META-INF/services/com.codeborne.selenide.impl.Photographer
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1 @@ | ||
com.codeborne.selenide.fullscreenshot.FullSizePhotographer |
8 changes: 8 additions & 0 deletions
8
modules/full-screenshot/src/main/resources/get-screen-size.js
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,8 @@ | ||
(() => { | ||
const fullWidth = Math.max(document.body.scrollWidth, document.documentElement.scrollWidth, document.body.offsetWidth, document.documentElement.offsetWidth, document.body.clientWidth, document.documentElement.clientWidth); | ||
const fullHeight = Math.max(document.body.scrollHeight, document.documentElement.scrollHeight, document.body.offsetHeight, document.documentElement.offsetHeight, document.body.clientHeight, document.documentElement.clientHeight); | ||
const viewWidth = window.innerWidth; | ||
const viewHeight = window.innerHeight; | ||
const exceedViewport = fullWidth > viewWidth || fullHeight > viewHeight; | ||
return {fullWidth, fullHeight, exceedViewport}; | ||
})() |
13 changes: 13 additions & 0 deletions
13
...screenshot/src/test/java/integration/ExistingScreenshotTestsWithFullSizePhotographer.java
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,13 @@ | ||
package integration; | ||
|
||
import org.junit.platform.suite.api.SelectClasses; | ||
import org.junit.platform.suite.api.Suite; | ||
|
||
@Suite | ||
@SelectClasses({ | ||
ScreenshotsTest.class, | ||
ScreenshotTest.class, | ||
ScreenshotInIframeTest.class | ||
}) | ||
public class ExistingScreenshotTestsWithFullSizePhotographer { | ||
} |
32 changes: 32 additions & 0 deletions
32
modules/full-screenshot/src/test/java/integration/ScreenshotTestHelper.java
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,32 @@ | ||
package integration; | ||
|
||
import org.slf4j.Logger; | ||
import org.slf4j.LoggerFactory; | ||
|
||
import javax.imageio.ImageIO; | ||
import java.awt.image.BufferedImage; | ||
import java.io.File; | ||
import java.io.IOException; | ||
|
||
import static org.assertj.core.api.Assertions.assertThat; | ||
|
||
public class ScreenshotTestHelper { | ||
private static final Logger log = LoggerFactory.getLogger(ScreenshotTestHelper.class); | ||
|
||
static void verifyScreenshotSize(File screenshot, int width, int height) throws IOException { | ||
BufferedImage img = ImageIO.read(screenshot); | ||
log.info("Verify screenshot {} of size {}x{}", screenshot.getAbsolutePath(), img.getWidth(), img.getHeight()); | ||
if (nearlyEqual(img.getWidth(), width * 2) && nearlyEqual(img.getHeight(), height * 2)) { | ||
// it's Retina display, it has 2x more pixels | ||
log.info("Screenshot matches {}x{} on Retina display", width, height); | ||
} | ||
else { | ||
assertThat(img.getWidth()).isBetween(width - 50, width + 50); | ||
assertThat(img.getHeight()).isBetween(height - 50, height + 50); | ||
} | ||
} | ||
|
||
private static boolean nearlyEqual(int actual, int expected) { | ||
return actual > expected - 50 && actual < expected + 50; | ||
} | ||
} |
59 changes: 59 additions & 0 deletions
59
modules/full-screenshot/src/test/java/integration/ScreenshotsWithWebdriverListenersTest.java
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,59 @@ | ||
package integration; | ||
|
||
import com.codeborne.selenide.Configuration; | ||
import com.codeborne.selenide.Selenide; | ||
import com.codeborne.selenide.WebDriverRunner; | ||
import org.junit.jupiter.api.AfterEach; | ||
import org.junit.jupiter.api.BeforeEach; | ||
import org.junit.jupiter.api.Test; | ||
import org.openqa.selenium.OutputType; | ||
import org.openqa.selenium.support.events.AbstractWebDriverEventListener; | ||
import org.openqa.selenium.support.events.WebDriverListener; | ||
|
||
import java.io.File; | ||
import java.io.IOException; | ||
|
||
import static integration.ScreenshotTestHelper.verifyScreenshotSize; | ||
|
||
@SuppressWarnings("deprecation") | ||
public class ScreenshotsWithWebdriverListenersTest extends IntegrationTest { | ||
private final DeprecatedListener deprecatedListener = new DeprecatedListener(); | ||
private final Selenium4Listener listener = new Selenium4Listener(); | ||
private final int width = 2200; | ||
private final int height = 3300; | ||
|
||
@AfterEach | ||
@BeforeEach | ||
void tearDown() { | ||
WebDriverRunner.removeListener(listener); | ||
WebDriverRunner.removeListener(deprecatedListener); | ||
Selenide.closeWebDriver(); | ||
Configuration.browserSize = "400x300"; | ||
} | ||
|
||
@Test | ||
void canTakeFullScreenshotWithSelenium4Listeners() throws IOException { | ||
WebDriverRunner.addListener(listener); | ||
openFile("page_of_fixed_size_2200x3300.html"); | ||
|
||
File screenshot = Selenide.screenshot(OutputType.FILE); | ||
|
||
verifyScreenshotSize(screenshot, width, height); | ||
} | ||
|
||
@Test | ||
void canTakeFullScreenshotWithSelenium3Listeners() throws IOException { | ||
WebDriverRunner.addListener(deprecatedListener); | ||
openFile("page_of_fixed_size_2200x3300.html"); | ||
|
||
File screenshot = Selenide.screenshot(OutputType.FILE); | ||
|
||
verifyScreenshotSize(screenshot, width, height); | ||
} | ||
|
||
public static class Selenium4Listener implements WebDriverListener { | ||
} | ||
|
||
public static class DeprecatedListener extends AbstractWebDriverEventListener { | ||
} | ||
} |
22 changes: 22 additions & 0 deletions
22
modules/full-screenshot/src/test/resources/page_of_fixed_size_2200x3300.html
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,22 @@ | ||
<!DOCTYPE html> | ||
<html lang="en"> | ||
<head> | ||
<title>Test::page of fixed size 2200x3300</title> | ||
<meta charset="UTF-8"> | ||
<meta http-equiv="Content-Type" content="text/html; charset=utf-8"/> | ||
<style> | ||
#the_div { | ||
text-align: center; | ||
border: red 3px solid; | ||
width: 2200px; | ||
height: 3300px; | ||
background: #0ff; | ||
} | ||
</style> | ||
</head> | ||
<body> | ||
<div id="the_div"> | ||
This should be a div of size 2222x3333 | ||
</div> | ||
</body> | ||
</html> |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters