16
16
17
17
package com .microsoft .playwright ;
18
18
19
- import com .google .gson .Gson ;
20
- import com .google .gson .annotations .SerializedName ;
21
19
import com .microsoft .playwright .options .AriaRole ;
22
20
import com .microsoft .playwright .options .Location ;
23
21
import com .microsoft .playwright .options .MouseButton ;
27
25
import org .junit .jupiter .api .Test ;
28
26
import org .junit .jupiter .api .io .TempDir ;
29
27
30
- import java .io .File ;
31
28
import java .io .IOException ;
32
29
import java .nio .file .Files ;
33
30
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 ;
42
34
import static org .junit .jupiter .api .Assertions .*;
43
35
44
36
public class TestTracing extends TestBase {
@@ -57,7 +49,7 @@ void launchBrowser(@TempDir Path tempDir) {
57
49
}
58
50
59
51
@ Test
60
- void shouldCollectTrace1 (@ TempDir Path tempDir ) {
52
+ void shouldCollectTrace1 (@ TempDir Path tempDir ) throws Exception {
61
53
context .tracing ().start (new Tracing .StartOptions ().setName ("test" )
62
54
.setScreenshots (true ).setSnapshots (true ));
63
55
page .navigate (server .EMPTY_PAGE );
@@ -68,10 +60,18 @@ void shouldCollectTrace1(@TempDir Path tempDir) {
68
60
context .tracing ().stop (new Tracing .StopOptions ().setPath (traceFile ));
69
61
70
62
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
+ });
71
71
}
72
72
73
73
@ Test
74
- void shouldCollectTwoTraces (@ TempDir Path tempDir ) {
74
+ void shouldCollectTwoTraces (@ TempDir Path tempDir ) throws Exception {
75
75
context .tracing ().start (new Tracing .StartOptions ().setName ("test1" )
76
76
.setScreenshots (true ).setSnapshots (true ));
77
77
page .navigate (server .EMPTY_PAGE );
@@ -89,10 +89,25 @@ void shouldCollectTwoTraces(@TempDir Path tempDir) {
89
89
90
90
assertTrue (Files .exists (traceFile1 ));
91
91
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
+ });
92
107
}
93
108
94
109
@ Test
95
- void shouldWorkWithMultipleChunks (@ TempDir Path tempDir ) {
110
+ void shouldWorkWithMultipleChunks (@ TempDir Path tempDir ) throws Exception {
96
111
context .tracing ().start (new Tracing .StartOptions ().setScreenshots (true ).setSnapshots (true ));
97
112
page .navigate (server .PREFIX + "/frames/frame.html" );
98
113
@@ -109,28 +124,60 @@ void shouldWorkWithMultipleChunks(@TempDir Path tempDir) {
109
124
110
125
assertTrue (Files .exists (traceFile1 ));
111
126
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
+ });
112
143
}
113
144
114
145
@ Test
115
- void shouldCollectSources (@ TempDir Path tmpDir ) throws IOException {
146
+ void shouldCollectSources (@ TempDir Path tmpDir ) throws Exception {
116
147
Assumptions .assumeTrue (System .getenv ("PLAYWRIGHT_JAVA_SRC" ) != null , "PLAYWRIGHT_JAVA_SRC must point to the directory containing this test source." );
117
148
context .tracing ().start (new Tracing .StartOptions ().setSources (true ));
118
149
page .navigate (server .EMPTY_PAGE );
119
150
page .setContent ("<button>Click</button>" );
120
- page . click ( "'Click'" );
151
+ myMethodOuter ( );
121
152
Path trace = tmpDir .resolve ("trace1.zip" );
122
153
context .tracing ().stop (new Tracing .StopOptions ().setPath (trace ));
123
154
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
+ }
127
178
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 ();
134
181
}
135
182
136
183
@ Test
@@ -140,7 +187,7 @@ void shouldNotFailWhenSourcesSetExplicitlyToFalse() throws IOException {
140
187
}
141
188
142
189
@ Test
143
- void shouldRespectTracesDirAndName (@ TempDir Path tempDir ) {
190
+ void shouldRespectTracesDirAndName (@ TempDir Path tempDir ) throws Exception {
144
191
Path tracesDir = tempDir .resolve ("trace-dir" );
145
192
BrowserType .LaunchOptions options = createLaunchOptions ();
146
193
options .setTracesDir (tracesDir );
@@ -159,6 +206,24 @@ void shouldRespectTracesDirAndName(@TempDir Path tempDir) {
159
206
context .tracing ().stop (new Tracing .StopOptions ().setPath (tempDir .resolve ("trace2.zip" )));
160
207
assertTrue (Files .exists (tracesDir .resolve ("name2.trace" )));
161
208
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
+ });
162
227
}
163
228
}
164
229
@@ -179,11 +244,9 @@ void canCallTracingGroupGroupEndAtAnyTimeAndAutoClose(@TempDir Path tempDir) thr
179
244
context .tracing ().groupEnd ();
180
245
context .tracing ().groupEnd ();
181
246
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
+ });
187
250
}
188
251
189
252
@ Test
@@ -202,9 +265,16 @@ void traceGroupGroupEnd(@TempDir Path tempDir) throws Exception {
202
265
Path traceFile1 = tempDir .resolve ("trace1.zip" );
203
266
context .tracing ().stop (new Tracing .StopOptions ().setPath (traceFile1 ));
204
267
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
+ });
208
278
}
209
279
210
280
@ Test
@@ -240,64 +310,53 @@ void shouldTraceVariousAPIs(@TempDir Path tempDir) throws Exception {
240
310
Path traceFile1 = tempDir .resolve ("trace1.zip" );
241
311
context .tracing ().stop (new Tracing .StopOptions ().setPath (traceFile1 ));
242
312
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
+ });
270
339
}
271
340
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 ));
293
355
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
+ });
302
361
}
303
362
}
0 commit comments