Skip to content

Commit 39b28fa

Browse files
fuzzie360claude
andcommitted
test: let browsers own their decoders and workers own their contexts
The last ten BrowserStack failures were tests holding browsers to answers that were never theirs to give. read-image-bitmap asserted the top-left JPEG pixel sums to exactly 3.22. Safari's decoder says 3.23. Firefox's own 2D decode says 3.22 -- its cpu mode passed -- but its WebGL ImageBitmap upload applies color management the 2D canvas does not, and lands on 3.07. The test now compares against the same browser's own decode of the same bitmap, inside a band wide enough for an upload-path shift and far too narrow for what the test actually guards against: a zero read, an all-white read, or garbage. The offscreen-canvas workers built GPU with the requested mode and let an unsupported one throw uncaught, which surfaced as a global failure attached to no test. Firefox on Windows has no WebGL2 in a Worker even though the page has it, so the page-side isOffscreenCanvasSupported guard could not know. The worker now reports an unsupported mode as data, and the page passes it as that browser's honest answer -- any other worker error still fails. Verified on the two targets that were failing: Firefox and Safari both pass these modules on BrowserStack now, and the M1 run stays green. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01RUTVDFaHav3uAdN3XfZLyx
1 parent 375ce28 commit 39b28fa

3 files changed

Lines changed: 66 additions & 5 deletions

File tree

test/features/offscreen-canvas.js

Lines changed: 22 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,17 @@ if (typeof importScripts !== 'undefined') {
22
// inside Worker
33
importScripts('../../dist/gpu-browser.js');
44
onmessage = function (e) {
5-
const gpu = new GPU({ mode: e.data });
5+
// A worker does not necessarily have the contexts the page has -- Firefox
6+
// on Windows offers no WebGL2 here -- and an uncaught throw would surface
7+
// as a global failure with no test attached. Report it as data and let the
8+
// page decide what it proves.
9+
let gpu;
10+
try {
11+
gpu = new GPU({ mode: e.data });
12+
} catch (error) {
13+
postMessage({ unsupported: String(error.message || error) });
14+
return;
15+
}
616
const a = [1,2,3];
717
const b = [3,2,1];
818
const kernel = gpu.createKernel(function(a, b) {
@@ -19,6 +29,17 @@ if (typeof importScripts !== 'undefined') {
1929
function testOffscreenCanvas(requestedMode, done) {
2030
const worker = new Worker('features/offscreen-canvas.js');
2131
worker.onmessage = function (e) {
32+
// The worker owns the answer to "is this mode available here": the page
33+
// may have WebGL2 while the worker does not (Firefox on Windows). An
34+
// unsupported mode is that browser's honest answer, not a gpu.js failure.
35+
if (e.data.unsupported) {
36+
assert.ok(
37+
/not supported/i.test(e.data.unsupported),
38+
`worker reported: ${e.data.unsupported}`
39+
);
40+
done();
41+
return;
42+
}
2243
// GPU keeps the mode it was given; only auto resolves to the chosen
2344
// kernel's own mode, which is 'gpu' for all of the WebGL backends. Asking
2445
// for 'webgl' and expecting 'gpu' back was never going to hold, and

test/features/read-image-bitmap.js

Lines changed: 22 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -14,11 +14,30 @@ function readImageBitmap(mode, done) {
1414
output: [1]
1515
});
1616
image.onload = async function() {
17-
const imageBitmapPromise = createImageBitmap(image, 0, 0, 1, 1);
18-
const imageBitmap = await imageBitmapPromise;
17+
const imageBitmap = await createImageBitmap(image, 0, 0, 1, 1);
18+
19+
// What this test guards is that an ImageBitmap can be read at all -- the
20+
// exact channel values belong to the browser, twice over. The JPEG decode
21+
// itself varies by a bit per channel (Safari lands on 3.23), and the WebGL
22+
// texture upload may additionally apply color management the 2D canvas
23+
// does not (Firefox on Windows lands on 3.07 for the same bitmap its own
24+
// 2D decode reads as 3.22). So: compare against this browser's own decode
25+
// of the same bitmap, with a band wide enough for an upload-path shift but
26+
// far too narrow for the real failures -- a zero read, an all-white read,
27+
// or garbage.
28+
const canvas = document.createElement('canvas');
29+
canvas.width = canvas.height = 1;
30+
const context = canvas.getContext('2d', { willReadFrequently: true });
31+
context.drawImage(imageBitmap, 0, 0);
32+
const data = context.getImageData(0, 0, 1, 1).data;
33+
const expected = (data[0] + data[1] + data[2] + data[3]) / 255;
34+
1935
const result = kernel(imageBitmap);
2036
assert.equal(result.length, 1);
21-
assert.equal(result[0].toFixed(2), 3.22);
37+
assert.ok(
38+
Math.abs(result[0] - expected) < 0.2,
39+
`read ${result[0]}, browser's own decode gives ${expected.toFixed(2)}`
40+
);
2241
await gpu.destroy();
2342
done();
2443
};

test/features/read-offscreen-canvas.js

Lines changed: 22 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,17 @@ if (typeof importScripts !== 'undefined') {
22
// inside Worker
33
importScripts('../../dist/gpu-browser.js');
44
onmessage = function (e) {
5-
const gpu = new GPU({ mode: e.data });
5+
// A worker does not necessarily have the contexts the page has -- Firefox
6+
// on Windows offers no WebGL2 here -- and an uncaught throw would surface
7+
// as a global failure with no test attached. Report it as data and let the
8+
// page decide what it proves.
9+
let gpu;
10+
try {
11+
gpu = new GPU({ mode: e.data });
12+
} catch (error) {
13+
postMessage({ unsupported: String(error.message || error) });
14+
return;
15+
}
616
const kernel1 = gpu.createKernel(function() {
717
this.color(1, 1, 1, 1);
818
}, {
@@ -27,6 +37,17 @@ if (typeof importScripts !== 'undefined') {
2737
function testReadOffscreenCanvas(mode, done) {
2838
const worker = new Worker('features/read-offscreen-canvas.js');
2939
worker.onmessage = function (e) {
40+
// The worker owns the answer to "is this mode available here": the page
41+
// may have WebGL2 while the worker does not (Firefox on Windows). An
42+
// unsupported mode is that browser's honest answer, not a gpu.js failure.
43+
if (e.data.unsupported) {
44+
assert.ok(
45+
/not supported/i.test(e.data.unsupported),
46+
`worker reported: ${e.data.unsupported}`
47+
);
48+
done();
49+
return;
50+
}
3051
const { result } = e.data;
3152
if (mode) assert.equal(e.data.mode, mode, 'GPU mode used in Worker');
3253
assert.deepEqual(result, Float32Array.from([4]));

0 commit comments

Comments
 (0)