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+
78162EOT;
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
84169EOT;
85170 private const string CLASS_FOOTER = <<<'EOT'
86- </ul>
171+ </ul>
172+ </section>
173+
87174EOT;
88175 private const string PAGE_FOOTER = <<<'EOT'
89-
176+ </main>
90177 </body>
91178</html>
92179EOT;
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