@@ -58,39 +58,60 @@ function codeUnitStr(char) {
5858 return 'U+' + char . charCodeAt ( 0 ) . toString ( 16 ) ;
5959}
6060
61+ class ReportResult {
62+ constructor ( name ) {
63+ this . test = name ;
64+ this . status = 'OK' ;
65+ this . subtests = [ ] ;
66+ }
67+
68+ addSubtest ( name , status , message ) {
69+ const subtest = {
70+ status,
71+ // https://github.com/web-platform-tests/wpt/blob/b24eedd/resources/testharness.js#L3722
72+ name : sanitizeUnpairedSurrogates ( name ) ,
73+ } ;
74+ if ( message ) {
75+ // https://github.com/web-platform-tests/wpt/blob/b24eedd/resources/testharness.js#L4506
76+ subtest . message = sanitizeUnpairedSurrogates ( message ) ;
77+ }
78+ this . subtests . push ( subtest ) ;
79+ return subtest ;
80+ }
81+
82+ finish ( status ) {
83+ this . status = status ?? 'OK' ;
84+ }
85+ }
86+
87+ // Generates a report that can be uploaded to wpt.fyi.
88+ // Checkout https://github.com/web-platform-tests/wpt.fyi/tree/main/api#results-creation
89+ // for more details.
6190class WPTReport {
6291 constructor ( path ) {
6392 this . filename = `report-${ path . replaceAll ( '/' , '-' ) } .json` ;
64- this . results = [ ] ;
93+ /** @type {Map<string, ReportResult> } */
94+ this . results = new Map ( ) ;
6595 this . time_start = Date . now ( ) ;
6696 }
6797
68- addResult ( name , status ) {
69- const result = {
70- test : name ,
71- status,
72- subtests : [ ] ,
73- addSubtest ( name , status , message ) {
74- const subtest = {
75- status,
76- // https://github.com/web-platform-tests/wpt/blob/b24eedd/resources/testharness.js#L3722
77- name : sanitizeUnpairedSurrogates ( name ) ,
78- } ;
79- if ( message ) {
80- // https://github.com/web-platform-tests/wpt/blob/b24eedd/resources/testharness.js#L4506
81- subtest . message = sanitizeUnpairedSurrogates ( message ) ;
82- }
83- this . subtests . push ( subtest ) ;
84- return subtest ;
85- } ,
86- } ;
87- this . results . push ( result ) ;
98+ /**
99+ * Get or create a ReportResult for a test spec.
100+ * @param {WPTTestSpec } spec
101+ */
102+ getResult ( spec ) {
103+ const name = `/${ spec . getRelativePath ( ) } ${ spec . variant } ` ;
104+ if ( this . results . has ( name ) ) {
105+ return this . results . get ( name ) ;
106+ }
107+ const result = new ReportResult ( name ) ;
108+ this . results . set ( name , result ) ;
88109 return result ;
89110 }
90111
91112 write ( ) {
92113 this . time_end = Date . now ( ) ;
93- this . results = this . results . filter ( ( result ) => {
114+ const results = Array . from ( this . results . values ( ) ) . filter ( ( result ) => {
94115 return result . status === 'SKIP' || result . subtests . length !== 0 ;
95116 } ) . map ( ( result ) => {
96117 const url = new URL ( result . test , 'http://wpt' ) ;
@@ -110,7 +131,12 @@ class WPTReport {
110131 os : getOs ( ) ,
111132 } ;
112133
113- fs . writeFileSync ( `out/wpt/${ this . filename } ` , JSON . stringify ( this ) ) ;
134+ fs . writeFileSync ( `out/wpt/${ this . filename } ` , JSON . stringify ( {
135+ time_start : this . time_start ,
136+ time_end : this . time_end ,
137+ run_info : this . run_info ,
138+ results : results ,
139+ } ) ) ;
114140 }
115141}
116142
@@ -642,14 +668,13 @@ class WPTRunner {
642668 this . inProgress . add ( spec ) ;
643669 this . workers . set ( spec , worker ) ;
644670
645- let reportResult ;
671+ const reportResult = this . report ?. getResult ( spec ) ;
646672 worker . on ( 'message' , ( message ) => {
647673 switch ( message . type ) {
648674 case 'result' :
649- reportResult ||= this . report ?. addResult ( `/${ relativePath } ${ spec . variant } ` , 'OK' ) ;
650675 return this . resultCallback ( spec , message . result , reportResult ) ;
651676 case 'completion' :
652- return this . completionCallback ( spec , message . status ) ;
677+ return this . completionCallback ( spec , message . status , reportResult ) ;
653678 default :
654679 throw new Error ( `Unexpected message from worker: ${ message . type } ` ) ;
655680 }
@@ -661,6 +686,7 @@ class WPTRunner {
661686 // This can happen normally, for example in timers tests.
662687 return ;
663688 }
689+ // Generate a subtest failure for visibility.
664690 this . fail (
665691 spec ,
666692 {
@@ -670,7 +696,10 @@ class WPTRunner {
670696 stack : inspect ( err ) ,
671697 } ,
672698 kUncaught ,
699+ reportResult ,
673700 ) ;
701+ // Mark the whole test as failed in wpt.fyi report.
702+ reportResult ?. finish ( 'ERROR' ) ;
674703 this . inProgress . delete ( spec ) ;
675704 } ) ;
676705
@@ -681,6 +710,9 @@ class WPTRunner {
681710 process . on ( 'exit' , ( ) => {
682711 for ( const spec of this . inProgress ) {
683712 this . fail ( spec , { name : 'Incomplete' } , kIncomplete ) ;
713+ // Mark the whole test as failed in wpt.fyi report.
714+ const reportResult = this . report ?. getResult ( spec ) ;
715+ reportResult ?. finish ( 'ERROR' ) ;
684716 }
685717 inspect . defaultOptions . depth = Infinity ;
686718 // Sorts the rules to have consistent output
@@ -780,6 +812,7 @@ class WPTRunner {
780812 * in one test file).
781813 * @param {WPTTestSpec } spec
782814 * @param {Test } test The Test object returned by WPT harness
815+ * @param {ReportResult } reportResult The report result object
783816 */
784817 resultCallback ( spec , test , reportResult ) {
785818 const status = this . getTestStatus ( test . status ) ;
@@ -794,13 +827,17 @@ class WPTRunner {
794827 * Report the status of each WPT test (one per file)
795828 * @param {WPTTestSpec } spec
796829 * @param {object } harnessStatus - The status object returned by WPT harness.
830+ * @param {ReportResult } reportResult The report result object
797831 */
798- completionCallback ( spec , harnessStatus ) {
832+ completionCallback ( spec , harnessStatus , reportResult ) {
799833 const status = this . getTestStatus ( harnessStatus . status ) ;
800834
801835 // Treat it like a test case failure
802836 if ( status === kTimeout ) {
803- this . fail ( spec , { name : 'WPT testharness timeout' } , kTimeout ) ;
837+ this . fail ( spec , { name : 'WPT testharness timeout' } , kTimeout , reportResult ) ;
838+ reportResult ?. finish ( 'TIMEOUT' ) ;
839+ } else {
840+ reportResult ?. finish ( ) ;
804841 }
805842 this . inProgress . delete ( spec ) ;
806843 // Always force termination of the worker. Some tests allocate resources
0 commit comments