Skip to content

Commit 2a6cdff

Browse files
authored
chore: migrate Trace Viewer tests to use real Trace viewer (#1830)
1 parent 44161e0 commit 2a6cdff

File tree

3 files changed

+279
-95
lines changed

3 files changed

+279
-95
lines changed

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

Lines changed: 11 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -23,6 +23,7 @@
2323
import java.util.*;
2424
import java.util.concurrent.CompletableFuture;
2525
import java.util.concurrent.Future;
26+
import java.util.function.Function;
2627
import java.util.zip.GZIPOutputStream;
2728

2829
import static com.microsoft.playwright.Utils.copy;
@@ -40,6 +41,7 @@ public class Server implements HttpHandler {
4041
private final Map<String, String> csp = Collections.synchronizedMap(new HashMap<>());
4142
private final Map<String, HttpHandler> routes = Collections.synchronizedMap(new HashMap<>());
4243
private final Set<String> gzipRoutes = Collections.synchronizedSet(new HashSet<>());
44+
private Function<String, InputStream> resourceProvider;
4345

4446
private static class Auth {
4547
public final String user;
@@ -75,6 +77,8 @@ private Server(int port, boolean https) throws IOException {
7577
server.createContext("/", this);
7678
server.setExecutor(null); // creates a default executor
7779
server.start();
80+
// Resources from "src/test/resources/" are copied to "resources/" directory in the jar.
81+
resourceProvider = path -> Server.class.getClassLoader().getResourceAsStream("resources" + path);
7882
}
7983

8084
public void stop() {
@@ -93,6 +97,10 @@ void enableGzip(String path) {
9397
gzipRoutes.add(path);
9498
}
9599

100+
void setResourceProvider(Function<String, InputStream> resourceProvider) {
101+
this.resourceProvider = resourceProvider;
102+
}
103+
96104
static class Request {
97105
public final String url;
98106
public final String method;
@@ -187,18 +195,16 @@ public void handle(HttpExchange exchange) throws IOException {
187195
path = "/index.html";
188196
}
189197

190-
// Resources from "src/test/resources/" are copied to "resources/" directory in the jar.
191-
String resourcePath = "resources" + path;
192-
InputStream resource = getClass().getClassLoader().getResourceAsStream(resourcePath);
198+
InputStream resource = resourceProvider.apply(path);
193199
if (resource == null) {
194200
exchange.getResponseHeaders().add("Content-Type", "text/plain");
195201
exchange.sendResponseHeaders(404, 0);
196202
try (Writer writer = new OutputStreamWriter(exchange.getResponseBody())) {
197-
writer.write("File not found: " + resourcePath);
203+
writer.write("File not found: " + path);
198204
}
199205
return;
200206
}
201-
exchange.getResponseHeaders().add("Content-Type", mimeType(new File(resourcePath)));
207+
exchange.getResponseHeaders().add("Content-Type", mimeType(new File(path)));
202208
ByteArrayOutputStream body = new ByteArrayOutputStream();
203209
OutputStream output = body;
204210
if (gzipRoutes.contains(path)) {

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

Lines changed: 149 additions & 90 deletions
Original file line numberDiff line numberDiff line change
@@ -16,8 +16,6 @@
1616

1717
package com.microsoft.playwright;
1818

19-
import com.google.gson.Gson;
20-
import com.google.gson.annotations.SerializedName;
2119
import com.microsoft.playwright.options.AriaRole;
2220
import com.microsoft.playwright.options.Location;
2321
import com.microsoft.playwright.options.MouseButton;
@@ -27,18 +25,12 @@
2725
import org.junit.jupiter.api.Test;
2826
import org.junit.jupiter.api.io.TempDir;
2927

30-
import java.io.File;
3128
import java.io.IOException;
3229
import java.nio.file.Files;
3330
import java.nio.file.Path;
34-
import java.nio.file.Paths;
35-
import java.util.Arrays;
36-
import java.util.List;
37-
import java.util.Map;
38-
import java.util.stream.Collectors;
39-
40-
import static java.nio.charset.StandardCharsets.UTF_8;
41-
import static java.util.Arrays.asList;
31+
import java.util.regex.Pattern;
32+
33+
import static com.microsoft.playwright.assertions.PlaywrightAssertions.assertThat;
4234
import static org.junit.jupiter.api.Assertions.*;
4335

4436
public class TestTracing extends TestBase {
@@ -57,7 +49,7 @@ void launchBrowser(@TempDir Path tempDir) {
5749
}
5850

5951
@Test
60-
void shouldCollectTrace1(@TempDir Path tempDir) {
52+
void shouldCollectTrace1(@TempDir Path tempDir) throws Exception {
6153
context.tracing().start(new Tracing.StartOptions().setName("test")
6254
.setScreenshots(true).setSnapshots(true));
6355
page.navigate(server.EMPTY_PAGE);
@@ -68,10 +60,18 @@ void shouldCollectTrace1(@TempDir Path tempDir) {
6860
context.tracing().stop(new Tracing.StopOptions().setPath(traceFile));
6961

7062
assertTrue(Files.exists(traceFile));
63+
TraceViewerPage.showTraceViewer(this.browserType, traceFile, traceViewer -> {
64+
assertThat(traceViewer.actionTitles()).hasText(new Pattern[] {
65+
Pattern.compile("Navigate to \"/empty.html\""),
66+
Pattern.compile("Set content"),
67+
Pattern.compile("Click"),
68+
Pattern.compile("Close")
69+
});
70+
});
7171
}
7272

7373
@Test
74-
void shouldCollectTwoTraces(@TempDir Path tempDir) {
74+
void shouldCollectTwoTraces(@TempDir Path tempDir) throws Exception {
7575
context.tracing().start(new Tracing.StartOptions().setName("test1")
7676
.setScreenshots(true).setSnapshots(true));
7777
page.navigate(server.EMPTY_PAGE);
@@ -89,10 +89,25 @@ void shouldCollectTwoTraces(@TempDir Path tempDir) {
8989

9090
assertTrue(Files.exists(traceFile1));
9191
assertTrue(Files.exists(traceFile2));
92+
93+
TraceViewerPage.showTraceViewer(this.browserType, traceFile1, traceViewer -> {
94+
assertThat(traceViewer.actionTitles()).hasText(new Pattern[] {
95+
Pattern.compile("Navigate to \"/empty.html\""),
96+
Pattern.compile("Set content"),
97+
Pattern.compile("Click")
98+
});
99+
});
100+
101+
TraceViewerPage.showTraceViewer(this.browserType, traceFile2, traceViewer -> {
102+
assertThat(traceViewer.actionTitles()).hasText(new Pattern[] {
103+
Pattern.compile("Double click"),
104+
Pattern.compile("Close")
105+
});
106+
});
92107
}
93108

94109
@Test
95-
void shouldWorkWithMultipleChunks(@TempDir Path tempDir) {
110+
void shouldWorkWithMultipleChunks(@TempDir Path tempDir) throws Exception {
96111
context.tracing().start(new Tracing.StartOptions().setScreenshots(true).setSnapshots(true));
97112
page.navigate(server.PREFIX + "/frames/frame.html");
98113

@@ -109,28 +124,60 @@ void shouldWorkWithMultipleChunks(@TempDir Path tempDir) {
109124

110125
assertTrue(Files.exists(traceFile1));
111126
assertTrue(Files.exists(traceFile2));
127+
128+
TraceViewerPage.showTraceViewer(this.browserType, traceFile1, traceViewer -> {
129+
assertThat(traceViewer.actionTitles()).hasText(new Pattern[] {
130+
Pattern.compile("Set content"),
131+
Pattern.compile("Click")
132+
});
133+
traceViewer.selectSnapshot("After");
134+
FrameLocator frame = traceViewer.snapshotFrame("Set content", 0, false);
135+
assertThat(frame.locator("button")).hasText("Click");
136+
});
137+
138+
TraceViewerPage.showTraceViewer(this.browserType, traceFile2, traceViewer -> {
139+
assertThat(traceViewer.actionTitles()).containsText(new String[] {"Hover"});
140+
FrameLocator frame = traceViewer.snapshotFrame("Hover", 0, false);
141+
assertThat(frame.locator("button")).hasText("Click");
142+
});
112143
}
113144

114145
@Test
115-
void shouldCollectSources(@TempDir Path tmpDir) throws IOException {
146+
void shouldCollectSources(@TempDir Path tmpDir) throws Exception {
116147
Assumptions.assumeTrue(System.getenv("PLAYWRIGHT_JAVA_SRC") != null, "PLAYWRIGHT_JAVA_SRC must point to the directory containing this test source.");
117148
context.tracing().start(new Tracing.StartOptions().setSources(true));
118149
page.navigate(server.EMPTY_PAGE);
119150
page.setContent("<button>Click</button>");
120-
page.click("'Click'");
151+
myMethodOuter();
121152
Path trace = tmpDir.resolve("trace1.zip");
122153
context.tracing().stop(new Tracing.StopOptions().setPath(trace));
123154

124-
Map<String, byte[]> entries = Utils.parseZip(trace);
125-
Map<String, byte[]> sources = entries.entrySet().stream().filter(e -> e.getKey().endsWith(".txt")).collect(Collectors.toMap(Map.Entry::getKey, Map.Entry::getValue));
126-
assertEquals(1, sources.size());
155+
TraceViewerPage.showTraceViewer(this.browserType, trace, traceViewer -> {
156+
assertThat(traceViewer.actionTitles()).hasText(new Pattern[] {
157+
Pattern.compile("Navigate to \"/empty.html\""),
158+
Pattern.compile("Set content"),
159+
Pattern.compile("Click")
160+
});
161+
traceViewer.showSourceTab();
162+
assertThat(traceViewer.stackFrames()).containsText(new Pattern[] {
163+
Pattern.compile("myMethodInner"),
164+
Pattern.compile("myMethodOuter"),
165+
Pattern.compile("shouldCollectSources")
166+
});
167+
traceViewer.selectAction("Set content");
168+
assertThat(traceViewer.page().locator(".source-tab-file-name"))
169+
.hasAttribute("title", Pattern.compile(".*TestTracing\\.java"));
170+
assertThat(traceViewer.page().locator(".source-line-running"))
171+
.containsText("page.setContent(\"<button>Click</button>\");");
172+
});
173+
}
174+
175+
private void myMethodOuter() {
176+
myMethodInner();
177+
}
127178

128-
String path = getClass().getName().replace('.', File.separatorChar);
129-
String[] srcRoots = System.getenv("PLAYWRIGHT_JAVA_SRC").split(File.pathSeparator);
130-
// Resolve in the last specified source dir.
131-
Path sourceFile = Paths.get(srcRoots[srcRoots.length - 1], path + ".java");
132-
byte[] thisFile = Files.readAllBytes(sourceFile);
133-
assertEquals(new String(thisFile, UTF_8), new String(sources.values().iterator().next(), UTF_8));
179+
private void myMethodInner() {
180+
page.getByText("Click").click();
134181
}
135182

136183
@Test
@@ -140,7 +187,7 @@ void shouldNotFailWhenSourcesSetExplicitlyToFalse() throws IOException {
140187
}
141188

142189
@Test
143-
void shouldRespectTracesDirAndName(@TempDir Path tempDir) {
190+
void shouldRespectTracesDirAndName(@TempDir Path tempDir) throws Exception {
144191
Path tracesDir = tempDir.resolve("trace-dir");
145192
BrowserType.LaunchOptions options = createLaunchOptions();
146193
options.setTracesDir(tracesDir);
@@ -159,6 +206,24 @@ void shouldRespectTracesDirAndName(@TempDir Path tempDir) {
159206
context.tracing().stop(new Tracing.StopOptions().setPath(tempDir.resolve("trace2.zip")));
160207
assertTrue(Files.exists(tracesDir.resolve("name2.trace")));
161208
assertTrue(Files.exists(tracesDir.resolve("name2.network")));
209+
210+
TraceViewerPage.showTraceViewer(this.browserType, tempDir.resolve("trace1.zip"), traceViewer -> {
211+
assertThat(traceViewer.actionTitles()).hasText(new Pattern[] {
212+
Pattern.compile("Navigate to \"/one-style.html\"")
213+
});
214+
FrameLocator frame = traceViewer.snapshotFrame("Navigate", 0, false);
215+
assertThat(frame.locator("body")).hasCSS("background-color", "rgb(255, 192, 203)");
216+
assertThat(frame.locator("body")).hasText("hello, world!");
217+
});
218+
219+
TraceViewerPage.showTraceViewer(this.browserType, tempDir.resolve("trace2.zip"), traceViewer -> {
220+
assertThat(traceViewer.actionTitles()).hasText(new Pattern[] {
221+
Pattern.compile("Navigate to \"/har.html\"")
222+
});
223+
FrameLocator frame = traceViewer.snapshotFrame("Navigate", 0, false);
224+
assertThat(frame.locator("body")).hasCSS("background-color", "rgb(255, 192, 203)");
225+
assertThat(frame.locator("body")).hasText("hello, world!");
226+
});
162227
}
163228
}
164229

@@ -179,11 +244,9 @@ void canCallTracingGroupGroupEndAtAnyTimeAndAutoClose(@TempDir Path tempDir) thr
179244
context.tracing().groupEnd();
180245
context.tracing().groupEnd();
181246

182-
List<TraceEvent> events = parseTraceEvents(traceFile1);
183-
List<TraceEvent> groups = events.stream().filter(e -> "tracingGroup".equals(e.method)).collect(Collectors.toList());
184-
assertEquals(1, groups.size());
185-
assertEquals("actual", groups.get(0).title);
186-
247+
TraceViewerPage.showTraceViewer(this.browserType, traceFile1, traceViewer -> {
248+
assertThat(traceViewer.actionTitles()).containsText(new String[] {"actual", "Navigate to \"/empty.html\""});
249+
});
187250
}
188251

189252
@Test
@@ -202,9 +265,16 @@ void traceGroupGroupEnd(@TempDir Path tempDir) throws Exception {
202265
Path traceFile1 = tempDir.resolve("trace1.zip");
203266
context.tracing().stop(new Tracing.StopOptions().setPath(traceFile1));
204267

205-
List<TraceEvent> events = parseTraceEvents(traceFile1);
206-
List<String> calls = events.stream().filter(e -> e.renderedTitle() != null).map(e -> e.renderedTitle()).collect(Collectors.toList());
207-
assertEquals(asList("outer group", "Frame.goto", "inner group 1", "Frame.click", "inner group 2", "Frame.isVisible"), calls);
268+
TraceViewerPage.showTraceViewer(this.browserType, traceFile1, traceViewer -> {
269+
traceViewer.expandAction("inner group 1");
270+
assertThat(traceViewer.actionTitles()).hasText(new Pattern[] {
271+
Pattern.compile("outer group"),
272+
Pattern.compile("Navigate to \"data:"),
273+
Pattern.compile("inner group 1"),
274+
Pattern.compile("Click"),
275+
Pattern.compile("inner group 2"),
276+
});
277+
});
208278
}
209279

210280
@Test
@@ -240,64 +310,53 @@ void shouldTraceVariousAPIs(@TempDir Path tempDir) throws Exception {
240310
Path traceFile1 = tempDir.resolve("trace1.zip");
241311
context.tracing().stop(new Tracing.StopOptions().setPath(traceFile1));
242312

243-
List<TraceEvent> events = parseTraceEvents(traceFile1);
244-
List<String> calls = events.stream().filter(e -> e.renderedTitle() != null).map(e -> e.renderedTitle())
245-
.collect(Collectors.toList());
246-
assertEquals(asList(
247-
"BrowserContext.clockInstall",
248-
"Frame.setContent",
249-
"Frame.click",
250-
"Frame.click",
251-
"Page.keyboardType",
252-
"Page.keyboardPress",
253-
"Page.keyboardDown",
254-
"Page.keyboardInsertText",
255-
"Page.keyboardUp",
256-
"Page.mouseMove",
257-
"Page.mouseDown",
258-
"Page.mouseMove",
259-
"Page.mouseWheel",
260-
"Page.mouseUp",
261-
"BrowserContext.clockFastForward",
262-
"BrowserContext.clockFastForward",
263-
"BrowserContext.clockPauseAt",
264-
"BrowserContext.clockRunFor",
265-
"BrowserContext.clockSetFixedTime",
266-
"BrowserContext.clockSetSystemTime",
267-
"BrowserContext.clockResume",
268-
"Frame.click"),
269-
calls);
313+
TraceViewerPage.showTraceViewer(this.browserType, traceFile1, traceViewer -> {
314+
assertThat(traceViewer.actionTitles()).hasText(new Pattern[] {
315+
Pattern.compile("Install clock"),
316+
Pattern.compile("Set content"),
317+
Pattern.compile("Click"),
318+
Pattern.compile("Click"),
319+
Pattern.compile("Type"),
320+
Pattern.compile("Press"),
321+
Pattern.compile("Key down"),
322+
Pattern.compile("Insert"),
323+
Pattern.compile("Key up"),
324+
Pattern.compile("Mouse move"),
325+
Pattern.compile("Mouse down"),
326+
Pattern.compile("Mouse move"),
327+
Pattern.compile("Mouse wheel"),
328+
Pattern.compile("Mouse up"),
329+
Pattern.compile("Fast forward clock"),
330+
Pattern.compile("Fast forward clock"),
331+
Pattern.compile("Pause clock"),
332+
Pattern.compile("Run clock"),
333+
Pattern.compile("Set fixed time"),
334+
Pattern.compile("Set system time"),
335+
Pattern.compile("Resume clock"),
336+
Pattern.compile("Click")
337+
});
338+
});
270339
}
271340

272-
private static class TraceEvent {
273-
String type;
274-
String name;
275-
String title;
276-
@SerializedName("class")
277-
String clazz;
278-
String method;
279-
Double startTime;
280-
Double endTime;
281-
String callId;
282-
283-
String renderedTitle() {
284-
if (title != null) {
285-
return title;
286-
}
287-
if (clazz != null && method != null) {
288-
return clazz + "." + method;
289-
}
290-
return null;
291-
}
292-
}
341+
@Test
342+
public void shouldNotRecordNetworkActions(@TempDir Path tempDir) throws Exception {
343+
context.tracing().start(new Tracing.StartOptions());
344+
345+
page.onRequest(request -> {
346+
request.allHeaders();
347+
});
348+
page.onResponse(response -> {
349+
response.text();
350+
});
351+
page.navigate(server.EMPTY_PAGE);
352+
353+
Path traceFile1 = tempDir.resolve("trace1.zip");
354+
context.tracing().stop(new Tracing.StopOptions().setPath(traceFile1));
293355

294-
private static List<TraceEvent> parseTraceEvents(Path traceFile) throws IOException {
295-
Map<String, byte[]> files = Utils.parseZip(traceFile);
296-
Map<String, byte[]> traces = files.entrySet().stream().filter(e -> e.getKey().endsWith(".trace")).collect(Collectors.toMap(Map.Entry::getKey, Map.Entry::getValue));
297-
assertNotNull(traces.get("trace.trace"));
298-
return Arrays.stream(new String(traces.get("trace.trace"), UTF_8)
299-
.split("\n"))
300-
.map(s -> new Gson().fromJson(s, TraceEvent.class))
301-
.collect(Collectors.toList());
356+
TraceViewerPage.showTraceViewer(this.browserType, traceFile1, traceViewer -> {
357+
assertThat(traceViewer.actionTitles()).hasText(new Pattern[] {
358+
Pattern.compile("Navigate to \"/empty.html\"")
359+
});
360+
});
302361
}
303362
}

0 commit comments

Comments
 (0)