fix(settings): preserve multiline proxy bypass rules (#20957)

This commit is contained in:
Jinjing
2026-09-15 22:08:40 -07:00
committed by GitHub
parent bfc297df99
commit b0d46e2d3d
4 changed files with 128 additions and 6 deletions
@@ -0,0 +1,63 @@
// @vitest-environment happy-dom
import { cleanup, fireEvent, render } from '@testing-library/react'
import { afterEach, describe, expect, it, vi } from 'vitest'
import { getDefaultSettings } from '../../../../shared/constants'
import { AdvancedNetworkSettingsSection } from './AdvancedNetworkSettingsSection'
afterEach(() => cleanup())
describe('AdvancedNetworkSettingsSection bypass rules control', () => {
it('keeps newline input and canonicalizes it when focus leaves the textarea', async () => {
const updateSettings = vi.fn()
const { container } = render(
<AdvancedNetworkSettingsSection
settings={{ ...getDefaultSettings('/tmp'), httpProxyBypassRules: '' }}
updateSettings={updateSettings}
/>
)
const configureButton = Array.from(container.querySelectorAll('button')).find((button) =>
button.textContent?.includes('Configure proxy')
)
expect(configureButton).not.toBeUndefined()
fireEvent.click(configureButton!)
const textarea = container.querySelector<HTMLTextAreaElement>(
'#settings-http-proxy-bypass-rules'
)
expect(textarea).not.toBeNull()
fireEvent.change(textarea!, { target: { value: 'localhost\n127.0.0.1\n*.internal.corp' } })
fireEvent.blur(textarea!)
expect(updateSettings).toHaveBeenCalledWith({
httpProxyBypassRules: 'localhost;127.0.0.1;*.internal.corp'
})
})
it('does not commit when Enter is pressed inside the textarea', () => {
const updateSettings = vi.fn()
const { container } = render(
<AdvancedNetworkSettingsSection
settings={{ ...getDefaultSettings('/tmp'), httpProxyBypassRules: '' }}
updateSettings={updateSettings}
/>
)
fireEvent.click(
Array.from(container.querySelectorAll('button')).find((button) =>
button.textContent?.includes('Configure proxy')
)!
)
const textarea = container.querySelector<HTMLTextAreaElement>(
'#settings-http-proxy-bypass-rules'
)!
textarea.focus()
fireEvent.keyDown(textarea, { key: 'Enter', code: 'Enter' })
expect(document.activeElement).toBe(textarea)
expect(updateSettings).not.toHaveBeenCalled()
})
})
@@ -1,6 +1,10 @@
import { renderToStaticMarkup } from 'react-dom/server'
import { createElement } from 'react'
import { describe, expect, it } from 'vitest'
import type { GlobalSettings } from '../../../../shared/global-settings-types'
import { getDefaultSettings } from '../../../../shared/constants'
import {
AdvancedNetworkSettingsSection,
createHttpProxyBypassRulesDraftState,
createHttpProxyUrlDraftState,
hasConfiguredNetworkProxy,
@@ -11,6 +15,23 @@ import {
} from './AdvancedNetworkSettingsSection'
describe('AdvancedNetworkSettingsSection proxy drafts', () => {
it('renders bypass rules as a multiline textarea', () => {
const markup = renderToStaticMarkup(
createElement(AdvancedNetworkSettingsSection, {
settings: {
...getDefaultSettings('/tmp'),
httpProxyBypassRules: 'localhost\n127.0.0.1\n*.internal.corp'
},
updateSettings: () => undefined
})
)
expect(markup).toMatch(/<textarea[^>]*id="settings-http-proxy-bypass-rules"[^>]*>/)
expect(markup).toContain('localhost')
expect(markup).toContain('127.0.0.1')
expect(markup).toContain('*.internal.corp')
})
it('keeps a committed proxy URL draft tied to the current persisted source', () => {
const current = createHttpProxyUrlDraftState(undefined)
@@ -9,6 +9,7 @@ import { Button } from '../ui/button'
import { Collapsible, CollapsibleContent, CollapsibleTrigger } from '../ui/collapsible'
import { Input } from '../ui/input'
import { Label } from '../ui/label'
import { Textarea } from '../ui/textarea'
import { getAdvancedNetworkSearchEntries } from './advanced-network-search'
import { SearchableSetting } from './SearchableSetting'
import { matchesSettingsSearch, normalizeSettingsSearchQuery } from './settings-search'
@@ -304,16 +305,11 @@ export function AdvancedNetworkSettingsSection({
'Proxy Bypass Rules'
)}
</Label>
<Input
<Textarea
id="settings-http-proxy-bypass-rules"
value={httpProxyBypassRulesDraft}
onChange={(e) => updateHttpProxyBypassRulesDraft(e.target.value)}
onBlur={commitHttpProxyBypassRules}
onKeyDown={(e) => {
if (e.key === 'Enter') {
e.currentTarget.blur()
}
}}
placeholder={translate(
'auto.components.settings.AdvancedNetworkSettingsSection.3e431564b5',
'localhost, 127.0.0.1, *.internal'
@@ -322,6 +318,7 @@ export function AdvancedNetworkSettingsSection({
autoCorrect="off"
autoComplete="off"
spellCheck={false}
rows={3}
className="font-mono text-xs"
/>
<p className="text-xs text-muted-foreground">
@@ -0,0 +1,41 @@
import { test, expect } from './helpers/orca-app'
import { waitForSessionReady } from './helpers/store'
test.describe('network proxy bypass rules', () => {
test('preserves newline-separated hosts and canonicalizes them on blur', async ({ orcaPage }) => {
await waitForSessionReady(orcaPage)
const original = await orcaPage.evaluate(() => window.api.settings.get())
try {
await orcaPage.evaluate(() => {
const state = window.__store?.getState()
state?.openSettingsTarget({ pane: 'advanced', repoId: null })
state?.openSettingsPage()
})
await expect(orcaPage.getByRole('heading', { name: 'Advanced', exact: true })).toBeVisible()
await orcaPage.getByRole('button', { name: 'Configure proxy' }).click()
const bypassRules = orcaPage.locator('#settings-http-proxy-bypass-rules')
await expect(bypassRules).toBeVisible()
await expect(bypassRules).toHaveJSProperty('tagName', 'TEXTAREA')
await bypassRules.fill('localhost\n127.0.0.1\n*.internal.corp')
await expect(bypassRules).toHaveValue('localhost\n127.0.0.1\n*.internal.corp')
await orcaPage.locator('#settings-http-proxy-url').focus()
await expect
.poll(
async () =>
(await orcaPage.evaluate(() => window.api.settings.get())).httpProxyBypassRules
)
.toBe('localhost;127.0.0.1;*.internal.corp')
await expect(bypassRules).toHaveValue('localhost;127.0.0.1;*.internal.corp')
} finally {
await orcaPage.evaluate(
(settings) =>
window.api.settings.set({ httpProxyBypassRules: settings.httpProxyBypassRules ?? '' }),
original
)
}
})
})