test: harden Windows cursor diagnostic
This commit is contained in:
@@ -18,7 +18,7 @@ export interface WindowsCursorSampleEvent {
|
|||||||
width: number;
|
width: number;
|
||||||
height: number;
|
height: number;
|
||||||
} | null;
|
} | null;
|
||||||
asset?: WindowsCursorAssetPayload;
|
asset: WindowsCursorAssetPayload | null;
|
||||||
}
|
}
|
||||||
|
|
||||||
export interface WindowsCursorReadyEvent {
|
export interface WindowsCursorReadyEvent {
|
||||||
|
|||||||
@@ -3,10 +3,25 @@ import fs from "node:fs";
|
|||||||
import os from "node:os";
|
import os from "node:os";
|
||||||
import path from "node:path";
|
import path from "node:path";
|
||||||
|
|
||||||
const SAMPLE_INTERVAL_MS = Number(process.env.CURSOR_TEST_SAMPLE_INTERVAL_MS ?? 25);
|
function readPositiveIntEnv(name, fallback) {
|
||||||
const DURATION_MS = Number(process.env.CURSOR_TEST_DURATION_MS ?? 1800);
|
const raw = process.env[name];
|
||||||
const SCREEN_FRAME_INTERVAL_MS = Number(process.env.CURSOR_TEST_SCREEN_FRAME_INTERVAL_MS ?? 100);
|
if (raw === undefined) {
|
||||||
const READY_TIMEOUT_MS = 5000;
|
return fallback;
|
||||||
|
}
|
||||||
|
|
||||||
|
const parsed = Number(raw);
|
||||||
|
if (!Number.isFinite(parsed) || parsed <= 0) {
|
||||||
|
console.warn(`[cursor-native-test] ignoring invalid ${name}=${raw}; using ${fallback}`);
|
||||||
|
return fallback;
|
||||||
|
}
|
||||||
|
|
||||||
|
return Math.floor(parsed);
|
||||||
|
}
|
||||||
|
|
||||||
|
const SAMPLE_INTERVAL_MS = readPositiveIntEnv("CURSOR_TEST_SAMPLE_INTERVAL_MS", 25);
|
||||||
|
const DURATION_MS = readPositiveIntEnv("CURSOR_TEST_DURATION_MS", 1800);
|
||||||
|
const SCREEN_FRAME_INTERVAL_MS = readPositiveIntEnv("CURSOR_TEST_SCREEN_FRAME_INTERVAL_MS", 100);
|
||||||
|
const READY_TIMEOUT_MS = readPositiveIntEnv("CURSOR_TEST_READY_TIMEOUT_MS", 5000);
|
||||||
const OUTPUT_DIR =
|
const OUTPUT_DIR =
|
||||||
process.env.CURSOR_TEST_OUTPUT_DIR ??
|
process.env.CURSOR_TEST_OUTPUT_DIR ??
|
||||||
path.join(os.tmpdir(), `openscreen-cursor-native-${Date.now()}`);
|
path.join(os.tmpdir(), `openscreen-cursor-native-${Date.now()}`);
|
||||||
@@ -550,22 +565,32 @@ while ($stopwatch.ElapsedMilliseconds -le ${durationMs + 700}) {
|
|||||||
`;
|
`;
|
||||||
}
|
}
|
||||||
|
|
||||||
function waitForReady(events) {
|
function createReadyWaiter() {
|
||||||
return new Promise((resolve, reject) => {
|
let settled = false;
|
||||||
const startedAt = Date.now();
|
let resolveReady = null;
|
||||||
const timer = setInterval(() => {
|
const promise = new Promise((resolve, reject) => {
|
||||||
if (events.some((event) => event.type === "ready")) {
|
const timer = setTimeout(() => {
|
||||||
clearInterval(timer);
|
if (settled) {
|
||||||
resolve();
|
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
settled = true;
|
||||||
|
reject(new Error("Timed out waiting for cursor sampler readiness."));
|
||||||
|
}, READY_TIMEOUT_MS);
|
||||||
|
|
||||||
if (Date.now() - startedAt > READY_TIMEOUT_MS) {
|
resolveReady = () => {
|
||||||
clearInterval(timer);
|
if (settled) {
|
||||||
reject(new Error("Timed out waiting for cursor sampler readiness."));
|
return;
|
||||||
}
|
}
|
||||||
}, 25);
|
settled = true;
|
||||||
|
clearTimeout(timer);
|
||||||
|
resolve();
|
||||||
|
};
|
||||||
});
|
});
|
||||||
|
|
||||||
|
return {
|
||||||
|
promise,
|
||||||
|
resolve: () => resolveReady?.(),
|
||||||
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
function writeAssets(assets, outputDir) {
|
function writeAssets(assets, outputDir) {
|
||||||
@@ -1113,10 +1138,15 @@ function findPlaywrightChromiumExecutable(defaultPath) {
|
|||||||
const candidates = fs
|
const candidates = fs
|
||||||
.readdirSync(baseDir, { withFileTypes: true })
|
.readdirSync(baseDir, { withFileTypes: true })
|
||||||
.filter((entry) => entry.isDirectory() && entry.name.startsWith("chromium-"))
|
.filter((entry) => entry.isDirectory() && entry.name.startsWith("chromium-"))
|
||||||
.map((entry) => path.join(baseDir, entry.name, "chrome-win64", "chrome.exe"))
|
.map((entry) => ({
|
||||||
.filter((candidate) => fs.existsSync(candidate))
|
executablePath: path.join(baseDir, entry.name, "chrome-win64", "chrome.exe"),
|
||||||
.sort()
|
revision: Number.parseInt(entry.name.slice("chromium-".length), 10),
|
||||||
.reverse();
|
}))
|
||||||
|
.filter(
|
||||||
|
(candidate) => Number.isFinite(candidate.revision) && fs.existsSync(candidate.executablePath),
|
||||||
|
)
|
||||||
|
.sort((a, b) => b.revision - a.revision)
|
||||||
|
.map((candidate) => candidate.executablePath);
|
||||||
|
|
||||||
return candidates[0] ?? defaultPath;
|
return candidates[0] ?? defaultPath;
|
||||||
}
|
}
|
||||||
@@ -1169,6 +1199,7 @@ const events = [];
|
|||||||
const assets = new Map();
|
const assets = new Map();
|
||||||
let lineBuffer = "";
|
let lineBuffer = "";
|
||||||
let stoppingSampler = false;
|
let stoppingSampler = false;
|
||||||
|
const readyWaiter = createReadyWaiter();
|
||||||
const sampler = spawnPowerShell(buildSamplerScript(), {
|
const sampler = spawnPowerShell(buildSamplerScript(), {
|
||||||
onStdout: (chunk) => {
|
onStdout: (chunk) => {
|
||||||
lineBuffer += chunk;
|
lineBuffer += chunk;
|
||||||
@@ -1181,8 +1212,17 @@ const sampler = spawnPowerShell(buildSamplerScript(), {
|
|||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
const event = JSON.parse(trimmed);
|
let event;
|
||||||
|
try {
|
||||||
|
event = JSON.parse(trimmed);
|
||||||
|
} catch {
|
||||||
|
process.stderr.write(`[cursor-native-test] dropping non-JSON line: ${trimmed}\n`);
|
||||||
|
continue;
|
||||||
|
}
|
||||||
events.push(event);
|
events.push(event);
|
||||||
|
if (event.type === "ready") {
|
||||||
|
readyWaiter.resolve();
|
||||||
|
}
|
||||||
if (event.asset?.id && !assets.has(event.asset.id)) {
|
if (event.asset?.id && !assets.has(event.asset.id)) {
|
||||||
assets.set(event.asset.id, event.asset);
|
assets.set(event.asset.id, event.asset);
|
||||||
}
|
}
|
||||||
@@ -1197,7 +1237,7 @@ const sampler = spawnPowerShell(buildSamplerScript(), {
|
|||||||
let screenRecorder = null;
|
let screenRecorder = null;
|
||||||
|
|
||||||
try {
|
try {
|
||||||
await waitForReady(events);
|
await readyWaiter.promise;
|
||||||
screenRecorder = spawnPowerShell(buildScreenRecorderScript(OUTPUT_DIR, DURATION_MS), {
|
screenRecorder = spawnPowerShell(buildScreenRecorderScript(OUTPUT_DIR, DURATION_MS), {
|
||||||
onStderr: (chunk) => {
|
onStderr: (chunk) => {
|
||||||
if (!chunk.startsWith("#< CLIXML") && !chunk.startsWith("<Objs")) {
|
if (!chunk.startsWith("#< CLIXML") && !chunk.startsWith("<Objs")) {
|
||||||
|
|||||||
Reference in New Issue
Block a user