1+ "use strict" ;
2+
13// Copyright (C) 2022 Igalia, S.L. All rights reserved.
24// This code is governed by the BSD license found in the LICENSE file.
35/*---
@@ -6,8 +8,37 @@ description: |
68defines: [asyncTest, assert.throwsAsync]
79---*/
810
9- // Ensure a minimal `assert` object exists when running outside Test262
10- if ( typeof assert === 'undefined' ) var assert = { } ;
11+ // Ensure a minimal `assert` function exists when running outside Test262
12+ if ( typeof assert === 'undefined' ) {
13+ var assert = function ( actual , expected , message ) {
14+ function deepEqual ( a , b ) {
15+ if ( a === b ) return true ;
16+ if ( typeof a === 'number' && typeof b === 'number' && isNaN ( a ) && isNaN ( b ) ) return true ;
17+ if ( a && b && typeof a === 'object' && typeof b === 'object' ) {
18+ if ( Array . isArray ( a ) && Array . isArray ( b ) ) {
19+ if ( a . length !== b . length ) return false ;
20+ for ( var i = 0 ; i < a . length ; i ++ ) {
21+ if ( ! deepEqual ( a [ i ] , b [ i ] ) ) return false ;
22+ }
23+ return true ;
24+ }
25+ var aKeys = Object . keys ( a ) ;
26+ var bKeys = Object . keys ( b ) ;
27+ if ( aKeys . length !== bKeys . length ) return false ;
28+ for ( var i = 0 ; i < aKeys . length ; i ++ ) {
29+ var k = aKeys [ i ] ;
30+ if ( ! b . hasOwnProperty ( k ) || ! deepEqual ( a [ k ] , b [ k ] ) ) return false ;
31+ }
32+ return true ;
33+ }
34+ return false ;
35+ }
36+
37+ if ( ! deepEqual ( actual , expected ) ) {
38+ throw new Test262Error ( message || 'assertion failed' ) ;
39+ }
40+ } ;
41+ }
1142
1243// Minimal Test262 shims used by helpers
1344function Test262Error ( message ) {
@@ -33,25 +64,27 @@ function asyncTest(testFunc) {
3364 return ;
3465 }
3566 try {
36- testFunc ( ) . then (
37- function ( ) {
38- $DONE ( ) ;
39- } ,
40- function ( error ) {
41- $DONE ( error ) ;
42- }
43- ) ;
44- } catch ( syncError ) {
45- $DONE ( syncError ) ;
67+ console . log ( 'asyncTest: invoking testFunc' ) ;
68+ var res = testFunc ( ) ;
69+ console . log ( 'asyncTest: testFunc result' , res && res . constructor ? res . constructor . name : typeof res ) ;
70+ res . then (
71+ function ( ) {
72+ console . log ( 'asyncTest: resolved, calling $DONE' ) ;
73+ $DONE ( ) ;
74+ } ,
75+ function ( error ) {
76+ console . log ( 'asyncTest: rejected, calling $DONE with' , error ) ;
77+ $DONE ( error ) ;
78+ }
79+ ) ;
80+ } catch ( syncError ) {
81+ console . log ( 'asyncTest: threw synchronously' , syncError ) ;
82+ $DONE ( syncError ) ;
83+ }
4684 }
47- }
4885
4986/**
5087 * Asserts that a callback asynchronously throws an instance of a particular
51- * error (i.e., returns a promise whose rejection value is an object referencing
52- * the constructor).
53- *
54- * @param {Function } expectedErrorConstructor the expected constructor of the
5588 * rejection value
5689 * @param {Function } func the callback
5790 * @param {string } [message] the prefix to use for failure messages
@@ -116,14 +149,45 @@ assert.throwsAsync = function (expectedErrorConstructor, func, message) {
116149
117150// --- Test harness for running ---
118151{
152+ // Install a persistent $DONE dispatcher to avoid handler overwrite races
153+ if ( ! globalThis . __done_dispatcher_installed ) {
154+ ( function ( ) {
155+ var handlers = [ ] ;
156+ globalThis . $register_done = function ( fn ) {
157+ var id = handlers . length ;
158+ handlers . push ( { fn : fn , settled : false } ) ;
159+ return id ;
160+ } ;
161+ globalThis . $unregister_done = function ( id ) {
162+ if ( handlers [ id ] ) handlers [ id ] . settled = true ;
163+ } ;
164+ globalThis . $DONE = function ( err ) {
165+ // Deliver the call to the earliest un-settled registered handler
166+ for ( var i = 0 ; i < handlers . length ; i ++ ) {
167+ if ( ! handlers [ i ] . settled ) {
168+ handlers [ i ] . settled = true ;
169+ // Schedule handler invocation as a microtask to avoid deep synchronous
170+ // re-entrancy when handlers call $DONE recursively. This aligns with
171+ // Node's behavior and prevents stack overflow for many nested handlers.
172+ Promise . resolve ( ) . then ( function ( ) { try { handlers [ i ] . fn ( err ) ; } catch ( e ) { /* swallow */ } } ) ;
173+ break ;
174+ }
175+ }
176+ } ;
177+ } ) ( ) ;
178+ globalThis . __done_dispatcher_installed = true ;
179+ }
119180 // Run a single asyncTest and return a promise that resolves/rejects when $DONE is called
120181 // expectError: when true, the test is expected to call $DONE with an error
121182 function runSingleAsyncTest ( name , testFunc , expectError ) {
183+ console . log ( 'runSingleAsyncTest: start ->' , name ) ;
122184 return new Promise ( ( resolve ) => {
123185 var settled = false ;
124- globalThis . $DONE = function ( err ) {
186+ var doneId = globalThis . $register_done ( function ( err ) {
187+ console . log ( 'runSingleAsyncTest: $DONE called for' , name , 'err=' , err ) ;
125188 if ( settled ) return ;
126189 settled = true ;
190+ globalThis . $unregister_done ( doneId ) ;
127191 if ( expectError ) {
128192 if ( err === undefined ) {
129193 console . log ( 'asyncTest:' , name , '-> FAIL (expected error)' ) ;
@@ -141,7 +205,7 @@ assert.throwsAsync = function (expectedErrorConstructor, func, message) {
141205 resolve ( { name : name , ok : false , err} ) ;
142206 }
143207 }
144- } ;
208+ } ) ;
145209
146210 try {
147211 asyncTest ( testFunc ) ;
@@ -201,6 +265,10 @@ assert.throwsAsync = function (expectedErrorConstructor, func, message) {
201265
202266 await runThrowTests ( ) ;
203267
268+ for ( let i = 0 ; i < results . length ; i ++ ) {
269+ results [ i ] = await Promise . resolve ( results [ i ] ) ;
270+ }
271+ console . log ( 'DEBUG results:' , results ) ;
204272 const passed = results . filter ( r => r . ok ) . length ;
205273 const failed = results . length - passed ;
206274 console . log ( '\nSummary:' , passed , 'passed,' , failed , 'failed' ) ;
@@ -218,3 +286,18 @@ assert.throwsAsync = function (expectedErrorConstructor, func, message) {
218286 assert ( res , [ 1 , [ 2 , 3 ] ] , "Async function with rest" ) ;
219287 } ) ;
220288}
289+
290+ console . log ( '=== All async_n_throw_async_tests.js tests setup done ===' ) ;
291+
292+ try {
293+ var p = Promise . resolve ( 1 ) ;
294+ console . log ( "Promise.name:" , Promise . name ) ;
295+ console . log ( "p.constructor === Promise:" , p . constructor === Promise ) ;
296+ console . log ( "p.constructor.name:" , p . constructor . name ) ;
297+ } catch ( e ) {
298+ console . log ( "Error:" , e ) ;
299+ }
300+
301+ console . log ( '=== Running async_n_throw_async_tests_regression.js ===' ) ;
302+
303+ return true ;
0 commit comments