@@ -3,6 +3,7 @@ Tests for GPUDevice.onuncapturederror / addEventListener('uncapturederror')
33` ;
44
55import { makeTestGroup } from '../../../common/framework/test_group.js' ;
6+ import { raceWithRejectOnTimeout } from '../../../common/util/util.js' ;
67import { kGeneratableErrorScopeFilters } from '../../capability_info.js' ;
78import { ErrorTest } from '../../error_test.js' ;
89
@@ -38,3 +39,90 @@ g.test('uncapturederror_from_non_originating_thread')
3839(since deserialized ones don't have EventTarget/onuncapturederror).`
3940 )
4041 . unimplemented ( ) ;
42+
43+ g . test ( 'onuncapturederror_order_wrt_addEventListener' )
44+ . desc (
45+ `
46+ Test that onuncapturederror and addEventListener work in the correct order.
47+
48+ The spec says setting onuncapturederror adds a listener via addEventListener that
49+ calls the callback. Changing onuncapturederror changes the callback to the existing
50+ listener. Setting onuncapturederror to null removes the listener.
51+ `
52+ )
53+ . fn ( async t => {
54+ const callOrder : string [ ] = [ ] ;
55+
56+ const makeListener = ( id : string ) => {
57+ let resolve : ( ) => void ;
58+ return {
59+ getPromise ( ) {
60+ return new Promise < void > ( r => {
61+ resolve = r ;
62+ } ) ;
63+ } ,
64+ listener : ( ) => {
65+ t . debug ( `listener ${ id } called` ) ;
66+ callOrder . push ( id ) ;
67+ resolve ( ) ;
68+ } ,
69+ } ;
70+ } ;
71+
72+ const listenerA = makeListener ( 'a' ) ;
73+ const listenerB = makeListener ( 'b' ) ;
74+ const callbackC = makeListener ( 'c' ) ;
75+ const callbackD = makeListener ( 'd' ) ;
76+ const callbackE = makeListener ( 'e' ) ;
77+
78+ try {
79+ t . debug ( 'test they are called in the order added' ) ;
80+ {
81+ const promises = [ listenerA . getPromise ( ) , listenerB . getPromise ( ) , callbackC . getPromise ( ) ] ;
82+
83+ t . device . addEventListener ( 'uncapturederror' , listenerA . listener ) ;
84+ t . device . onuncapturederror = callbackC . listener ;
85+ t . device . addEventListener ( 'uncapturederror' , listenerB . listener ) ;
86+
87+ t . generateError ( 'validation' ) ;
88+ await raceWithRejectOnTimeout ( Promise . all ( promises ) , 5000 , 'timeout1' ) ;
89+
90+ const order = callOrder . join ( ',' ) ;
91+ t . expect ( ( ) => order === 'a,c,b' ) ;
92+ callOrder . length = 0 ;
93+ }
94+
95+ t . debug ( 'test changing onuncapturederror does not change the order' ) ;
96+ {
97+ const promises = [ listenerA . getPromise ( ) , listenerB . getPromise ( ) , callbackD . getPromise ( ) ] ;
98+
99+ t . device . onuncapturederror = callbackD . listener ;
100+
101+ t . generateError ( 'validation' ) ;
102+ await raceWithRejectOnTimeout ( Promise . all ( promises ) , 500 , 'timeout2' ) ;
103+
104+ const order = callOrder . join ( ',' ) ;
105+ t . expect ( ( ) => order === 'a,d,b' ) ;
106+ callOrder . length = 0 ;
107+ }
108+
109+ t . debug ( 'test clearing onuncapturederror then setting it does change the order' ) ;
110+ {
111+ const promises = [ listenerA . getPromise ( ) , listenerB . getPromise ( ) , callbackE . getPromise ( ) ] ;
112+
113+ t . device . onuncapturederror = null ;
114+ t . device . onuncapturederror = callbackE . listener ;
115+
116+ t . generateError ( 'validation' ) ;
117+ await raceWithRejectOnTimeout ( Promise . all ( promises ) , 500 , 'timeout3' ) ;
118+
119+ const order = callOrder . join ( ',' ) ;
120+ t . expect ( ( ) => order === 'a,b,e' ) ;
121+ callOrder . length = 0 ;
122+ }
123+ } finally {
124+ t . device . onuncapturederror = null ;
125+ t . device . removeEventListener ( 'uncapturederror' , listenerA . listener ) ;
126+ t . device . removeEventListener ( 'uncapturederror' , listenerB . listener ) ;
127+ }
128+ } ) ;
0 commit comments