@@ -58,46 +58,66 @@ 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 ) => {
94- return result . status === 'SKIP' || result . subtests . length !== 0 ;
95- } ) . map ( ( result ) => {
96- const url = new URL ( result . test , 'http://wpt' ) ;
97- url . pathname = url . pathname . replace ( / \. j s $ / , '.html' ) ;
98- result . test = url . href . slice ( url . origin . length ) ;
99- return result ;
100- } ) ;
114+ const results = Array . from ( this . results . values ( ) )
115+ . map ( ( result ) => {
116+ const url = new URL ( result . test , 'http://wpt' ) ;
117+ url . pathname = url . pathname . replace ( / \. j s $ / , '.html' ) ;
118+ result . test = url . href . slice ( url . origin . length ) ;
119+ return result ;
120+ } ) ;
101121
102122 /**
103123 * Return required and some optional properties
@@ -110,7 +130,12 @@ class WPTReport {
110130 os : getOs ( ) ,
111131 } ;
112132
113- fs . writeFileSync ( `out/wpt/${ this . filename } ` , JSON . stringify ( this ) ) ;
133+ fs . writeFileSync ( `out/wpt/${ this . filename } ` , JSON . stringify ( {
134+ time_start : this . time_start ,
135+ time_end : this . time_end ,
136+ run_info : this . run_info ,
137+ results : results ,
138+ } ) ) ;
114139 }
115140}
116141
@@ -642,14 +667,13 @@ class WPTRunner {
642667 this . inProgress . add ( spec ) ;
643668 this . workers . set ( spec , worker ) ;
644669
645- let reportResult ;
670+ const reportResult = this . report ?. getResult ( spec ) ;
646671 worker . on ( 'message' , ( message ) => {
647672 switch ( message . type ) {
648673 case 'result' :
649- reportResult ||= this . report ?. addResult ( `/${ relativePath } ${ spec . variant } ` , 'OK' ) ;
650674 return this . resultCallback ( spec , message . result , reportResult ) ;
651675 case 'completion' :
652- return this . completionCallback ( spec , message . status ) ;
676+ return this . completionCallback ( spec , message . status , reportResult ) ;
653677 default :
654678 throw new Error ( `Unexpected message from worker: ${ message . type } ` ) ;
655679 }
@@ -661,6 +685,8 @@ class WPTRunner {
661685 // This can happen normally, for example in timers tests.
662686 return ;
663687 }
688+ // Generate a subtest failure for visibility.
689+ // No need to record this synthetic failure with wpt.fyi.
664690 this . fail (
665691 spec ,
666692 {
@@ -671,6 +697,8 @@ class WPTRunner {
671697 } ,
672698 kUncaught ,
673699 ) ;
700+ // Mark the whole test as failed in wpt.fyi report.
701+ reportResult ?. finish ( 'ERROR' ) ;
674702 this . inProgress . delete ( spec ) ;
675703 } ) ;
676704
@@ -680,7 +708,11 @@ class WPTRunner {
680708
681709 process . on ( 'exit' , ( ) => {
682710 for ( const spec of this . inProgress ) {
711+ // No need to record this synthetic failure with wpt.fyi.
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,19 @@ 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 ) {
837+ // No need to record this synthetic failure with wpt.fyi.
803838 this . fail ( spec , { name : 'WPT testharness timeout' } , kTimeout ) ;
839+ // Mark the whole test as TIMEOUT in wpt.fyi report.
840+ reportResult ?. finish ( 'TIMEOUT' ) ;
841+ } else {
842+ reportResult ?. finish ( ) ;
804843 }
805844 this . inProgress . delete ( spec ) ;
806845 // Always force termination of the worker. Some tests allocate resources
0 commit comments