Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
128 changes: 102 additions & 26 deletions test/e2e-browser/specs/agent-chat.spec.ts
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,14 @@ test.describe('Agent Chat', () => {
.toBeVisible({ timeout: 10_000 })
}

async function getActiveLeaf(harness: any) {
const tabId = await harness.getActiveTabId()
expect(tabId).toBeTruthy()
const layout = await harness.getPaneLayout(tabId!)
expect(layout?.type).toBe('leaf')
return { tabId: tabId!, paneId: layout.id as string }
}

test('pane picker shows base pane types', async ({ freshellPage, page, terminal }) => {
await terminal.waitForTerminal()
await openPanePicker(page)
Expand All @@ -37,37 +45,105 @@ test.describe('Agent Chat', () => {
expect(shellVisible || wslVisible || cmdVisible || psVisible).toBe(true)
})

test('agent chat provider appears when CLI is available', async ({ freshellPage, page, harness, terminal }) => {
test('agent chat provider appears when the Claude CLI is available and enabled', async ({ freshellPage, page, terminal }) => {
await terminal.waitForTerminal()

// Check if any agent chat provider is available via Redux state
const state = await harness.getState()
const availableClis = state.connection?.availableClis ?? {}
const enabledProviders = state.settings?.settings?.codingCli?.enabledProviders ?? []

// Find a provider that is both available and enabled
const hasProvider = Object.keys(availableClis).some(
(cli) => availableClis[cli] && enabledProviders.includes(cli)
)

if (!hasProvider) {
// No CLI providers available in the isolated test env -- skip
test.skip()
return
}
await page.evaluate(() => {
const harness = window.__FRESHELL_TEST_HARNESS__
harness?.dispatch({
type: 'connection/setAvailableClis',
payload: { claude: true },
})
harness?.dispatch({
type: 'settings/updateSettingsLocal',
payload: {
codingCli: {
enabledProviders: ['claude'],
},
},
})
})

await openPanePicker(page)

// The picker should show more than just Shell/Editor/Browser
const pickerOptions = page.locator('[data-testid="pane-picker-options"] button')
const count = await pickerOptions.count()
expect(count).toBeGreaterThan(3)
await expect(page.getByRole('button', { name: /^Freshclaude$/i })).toBeVisible()
})

test.skip('agent chat permission banners appear', async ({ freshellPage, page }) => {
// This test requires a live SDK session to trigger permission requests.
// In the isolated test environment, no SDK session is available.
// Skipping until a mock SDK bridge is implemented.
test('agent chat permission banners appear and allow sends a response', async ({ freshellPage, page, harness, terminal }) => {
await terminal.waitForTerminal()
const { tabId, paneId } = await getActiveLeaf(harness)
const sessionId = 'sdk-e2e-permission'
const cliSessionId = '33333333-3333-4333-8333-333333333333'

await page.evaluate((currentPaneId: string) => {
window.__FRESHELL_TEST_HARNESS__?.setAgentChatNetworkEffectsSuppressed(currentPaneId, true)
}, paneId)

await page.evaluate(({ currentTabId, currentPaneId, currentSessionId, currentCliSessionId }) => {
const harness = window.__FRESHELL_TEST_HARNESS__
harness?.dispatch({
type: 'agentChat/sessionCreated',
payload: {
requestId: 'req-e2e-permission',
sessionId: currentSessionId,
},
})
harness?.dispatch({
type: 'agentChat/sessionInit',
payload: {
sessionId: currentSessionId,
cliSessionId: currentCliSessionId,
},
})
harness?.dispatch({
type: 'agentChat/addPermissionRequest',
payload: {
sessionId: currentSessionId,
requestId: 'perm-e2e',
subtype: 'can_use_tool',
tool: {
name: 'Bash',
input: { command: 'echo hello-from-permission-banner' },
},
},
})
harness?.dispatch({
type: 'panes/updatePaneContent',
payload: {
tabId: currentTabId,
paneId: currentPaneId,
content: {
kind: 'agent-chat',
provider: 'freshclaude',
createRequestId: 'req-e2e-permission',
sessionId: currentSessionId,
resumeSessionId: currentCliSessionId,
status: 'running',
},
},
})
}, {
currentTabId: tabId,
currentPaneId: paneId,
currentSessionId: sessionId,
currentCliSessionId: cliSessionId,
})

const banner = page.getByRole('alert', { name: /permission request for bash/i })
await expect(banner).toBeVisible()
await expect(banner).toContainText('Permission requested: Bash')
await expect(banner).toContainText('$ echo hello-from-permission-banner')

await harness.clearSentWsMessages()
await banner.getByRole('button', { name: /allow tool use/i }).click()

await expect.poll(async () => {
const sent = await harness.getSentWsMessages()
return sent.find((msg: any) => msg?.type === 'sdk.permission.respond') ?? null
}).toMatchObject({
type: 'sdk.permission.respond',
sessionId,
requestId: 'perm-e2e',
behavior: 'allow',
})
})

test('picker creates shell pane when shell is selected', async ({ freshellPage, page, harness, terminal }) => {
Expand Down
Loading
Loading