open-design/apps/daemon/tests/browser-open.test.ts
Sapientropic 5390541f34
fix daemon browser opener on Windows (#953)
Co-authored-by: Sapientropic <194952804+Sapientropic@users.noreply.github.com>
2026-05-09 22:04:07 +08:00

40 lines
1.6 KiB
TypeScript

import { EventEmitter } from 'node:events';
import type { ChildProcess } from 'node:child_process';
import { describe, expect, it, vi } from 'vitest';
import { createBrowserOpenInvocation, openBrowser } from '../src/browser-open.js';
describe('browser open helper', () => {
it('opens URLs on Windows through cmd.exe instead of spawning the shell builtin directly', () => {
const invocation = createBrowserOpenInvocation('win32', 'http://127.0.0.1:7456/');
expect(invocation.command).toMatch(/cmd(?:\.exe)?$/i);
expect(invocation.args.slice(0, 3)).toEqual(['/d', '/s', '/c']);
expect(invocation.args[3]).toContain('start "" "http://127.0.0.1:7456/"');
expect(invocation.options).toMatchObject({ windowsVerbatimArguments: true });
});
it('escapes cmd.exe metacharacters before opening Windows URLs', () => {
const invocation = createBrowserOpenInvocation('win32', 'https://example.test/a b?q=%USERPROFILE%&name="A"');
expect(invocation.args[3]).toMatch(/^"start "" /);
expect(invocation.args[3]).toContain('"^%"USERPROFILE"^%"');
expect(invocation.args[3]).toContain('name=""A""');
});
it('handles opener spawn errors without crashing the daemon', () => {
const child = new EventEmitter() as ChildProcess;
child.unref = vi.fn() as ChildProcess['unref'];
const spawn = vi.fn(() => child);
const warn = vi.fn();
openBrowser('http://127.0.0.1:7456/', {
platform: 'linux',
spawn,
warn,
});
expect(() => child.emit('error', new Error('spawn xdg-open ENOENT'))).not.toThrow();
expect(warn).toHaveBeenCalledWith(expect.stringContaining('failed to open browser'));
});
});