Skip to content

Commit b490d2a

Browse files
committed
chore: make ScreencastFrame an interface in the playwright package
ScreencastFrame represents an event payload dispatched to the client, so model it like WebSocketFrame: a top-level interface in the com.microsoft.playwright package with accessor methods, and a hidden *Impl class in the impl package. Generator-side: when an Object inside a function arg carries a langAlias, register it as a CustomInterface (rather than a CustomClass of public fields) and write it to the playwright package directory. This is a breaking change to the screencast API introduced in 1.59: frame.data -> frame.data(), and the type now lives in com.microsoft.playwright instead of com.microsoft.playwright.options.
1 parent 00b588d commit b490d2a

5 files changed

Lines changed: 127 additions & 26 deletions

File tree

playwright/src/main/java/com/microsoft/playwright/options/ScreencastFrame.java renamed to playwright/src/main/java/com/microsoft/playwright/ScreencastFrame.java

Lines changed: 7 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -14,25 +14,21 @@
1414
* limitations under the License.
1515
*/
1616

17-
package com.microsoft.playwright.options;
17+
package com.microsoft.playwright;
1818

19-
public class ScreencastFrame {
19+
public interface ScreencastFrame {
2020
/**
2121
* JPEG-encoded frame data.
2222
*/
23-
public byte[] data;
23+
byte[] data();
24+
2425
/**
2526
* Width of the page viewport at the time the frame was captured.
2627
*/
27-
public int viewportWidth;
28+
int viewportWidth();
29+
2830
/**
2931
* Height of the page viewport at the time the frame was captured.
3032
*/
31-
public int viewportHeight;
32-
33-
public ScreencastFrame(byte[] data, int viewportWidth, int viewportHeight) {
34-
this.data = data;
35-
this.viewportWidth = viewportWidth;
36-
this.viewportHeight = viewportHeight;
37-
}
33+
int viewportHeight();
3834
}
Lines changed: 46 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,46 @@
1+
/*
2+
* Copyright (c) Microsoft Corporation.
3+
*
4+
* Licensed under the Apache License, Version 2.0 (the "License");
5+
* you may not use this file except in compliance with the License.
6+
* You may obtain a copy of the License at
7+
*
8+
* http://www.apache.org/licenses/LICENSE-2.0
9+
*
10+
* Unless required by applicable law or agreed to in writing, software
11+
* distributed under the License is distributed on an "AS IS" BASIS,
12+
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13+
* See the License for the specific language governing permissions and
14+
* limitations under the License.
15+
*/
16+
17+
package com.microsoft.playwright.impl;
18+
19+
import com.microsoft.playwright.ScreencastFrame;
20+
21+
class ScreencastFrameImpl implements ScreencastFrame {
22+
private final byte[] data;
23+
private final int viewportWidth;
24+
private final int viewportHeight;
25+
26+
ScreencastFrameImpl(byte[] data, int viewportWidth, int viewportHeight) {
27+
this.data = data;
28+
this.viewportWidth = viewportWidth;
29+
this.viewportHeight = viewportHeight;
30+
}
31+
32+
@Override
33+
public byte[] data() {
34+
return data;
35+
}
36+
37+
@Override
38+
public int viewportWidth() {
39+
return viewportWidth;
40+
}
41+
42+
@Override
43+
public int viewportHeight() {
44+
return viewportHeight;
45+
}
46+
}

playwright/src/main/java/com/microsoft/playwright/impl/ScreencastImpl.java

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -19,7 +19,7 @@
1919
import com.google.gson.JsonObject;
2020
import com.microsoft.playwright.PlaywrightException;
2121
import com.microsoft.playwright.Screencast;
22-
import com.microsoft.playwright.options.ScreencastFrame;
22+
import com.microsoft.playwright.ScreencastFrame;
2323

2424
import java.nio.file.Path;
2525
import java.util.function.Consumer;
@@ -46,7 +46,7 @@ void handleScreencastFrame(JsonObject params) {
4646
byte[] data = java.util.Base64.getDecoder().decode(dataBase64);
4747
int viewportWidth = params.get("viewportWidth").getAsInt();
4848
int viewportHeight = params.get("viewportHeight").getAsInt();
49-
onFrame.accept(new ScreencastFrame(data, viewportWidth, viewportHeight));
49+
onFrame.accept(new ScreencastFrameImpl(data, viewportWidth, viewportHeight));
5050
}
5151

5252
@Override

playwright/src/test/java/com/microsoft/playwright/TestScreencast.java

Lines changed: 5 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -16,7 +16,6 @@
1616

1717
package com.microsoft.playwright;
1818

19-
import com.microsoft.playwright.options.ScreencastFrame;
2019
import org.junit.jupiter.api.Test;
2120
import org.junit.jupiter.api.io.TempDir;
2221

@@ -113,9 +112,9 @@ void screencastStartShouldDeliverFramesViaOnFrame() throws Exception {
113112
assertFalse(frames.isEmpty(), "expected at least one frame");
114113
// JPEG-encoded frames start with FF D8.
115114
for (ScreencastFrame frame : frames) {
116-
assertNotNull(frame.data);
117-
assertEquals((byte) 0xFF, frame.data[0]);
118-
assertEquals((byte) 0xD8, frame.data[1]);
115+
assertNotNull(frame.data());
116+
assertEquals((byte) 0xFF, frame.data()[0]);
117+
assertEquals((byte) 0xD8, frame.data()[1]);
119118
}
120119
} finally {
121120
context.close();
@@ -135,8 +134,8 @@ void onFrameShouldReceiveViewportSize() {
135134
page.screencast().stop();
136135
assertFalse(frames.isEmpty(), "expected at least one frame");
137136
for (ScreencastFrame frame : frames) {
138-
assertEquals(1000, frame.viewportWidth);
139-
assertEquals(400, frame.viewportHeight);
137+
assertEquals(1000, frame.viewportWidth());
138+
assertEquals(400, frame.viewportHeight());
140139
}
141140
} finally {
142141
context.close();

tools/api-generator/src/main/java/com/microsoft/playwright/tools/ApiGenerator.java

Lines changed: 67 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -328,8 +328,16 @@ private void createClassesAndEnums(JsonObject jsonObject) {
328328
}
329329
if ("function".equals(jsonObject.get("name").getAsString()) && jsonObject.has("args")) {
330330
for (JsonElement item : jsonObject.getAsJsonArray("args")) {
331-
if (item.isJsonObject() && javaAlias(item.getAsJsonObject()) != null) {
332-
createClassesAndEnums(item.getAsJsonObject());
331+
if (!item.isJsonObject()) {
332+
continue;
333+
}
334+
JsonObject argObject = item.getAsJsonObject();
335+
if (!"Object".equals(argObject.get("name").getAsString())) {
336+
continue;
337+
}
338+
String alias = javaAlias(argObject);
339+
if (alias != null) {
340+
typeScope().createTopLevelInterface(alias, this, argObject);
333341
}
334342
}
335343
return;
@@ -609,6 +617,14 @@ void createTopLevelClass(String name, Element parent, JsonObject jsonObject) {
609617
}
610618
}
611619

620+
void createTopLevelInterface(String name, Element parent, JsonObject jsonObject) {
621+
Map<String, TypeDefinition> map = topLevelTypes();
622+
TypeDefinition existing = map.putIfAbsent(name, new CustomInterface(parent, name, jsonObject));
623+
if (existing != null && !(existing instanceof CustomInterface)) {
624+
throw new RuntimeException("Two interfaces with same name have different values:\n" + jsonObject + "\n" + existing.jsonElement);
625+
}
626+
}
627+
612628
void createNestedClass(String name, Element parent, JsonObject jsonObject) {
613629
for (CustomClass c : classes) {
614630
if (c.name.equals(name)) {
@@ -848,7 +864,7 @@ class Field extends Element {
848864
final String name;
849865
final TypeRef type;
850866

851-
Field(CustomClass parent, String name, JsonObject jsonElement) {
867+
Field(TypeDefinition parent, String name, JsonObject jsonElement) {
852868
super(parent, jsonElement);
853869
this.name = name;
854870
this.type = new TypeRef(this, jsonElement.getAsJsonObject().get("type"));
@@ -1159,6 +1175,43 @@ private void writeConstructor(List<String> output, String bodyOffset) {
11591175
}
11601176
}
11611177

1178+
class CustomInterface extends TypeDefinition {
1179+
final String name;
1180+
final List<Field> fields = new ArrayList<>();
1181+
1182+
CustomInterface(Element parent, String name, JsonObject jsonElement) {
1183+
super(parent, true, jsonElement);
1184+
this.name = name;
1185+
if (jsonElement.has("properties")) {
1186+
for (JsonElement item : jsonElement.getAsJsonArray("properties")) {
1187+
JsonObject propertyJson = item.getAsJsonObject();
1188+
fields.add(new Field(this, propertyJson.get("name").getAsString(), propertyJson));
1189+
}
1190+
}
1191+
}
1192+
1193+
@Override
1194+
String name() {
1195+
return name;
1196+
}
1197+
1198+
@Override
1199+
void writeTo(List<String> output, String offset) {
1200+
output.add(offset + "public interface " + name + " {");
1201+
String bodyOffset = offset + " ";
1202+
boolean first = true;
1203+
for (Field f : fields) {
1204+
if (!first) {
1205+
output.add("");
1206+
}
1207+
first = false;
1208+
writeJavadoc(output, bodyOffset, f.comment());
1209+
output.add(bodyOffset + f.type.toJava() + " " + f.name + "();");
1210+
}
1211+
output.add(offset + "}");
1212+
}
1213+
}
1214+
11621215
class Enum extends TypeDefinition {
11631216
final List<String> enumValues;
11641217

@@ -1207,18 +1260,25 @@ public class ApiGenerator {
12071260
System.out.println("Writing assertion files to: " + dir.getCanonicalPath());
12081261
generate(api, assertionsDir, "com.microsoft.playwright.assertions", isAssertion().and(isSoftAssertion().negate()), sharedTypes);
12091262

1210-
writeTopLevelTypes(sharedTypes, optionsDir, "com.microsoft.playwright");
1263+
writeTopLevelTypes(sharedTypes, dir, optionsDir, "com.microsoft.playwright");
12111264
}
12121265

1213-
private void writeTopLevelTypes(Map<String, TypeDefinition> topLevelTypes, File optionsDir, String packageName) throws IOException {
1266+
private void writeTopLevelTypes(Map<String, TypeDefinition> topLevelTypes, File dir, File optionsDir, String packageName) throws IOException {
12141267
for (TypeDefinition e : topLevelTypes.values()) {
12151268
List<String> lines = new ArrayList<>();
12161269
lines.add(Interface.header);
1217-
lines.add("package " + packageName + ".options;");
1270+
File targetDir;
1271+
if (e instanceof CustomInterface) {
1272+
lines.add("package " + packageName + ";");
1273+
targetDir = dir;
1274+
} else {
1275+
lines.add("package " + packageName + ".options;");
1276+
targetDir = optionsDir;
1277+
}
12181278
lines.add("");
12191279
e.writeTo(lines, "");
12201280
String text = String.join("\n", lines);
1221-
try (FileWriter writer = new FileWriter(new File(optionsDir, e.name() + ".java"))) {
1281+
try (FileWriter writer = new FileWriter(new File(targetDir, e.name() + ".java"))) {
12221282
writer.write(text);
12231283
}
12241284
}

0 commit comments

Comments
 (0)