test(ui): follow the shared model picker in four e2e specs

The agent task form, the scheduling rule sheet and the add-on model
selector now draw the shared picker: a button that opens a listbox, with
a warm or cold tag inside each option name. Four specs still used the
old select, combobox and exact option names.

Task and rule specs open the picker button and choose from the list. The
rule spec types a custom name in the filter and takes it with Enter. The
diarization and 3D animation specs match options by their model name
prefix, as the other specs already do.

Assisted-by: Claude Code:claude-sonnet-5-5
Signed-off-by: Ettore Di Giacinto <mudler@localai.io>
This commit is contained in:
Ettore Di Giacinto committed 2026-11-03 10:57:02 +00:00
1 parent c8b757f4a3
commit 0bcf6b648e
4 files changed
+12 -9

No files matched your search

@@ -57,7 +57,8 @@ test('an agent task is created, run with a parameter, and its job is listed with
await page.getByRole('button', { name: 'New task' }).click()
const form = page.getByTestId('agent-task-form')
await form.getByLabel('Name').fill(name)
await form.getByLabel('Model').selectOption('mock-model')
await form.getByRole('button', { name: 'Model' }).click()
await page.getByRole('option', { name: /^mock-model/ }).click()
await form.getByLabel('Prompt').fill('Say hello to {{.who}}')
await page.getByRole('button', { name: 'Save task' }).click()
await expect(form).toHaveCount(0)
@@ -128,7 +128,7 @@ for (const change of ['recording', 'model']) test(`late inference and save canno
await page.getByRole('button', { name: 'Diarize', exact: true }).click(); await req
const replace = async () => {
if (change === 'recording') await page.getByLabel('Recording', { exact: true }).setInputFiles({ ...file, name: 'new.wav' })
else { await page.getByRole('button', { name: 'diarizer', exact: true }).click(); await page.getByRole('option', { name: 'other', exact: true }).click() }
else { await page.getByRole('button', { name: 'diarizer', exact: true }).click(); await page.getByRole('option', { name: /^other/ }).click() }
}
const inferenceResponse = page.waitForResponse('**/v1/audio/diarization')
await replace(); release(); await inferenceResponse
@@ -124,8 +124,10 @@ test.describe('Placement rules: the sheet', () => {
await page.goto('/app/scheduling')
await page.getByRole('button', { name: 'New rule' }).click()
await expect(page.getByRole('button', { name: 'Save rule' })).toBeDisabled()
await page.getByRole('combobox', { name: 'Model' }).fill('new-model')
await page.keyboard.press('Escape')
await page.getByRole('button', { name: 'Model' }).click()
await page.getByRole('combobox', { name: 'Filter models' }).fill('new-model')
await page.keyboard.press('Enter')
await expect(page.getByRole('button', { name: 'Model' })).toContainText('new-model')
await expect(page.getByTestId('rule-sheet')).toBeVisible()
await page.getByRole('radio', { name: 'Auto-scaling' }).click()
await page.getByLabel('Min replicas').fill('2')
@@ -146,7 +148,7 @@ test.describe('Placement rules: the sheet', () => {
await expect(page.getByTestId('rule-sheet')).toBeVisible({ timeout: 15_000 })
await expect(page.getByRole('radio', { name: 'Auto-scaling' })).toHaveAttribute('aria-checked', 'true')
await expect(page.getByLabel('Min replicas')).toHaveValue('2')
await expect(page.getByRole('combobox', { name: 'Model' })).toHaveValue('kokoro-82m')
await expect(page.getByRole('button', { name: 'Model' })).toContainText('kokoro-82m')
await expect(page).not.toHaveURL(/new=/)
})
@@ -50,7 +50,7 @@ test('switches inputs, generates animation, scrubs playback and restores history
})
await page.goto('/app/addons/studio/studio/threed')
await page.getByRole('button', { name: 'trellis-test', exact: true }).click()
await page.getByRole('option', { name: 'kimodo-test', exact: true }).click()
await page.getByRole('option', { name: /^kimodo-test/ }).click()
await expect(page.locator('#threed-image-file')).toHaveCount(0)
await page.getByLabel('Motion prompt').fill('Walk forward and wave')
await page.getByLabel('Frames (30 FPS)').fill('90')
@@ -89,7 +89,7 @@ test('plays in real time across delayed frames, looping, pause and seek', async
await page.route('**/3d/animate', route => route.fulfill({ json: { data: [{ url: '/generated-3d/animation.glb' }] } }))
await page.goto('/app/addons/studio/studio/threed')
await page.getByRole('button', { name: 'trellis-test', exact: true }).click()
await page.getByRole('option', { name: 'kimodo-test', exact: true }).click()
await page.getByRole('option', { name: /^kimodo-test/ }).click()
await page.getByLabel('Motion prompt').fill('Walk.')
await page.getByRole('button', { name: /Generate$/ }).click()
await page.getByRole('button', { name: 'Pause', exact: true }).click()
@@ -145,7 +145,7 @@ test('validates the prompt byte limit before submitting', async ({ page }) => {
// The model query is now read as a hand-off, so pick the model in the page as a person would.
await page.goto('/app/addons/studio/studio/threed')
await page.getByRole('button', { name: 'trellis-test', exact: true }).click()
await page.getByRole('option', { name: 'kimodo-test', exact: true }).click()
await page.getByRole('option', { name: /^kimodo-test/ }).click()
await page.getByLabel('Motion prompt').fill('🦊'.repeat(1025))
await expect(page.getByRole('alert')).toContainText('4096 byte limit')
expect(await page.getByLabel('Motion prompt').evaluate(element => element.checkValidity())).toBe(false)
@@ -181,7 +181,7 @@ test('reports unsupported skeleton transforms without displaying a stale pose',
await page.route('**/3d/animate', route => route.fulfill({ json: { data: [{ url: '/generated-3d/animation.glb' }] } }))
await page.goto('/app/addons/studio/studio/threed')
await page.getByRole('button', { name: 'trellis-test', exact: true }).click()
await page.getByRole('option', { name: 'kimodo-test', exact: true }).click()
await page.getByRole('option', { name: /^kimodo-test/ }).click()
await page.getByLabel('Motion prompt').fill('Walk.')
await page.getByRole('button', { name: /Generate$/ }).click()
await expect(page.getByRole('alert')).toContainText('Invalid skeleton transform')