experiments in a post-browser web
10
fork

Configure Feed

Select the types of activity you want to include in your feed.

fix(window): handle external URLs with no explicit position

- Compute centered screen coordinates when x/y are undefined before canvas
bounds adjustment, preventing NaN window positions
- Expose handleExternalUrl on test utilities for Playwright access
- Add deterministic test for main-process external URL flow

+67 -1
+2 -1
backend/electron/entry.ts
··· 30 30 registerExternalUrlHandlers, 31 31 registerSecondInstanceHandler, 32 32 handleCliUrl, 33 + handleExternalUrl, 33 34 // Background window 34 35 createBackgroundWindow, 35 36 // App lifecycle ··· 108 109 const DEBUG = !!process.env.DEBUG; 109 110 110 111 // Expose test utilities on global for Playwright evaluateMain access 111 - (globalThis as any).__peek_test = { handleLocalShortcut }; 112 + (globalThis as any).__peek_test = { handleLocalShortcut, handleExternalUrl }; 112 113 (globalThis as any).__peek_electron = { globalShortcut }; 113 114 114 115 // Parse --load-extension CLI arguments for dev workflow
+13
backend/electron/ipc.ts
··· 2320 2320 const CANVAS_MARGIN = 8; 2321 2321 const CANVAS_TRIGGER_ZONE = 8; 2322 2322 const CANVAS_NAVBAR_HEIGHT = 36; // Always reserve space for navbar (avoids resize jumps) 2323 + 2324 + // When no explicit position is provided (e.g., external URLs, pubsub-triggered opens), 2325 + // compute a centered position first so canvas bounds adjustment has valid coordinates. 2326 + // Without this, undefined x/y produces NaN which breaks window positioning. 2327 + if (winOptions.x === undefined || winOptions.y === undefined) { 2328 + const primaryDisplay = screen.getPrimaryDisplay(); 2329 + const { width: screenW, height: screenH } = primaryDisplay.workAreaSize; 2330 + const winW = winOptions.width as number || APP_DEF_WIDTH; 2331 + const winH = winOptions.height as number || APP_DEF_HEIGHT; 2332 + winOptions.x = Math.round((screenW - winW) / 2); 2333 + winOptions.y = Math.round((screenH - winH) / 2); 2334 + } 2335 + 2323 2336 // winOptions.x/y/width/height are currently the webview screen coordinates 2324 2337 canvasWebviewBounds = { 2325 2338 x: winOptions.x as number,
+52
tests/desktop/smoke.spec.ts
··· 943 943 }, externalWindow.id); 944 944 } 945 945 }); 946 + 947 + test('handleExternalUrl from main process opens URL correctly', async () => { 948 + // This tests the REAL external URL path — calling handleExternalUrl from 949 + // the main process, which is what happens when macOS sends an open-url event 950 + // or when Peek receives a second-instance signal with a URL argument. 951 + // The previous test simulates via pubsub from the renderer; this test 952 + // exercises the full main-process -> pubsub -> renderer -> window-open flow. 953 + 954 + await waitForExtensionsReady(sharedBgWindow, 15000); 955 + 956 + // Get initial window count (include internal to see ALL windows) 957 + const initialList = await sharedBgWindow.evaluate(async () => { 958 + return await (window as any).app.window.list(); 959 + }); 960 + const initialCount = initialList.windows?.length || 0; 961 + 962 + const testUrl = 'https://example.com/main-process-external-test'; 963 + 964 + // Call handleExternalUrl from the main process (simulates real OS open-url) 965 + const mainResult = await sharedApp.evaluateMain!(({ app }) => { 966 + const { handleExternalUrl } = (globalThis as any).__peek_test; 967 + if (!handleExternalUrl) return { error: 'handleExternalUrl not found on __peek_test' }; 968 + handleExternalUrl('https://example.com/main-process-external-test', 'os'); 969 + return { success: true }; 970 + }); 971 + 972 + // Verify main process call succeeded 973 + expect((mainResult as any).error).toBeUndefined(); 974 + 975 + // Wait for window with the specific URL to appear (deterministic — no count-based checks) 976 + let externalWindow: any = null; 977 + const deadline = Date.now() + 5000; 978 + while (Date.now() < deadline) { 979 + const list = await sharedBgWindow.evaluate(async () => { 980 + return await (window as any).app.window.list(); 981 + }); 982 + externalWindow = list.windows?.find((w: any) => 983 + w.url && (w.url.includes('main-process-external-test') || w.url.includes(encodeURIComponent('main-process-external-test'))) 984 + ); 985 + if (externalWindow) break; 986 + await sleep(100); 987 + } 988 + 989 + expect(externalWindow).toBeTruthy(); 990 + 991 + // Clean up 992 + if (externalWindow) { 993 + await sharedBgWindow.evaluate(async (id: number) => { 994 + await (window as any).app.window.close(id); 995 + }, externalWindow.id); 996 + } 997 + }); 946 998 }); 947 999 948 1000 // ============================================================================