Skip to content

Commit d3b6be8

Browse files
authored
Test onuncapturederror order vs addEventListener (#4397)
* Test onuncapturederror order vs addEventListener The Web spec says setting onuncaptrederror adds a listener via addEventListener that calls the callback. Changing onuncapturederror changes the callback to the existing listener. Setting onuncapturederror to null removes the listener.
1 parent 66064ce commit d3b6be8

1 file changed

Lines changed: 88 additions & 0 deletions

File tree

src/webgpu/api/operation/uncapturederror.spec.ts

Lines changed: 88 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,7 @@ Tests for GPUDevice.onuncapturederror / addEventListener('uncapturederror')
33
`;
44

55
import { makeTestGroup } from '../../../common/framework/test_group.js';
6+
import { raceWithRejectOnTimeout } from '../../../common/util/util.js';
67
import { kGeneratableErrorScopeFilters } from '../../capability_info.js';
78
import { 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

Comments
 (0)