From 10b3d84b7ce95212565aac8fabbb80ee223d100a Mon Sep 17 00:00:00 2001 From: Neil <4138956+nwparker@users.noreply.github.com> Date: Sat, 26 Sep 2026 12:57:26 -0700 Subject: [PATCH] perf: build browser settings search catalog once per render (#23155) --- .../BrowserPane.search-catalog.test.tsx | 129 ++++++++++++++++++ .../src/components/settings/BrowserPane.tsx | 31 ++--- 2 files changed, 141 insertions(+), 19 deletions(-) create mode 100644 src/renderer/src/components/settings/BrowserPane.search-catalog.test.tsx diff --git a/src/renderer/src/components/settings/BrowserPane.search-catalog.test.tsx b/src/renderer/src/components/settings/BrowserPane.search-catalog.test.tsx new file mode 100644 index 00000000000..20517cf7276 --- /dev/null +++ b/src/renderer/src/components/settings/BrowserPane.search-catalog.test.tsx @@ -0,0 +1,129 @@ +// @vitest-environment happy-dom +import { cleanup, fireEvent, render, screen } from '@testing-library/react' +import { afterEach, beforeEach, expect, it, vi } from 'vitest' +import { getDefaultSettings } from '../../../../shared/constants' +import { BrowserPane } from './BrowserPane' +import { getBrowserPaneSearchEntries } from './browser-search' +import type * as BrowserSearch from './browser-search' + +const fake = vi.hoisted(() => ({ + query: '', + locale: { language: 'en' }, + translate: vi.fn((_key: string, fallback: string) => fallback), + setHost: vi.fn(), + profiles: [], + repos: [], + map: new Map(), + environments: [], + hostOptions: [{ id: 'local', kind: 'local', label: 'Local' }] +})) +vi.mock('@/i18n/i18n', () => ({ i18n: fake.locale, translate: fake.translate })) +vi.mock('./browser-search', async (importOriginal) => { + const original = await importOriginal() + return { ...original, getBrowserPaneSearchEntries: vi.fn(original.getBrowserPaneSearchEntries) } +}) +vi.mock('@/store', () => ({ + useAppStore: (selector: (state: Record) => unknown) => + selector({ + settingsSearchQuery: fake.query, + browserDefaultUrl: '', + browserSessionProfiles: fake.profiles, + repos: fake.repos, + sshTargetLabels: fake.map, + sshConnectionStates: fake.map, + runtimeEnvironments: fake.environments, + runtimeStatusByEnvironmentId: fake.map, + browserSessionHostIdOverride: null, + setBrowserSessionHostId: fake.setHost + }) +})) +vi.mock('@/components/terminal-pane/pane-helpers', () => ({ isMacUserAgent: () => false })) +vi.mock('../sidebar/sidebar-host-options', () => ({ + buildSidebarHostOptions: () => fake.hostOptions +})) +vi.mock('./BrowserHomePageSetting', () => ({ + BrowserHomePageSetting: ({ + value, + onChange + }: { + value: string + onChange: (value: string) => void + }) => ( + onChange(event.target.value)} + /> + ) +})) +vi.mock('./BrowserUsePane', () => ({ BrowserUseSetup: () => Browser use row })) +vi.mock('./BrowserDefaultZoomSetting', () => ({ + BrowserDefaultZoomSetting: () => Zoom row +})) +vi.mock('./BrowserSearchEngineSetting', () => ({ + BrowserSearchEngineSetting: () => Search row +})) +vi.mock('./BrowserLinkRoutingSetting', () => ({ + BrowserLinkRoutingSetting: () => Routing row +})) +vi.mock('./BrowserLinkRoutingModifierSetting', () => ({ + BrowserLinkRoutingModifierSetting: () => Modifier row +})) +vi.mock('./BrowserTerminalLinkActionsSetting', () => ({ + BrowserTerminalLinkActionsSetting: () => Terminal links row +})) +vi.mock('./BrowserLocalhostWorktreeLabelsSetting', () => ({ + BrowserLocalhostWorktreeLabelsSetting: () => Localhost row +})) +vi.mock('./BrowserClientHostedRemoteSetting', () => ({ + BrowserClientHostedRemoteSetting: () => Remote row +})) +vi.mock('./BrowserSshWorkspaceRoutingSetting', () => ({ + BrowserSshWorkspaceRoutingSetting: () => SSH row +})) +vi.mock('./BrowserUserAgentSetting', () => ({ + BrowserUserAgentSetting: () => Identity row +})) +vi.mock('./SettingsFormControls', () => ({ SettingsSubsectionHeader: () => null })) +vi.mock('./BrowserSessionCookiesSection', () => ({ + BrowserSessionCookiesSection: () => Cookies row +})) +vi.mock('./BrowserNewProfileDialog', () => ({ BrowserNewProfileDialog: () => null })) + +beforeEach(() => { + vi.clearAllMocks() + fake.query = '' + fake.locale.language = 'en' + fake.translate.mockImplementation((_key, fallback) => fallback) +}) +afterEach(cleanup) +it('builds one catalog per render while typing a home page draft', () => { + render() + vi.clearAllMocks() + for (let index = 1; index <= 20; index++) { + fireEvent.change(screen.getByRole('textbox'), { target: { value: 'x'.repeat(index) } }) + } + expect(getBrowserPaneSearchEntries).toHaveBeenCalledTimes(20) +}) +it('keeps targeted search visibility', () => { + fake.query = 'Default Home Page' + render() + expect(screen.getByRole('textbox')).toBeTruthy() + expect(screen.queryByText('Cookies row')).toBeNull() +}) + +it('rebuilds metadata in the next render after the language changes', () => { + fake.query = 'Default Home Page' + const settings = getDefaultSettings('/synthetic') + const view = render() + expect(screen.getByRole('textbox')).toBeTruthy() + fake.locale.language = 'synthetic-locale' + fake.query = 'Translated home' + fake.translate.mockImplementation((_key, fallback) => + fallback === 'Default Home Page' ? 'Translated home' : fallback + ) + vi.mocked(getBrowserPaneSearchEntries).mockClear() + view.rerender() + expect(screen.getByRole('textbox')).toBeTruthy() + expect(screen.queryByText('Cookies row')).toBeNull() +}) diff --git a/src/renderer/src/components/settings/BrowserPane.tsx b/src/renderer/src/components/settings/BrowserPane.tsx index be271b61785..41b330b2c33 100644 --- a/src/renderer/src/components/settings/BrowserPane.tsx +++ b/src/renderer/src/components/settings/BrowserPane.tsx @@ -102,25 +102,18 @@ export function BrowserPane({ const selectedSearchEngine = browserDefaultSearchEngine ?? 'google' - const showHomePage = matchesSettingsSearch(searchQuery, [getBrowserPaneSearchEntries()[0]]) - const showSearchEngine = matchesSettingsSearch(searchQuery, [getBrowserPaneSearchEntries()[1]]) - const showDefaultZoom = matchesSettingsSearch(searchQuery, [getBrowserPaneSearchEntries()[2]]) - const showLinkRouting = matchesSettingsSearch(searchQuery, [getBrowserPaneSearchEntries()[3]]) - const showLinkRoutingModifier = matchesSettingsSearch(searchQuery, [ - getBrowserPaneSearchEntries()[4] - ]) - const showTerminalLinkActions = matchesSettingsSearch(searchQuery, [ - getBrowserPaneSearchEntries()[5] - ]) - const showLocalhostLabels = matchesSettingsSearch(searchQuery, [getBrowserPaneSearchEntries()[6]]) - const showCookies = matchesSettingsSearch(searchQuery, [getBrowserPaneSearchEntries()[7]]) - const showClientHostedRemote = matchesSettingsSearch(searchQuery, [ - getBrowserPaneSearchEntries()[8] - ]) - const showSshWorkspaceRouting = matchesSettingsSearch(searchQuery, [ - getBrowserPaneSearchEntries()[9] - ]) - const showUserAgent = matchesSettingsSearch(searchQuery, [getBrowserPaneSearchEntries()[10]]) + const browserSearchEntries = getBrowserPaneSearchEntries() + const showHomePage = matchesSettingsSearch(searchQuery, [browserSearchEntries[0]]) + const showSearchEngine = matchesSettingsSearch(searchQuery, [browserSearchEntries[1]]) + const showDefaultZoom = matchesSettingsSearch(searchQuery, [browserSearchEntries[2]]) + const showLinkRouting = matchesSettingsSearch(searchQuery, [browserSearchEntries[3]]) + const showLinkRoutingModifier = matchesSettingsSearch(searchQuery, [browserSearchEntries[4]]) + const showTerminalLinkActions = matchesSettingsSearch(searchQuery, [browserSearchEntries[5]]) + const showLocalhostLabels = matchesSettingsSearch(searchQuery, [browserSearchEntries[6]]) + const showCookies = matchesSettingsSearch(searchQuery, [browserSearchEntries[7]]) + const showClientHostedRemote = matchesSettingsSearch(searchQuery, [browserSearchEntries[8]]) + const showSshWorkspaceRouting = matchesSettingsSearch(searchQuery, [browserSearchEntries[9]]) + const showUserAgent = matchesSettingsSearch(searchQuery, [browserSearchEntries[10]]) const showBrowserUse = matchesSettingsSearch(searchQuery, getBrowserUsePaneSearchEntries()) const isMac = isMacUserAgent() const linkRoutingDescription = getBrowserLinkRoutingDescription(