Skip to content

Commit 5a82609

Browse files
Improve TestDox HTML report
1 parent d00f59d commit 5a82609

10 files changed

Lines changed: 1114 additions & 207 deletions

File tree

ChangeLog-13.3.md

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -9,4 +9,8 @@ All notable changes of the PHPUnit 13.3 release series are documented in this fi
99
* [#6701](https://github.com/sebastianbergmann/phpunit/pull/6701): Allow `expectOutputString()` and `expectOutputRegex()` to be combined and repeated
1010
* [#6710](https://github.com/sebastianbergmann/phpunit/pull/6710): Deprecation Filters
1111

12+
### Changed
13+
14+
* Improved TestDox HTML report
15+
1216
[13.3.0]: https://github.com/sebastianbergmann/phpunit/compare/13.2...main

src/Logging/TestDox/HtmlRenderer.php

Lines changed: 148 additions & 32 deletions
Original file line numberDiff line numberDiff line change
@@ -26,67 +26,154 @@
2626
<html lang="en">
2727
<head>
2828
<meta charset="utf-8"/>
29+
<meta name="viewport" content="width=device-width, initial-scale=1"/>
2930
<title>Test Documentation</title>
3031
<style>
32+
:root {
33+
color-scheme: light dark;
34+
35+
--background: light-dark(#f4f5f7, #16181d);
36+
--card-background: light-dark(#ffffff, #1f2228);
37+
--border: light-dark(#e2e4e8, #30343c);
38+
--text: light-dark(#1a1a1a, #e6e8eb);
39+
--muted: light-dark(#6b7280, #9aa1ab);
40+
--shadow: light-dark(0 1px 3px rgba(0, 0, 0, 0.08), 0 1px 3px rgba(0, 0, 0, 0.4));
41+
42+
--passed-background: light-dark(#d6e6f2, #1e3550);
43+
--failed-background: light-dark(#fad4c0, #4a2a10);
44+
}
45+
46+
*, *::before, *::after {
47+
box-sizing: border-box;
48+
}
49+
3150
body {
3251
text-rendering: optimizeLegibility;
33-
font-family: Source SansSerif Pro, Arial, sans-serif;
52+
font-family: Source SansSerif Pro, -apple-system, BlinkMacSystemFont, "Segoe UI", Arial, sans-serif;
3453
font-variant-ligatures: common-ligatures;
3554
font-kerning: normal;
36-
margin-left: 2rem;
37-
background-color: #fff;
38-
color: #000;
55+
line-height: 1.5;
56+
margin: 0;
57+
padding: 2.5rem 1rem;
58+
background-color: var(--background);
59+
color: var(--text);
60+
}
61+
62+
.summary,
63+
main {
64+
max-width: 52rem;
65+
margin: 0 auto;
66+
}
67+
68+
.summary {
69+
margin-bottom: 1.5rem;
3970
}
4071
41-
body > ul > li {
42-
font-size: larger;
72+
.summary h1 {
73+
font-size: 1.5rem;
74+
font-weight: 600;
75+
margin: 0 0 0.25rem;
4376
}
4477
45-
h2 {
46-
font-size: larger;
47-
text-decoration-line: underline;
48-
text-decoration-thickness: 2px;
78+
.counts {
4979
margin: 0;
50-
padding: 0.5rem 0;
80+
color: var(--muted);
81+
}
82+
83+
.counts .passed,
84+
.counts .failed {
85+
display: inline-block;
86+
padding: 0.1rem 0.5rem;
87+
border-radius: 0.25rem;
88+
color: var(--text);
89+
font-weight: 600;
90+
}
91+
92+
.counts .passed {
93+
background-color: var(--passed-background);
94+
}
95+
96+
.counts .failed {
97+
background-color: var(--failed-background);
98+
}
99+
100+
.test-class {
101+
background-color: var(--card-background);
102+
border: 1px solid var(--border);
103+
border-radius: 0.5rem;
104+
box-shadow: var(--shadow);
105+
padding: 1rem 1.25rem;
106+
margin-bottom: 1rem;
107+
}
108+
109+
.test-class h2 {
110+
font-size: 1.1rem;
111+
font-weight: 600;
112+
margin: 0 0 0.5rem;
113+
padding-bottom: 0.5rem;
114+
border-bottom: 1px solid var(--border);
51115
}
52116
53117
ul {
54118
list-style: none;
55-
margin: 0 0 2rem;
56-
padding: 0 0 0 1rem;
57-
text-indent: -1rem;
119+
margin: 0;
120+
padding: 0;
121+
}
122+
123+
li {
124+
position: relative;
125+
margin-bottom: 0.25rem;
126+
padding: 0.25rem 0.5rem 0.25rem 1.9rem;
127+
border-radius: 0.25rem;
128+
}
129+
130+
li::before {
131+
position: absolute;
132+
left: 0.5rem;
133+
}
134+
135+
li.success {
136+
background-color: var(--passed-background);
58137
}
59138
60-
.success:before {
61-
color: #4e9a06;
139+
li.success::before {
62140
content: '✓';
63-
padding-right: 0.5rem;
64141
}
65142
66-
.defect {
67-
color: #a40000;
143+
li.defect {
144+
background-color: var(--failed-background);
68145
}
69146
70-
.defect:before {
71-
color: #a40000;
147+
li.defect::before {
72148
content: '✗';
73-
padding-right: 0.5rem;
74149
}
75150
</style>
76151
</head>
77152
<body>
153+
EOT;
154+
private const string SUMMARY = <<<'EOT'
155+
156+
<header class="summary">
157+
<h1>Test Documentation</h1>
158+
<p class="counts">%s</p>
159+
</header>
160+
<main>
161+
78162
EOT;
79163
private const string CLASS_HEADER = <<<'EOT'
80164
81-
<h2>%s</h2>
82-
<ul>
165+
<section class="test-class">
166+
<h2>%s</h2>
167+
<ul>
83168

84169
EOT;
85170
private const string CLASS_FOOTER = <<<'EOT'
86-
</ul>
171+
</ul>
172+
</section>
173+
87174
EOT;
88175
private const string PAGE_FOOTER = <<<'EOT'
89-
176+
</main>
90177
</body>
91178
</html>
92179
EOT;
@@ -96,7 +183,9 @@
96183
*/
97184
public function render(array $tests): string
98185
{
99-
$buffer = self::PAGE_HEADER;
186+
$successful = 0;
187+
$defective = 0;
188+
$classes = '';
100189

101190
foreach ($tests as $_tests) {
102191
$list = $_tests->asArray();
@@ -105,7 +194,7 @@ public function render(array $tests): string
105194
continue;
106195
}
107196

108-
$buffer .= sprintf(
197+
$classes .= sprintf(
109198
self::CLASS_HEADER,
110199
htmlspecialchars(
111200
$list[0]->test()->testDox()->prettifiedClassName(),
@@ -114,17 +203,44 @@ public function render(array $tests): string
114203
);
115204

116205
foreach ($this->reduce($_tests) as $prettifiedMethodName => $outcome) {
117-
$buffer .= sprintf(
118-
" <li class=\"%s\">%s</li>\n",
206+
if ($outcome === 'success') {
207+
$successful++;
208+
} else {
209+
$defective++;
210+
}
211+
212+
$classes .= sprintf(
213+
" <li class=\"%s\">%s</li>\n",
119214
$outcome,
120215
htmlspecialchars($prettifiedMethodName, ENT_QUOTES | ENT_SUBSTITUTE),
121216
);
122217
}
123218

124-
$buffer .= self::CLASS_FOOTER;
219+
$classes .= self::CLASS_FOOTER;
220+
}
221+
222+
return self::PAGE_HEADER .
223+
sprintf(self::SUMMARY, $this->summarize($successful, $defective)) .
224+
$classes .
225+
self::PAGE_FOOTER;
226+
}
227+
228+
private function summarize(int $successful, int $defective): string
229+
{
230+
$passed = sprintf(
231+
'<span class="passed">%d passed</span>',
232+
$successful,
233+
);
234+
235+
if ($defective === 0) {
236+
return $passed;
125237
}
126238

127-
return $buffer . self::PAGE_FOOTER;
239+
return sprintf(
240+
'%s · <span class="failed">%d failed</span>',
241+
$passed,
242+
$defective,
243+
);
128244
}
129245

130246
/**

0 commit comments

Comments
 (0)