feat: implement {Page,ElementHandle}.screenshot methods (#36)
This commit is contained in:
@@ -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");
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user