From 4155f54ae7c13ef517ec3414052fbc92e17587f9 Mon Sep 17 00:00:00 2001 From: Inline Pizza <249805557+InlinePizza@users.noreply.github.com> Date: Thu, 26 Feb 2026 16:38:36 -0800 Subject: [PATCH 1/3] fix: recording on macos #273 --- src/tests/startRecording.js | 95 ++++++++++++++++++++----------------- src/tests/stopRecording.js | 12 +++++ 2 files changed, 64 insertions(+), 43 deletions(-) diff --git a/src/tests/startRecording.js b/src/tests/startRecording.js index 44432328..faa960ad 100644 --- a/src/tests/startRecording.js +++ b/src/tests/startRecording.js @@ -99,10 +99,9 @@ async function startRecording({ config, context, step, driver }) { await driver.execute(() => (document.title = "RECORDER")); config.recording.tab = await driver.getWindowHandle(); - // Start recording - const recorder = await driver.execute((baseName) => { - let stream; - let recorder; + // Start recording using executeAsync so we properly wait for + // getDisplayMedia() to resolve before switching tabs. + const recorderStarted = await driver.executeAsync((baseName, done) => { const displayMediaOptions = { video: { displaySurface: "browser", @@ -116,53 +115,63 @@ async function startRecording({ config, context, step, driver }) { surfaceSwitching: "include", monitorTypeSurfaces: "include", }; - async function startCapture(displayMediaOptions) { + + (async () => { try { - const captureStream = await navigator.mediaDevices.getDisplayMedia( + const stream = await navigator.mediaDevices.getDisplayMedia( displayMediaOptions ); - return captureStream; - } catch (err) { - console.error(`Error: ${err}`); - return null; - } - } - async function captureAndDownload() { - stream = await startCapture(displayMediaOptions); - if (stream) { - await recordStream(stream); - } - return stream; - } - async function recordStream(stream) { - window.recorder = new MediaRecorder(stream, { mimeType: "video/webm" }); // or 'video/mp4' - let data = []; + if (!stream) { + done(false); + return; + } - window.recorder.ondataavailable = (event) => data.push(event.data); - window.recorder.start(); + window.recorder = new MediaRecorder(stream, { mimeType: "video/webm" }); + let data = []; - let stopped = new Promise((resolve, reject) => { - window.recorder.onstop = resolve; - window.recorder.onerror = (event) => reject(event.name); - }); + window.recorder.ondataavailable = (event) => data.push(event.data); - await stopped; + // When recording stops, create a download link for the file + window.recorder.onstop = () => { + let blob = new Blob(data, { type: "video/webm" }); + let url = URL.createObjectURL(blob); + let a = document.createElement("a"); + a.style.display = "none"; + a.href = url; + a.download = `${baseName}.webm`; + document.body.appendChild(a); + a.click(); + setTimeout(() => { + document.body.removeChild(a); + window.URL.revokeObjectURL(url); + }, 100); + }; - let blob = new Blob(data, { type: "video/webm" }); - let url = URL.createObjectURL(blob); - let a = document.createElement("a"); - a.style.display = "none"; - a.href = url; - a.download = `${baseName}.webm`; - document.body.appendChild(a); - a.click(); - setTimeout(() => { - document.body.removeChild(a); - window.URL.revokeObjectURL(url); - }, 100); - } - captureAndDownload(); + window.recorder.start(); + done(true); + } catch (err) { + console.error(`Error starting recording: ${err}`); + done(false); + } + })(); }, baseName); + + if (!recorderStarted) { + config.recording = null; + result.status = "FAIL"; + result.description = + "Failed to start recording. getDisplayMedia may have been rejected. " + + "On macOS, ensure Chrome has screen recording permission in " + + "System Preferences > Privacy & Security > Screen Recording."; + // Clean up: close the recorder tab and switch back + await driver.closeWindow(); + await driver.switchToWindow(originalTab); + await driver.execute((documentTitle) => { + document.title = documentTitle; + }, documentTitle); + return result; + } + // Switch to original tab await driver.switchToWindow(originalTab); // Set document title back to original diff --git a/src/tests/stopRecording.js b/src/tests/stopRecording.js index 81e589ac..7dc54739 100644 --- a/src/tests/stopRecording.js +++ b/src/tests/stopRecording.js @@ -36,6 +36,18 @@ async function stopRecording({ config, step, driver }) { // Switch to recording tab await driver.switchToWindow(config.recording.tab); + // Verify the recorder was properly initialized + const recorderExists = await driver.execute(() => { + return typeof window.recorder !== "undefined" && window.recorder !== null; + }); + if (!recorderExists) { + result.status = "FAIL"; + result.description = + "Recording was not properly started. The recorder object doesn't exist in the browser context."; + await driver.closeWindow(); + config.recording = null; + return result; + } // Stop recording await driver.execute(() => { window.recorder.stop(); From c253f9f2c4d802115e10c155cd7c2a8bb6c00cad Mon Sep 17 00:00:00 2001 From: Inline Pizza <249805557+InlinePizza@users.noreply.github.com> Date: Thu, 26 Feb 2026 16:43:27 -0800 Subject: [PATCH 2/3] fixup! fix: recording on macos #273 --- src/tests/startRecording.js | 79 ++++++++++++++++++++++--------------- 1 file changed, 47 insertions(+), 32 deletions(-) diff --git a/src/tests/startRecording.js b/src/tests/startRecording.js index faa960ad..00577085 100644 --- a/src/tests/startRecording.js +++ b/src/tests/startRecording.js @@ -102,6 +102,8 @@ async function startRecording({ config, context, step, driver }) { // Start recording using executeAsync so we properly wait for // getDisplayMedia() to resolve before switching tabs. const recorderStarted = await driver.executeAsync((baseName, done) => { + let stream; + let recorder; const displayMediaOptions = { video: { displaySurface: "browser", @@ -115,45 +117,58 @@ async function startRecording({ config, context, step, driver }) { surfaceSwitching: "include", monitorTypeSurfaces: "include", }; - - (async () => { + async function startCapture(displayMediaOptions) { try { - const stream = await navigator.mediaDevices.getDisplayMedia( + const captureStream = await navigator.mediaDevices.getDisplayMedia( displayMediaOptions ); - if (!stream) { - done(false); - return; - } + return captureStream; + } catch (err) { + console.error(`Error: ${err}`); + return null; + } + } + async function captureAndDownload() { + stream = await startCapture(displayMediaOptions); + if (stream) { + await recordStream(stream); + } else { + done(false); + } + return stream; + } + async function recordStream(stream) { + window.recorder = new MediaRecorder(stream, { mimeType: "video/webm" }); // or 'video/mp4' + let data = []; - window.recorder = new MediaRecorder(stream, { mimeType: "video/webm" }); - let data = []; + window.recorder.ondataavailable = (event) => data.push(event.data); + window.recorder.start(); - window.recorder.ondataavailable = (event) => data.push(event.data); + // Signal that recording has started successfully. + // executeAsync resolves here; the rest continues in the browser. + done(true); - // When recording stops, create a download link for the file - window.recorder.onstop = () => { - let blob = new Blob(data, { type: "video/webm" }); - let url = URL.createObjectURL(blob); - let a = document.createElement("a"); - a.style.display = "none"; - a.href = url; - a.download = `${baseName}.webm`; - document.body.appendChild(a); - a.click(); - setTimeout(() => { - document.body.removeChild(a); - window.URL.revokeObjectURL(url); - }, 100); - }; + let stopped = new Promise((resolve, reject) => { + window.recorder.onstop = resolve; + window.recorder.onerror = (event) => reject(event.name); + }); - window.recorder.start(); - done(true); - } catch (err) { - console.error(`Error starting recording: ${err}`); - done(false); - } - })(); + await stopped; + + let blob = new Blob(data, { type: "video/webm" }); + let url = URL.createObjectURL(blob); + let a = document.createElement("a"); + a.style.display = "none"; + a.href = url; + a.download = `${baseName}.webm`; + document.body.appendChild(a); + a.click(); + setTimeout(() => { + document.body.removeChild(a); + window.URL.revokeObjectURL(url); + }, 100); + } + captureAndDownload(); }, baseName); if (!recorderStarted) { From ceb02c297de8b63d6b48f01c7a6b4049070b7b77 Mon Sep 17 00:00:00 2001 From: Inline Pizza <249805557+InlinePizza@users.noreply.github.com> Date: Thu, 26 Feb 2026 17:16:52 -0800 Subject: [PATCH 3/3] fixup: use logger where possible on node side --- src/tests/startRecording.js | 2 ++ 1 file changed, 2 insertions(+) diff --git a/src/tests/startRecording.js b/src/tests/startRecording.js index 00577085..c5aca957 100644 --- a/src/tests/startRecording.js +++ b/src/tests/startRecording.js @@ -1,4 +1,5 @@ const { validate } = require("doc-detective-common"); +const { log } = require("../utils"); const { instantiateCursor } = require("./moveTo"); const path = require("path"); const fs = require("fs"); @@ -178,6 +179,7 @@ async function startRecording({ config, context, step, driver }) { "Failed to start recording. getDisplayMedia may have been rejected. " + "On macOS, ensure Chrome has screen recording permission in " + "System Preferences > Privacy & Security > Screen Recording."; + log(config, "error", result.description); // Clean up: close the recorder tab and switch back await driver.closeWindow(); await driver.switchToWindow(originalTab);