Skip to content

Commit eb46ba4

Browse files
authored
fix(junit): save traces of parameterized tests to separate dirs (#2004)
1 parent 4217d84 commit eb46ba4

2 files changed

Lines changed: 126 additions & 0 deletions

File tree

‎playwright/src/main/java/com/microsoft/playwright/impl/junit/BrowserContextExtension.java‎

Lines changed: 38 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -22,9 +22,12 @@
2222
import org.junit.jupiter.api.extension.*;
2323

2424
import java.io.IOException;
25+
import java.nio.charset.StandardCharsets;
2526
import java.nio.file.Files;
2627
import java.nio.file.Path;
2728
import java.nio.file.Paths;
29+
import java.security.MessageDigest;
30+
import java.security.NoSuchAlgorithmException;
2831

2932
import static com.microsoft.playwright.impl.junit.ExtensionUtils.*;
3033
import static com.microsoft.playwright.impl.junit.PageExtension.cleanUpPage;
@@ -130,9 +133,44 @@ private static Path getOutputPath(ExtensionContext extensionContext) {
130133
String outputDirName = extensionContext.getRequiredTestClass().getName() + "." +
131134
extensionContext.getRequiredTestMethod().getName() + "-" +
132135
browserType.name();
136+
if (isTestTemplateInvocation(extensionContext)) {
137+
// Each invocation of a parameterized or repeated test gets its own directory.
138+
outputDirName += "-" + trimLongString(sanitizeForFilePath(extensionContext.getDisplayName()), 60);
139+
}
133140
return defaultOutputPath.resolve(outputDirName);
134141
}
135142

143+
private static boolean isTestTemplateInvocation(ExtensionContext extensionContext) {
144+
return extensionContext.getParent().flatMap(ExtensionContext::getTestMethod).isPresent();
145+
}
146+
147+
private static String sanitizeForFilePath(String s) {
148+
return s.replaceAll("[\\x00-\\x2C\\x2E-\\x2F\\x3A-\\x40\\x5B-\\x60\\x7B-\\x7F]+", "-");
149+
}
150+
151+
private static String trimLongString(String s, int length) {
152+
if (s.length() <= length) {
153+
return s;
154+
}
155+
String middle = "-" + calculateSha1(s).substring(0, 5) + "-";
156+
int start = (length - middle.length()) / 2;
157+
int end = length - middle.length() - start;
158+
return s.substring(0, start) + middle + s.substring(s.length() - end);
159+
}
160+
161+
private static String calculateSha1(String s) {
162+
try {
163+
byte[] digest = MessageDigest.getInstance("SHA-1").digest(s.getBytes(StandardCharsets.UTF_8));
164+
StringBuilder hex = new StringBuilder();
165+
for (byte b : digest) {
166+
hex.append(String.format("%02x", b));
167+
}
168+
return hex.toString();
169+
} catch (NoSuchAlgorithmException e) {
170+
throw new RuntimeException(e);
171+
}
172+
}
173+
136174
private static Path getDefaultOutputPath(ExtensionContext extensionContext) {
137175
Options options = OptionsExtension.getOptions(extensionContext);
138176
Path outputPath = options.outputDir;
Lines changed: 88 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,88 @@
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.junit;
18+
19+
import com.microsoft.playwright.Browser;
20+
import com.microsoft.playwright.Page;
21+
import org.junit.jupiter.api.AfterAll;
22+
import org.junit.jupiter.api.RepeatedTest;
23+
import org.junit.jupiter.api.Test;
24+
import org.junit.jupiter.api.io.TempDir;
25+
import org.junit.jupiter.params.ParameterizedTest;
26+
import org.junit.jupiter.params.provider.ValueSource;
27+
28+
import java.io.IOException;
29+
import java.nio.file.Files;
30+
import java.nio.file.Path;
31+
import java.util.List;
32+
import java.util.stream.Collectors;
33+
import java.util.stream.Stream;
34+
35+
import static org.junit.jupiter.api.Assertions.assertEquals;
36+
import static org.junit.jupiter.api.Assertions.assertTrue;
37+
38+
@FixtureTest
39+
@UsePlaywright(TestFixtureTraceOutputDir.TraceOptions.class)
40+
public class TestFixtureTraceOutputDir {
41+
@TempDir
42+
static Path outputDir;
43+
private static String browserName;
44+
45+
public static class TraceOptions implements OptionsFactory {
46+
@Override
47+
public Options getOptions() {
48+
return new Options().setTrace(Options.Trace.ON).setOutputDir(outputDir);
49+
}
50+
}
51+
52+
@Test
53+
void shouldSaveTrace(Browser browser, Page page) {
54+
browserName = browser.browserType().name();
55+
page.setContent("<div>test</div>");
56+
}
57+
58+
@ParameterizedTest(name = "[{index}] {0}")
59+
@ValueSource(strings = {"foo", "bar"})
60+
void shouldSaveTracePerParameterizedInvocation(String value, Page page) {
61+
page.setContent("<div>" + value + "</div>");
62+
}
63+
64+
@RepeatedTest(2)
65+
void shouldSaveTracePerRepetition(Page page) {
66+
page.setContent("<div>repeated</div>");
67+
}
68+
69+
@AfterAll
70+
static void shouldWriteTraceOfEachInvocationToSeparateDir() throws IOException {
71+
String prefix = TestFixtureTraceOutputDir.class.getName() + ".";
72+
List<String> expected = Stream.of(
73+
"shouldSaveTrace-" + browserName,
74+
"shouldSaveTracePerParameterizedInvocation-" + browserName + "--1-foo",
75+
"shouldSaveTracePerParameterizedInvocation-" + browserName + "--2-bar",
76+
"shouldSaveTracePerRepetition-" + browserName + "-repetition-1-of-2",
77+
"shouldSaveTracePerRepetition-" + browserName + "-repetition-2-of-2"
78+
).map(name -> prefix + name).sorted().collect(Collectors.toList());
79+
List<String> actual;
80+
try (Stream<Path> dirs = Files.list(outputDir)) {
81+
actual = dirs.map(dir -> dir.getFileName().toString()).sorted().collect(Collectors.toList());
82+
}
83+
assertEquals(expected, actual);
84+
for (String dir : actual) {
85+
assertTrue(Files.exists(outputDir.resolve(dir).resolve("trace.zip")), dir);
86+
}
87+
}
88+
}

0 commit comments

Comments
 (0)