1
0
mirror of synced 2026-08-05 06:56:56 +00:00

feat: implement {Page,ElementHandle}.screenshot methods (#36)

This commit is contained in:
Yury Semikhatsky
2020-10-22 22:41:34 -07:00
committed by GitHub
parent 7f8b2a9a10
commit 5f578aae41
14 changed files with 182 additions and 36 deletions
+5 -3
View File
@@ -15,16 +15,18 @@ package com.microsoft.playwright.example;
import com.microsoft.playwright.*;
import java.io.File;
public class Main {
public static void main(String[] args) {
Playwright playwright = Playwright.create();
Browser browser = playwright.chromium().launch(
new BrowserType.LaunchOptions().withHeadless(false));
Browser browser = playwright.chromium().launch();
BrowserContext context = browser.newContext(
new Browser.NewContextOptions().withViewport(800, 600));
Page page = context.newPage();
page.navigate("https://webkit.org", null);
page.navigate("https://webkit.org");
page.click("text=check feature status");
page.screenshot(new Page.ScreenshotOptions().withPath(new File("s.png")));
browser.close();
}
}
@@ -547,7 +547,7 @@ class Interface extends TypeDefinition {
if (jsonName.equals("Route")) {
output.add("import java.nio.charset.StandardCharsets;");
}
if (asList("Page", "Frame", "ElementHandle", "FileChooser").contains(jsonName)) {
if (asList("Page", "Frame", "ElementHandle", "FileChooser", "ChromiumBrowser", "Route").contains(jsonName)) {
output.add("import java.io.File;");
}
output.add("import java.util.*;");
@@ -94,6 +94,17 @@ class Types {
add("Mouse.up.options.button", "\"left\"|\"middle\"|\"right\"", "Button", new Empty());
add("BrowserType.launchPersistentContext.options.colorScheme", "\"dark\"|\"light\"|\"no-preference\"", "ColorScheme");
// File
add("Page.addScriptTag.options.path", "string", "File");
add("Page.addStyleTag.options.path", "string", "File");
add("Page.pdf.options.path", "string", "File");
add("Page.screenshot.options.path", "string", "File");
add("Frame.addScriptTag.options.path", "string", "File");
add("Frame.addStyleTag.options.path", "string", "File");
add("ElementHandle.screenshot.options.path", "string", "File");
add("Route.fulfill.response.path", "string", "File");
add("ChromiumBrowser.startTracing.options.path", "string", "File");
// Route
add("BrowserContext.route.handler", "function(Route, Request)", "BiConsumer<Route, Request>");
add("BrowserContext.unroute.handler", "function(Route, Request)", "BiConsumer<Route, Request>");
@@ -16,15 +16,16 @@
package com.microsoft.playwright;
import java.io.File;
import java.util.*;
public interface ChromiumBrowser extends Browser {
class StartTracingOptions {
public String path;
public File path;
public Boolean screenshots;
public List<String> categories;
public StartTracingOptions withPath(String path) {
public StartTracingOptions withPath(File path) {
this.path = path;
return this;
}
@@ -240,13 +240,13 @@ public interface ElementHandle extends JSHandle {
}
class ScreenshotOptions {
public enum Type { JPEG, PNG }
public String path;
public File path;
public Type type;
public Integer quality;
public Boolean omitBackground;
public Integer timeout;
public ScreenshotOptions withPath(String path) {
public ScreenshotOptions withPath(File path) {
this.path = path;
return this;
}
@@ -25,7 +25,7 @@ public interface Frame {
enum LoadState { DOMCONTENTLOADED, LOAD, NETWORKIDLE }
class AddScriptTagOptions {
public String url;
public String path;
public File path;
public String content;
public String type;
@@ -33,7 +33,7 @@ public interface Frame {
this.url = url;
return this;
}
public AddScriptTagOptions withPath(String path) {
public AddScriptTagOptions withPath(File path) {
this.path = path;
return this;
}
@@ -48,14 +48,14 @@ public interface Frame {
}
class AddStyleTagOptions {
public String url;
public String path;
public File path;
public String content;
public AddStyleTagOptions withUrl(String url) {
this.url = url;
return this;
}
public AddStyleTagOptions withPath(String path) {
public AddStyleTagOptions withPath(File path) {
this.path = path;
return this;
}
@@ -108,7 +108,7 @@ public interface Page {
}
class AddScriptTagOptions {
public String url;
public String path;
public File path;
public String content;
public String type;
@@ -116,7 +116,7 @@ public interface Page {
this.url = url;
return this;
}
public AddScriptTagOptions withPath(String path) {
public AddScriptTagOptions withPath(File path) {
this.path = path;
return this;
}
@@ -131,14 +131,14 @@ public interface Page {
}
class AddStyleTagOptions {
public String url;
public String path;
public File path;
public String content;
public AddStyleTagOptions withUrl(String url) {
this.url = url;
return this;
}
public AddStyleTagOptions withPath(String path) {
public AddStyleTagOptions withPath(File path) {
this.path = path;
return this;
}
@@ -476,7 +476,7 @@ public interface Page {
return this;
}
}
public String path;
public File path;
public Integer scale;
public Boolean displayHeaderFooter;
public String headerTemplate;
@@ -490,7 +490,7 @@ public interface Page {
public Margin margin;
public Boolean preferCSSPageSize;
public PdfOptions withPath(String path) {
public PdfOptions withPath(File path) {
this.path = path;
return this;
}
@@ -605,7 +605,7 @@ public interface Page {
return this;
}
}
public String path;
public File path;
public Type type;
public Integer quality;
public Boolean fullPage;
@@ -613,7 +613,7 @@ public interface Page {
public Boolean omitBackground;
public Integer timeout;
public ScreenshotOptions withPath(String path) {
public ScreenshotOptions withPath(File path) {
this.path = path;
return this;
}
@@ -17,6 +17,7 @@
package com.microsoft.playwright;
import java.nio.charset.StandardCharsets;
import java.io.File;
import java.util.*;
public interface Route {
@@ -47,7 +48,7 @@ public interface Route {
public Map<String, String> headers;
public String contentType;
public String body;
public String path;
public File path;
public FulfillResponse withStatus(Integer status) {
this.status = status;
@@ -65,7 +66,7 @@ public interface Route {
this.body = body;
return this;
}
public FulfillResponse withPath(String path) {
public FulfillResponse withPath(File path) {
this.path = path;
return this;
}
@@ -17,16 +17,18 @@ package com.microsoft.playwright.example;
import com.microsoft.playwright.*;
import java.io.File;
public class Main {
public static void main(String[] args) {
Playwright playwright = Playwright.create();
Browser browser = playwright.chromium().launch(
new BrowserType.LaunchOptions().withHeadless(false).withSlowMo(1000));
Browser browser = playwright.chromium().launch();
BrowserContext context = browser.newContext(
new Browser.NewContextOptions().withViewport(800, 600));
Page page = context.newPage();
page.navigate("https://webkit.org", null);
page.navigate("https://webkit.org");
page.click("text=check feature status");
page.screenshot(new Page.ScreenshotOptions().withPath(new File("s.png")));
browser.close();
}
}
@@ -20,13 +20,14 @@ import com.google.gson.Gson;
import com.google.gson.JsonArray;
import com.google.gson.JsonElement;
import com.google.gson.JsonObject;
import com.microsoft.playwright.Deferred;
import com.microsoft.playwright.ElementHandle;
import com.microsoft.playwright.FileChooser;
import com.microsoft.playwright.Frame;
import com.microsoft.playwright.*;
import java.io.DataOutputStream;
import java.io.File;
import java.io.FileOutputStream;
import java.io.IOException;
import java.util.ArrayList;
import java.util.Base64;
import java.util.List;
import static com.microsoft.playwright.impl.Serialization.deserialize;
@@ -232,9 +233,38 @@ class ElementHandleImpl extends JSHandleImpl implements ElementHandle {
sendMessage("press", params);
}
private static String toProtocol(ScreenshotOptions.Type type) {
return type.toString().toLowerCase();
}
@Override
public byte[] screenshot(ScreenshotOptions options) {
return new byte[0];
if (options == null) {
options = new ScreenshotOptions();
}
if (options.type == null) {
options.type = ScreenshotOptions.Type.PNG;
if (options.path != null) {
int extStart = options.path.getName().lastIndexOf('.');
if (extStart != -1) {
String extension = options.path.getName().substring(extStart).toLowerCase();
if (".jpeg".equals(extension) || ".jpg".equals(extension)) {
options.type = ScreenshotOptions.Type.JPEG;
}
}
}
}
JsonObject params = new Gson().toJsonTree(options).getAsJsonObject();
params.remove("type");
params.addProperty("type", toProtocol(options.type));
params.remove("path");
JsonObject json = sendMessage("screenshot", params).getAsJsonObject();
byte[] buffer = Base64.getDecoder().decode(json.get("binary").getAsString());
if (options.path != null) {
Utils.writeToFile(buffer, options.path);
}
return buffer;
}
@Override
@@ -143,12 +143,12 @@ public class FrameImpl extends ChannelOwner implements Frame {
params.remove("path");
byte[] encoded = new byte[0];
try {
encoded = Files.readAllBytes(Paths.get(options.path));
encoded = Files.readAllBytes(options.path.toPath());
} catch (IOException e) {
throw new RuntimeException("Failed to read from file", e);
}
String content = new String(encoded, StandardCharsets.UTF_8);
content += "//# sourceURL=" + options.path.replace("\n", "");
content += "//# sourceURL=" + options.path.getPath().replace("\n", "");
params.addProperty("content", content);
}
JsonElement json = sendMessage("addScriptTag", params);
@@ -165,12 +165,12 @@ public class FrameImpl extends ChannelOwner implements Frame {
params.remove("path");
byte[] encoded = new byte[0];
try {
encoded = Files.readAllBytes(Paths.get(options.path));
encoded = Files.readAllBytes(options.path.toPath());
} catch (IOException e) {
throw new RuntimeException("Failed to read from file", e);
}
String content = new String(encoded, StandardCharsets.UTF_8);
content += "/*# sourceURL=" + options.path.replace("\n", "") + "*/";
content += "/*# sourceURL=" + options.path.getPath().replace("\n", "") + "*/";
params.addProperty("content", content);
}
JsonElement json = sendMessage("addStyleTag", params);
@@ -21,7 +21,7 @@ import com.google.gson.JsonArray;
import com.google.gson.JsonObject;
import com.microsoft.playwright.*;
import java.io.File;
import java.io.*;
import java.nio.file.Watchable;
import java.util.*;
import java.util.function.BiConsumer;
@@ -535,9 +535,38 @@ public class PageImpl extends ChannelOwner implements Page {
}
}
private static String toProtocol(ScreenshotOptions.Type type) {
return type.toString().toLowerCase();
}
@Override
public byte[] screenshot(ScreenshotOptions options) {
return new byte[0];
if (options == null) {
options = new ScreenshotOptions();
}
if (options.type == null) {
options.type = ScreenshotOptions.Type.PNG;
if (options.path != null) {
int extStart = options.path.getName().lastIndexOf('.');
if (extStart != -1) {
String extension = options.path.getName().substring(extStart).toLowerCase();
if (".jpeg".equals(extension) || ".jpg".equals(extension)) {
options.type = ScreenshotOptions.Type.JPEG;
}
}
}
}
JsonObject params = new Gson().toJsonTree(options).getAsJsonObject();
params.remove("type");
params.addProperty("type", toProtocol(options.type));
params.remove("path");
JsonObject json = sendMessage("screenshot", params).getAsJsonObject();
byte[] buffer = Base64.getDecoder().decode(json.get("binary").getAsString());
if (options.path != null) {
Utils.writeToFile(buffer, options.path);
}
return buffer;
}
@Override
@@ -19,7 +19,9 @@ package com.microsoft.playwright.impl;
import com.google.gson.Gson;
import com.microsoft.playwright.FileChooser;
import java.io.DataOutputStream;
import java.io.File;
import java.io.FileOutputStream;
import java.io.IOException;
import java.nio.file.Files;
import java.util.*;
@@ -117,4 +119,20 @@ class Utils {
}
return payloads.toArray(new FileChooser.FilePayload[0]);
}
static void writeToFile(byte[] buffer, File path) {
File dir = path.getParentFile();
if (dir != null) {
if (!dir.exists()) {
if (!dir.mkdirs()) {
throw new RuntimeException("Failed to create parent directory: " + dir.getPath());
}
}
}
try (DataOutputStream out = new DataOutputStream(new FileOutputStream(path));) {
out.write(buffer);
} catch (IOException e) {
throw new RuntimeException("Failed to write to file", e);
}
}
}
@@ -0,0 +1,52 @@
/**
* Copyright (c) Microsoft Corporation.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package com.microsoft.playwright;
import org.junit.jupiter.api.Test;
import javax.imageio.ImageIO;
import java.awt.image.BufferedImage;
import java.io.ByteArrayInputStream;
import java.io.IOException;
import static org.junit.jupiter.api.Assertions.assertEquals;
// TODO: suite.skip(browserName === "firefox" && headful");
public class TestPageScreenshot extends TestBase {
@Test
void shouldWork() throws IOException {
page.setViewportSize(500, 500);
page.navigate(server.PREFIX + "/grid.html");
byte[] screenshot = page.screenshot();
BufferedImage image = ImageIO.read(new ByteArrayInputStream(screenshot));
assertEquals(500, image.getWidth());
assertEquals(500, image.getHeight());
// expect(screenshot).toMatchSnapshot("screenshot-sanity.png");
}
@Test
void shouldClipRect() throws IOException {
page.setViewportSize(500, 500);
page.navigate(server.PREFIX + "/grid.html");
byte[] screenshot = page.screenshot(new Page.ScreenshotOptions()
.setClip().withX(50).withY(100).withWidth(150).withHeight(100).done());
BufferedImage image = ImageIO.read(new ByteArrayInputStream(screenshot));
assertEquals(150, image.getWidth());
assertEquals(100, image.getHeight());
// expect(screenshot).toMatchSnapshot("screenshot-clip-rect.png");
}
}