// Technique 1: a fixed seed. // Every track's glue asks the browser for its seed the same way: it makes a Uint32Array of length 1 and hands it to // crypto.getRandomValues (JS: `new Uint32Array(1)`; Scala: `new Uint32Array(1)`; F#: `Array.zeroCreate 1`, // which Fable compiles to a Uint32Array). This init script replaces `getRandomValues` before any page script runs, // writes the seed into such an array, and logs every call so a test can prove the page asked exactly once, in exactly // that shape. Any other request (none of the pages makes one) falls through to the real generator and is logged too. /** The seed every test uses unless it says otherwise. Above 2^31 on purpose: a track that read the seed as a signed * 32-bit number would start a different game and every comparison with the model would fail. */ export const SEED = 0xdeadbeef /** Runs in the page (Playwright serialises it), so it may use only its argument. */ const seedScript = (seed) => { const real = Crypto.prototype.getRandomValues const calls = [] Object.defineProperty(window, '__e2eSeedCalls', { value: calls }) Crypto.prototype.getRandomValues = function (array) { const type = array?.constructor?.name calls.push({ type, length: array?.length }) if (type === 'Uint32Array' && array.length === 1) { array[0] = seed return array } return real.call(this, array) } } /** Install the fixed seed for every document the page loads from now on. */ export const fixSeed = (page, seed = SEED) => page.addInitScript(seedScript, seed) /** The calls the current document made to crypto.getRandomValues: [{type, length}]. */ export const seedCalls = (page) => page.evaluate(() => window.__e2eSeedCalls ?? null)