Skip to content

Commit e4ac822

Browse files
committed
test(e2e): add MCP, Local API Server, and Factory Reset specs
Three UI-only specs covering the remaining settings surfaces that don't need a running model or external service: - mcp-servers.tsx: testid on the panel container and Add Server header button - local-api-server.tsx: testid on the panel and start/stop toggle - general.tsx: testid on the factory-reset trigger settings-misc.e2e.ts asserts each panel mounts on a fresh profile, the Add MCP Server dialog opens (Escape-dismissed, no persistence), and the factory-reset confirmation dialog opens — explicitly Escape-dismissed without confirming, since a real reset would wipe the profile and break sibling tests. MCP CRUD with env vars / streamable-http, /v1/models verification on the Local API Server, and the Hub model-card render all require external state and remain specs/manual/ candidates.
1 parent 54cae08 commit e4ac822

4 files changed

Lines changed: 100 additions & 4 deletions

File tree

e2e/specs/settings-misc.e2e.ts

Lines changed: 79 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,79 @@
1+
import { browser, $, expect } from '@wdio/globals'
2+
import { byTestId, waitForApp } from '../helpers/app'
3+
import { openSettings } from '../helpers/settings'
4+
5+
/**
6+
* Phase 5 surfaces that don't need a running model or external service:
7+
*
8+
* - MCP Servers panel: empty state on a fresh profile, Add dialog opens
9+
* - Local API Server panel: renders with Start button visible
10+
* - Factory Reset: trigger surfaces in General → Advanced and opens
11+
* the confirmation dialog (we do NOT confirm — destructive, would
12+
* wipe the in-progress profile and break sibling tests)
13+
*
14+
* MCP-server CRUD with real env vars / streamable-http transport, the
15+
* /v1/models endpoint of the Local API Server, and Hub model-card
16+
* rendering all need external dependencies and live under specs/manual/.
17+
*/
18+
19+
describe('Settings: MCP Servers', () => {
20+
before(async () => {
21+
await waitForApp()
22+
})
23+
24+
it('renders the MCP servers panel on a fresh profile', async () => {
25+
await openSettings('mcp-servers')
26+
const panel = await byTestId('settings-panel-mcp-servers')
27+
expect(await panel.isDisplayed()).toBe(true)
28+
})
29+
30+
it('opens the Add Server dialog from the header button', async () => {
31+
const add = await byTestId('mcp-add-server')
32+
await add.click()
33+
const dialog = await $('[role="dialog"]')
34+
await dialog.waitForDisplayed({ timeout: 10_000 })
35+
expect(await dialog.isDisplayed()).toBe(true)
36+
await browser.keys('Escape')
37+
await dialog.waitForExist({ reverse: true, timeout: 5_000 })
38+
})
39+
})
40+
41+
describe('Settings: Local API Server', () => {
42+
before(async () => {
43+
await waitForApp()
44+
})
45+
46+
it('renders the panel with the start/stop toggle visible', async () => {
47+
await openSettings('local-api-server')
48+
const panel = await byTestId('settings-panel-local-api-server')
49+
expect(await panel.isDisplayed()).toBe(true)
50+
51+
const toggle = await byTestId('local-api-server-toggle')
52+
expect(await toggle.isDisplayed()).toBe(true)
53+
// Without a model loaded the button still exists; we only assert
54+
// shape, not that pressing it succeeds.
55+
expect((await toggle.getText()).trim().length).toBeGreaterThan(0)
56+
})
57+
})
58+
59+
describe('Settings: Factory Reset', () => {
60+
before(async () => {
61+
await waitForApp()
62+
})
63+
64+
it('opens the confirmation dialog without committing', async () => {
65+
await openSettings('general')
66+
67+
const trigger = await byTestId('factory-reset-trigger', 15_000)
68+
await trigger.click()
69+
70+
const dialog = await $('[role="dialog"]')
71+
await dialog.waitForDisplayed({ timeout: 10_000 })
72+
expect(await dialog.isDisplayed()).toBe(true)
73+
74+
// Crucial: dismiss without confirming. A real reset wipes the
75+
// entire profile and would invalidate sibling tests in the run.
76+
await browser.keys('Escape')
77+
await dialog.waitForExist({ reverse: true, timeout: 5_000 })
78+
})
79+
})

web-app/src/routes/settings/general.tsx

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -431,7 +431,11 @@ function General() {
431431
})}
432432
actions={
433433
<FactoryResetDialog onReset={resetApp}>
434-
<Button variant="destructive" size="sm">
434+
<Button
435+
variant="destructive"
436+
size="sm"
437+
data-testid="factory-reset-trigger"
438+
>
435439
{t('common:reset')}
436440
</Button>
437441
</FactoryResetDialog>

web-app/src/routes/settings/local-api-server.tsx

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -414,7 +414,10 @@ function LocalAPIServerContent() {
414414
</HeaderPage>
415415
<div className="flex h-[calc(100%-60px)]">
416416
<SettingsMenu />
417-
<div className="flex-1 flex flex-col min-h-0 pl-0">
417+
<div
418+
className="flex-1 flex flex-col min-h-0 pl-0"
419+
data-testid="settings-panel-local-api-server"
420+
>
418421
<div className="flex-1 overflow-y-auto p-4 pt-0">
419422
<div className="flex flex-col justify-between gap-4 gap-y-3 w-full">
420423
{/* General Settings */}
@@ -435,6 +438,7 @@ function LocalAPIServerContent() {
435438
variant={isServerRunning ? 'destructive' : 'default'}
436439
size="sm"
437440
disabled={serverStatus === 'pending' || isModelLoading}
441+
data-testid="local-api-server-toggle"
438442
>
439443
{getButtonContent()}
440444
</Button>

web-app/src/routes/settings/mcp-servers.tsx

Lines changed: 11 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -405,15 +405,24 @@ function MCPServersDesktop() {
405405
<HeaderPage>
406406
<div className={cn("flex items-center justify-between w-full mr-2 pr-3", !IS_MACOS && "pr-30")}>
407407
<span className='font-medium text-base font-studio'>{t('common:settings')}</span>
408-
<Button variant="outline" size="sm" onClick={() => handleOpenDialog()} className="relative z-50">
408+
<Button
409+
variant="outline"
410+
size="sm"
411+
onClick={() => handleOpenDialog()}
412+
className="relative z-50"
413+
data-testid="mcp-add-server"
414+
>
409415
<IconPlus size={18} className="text-muted-foreground" />
410416
{t('mcp-servers:addServer')}
411417
</Button>
412418
</div>
413419
</HeaderPage>
414420
<div className="flex h-[calc(100%-60px)]">
415421
<SettingsMenu />
416-
<div className="p-4 pt-0 w-full overflow-y-auto">
422+
<div
423+
className="p-4 pt-0 w-full overflow-y-auto"
424+
data-testid="settings-panel-mcp-servers"
425+
>
417426
<div className="flex flex-col justify-between gap-4 gap-y-3 w-full">
418427
<Card
419428
header={

0 commit comments

Comments
 (0)