@@ -33,182 +33,8 @@ flags.parse();
33
33
34
34
const ROOT_DIR = path . join ( __dirname , '..' ) ;
35
35
36
- // All non-OK harness statuses. Any non-OK harness status should be investigated
37
- // before being added to this list, so that we don't score tests in the wrong
38
- // way because of a test or infrastructure issue.
39
- const KNOWN_TEST_STATUSES = new Set ( [
40
- // ERROR due to duplicate subtest name, fixed in https://github.com/web-platform-tests/wpt/pull/38387
41
- '/css/css-color/parsing/color-invalid-color-function.html' ,
42
- // TIMEOUT in Safari due to https://webkit.org/b/212201
43
- '/css/css-grid/grid-definition/grid-limits-001.html' ,
44
- // TIMEOUT in Firefox and Safari, all subtests present
45
- '/css/css-scroll-snap/input/keyboard.html' ,
46
- // ERROR in Firefox, TIMEOUT in Safari, all subtests failing in Chrome
47
- '/css/css-scroll-snap/input/snap-area-overflow-boundary.html' ,
48
- // TIMEOUT in Chrome with TIMEOUT subtests
49
- '/dom/events/Event-dispatch-click.html' ,
50
- // ERROR in Safari but linked bug is fixed
51
- '/html/browsers/browsing-the-web/navigating-across-documents/replace-before-load/form-requestsubmit-during-load.html' ,
52
- '/html/browsers/browsing-the-web/navigating-across-documents/replace-before-load/form-requestsubmit-during-pageshow.html' ,
53
- // TIMEOUT in Safari, but just a single subtest
54
- '/html/semantics/forms/form-submission-0/form-double-submit-multiple-targets.html' ,
55
- // TIMEOUT in Firefox and Safari, but just a single subtest
56
- '/html/semantics/forms/form-submission-0/form-double-submit-to-different-origin-frame.html' ,
57
- // TIMEOUT in Safari but all passing subtests due to https://bugs.webkit.org/show_bug.cgi?id=235407
58
- '/html/semantics/forms/form-submission-target/rel-base-target.html' ,
59
- '/html/semantics/forms/form-submission-target/rel-button-target.html' ,
60
- '/html/semantics/forms/form-submission-target/rel-form-target.html' ,
61
- '/html/semantics/forms/form-submission-target/rel-input-target.html' ,
62
- // ERROR in Firefox 95 and Safari 15.2, since fixed
63
- '/html/semantics/interactive-elements/the-dialog-element/dialog-showModal.html' ,
64
- // ERROR in Chrome 96, since fixed
65
- '/html/semantics/interactive-elements/the-dialog-element/modal-dialog-ancestor-is-inert.html' ,
66
- // TIMEOUT in Safari, but all subtests present
67
- '/html/semantics/forms/textfieldselection/select-event.html' ,
68
- '/html/semantics/forms/textfieldselection/selection-start-end.html' ,
69
- '/html/semantics/forms/textfieldselection/textfieldselection-setRangeText.html' ,
70
- '/html/semantics/forms/textfieldselection/textfieldselection-setSelectionRange.html' ,
71
- // TIMEOUT in Firefox 98, since fixed
72
- '/html/semantics/forms/the-input-element/image-click-form-data.html' ,
73
- // TIMEOUT in Safari, but all subtests present
74
- '/html/semantics/forms/the-input-element/range-restore-oninput-onchange-event.html' ,
75
- // TIMEOUT in STP 137, since fixed
76
- '/html/semantics/interactive-elements/the-dialog-element/backdrop-receives-element-events.html' ,
77
- // TIMEOUT for one run in Safari but has since run successfully.
78
- '/css/css-scroll-snap/snap-at-user-scroll-end.html' ,
79
-
80
-
81
- /**
82
- * The tests below have non-OK statuses that have not been investigated as of today.
83
- */
84
- // interop-2023-contain
85
- '/css/css-contain/container-queries/nested-query-containers.html' ,
86
- '/css/css-contain/content-visibility/content-visibility-input-image.html' ,
87
- '/css/css-contain/content-visibility/content-visibility-031.html' ,
88
- '/css/css-contain/content-visibility/content-visibility-auto-state-changed.html' ,
89
- '/css/selectors/invalidation/fullscreen-pseudo-class-in-has.html' ,
90
- '/css/selectors/invalidation/modal-pseudo-class-in-has.html' ,
91
- '/css/selectors/invalidation/user-action-pseudo-classes-in-has.html' ,
92
- // interop-2023-modules
93
- '/html/semantics/scripting-1/the-script-element/import-assertions/empty-assertion-clause.html' ,
94
- '/html/semantics/scripting-1/the-script-element/import-assertions/unsupported-assertion.html' ,
95
- '/workers/modules/dedicated-worker-import-blob-url.any.html' ,
96
- '/workers/modules/dedicated-worker-import-blob-url.any.worker.html' ,
97
- '/workers/modules/dedicated-worker-import-data-url-cross-origin.html' ,
98
- '/workers/modules/dedicated-worker-import-data-url.any.html' ,
99
- '/workers/modules/dedicated-worker-import-data-url.any.worker.html' ,
100
- '/workers/modules/dedicated-worker-import-meta.html' ,
101
- '/workers/modules/dedicated-worker-import.any.html' ,
102
- '/workers/modules/dedicated-worker-import.any.worker.html' ,
103
- '/workers/modules/dedicated-worker-options-credentials.html' ,
104
- '/workers/modules/dedicated-worker-parse-error-failure.html' ,
105
- '/workers/modules/shared-worker-import-data-url-cross-origin.html' ,
106
- '/workers/modules/shared-worker-import-data-url.window.html' ,
107
- '/workers/modules/shared-worker-options-credentials.html' ,
108
- '/workers/modules/shared-worker-parse-error-failure.html' ,
109
- '/import-maps/acquiring/modulepreload-link-header.html' ,
110
- '/import-maps/acquiring/modulepreload.html' ,
111
- '/workers/modules/shared-worker-import-failure.html' ,
112
- '/import-maps/acquiring/dynamic-import.html' ,
113
- '/import-maps/acquiring/script-tag-inline.html' ,
114
- '/import-maps/acquiring/script-tag.html' ,
115
- '/import-maps/bare-specifiers.sub.html' ,
116
- // interop-2023-offscreencanvas
117
- '/html/canvas/offscreen/fill-and-stroke-styles/2d.pattern.paint.repeat.outside.html' ,
118
- '/html/canvas/offscreen/manual/filter/offscreencanvas.filter.w.html' ,
119
- '/html/canvas/offscreen/manual/convert-to-blob/offscreencanvas.convert.to.blob.w.html' ,
120
- '/html/canvas/offscreen/manual/draw-generic-family/2d.text.draw.generic.family.w.html' ,
121
- '/html/canvas/offscreen/manual/filter/offscreencanvas.filter.w.html' ,
122
- '/html/canvas/offscreen/manual/the-offscreen-canvas/offscreencanvas.commit.w.html' ,
123
- '/html/canvas/offscreen/manual/the-offscreen-canvas/offscreencanvas.transfer.to.imagebitmap.w.html' ,
124
- '/html/canvas/offscreen/manual/the-offscreen-canvas/offscreencanvas.transferrable.w.html' ,
125
- '/html/canvas/offscreen/fill-and-stroke-styles/2d.pattern.paint.repeat.basic.html' ,
126
- '/html/canvas/offscreen/drawing-images-to-the-canvas/2d.drawImage.animated.poster.html' ,
127
- '/html/canvas/offscreen/compositing/2d.composite.globalAlpha.imagepattern.html' ,
128
- '/html/canvas/offscreen/compositing/2d.composite.uncovered.pattern.copy.html' ,
129
- '/html/canvas/offscreen/compositing/2d.composite.uncovered.pattern.destination-atop.html' ,
130
- '/html/canvas/offscreen/compositing/2d.composite.uncovered.pattern.destination-in.html' ,
131
- '/html/canvas/offscreen/compositing/2d.composite.uncovered.pattern.source-in.html' ,
132
- '/html/canvas/offscreen/compositing/2d.composite.uncovered.pattern.source-out.html' ,
133
- '/html/canvas/offscreen/fill-and-stroke-styles/2d.pattern.basic.image.html' ,
134
- '/html/canvas/offscreen/fill-and-stroke-styles/2d.pattern.crosscanvas.html' ,
135
- '/html/canvas/offscreen/fill-and-stroke-styles/2d.pattern.paint.norepeat.basic.html' ,
136
- '/html/canvas/offscreen/fill-and-stroke-styles/2d.pattern.paint.norepeat.coord1.html' ,
137
- '/html/canvas/offscreen/fill-and-stroke-styles/2d.pattern.paint.norepeat.coord2.html' ,
138
- '/html/canvas/offscreen/fill-and-stroke-styles/2d.pattern.paint.norepeat.coord3.html' ,
139
- '/html/canvas/offscreen/fill-and-stroke-styles/2d.pattern.paint.norepeat.outside.html' ,
140
- '/html/canvas/offscreen/fill-and-stroke-styles/2d.pattern.paint.repeat.coord3.html' ,
141
- '/html/canvas/offscreen/fill-and-stroke-styles/2d.pattern.paint.repeatx.coord1.html' ,
142
- '/html/canvas/offscreen/fill-and-stroke-styles/2d.pattern.paint.repeatx.outside.html' ,
143
- '/html/canvas/offscreen/fill-and-stroke-styles/2d.pattern.paint.repeaty.basic.html' ,
144
- '/html/canvas/offscreen/fill-and-stroke-styles/2d.pattern.paint.repeaty.coord1.html' ,
145
- '/html/canvas/offscreen/fill-and-stroke-styles/2d.pattern.paint.repeaty.outside.html' ,
146
- '/html/canvas/offscreen/fill-and-stroke-styles/2d.pattern.repeat.empty.html' ,
147
- '/html/canvas/offscreen/shadows/2d.shadow.pattern.basic.html' ,
148
- '/html/canvas/offscreen/shadows/2d.shadow.pattern.transparent.2.html' ,
149
- '/html/canvas/offscreen/fill-and-stroke-styles/2d.pattern.paint.repeat.coord2.html' ,
150
- '/html/canvas/offscreen/fill-and-stroke-styles/2d.pattern.paint.repeatx.basic.html' ,
151
- '/html/canvas/offscreen/shadows/2d.shadow.pattern.alpha.html' ,
152
- '/html/canvas/offscreen/fill-and-stroke-styles/2d.pattern.paint.orientation.image.html' ,
153
- '/html/canvas/offscreen/fill-and-stroke-styles/2d.pattern.paint.repeat.coord1.html' ,
154
- '/html/canvas/offscreen/shadows/2d.shadow.pattern.transparent.1.html' ,
155
- // interop-2023-events
156
- '/uievents/mouse/cancel-mousedown-in-subframe.html' ,
157
- '/pointerevents/pointerevent_attributes_hoverable_pointers.html?mouse' ,
158
- '/pointerevents/pointerevent_attributes_nohover_pointers.html' ,
159
- '/pointerevents/pointerevent_disabled_form_control.html?mouse' ,
160
- '/html/user-activation/activation-trigger-pointerevent.html?mouse' ,
161
- '/pointerevents/pointerevent_movementxy.html?mouse' ,
162
- '/pointerevents/pointerevent_pointercapture_in_frame.html?mouse' ,
163
- '/uievents/mouse/attributes.html' ,
164
- // interop-2022-scrolling
165
- '/css/css-scroll-snap/snap-at-user-scroll-end.html' ,
166
- // interop-2023-webcodecs
167
- '/webcodecs/videoDecoder-codec-specific.https.any.html?av1' ,
168
- '/webcodecs/videoDecoder-codec-specific.https.any.html?h264_annexb' ,
169
- '/webcodecs/videoDecoder-codec-specific.https.any.html?h264_avc' ,
170
- '/webcodecs/videoDecoder-codec-specific.https.any.html?vp8' ,
171
- '/webcodecs/videoDecoder-codec-specific.https.any.html?vp9' ,
172
- '/webcodecs/videoDecoder-codec-specific.https.any.worker.html?av1' ,
173
- '/webcodecs/videoDecoder-codec-specific.https.any.worker.html?h264_annexb' ,
174
- '/webcodecs/videoDecoder-codec-specific.https.any.worker.html?h264_avc' ,
175
- '/webcodecs/videoDecoder-codec-specific.https.any.worker.html?vp8' ,
176
- '/webcodecs/videoDecoder-codec-specific.https.any.worker.html?vp9' ,
177
- '/webcodecs/videoDecoder-codec-specific.https.any.worker.html?av1' ,
178
- '/webcodecs/videoFrame-construction.any.html' ,
179
- '/webcodecs/videoFrame-construction.crossOriginSource.sub.html' ,
180
- '/webcodecs/videoFrame-construction.window.html' ,
181
- '/webcodecs/videoFrame-serialization.crossAgentCluster.https.html' ,
182
- '/webcodecs/videoFrame-serialization.crossAgentCluster.https.html' ,
183
- '/webcodecs/temporal-svc-encoding.https.any.html?h264' ,
184
- '/webcodecs/temporal-svc-encoding.https.any.html?vp8' ,
185
- '/webcodecs/temporal-svc-encoding.https.any.html?vp9' ,
186
- '/webcodecs/temporal-svc-encoding.https.any.worker.html?h264' ,
187
- '/webcodecs/temporal-svc-encoding.https.any.worker.html?vp8' ,
188
- '/webcodecs/temporal-svc-encoding.https.any.worker.html?vp9' ,
189
- '/webcodecs/videoFrame-serialization.crossAgentCluster.https.html' ,
190
- '/webcodecs/videoFrame-serialization.crossAgentCluster.https.html' ,
191
- '/webcodecs/videoFrame-serialization.crossAgentCluster.https.html' ,
192
- '/webcodecs/full-cycle-test.https.any.html?av1' ,
193
- '/webcodecs/full-cycle-test.https.any.html?h264_annexb' ,
194
- '/webcodecs/full-cycle-test.https.any.html?h264_avc' ,
195
- '/webcodecs/full-cycle-test.https.any.html?vp9_p0' ,
196
- '/webcodecs/full-cycle-test.https.any.html?vp9_p2' ,
197
- '/webcodecs/full-cycle-test.https.any.worker.html?av1' ,
198
- '/webcodecs/full-cycle-test.https.any.worker.html?h264_annexb' ,
199
- '/webcodecs/full-cycle-test.https.any.worker.html?h264_avc' ,
200
- '/webcodecs/full-cycle-test.https.any.worker.html?vp9_p0' ,
201
- '/webcodecs/full-cycle-test.https.any.worker.html?vp9_p2' ,
202
- '/webcodecs/full-cycle-test.https.any.html?vp8' ,
203
- '/webcodecs/full-cycle-test.https.any.worker.html?vp8' ,
204
- // interop-2023-webcomponents
205
- '/shadow-dom/focus/focus-shadowhost-display-none.html' ,
206
- '/custom-elements/form-associated/ElementInternals-labels.html' ,
207
- '/custom-elements/form-associated/ElementInternals-setFormValue.html' ,
208
- '/custom-elements/form-associated/ElementInternals-validation.html' ,
209
- '/custom-elements/form-associated/form-disabled-callback.html' ,
210
- ] ) ;
211
-
36
+ const RESULTS_TREE = Symbol ( 'run results tree' ) ;
37
+ const COLLECT_NON_OK_TESTS = Symbol ( 'flag for whether to collect non-OK tests for this run' ) ;
212
38
213
39
// Calculate interop score (passing in all browsers) for a category
214
40
// after tracking the category's scores for each browser.
@@ -277,16 +103,15 @@ function aggregateInteropTestScores(testPassCounts, numBrowsers) {
277
103
//
278
104
// 4. Because we round down twice, the score for a category can end up lower
279
105
// than if we used rational numbers.
280
- function scoreRuns ( runs , allTestsSet ) {
106
+ function scoreRuns ( runs , allTestsSet , nonOKTests ) {
281
107
const scores = [ ] ;
282
108
const testPassCounts = new Map ( ) ;
283
- const unexpectedNonOKTests = new Set ( ) ;
284
109
285
110
try {
286
111
for ( const run of runs ) {
287
112
// Sum of the integer 0-1000 scores for each test.
288
113
let score = 0 ;
289
- lib . results . walkTests ( run . tree , ( path , test , results ) => {
114
+ lib . results . walkTests ( run [ RESULTS_TREE ] , ( path , test , results ) => {
290
115
const testname = path + '/' + test ;
291
116
if ( ! allTestsSet . has ( testname ) ) {
292
117
return ;
@@ -305,8 +130,8 @@ function scoreRuns(runs, allTestsSet) {
305
130
testPassCounts . get ( testname ) [ 'subtestTotal' ] = [ ] ;
306
131
}
307
132
if ( 'subtests' in results ) {
308
- if ( results [ 'status' ] != 'OK' && ! KNOWN_TEST_STATUSES . has ( testname ) ) {
309
- unexpectedNonOKTests . add ( testname ) ;
133
+ if ( results [ 'status' ] != 'OK' && run [ COLLECT_NON_OK_TESTS ] ) {
134
+ nonOKTests . add ( testname ) ;
310
135
}
311
136
subtestTotal = results [ 'subtests' ] . length ;
312
137
for ( const subtest of results [ 'subtests' ] ) {
@@ -354,27 +179,19 @@ function scoreRuns(runs, allTestsSet) {
354
179
throw e ;
355
180
}
356
181
357
- // Log and tests with unexpected non-OK statuses.
358
- if ( unexpectedNonOKTests . size > 0 ) {
359
- console . log ( 'Unexpected non-OK status for tests:' ) ;
360
- for ( const testname of unexpectedNonOKTests . values ( ) ) {
361
- console . log ( testname ) ;
362
- }
363
- }
364
182
// Calculate the interop scores that have been saved and add
365
183
// the interop score to the end of the browsers' scores array.
366
184
scores . push ( aggregateInteropTestScores ( testPassCounts , runs . length ) ) ;
367
185
return scores ;
368
186
}
369
187
370
- async function scoreCategory ( category , experimental , products , alignedRuns ,
371
- testsSet ) {
188
+ async function scoreAlignedRuns ( alignedRuns , testsSet , nonOKTests ) {
372
189
// Score the test runs.
373
190
const before = Date . now ( ) ;
374
191
const dateToScores = new Map ( ) ;
375
192
for ( const [ date , runs ] of alignedRuns . entries ( ) ) {
376
193
const versions = runs . map ( run => run . browser_version ) ;
377
- const scores = scoreRuns ( runs , testsSet ) ;
194
+ const scores = scoreRuns ( runs , testsSet , nonOKTests ) ;
378
195
dateToScores . set ( date , { versions, scores} ) ;
379
196
}
380
197
const after = Date . now ( ) ;
@@ -432,22 +249,27 @@ async function main() {
432
249
// Load the test result trees into memory; creates a list of recursive tree
433
250
// structures: tree = { trees: [...], tests: [...] }. Each 'tree' represents a
434
251
// directory, each 'test' is the results from a given test file.
252
+ //
253
+ // Also set the LAST symbol to true on the last set of aligned runs, to allow
254
+ // logging non-OK harness statuses for only those.
435
255
console . log ( 'Iterating over all runs, loading test results' ) ;
436
256
before = Date . now ( ) ;
257
+ let lastRuns = null ;
437
258
for ( const runs of alignedRuns . values ( ) ) {
438
259
for ( const run of runs ) {
439
- // Just in case someone ever adds a 'tree' field to the JSON.
440
- if ( run . tree ) {
441
- throw new Error ( 'Run JSON contains "tree" field; code needs changed.' ) ;
442
- }
443
- run . tree = await lib . results . getGitTree ( repo , run ) ;
260
+ run [ RESULTS_TREE ] = await lib . results . getGitTree ( repo , run ) ;
444
261
}
262
+ lastRuns = runs ;
445
263
}
446
264
after = Date . now ( ) ;
447
265
console . log ( `Loading ${ alignedRuns . size } sets of runs took ` +
448
266
`${ after - before } ms` ) ;
267
+ for ( const run of lastRuns ) {
268
+ run [ COLLECT_NON_OK_TESTS ] = true ;
269
+ }
449
270
450
271
const dateToScoresMaps = new Map ( ) ;
272
+ const nonOKTests = new Set ( ) ;
451
273
452
274
// Map from labels to tests (includes)
453
275
const labeledTests = new Map ( ) ;
@@ -464,7 +286,12 @@ async function main() {
464
286
}
465
287
}
466
288
}
467
- // category is an object with "name" and "labels" props.
289
+
290
+ // Score each category and add scores to |dateToScores|. For runs that have
291
+ // COLLECT_NON_OK_TESTS set (the last ones) any non-OK harness statuses are
292
+ // added to |nonOKTests|.
293
+ //
294
+ // Note: category is an object with "name" and "labels" props.
468
295
for ( const category of categories ) {
469
296
console . log ( `Scoring runs for ${ category . name } ` ) ;
470
297
const testsSet = new Set ( ) ;
@@ -477,14 +304,20 @@ async function main() {
477
304
// Keep a unique set of tests associated with the category.
478
305
labeledTestsSet . forEach ( test => testsSet . add ( test ) ) ;
479
306
}
480
- const dateToScores = await scoreCategory ( category , experimental , products ,
481
- alignedRuns , testsSet ) ;
307
+ const dateToScores = await scoreAlignedRuns ( alignedRuns , testsSet , nonOKTests ) ;
482
308
// Store the entire dateToScores for producing the unified CSV later.
483
309
dateToScoresMaps . set ( category . name , dateToScores ) ;
484
310
}
485
311
312
+ // Write non-OK harness statuses to a file.
313
+ if ( nonOKTests . size ) {
314
+ const lines = Array . from ( nonOKTests ) . sort ( ) ;
315
+ lines . push ( '' ) ;
316
+ await fs . promises . writeFile ( 'non-ok-harness-statuses.txt' , lines . join ( '\n' ) , 'utf-8' ) ;
317
+ }
318
+
486
319
// TODO: Once the other score CSVs are no longer used, we can push
487
- // some of this logic into scoreCategory and simplify things.
320
+ // some of this logic into scoreAlignedRuns and simplify things.
488
321
let unifiedCsv = 'date' ;
489
322
for ( const product of products ) {
490
323
const categoryLabels = categories . map ( c => `${ product } -${ c . name } ` ) ;
0 commit comments