1
1
<!DOCTYPE html>
2
- < html lang =" en " >
2
+ < html >
3
3
< head >
4
- < meta charset ="UTF-8 ">
5
- < meta name ="viewport " content ="width=device-width, initial-scale=1.0 ">
6
4
< title > jsPDF Test Report</ title >
7
- < script src ="https://unpkg.com/react@18/umd/react.development.js "> </ script >
8
- < script src ="https://unpkg.com/react-dom@18/umd/react-dom.development.js "> </ script >
9
- < script src ="https://unpkg.com/@babel/standalone/babel.min.js "> </ script >
10
- < link rel ="
stylesheet "
href ="
https://cdn.jsdelivr.net/npm/@radix-ui/[email protected] /styles.css "
>
11
- < script src ="test-results.js "> </ script >
12
5
< style >
13
- : root {
14
- --background : 0 0% 100% ;
15
- --foreground : 222.2 84% 4.9% ;
16
- --muted : 210 40% 96.1% ;
17
- --muted-foreground : 215.4 16.3% 46.9% ;
18
- --popover : 0 0% 100% ;
19
- --popover-foreground : 222.2 84% 4.9% ;
20
- --card : 0 0% 100% ;
21
- --card-foreground : 222.2 84% 4.9% ;
22
- --border : 214.3 31.8% 91.4% ;
23
- --input : 214.3 31.8% 91.4% ;
24
- --primary : 222.2 47.4% 11.2% ;
25
- --primary-foreground : 210 40% 98% ;
26
- --secondary : 210 40% 96.1% ;
27
- --secondary-foreground : 222.2 47.4% 11.2% ;
28
- --accent : 210 40% 96.1% ;
29
- --accent-foreground : 222.2 47.4% 11.2% ;
30
- --destructive : 0 84.2% 60.2% ;
31
- --destructive-foreground : 210 40% 98% ;
32
- --ring : 215 20.2% 65.1% ;
33
- --radius : 0.5rem ;
34
- }
35
-
36
- * {
37
- margin : 0 ;
38
- padding : 0 ;
39
- box-sizing : border-box;
40
- }
41
-
42
6
body {
43
- font-family : system-ui, -apple-system, BlinkMacSystemFont, 'Segoe UI' , Roboto, 'Helvetica Neue' , sans-serif;
44
- background-color : hsl (var (--background ));
45
- color : hsl (var (--foreground ));
7
+ margin : 0 ;
8
+ font-family : system-ui, -apple-system, sans-serif;
46
9
}
47
-
48
- .layout {
10
+ .container {
49
11
display : grid;
50
12
grid-template-columns : 300px 1fr ;
51
13
height : 100vh ;
52
14
}
53
-
54
15
.sidebar {
55
- border-right : 1px solid hsl (var (--border ));
56
- padding : 1rem ;
16
+ background : # f5f5f5 ;
17
+ padding : 20px ;
18
+ border-right : 1px solid # ddd ;
57
19
overflow-y : auto;
58
20
}
59
-
60
21
.main {
61
- padding : 1 rem ;
22
+ padding : 20 px ;
62
23
overflow-y : auto;
63
24
}
64
-
65
- .test-item {
66
- padding : 0.75rem ;
67
- border : 1px solid hsl (var (--border ));
68
- border-radius : var (--radius );
69
- margin-bottom : 0.5rem ;
25
+ .summary {
26
+ margin-bottom : 20px ;
27
+ padding : 15px ;
28
+ background : white;
29
+ border-radius : 8px ;
30
+ box-shadow : 0 1px 3px rgba (0 , 0 , 0 , 0.1 );
31
+ }
32
+ .failure-item {
33
+ padding : 10px ;
34
+ margin : 5px 0 ;
35
+ background : white;
36
+ border-radius : 4px ;
70
37
cursor : pointer;
38
+ border : 1px solid # ddd ;
71
39
}
72
-
73
- .test-item : hover {
74
- background-color : hsl (var (--muted ));
40
+ .failure-item : hover {
41
+ background : # f0f0f0 ;
75
42
}
76
-
77
- . test-item . failed {
78
- border-color : hsl ( var ( --destructive )) ;
43
+ . failure-item . selected {
44
+ background : # e3f2fd ;
45
+ border-color : # 2196f3 ;
79
46
}
80
-
81
- .pdf-viewer {
82
- width : 100% ;
83
- height : calc (100vh - 2rem );
84
- border : 1px solid hsl (var (--border ));
85
- border-radius : var (--radius );
47
+ .pdf-view {
48
+ display : grid;
49
+ grid-template-columns : 1fr 1fr ;
50
+ gap : 20px ;
51
+ margin-top : 20px ;
86
52
}
87
-
88
- .viewer-controls {
89
- display : flex;
90
- gap : 1rem ;
91
- margin-bottom : 1rem ;
53
+ .pdf-container {
54
+ border : 1px solid # ddd ;
55
+ padding : 10px ;
56
+ border-radius : 4px ;
92
57
}
93
-
94
- .button {
95
- padding : 0.5rem 1rem ;
96
- background-color : hsl (var (--primary ));
97
- color : hsl (var (--primary-foreground ));
58
+ .pdf-container h3 {
59
+ margin-top : 0 ;
60
+ }
61
+ iframe {
62
+ width : 100% ;
63
+ height : 800px ;
98
64
border : none;
99
- border-radius : var (--radius );
100
- cursor : pointer;
101
65
}
102
-
103
- .button : hover {
104
- opacity : 0.9 ;
66
+ .differences {
67
+ white-space : pre-wrap;
68
+ font-family : monospace;
69
+ background : # f8f8f8 ;
70
+ padding : 10px ;
71
+ border-radius : 4px ;
72
+ margin-top : 20px ;
105
73
}
106
-
107
- .button .secondary {
108
- background-color : hsl (var (--secondary ));
109
- color : hsl (var (--secondary-foreground ));
74
+ .section {
75
+ margin-bottom : 30px ;
110
76
}
111
-
112
- .hex-view {
113
- font-family : monospace;
114
- white-space : pre-wrap;
115
- padding : 1rem ;
116
- background-color : hsl (var (--muted ));
117
- border-radius : var (--radius );
77
+ .section h3 {
78
+ margin-bottom : 10px ;
118
79
}
119
80
</ style >
120
81
</ head >
121
82
< body >
122
- < div id ="root "> </ div >
123
- < script type ="text/babel ">
124
- function App ( ) {
125
- const [ selectedTest , setSelectedTest ] = React . useState ( null ) ;
126
- const [ viewMode , setViewMode ] = React . useState ( 'actual' ) ;
127
- const [ testResults , setTestResults ] = React . useState ( window . TEST_RESULTS ) ;
83
+ < div class ="container ">
84
+ < div class ="sidebar ">
85
+ < div class ="summary section ">
86
+ < h2 > Test Summary</ h2 >
87
+ < div id ="summary "> </ div >
88
+ </ div >
89
+ < div class ="section ">
90
+ < h3 > Failed Tests</ h3 >
91
+ < div id ="failures "> </ div >
92
+ </ div >
93
+ < div class ="section ">
94
+ < h3 > Actual PDFs</ h3 >
95
+ < div id ="pdfs "> </ div >
96
+ </ div >
97
+ </ div >
98
+ < div class ="main ">
99
+ < div id ="details "> </ div >
100
+ </ div >
101
+ </ div >
102
+
103
+ <!-- Load test results -->
104
+ < script src ="test-results.js "> </ script >
128
105
129
- return (
130
- < div className = "layout" >
131
- < div className = "sidebar" >
132
- < h2 > Test Summary</ h2 >
133
- < div style = { { margin : '1rem 0' } } >
134
- < div > Total: { testResults . summary . total } </ div >
135
- < div style = { { color : 'green' } } > Passed: { testResults . summary . passed } </ div >
136
- < div style = { { color : 'orange' } } > Skipped: { testResults . summary . skipped } </ div >
137
- < div style = { { color : 'red' } } > Failed: { testResults . summary . failed } </ div >
138
- </ div >
139
- < h3 > Failed Tests</ h3 >
140
- { testResults . failures . map ( ( test , index ) => (
141
- < div
142
- key = { index }
143
- className = "test-item failed"
144
- onClick = { ( ) => setSelectedTest ( test ) }
145
- >
146
- < div > { test . name } </ div >
147
- < div style = { { fontSize : '0.875rem' , color : 'hsl(var(--muted-foreground))' } } >
148
- { test . differences . total } differences
149
- </ div >
150
- </ div >
151
- ) ) }
106
+ < script >
107
+ let selectedItem = null ;
108
+
109
+ function formatSummary ( results ) {
110
+ return `
111
+ <div>Total: ${ results . total } </div>
112
+ <div style="color: #4caf50">Passed: ${ results . passed } </div>
113
+ <div style="color: #f44336">Failed: ${ results . failed } </div>
114
+ <div style="color: #ff9800">Skipped: ${ results . skipped } </div>
115
+ ` ;
116
+ }
117
+
118
+ function showPdfComparison ( item ) {
119
+ const details = document . getElementById ( 'details' ) ;
120
+
121
+ // Update selected state in sidebar
122
+ if ( selectedItem ) {
123
+ document . getElementById ( selectedItem ) . classList . remove ( 'selected' ) ;
124
+ }
125
+ document . getElementById ( item . id ) . classList . add ( 'selected' ) ;
126
+ selectedItem = item . id ;
127
+
128
+ details . innerHTML = `
129
+ <h2>${ item . name } </h2>
130
+ <div class="pdf-view">
131
+ <div class="pdf-container">
132
+ <h3>Actual PDF</h3>
133
+ <iframe src="/${ item . actualPdf } "></iframe>
152
134
</div>
153
- < div className = "main" >
154
- { selectedTest ? (
155
- < >
156
- < div className = "viewer-controls" >
157
- < button
158
- className = { `button ${ viewMode === 'actual' ? '' : 'secondary' } ` }
159
- onClick = { ( ) => setViewMode ( 'actual' ) }
160
- >
161
- Actual
162
- </ button >
163
- < button
164
- className = { `button ${ viewMode === 'reference' ? '' : 'secondary' } ` }
165
- onClick = { ( ) => setViewMode ( 'reference' ) }
166
- >
167
- Reference
168
- </ button >
169
- < button
170
- className = { `button ${ viewMode === 'hex' ? '' : 'secondary' } ` }
171
- onClick = { ( ) => setViewMode ( 'hex' ) }
172
- >
173
- Hex Diff
174
- </ button >
175
- </ div >
176
- { viewMode === 'hex' ? (
177
- < div className = "hex-view" >
178
- { /* Placeholder for hex diff */ }
179
- Hex diff view coming soon...
180
- </ div >
181
- ) : (
182
- < iframe
183
- className = "pdf-viewer"
184
- src = { viewMode === 'actual' ? selectedTest . actualPdf : selectedTest . referencePdf }
185
- />
186
- ) }
187
- </ >
188
- ) : (
189
- < div style = { { padding : '2rem' , textAlign : 'center' } } >
190
- Select a test from the sidebar to view details
191
- </ div >
192
- ) }
135
+ <div class="pdf-container">
136
+ <h3>Reference PDF</h3>
137
+ <iframe src="/${ item . referencePdf } "></iframe>
193
138
</div>
194
139
</div>
195
- ) ;
140
+ ${ item . error ? `
141
+ <div class="differences">
142
+ <h3>Differences</h3>
143
+ <pre>${ item . error } </pre>
144
+ </div>
145
+ ` : '' }
146
+ ` ;
147
+ }
148
+
149
+ async function init ( ) {
150
+ const results = window . TEST_RESULTS ;
151
+
152
+ // Update summary
153
+ document . getElementById ( 'summary' ) . innerHTML = formatSummary ( results ) ;
154
+
155
+ // Update failures list
156
+ const failures = results . failures || [ ] ;
157
+ const failuresHtml = failures . map ( failure => `
158
+ <div id="failure_${ failure . name . replace ( / [ ^ a - z A - Z 0 - 9 ] / g, '_' ) } " class="failure-item" onclick='showPdfComparison(${ JSON . stringify ( { ...failure , id : "failure_" + failure . name . replace ( / [ ^ a - z A - Z 0 - 9 ] / g, '_' ) } ) . replace ( / ' / g, "'" ) } )'>
159
+ ${ failure . name }
160
+ </div>
161
+ ` ) . join ( '' ) ;
162
+ document . getElementById ( 'failures' ) . innerHTML = failuresHtml || '<div class="failure-item">No failures</div>' ;
163
+
164
+ // Load and display actual PDFs
165
+ try {
166
+ const response = await fetch ( '/api/pdfs' ) ;
167
+ const pdfs = await response . json ( ) ;
168
+ const pdfsHtml = pdfs . map ( pdf => `
169
+ <div id="pdf_${ pdf . name . replace ( / [ ^ a - z A - Z 0 - 9 ] / g, '_' ) } " class="failure-item" onclick='showPdfComparison(${ JSON . stringify ( { ...pdf , id : "pdf_" + pdf . name . replace ( / [ ^ a - z A - Z 0 - 9 ] / g, '_' ) } ) . replace ( / ' / g, "'" ) } )'>
170
+ ${ pdf . name }
171
+ </div>
172
+ ` ) . join ( '' ) ;
173
+ document . getElementById ( 'pdfs' ) . innerHTML = pdfsHtml || '<div class="failure-item">No PDFs found</div>' ;
174
+
175
+ // Show first failure by default, or first PDF if no failures
176
+ if ( failures . length > 0 ) {
177
+ showPdfComparison ( { ...failures [ 0 ] , id : "failure_" + failures [ 0 ] . name . replace ( / [ ^ a - z A - Z 0 - 9 ] / g, '_' ) } ) ;
178
+ } else if ( pdfs . length > 0 ) {
179
+ showPdfComparison ( { ...pdfs [ 0 ] , id : "pdf_" + pdfs [ 0 ] . name . replace ( / [ ^ a - z A - Z 0 - 9 ] / g, '_' ) } ) ;
180
+ }
181
+ } catch ( error ) {
182
+ console . error ( 'Failed to load PDFs:' , error ) ;
183
+ document . getElementById ( 'pdfs' ) . innerHTML = `
184
+ <div class="failure-item">
185
+ Failed to load PDFs: ${ error . message }
186
+ </div>
187
+ ` ;
188
+ }
196
189
}
197
190
198
- const root = ReactDOM . createRoot ( document . getElementById ( 'root' ) ) ;
199
- root . render ( < App /> ) ;
191
+ init ( ) ;
200
192
</ script >
201
193
</ body >
202
194
</ html >
0 commit comments