fix: stabilize macOS audio test and default browser detection
This commit is contained in:
@@ -8,7 +8,7 @@ import Testing
|
|||||||
let wav = makeWav16Mono(sampleRate: 8000, samples: 80)
|
let wav = makeWav16Mono(sampleRate: 8000, samples: 80)
|
||||||
defer { _ = TalkAudioPlayer.shared.stop() }
|
defer { _ = TalkAudioPlayer.shared.stop() }
|
||||||
|
|
||||||
_ = try await withTimeout(seconds: 2.0) {
|
_ = try await withTimeout(seconds: 4.0) {
|
||||||
await TalkAudioPlayer.shared.play(data: wav)
|
await TalkAudioPlayer.shared.play(data: wav)
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -27,7 +27,7 @@ import Testing
|
|||||||
await Task.yield()
|
await Task.yield()
|
||||||
_ = await TalkAudioPlayer.shared.play(data: wav)
|
_ = await TalkAudioPlayer.shared.play(data: wav)
|
||||||
|
|
||||||
_ = try await withTimeout(seconds: 2.0) {
|
_ = try await withTimeout(seconds: 4.0) {
|
||||||
await first.value
|
await first.value
|
||||||
}
|
}
|
||||||
#expect(true)
|
#expect(true)
|
||||||
|
|||||||
@@ -24,10 +24,10 @@ describe("browser default executable detection", () => {
|
|||||||
it("prefers default Chromium browser on macOS", async () => {
|
it("prefers default Chromium browser on macOS", async () => {
|
||||||
vi.mocked(execFileSync).mockImplementation((cmd, args) => {
|
vi.mocked(execFileSync).mockImplementation((cmd, args) => {
|
||||||
const argsStr = Array.isArray(args) ? args.join(" ") : "";
|
const argsStr = Array.isArray(args) ? args.join(" ") : "";
|
||||||
if (cmd === "/usr/bin/osascript" && argsStr.includes("id of application")) {
|
if (cmd === "/usr/bin/plutil" && argsStr.includes("LSHandlers")) {
|
||||||
return "com.google.Chrome";
|
return JSON.stringify([{ LSHandlerURLScheme: "http", LSHandlerRoleAll: "com.google.Chrome" }]);
|
||||||
}
|
}
|
||||||
if (cmd === "/usr/bin/osascript" && argsStr.includes("POSIX path")) {
|
if (cmd === "/usr/bin/osascript" && argsStr.includes("path to application id")) {
|
||||||
return "/Applications/Google Chrome.app";
|
return "/Applications/Google Chrome.app";
|
||||||
}
|
}
|
||||||
if (cmd === "/usr/bin/defaults") {
|
if (cmd === "/usr/bin/defaults") {
|
||||||
@@ -35,9 +35,11 @@ describe("browser default executable detection", () => {
|
|||||||
}
|
}
|
||||||
return "";
|
return "";
|
||||||
});
|
});
|
||||||
vi.mocked(fs.existsSync).mockImplementation((p) =>
|
vi.mocked(fs.existsSync).mockImplementation((p) => {
|
||||||
String(p).includes("/Applications/Google Chrome.app/Contents/MacOS/Google Chrome"),
|
const value = String(p);
|
||||||
);
|
if (value.includes("com.apple.launchservices.secure.plist")) return true;
|
||||||
|
return value.includes("/Applications/Google Chrome.app/Contents/MacOS/Google Chrome");
|
||||||
|
});
|
||||||
|
|
||||||
const { resolveBrowserExecutableForPlatform } = await import("./chrome.executables.js");
|
const { resolveBrowserExecutableForPlatform } = await import("./chrome.executables.js");
|
||||||
const exe = resolveBrowserExecutableForPlatform(
|
const exe = resolveBrowserExecutableForPlatform(
|
||||||
@@ -52,14 +54,16 @@ describe("browser default executable detection", () => {
|
|||||||
it("falls back when default browser is non-Chromium on macOS", async () => {
|
it("falls back when default browser is non-Chromium on macOS", async () => {
|
||||||
vi.mocked(execFileSync).mockImplementation((cmd, args) => {
|
vi.mocked(execFileSync).mockImplementation((cmd, args) => {
|
||||||
const argsStr = Array.isArray(args) ? args.join(" ") : "";
|
const argsStr = Array.isArray(args) ? args.join(" ") : "";
|
||||||
if (cmd === "/usr/bin/osascript" && argsStr.includes("id of application")) {
|
if (cmd === "/usr/bin/plutil" && argsStr.includes("LSHandlers")) {
|
||||||
return "com.apple.Safari";
|
return JSON.stringify([{ LSHandlerURLScheme: "http", LSHandlerRoleAll: "com.apple.Safari" }]);
|
||||||
}
|
}
|
||||||
return "";
|
return "";
|
||||||
});
|
});
|
||||||
vi.mocked(fs.existsSync).mockImplementation((p) =>
|
vi.mocked(fs.existsSync).mockImplementation((p) => {
|
||||||
String(p).includes("Google Chrome.app/Contents/MacOS/Google Chrome"),
|
const value = String(p);
|
||||||
);
|
if (value.includes("com.apple.launchservices.secure.plist")) return true;
|
||||||
|
return value.includes("Google Chrome.app/Contents/MacOS/Google Chrome");
|
||||||
|
});
|
||||||
|
|
||||||
const { resolveBrowserExecutableForPlatform } = await import("./chrome.executables.js");
|
const { resolveBrowserExecutableForPlatform } = await import("./chrome.executables.js");
|
||||||
const exe = resolveBrowserExecutableForPlatform(
|
const exe = resolveBrowserExecutableForPlatform(
|
||||||
|
|||||||
@@ -95,12 +95,17 @@ function exists(filePath: string) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
function execText(command: string, args: string[], timeoutMs = 1200): string | null {
|
function execText(
|
||||||
|
command: string,
|
||||||
|
args: string[],
|
||||||
|
timeoutMs = 1200,
|
||||||
|
maxBuffer = 1024 * 1024,
|
||||||
|
): string | null {
|
||||||
try {
|
try {
|
||||||
const output = execFileSync(command, args, {
|
const output = execFileSync(command, args, {
|
||||||
timeout: timeoutMs,
|
timeout: timeoutMs,
|
||||||
encoding: "utf8",
|
encoding: "utf8",
|
||||||
maxBuffer: 1024 * 1024,
|
maxBuffer,
|
||||||
});
|
});
|
||||||
return String(output ?? "").trim() || null;
|
return String(output ?? "").trim() || null;
|
||||||
} catch {
|
} catch {
|
||||||
@@ -140,14 +145,12 @@ function detectDefaultChromiumExecutable(
|
|||||||
}
|
}
|
||||||
|
|
||||||
function detectDefaultChromiumExecutableMac(): BrowserExecutable | null {
|
function detectDefaultChromiumExecutableMac(): BrowserExecutable | null {
|
||||||
const bundleId = execText("/usr/bin/osascript", [
|
const bundleId = detectDefaultBrowserBundleIdMac();
|
||||||
"-e",
|
if (!bundleId || !CHROMIUM_BUNDLE_IDS.has(bundleId)) return null;
|
||||||
'id of application (path to default application for URL "http://example.com")',
|
|
||||||
]);
|
|
||||||
if (!bundleId || !CHROMIUM_BUNDLE_IDS.has(bundleId.trim())) return null;
|
|
||||||
const appPathRaw = execText("/usr/bin/osascript", [
|
const appPathRaw = execText("/usr/bin/osascript", [
|
||||||
"-e",
|
"-e",
|
||||||
'POSIX path of (path to default application for URL "http://example.com")',
|
`POSIX path of (path to application id "${bundleId}")`,
|
||||||
]);
|
]);
|
||||||
if (!appPathRaw) return null;
|
if (!appPathRaw) return null;
|
||||||
const appPath = appPathRaw.trim().replace(/\/$/, "");
|
const appPath = appPathRaw.trim().replace(/\/$/, "");
|
||||||
@@ -162,6 +165,45 @@ function detectDefaultChromiumExecutableMac(): BrowserExecutable | null {
|
|||||||
return { kind: inferKindFromIdentifier(bundleId), path: exePath };
|
return { kind: inferKindFromIdentifier(bundleId), path: exePath };
|
||||||
}
|
}
|
||||||
|
|
||||||
|
function detectDefaultBrowserBundleIdMac(): string | null {
|
||||||
|
const plistPath = path.join(
|
||||||
|
os.homedir(),
|
||||||
|
"Library/Preferences/com.apple.LaunchServices/com.apple.launchservices.secure.plist",
|
||||||
|
);
|
||||||
|
if (!exists(plistPath)) return null;
|
||||||
|
const handlersRaw = execText(
|
||||||
|
"/usr/bin/plutil",
|
||||||
|
["-extract", "LSHandlers", "json", "-o", "-", "--", plistPath],
|
||||||
|
2000,
|
||||||
|
5 * 1024 * 1024,
|
||||||
|
);
|
||||||
|
if (!handlersRaw) return null;
|
||||||
|
let handlers: unknown;
|
||||||
|
try {
|
||||||
|
handlers = JSON.parse(handlersRaw);
|
||||||
|
} catch {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
if (!Array.isArray(handlers)) return null;
|
||||||
|
|
||||||
|
const resolveScheme = (scheme: string) => {
|
||||||
|
let candidate: string | null = null;
|
||||||
|
for (const entry of handlers) {
|
||||||
|
if (!entry || typeof entry !== "object") continue;
|
||||||
|
const record = entry as Record<string, unknown>;
|
||||||
|
if (record.LSHandlerURLScheme !== scheme) continue;
|
||||||
|
const role =
|
||||||
|
(typeof record.LSHandlerRoleAll === "string" && record.LSHandlerRoleAll) ||
|
||||||
|
(typeof record.LSHandlerRoleViewer === "string" && record.LSHandlerRoleViewer) ||
|
||||||
|
null;
|
||||||
|
if (role) candidate = role;
|
||||||
|
}
|
||||||
|
return candidate;
|
||||||
|
};
|
||||||
|
|
||||||
|
return resolveScheme("http") ?? resolveScheme("https");
|
||||||
|
}
|
||||||
|
|
||||||
function detectDefaultChromiumExecutableLinux(): BrowserExecutable | null {
|
function detectDefaultChromiumExecutableLinux(): BrowserExecutable | null {
|
||||||
const desktopId =
|
const desktopId =
|
||||||
execText("xdg-settings", ["get", "default-web-browser"]) ||
|
execText("xdg-settings", ["get", "default-web-browser"]) ||
|
||||||
|
|||||||
Reference in New Issue
Block a user