Files
LocalAI/core/http/react-ui/e2e/navigation.spec.js
T
mudler-agentandEttore Di Giacinto e1125c8aea test(ui): turn the feature switches on in the navigation specs (#12895)
The sidebar and the Build overview show the Add-ons and Fine-tuning entries
only when the server reports those switches on. With no add-on owner
running, the server reports the add-ons switch off, and the test server
has the fine-tuning switch off, so the two specs failed on master.

The two tests are about those entries being shown, so they set the switches
on and keep the server's other flags.

Assisted-by: Claude Code:claude-opus-5-5

Signed-off-by: Ettore Di Giacinto <mudler@localai.io>
Co-authored-by: Ettore Di Giacinto <mudler@localai.io>
2026-10-25 09:10:47 +01:00

100 lines
4.8 KiB
JavaScript

import { test, expect } from './coverage-fixtures.js'
import { stubAddonRoutes } from './addons-fixtures.js'
test.describe('Navigation', () => {
test('/ redirects to /app', async ({ page }) => {
await page.goto('/')
await expect(page).toHaveURL(/\/app/)
})
test('/app shows the home page', async ({ page }) => {
await page.goto('/app')
await expect(page.locator('.sidebar')).toBeVisible()
await expect(page.locator('.home-page')).toBeVisible()
})
test('top menu exposes Home and Models', async ({ page }) => {
await page.goto('/app')
await expect(page.locator('.sidebar-nav a.nav-item[href="/app"]')).toBeVisible()
const models = page.locator('.sidebar-nav a.nav-item[href="/app/models"]')
await expect(models).toBeVisible()
await expect(models.locator('.nav-label')).toHaveText('Models')
})
test('the sidebar has Chat, Models and Add-ons, no Settings and no Create tier', async ({ page }) => {
await stubAddonRoutes(page)
await page.goto('/app')
await expect(page.locator('.sidebar-section-title', { hasText: 'Create' })).toHaveCount(0)
for (const href of ['/app/chat', '/app/models', '/app/addons']) {
await expect(page.locator(`.sidebar-nav a.nav-item[href="${href}"]`).first()).toBeVisible()
}
// Settings lives under the Operate hub, not in the sidebar.
await expect(page.locator('.sidebar-nav a.nav-item[href="/app/settings"]')).toHaveCount(0)
await page.locator('.sidebar-nav a.nav-item', { hasText: 'Operate' }).click()
await expect(page).toHaveURL(/\/app\/operate$/)
const settingsTab = page.locator('.dk-hubtabs [data-hub-tab="settings"]')
await expect(settingsTab).toBeVisible()
await settingsTab.click()
await expect(page).toHaveURL(/\/app\/settings/)
await expect(page.locator('.dk-hubtabs [data-hub-tab="settings"]')).toHaveAttribute('aria-current', 'page')
// Studio and Talk are add-ons: the sidebar does not list them; they are in the drawer while installed.
for (const href of ['/app/studio', '/app/talk']) {
await expect(page.locator(`.sidebar-nav a.nav-item[href="${href}"]`)).toHaveCount(0)
}
})
test('Build and Operate sit under a Workspace label', async ({ page }) => {
await page.goto('/app')
await expect(page.locator('.sidebar-section-title', { hasText: 'Workspace' })).toBeVisible()
await expect(page.locator('.sidebar-nav a.nav-item', { hasText: 'Build' })).toBeVisible()
await expect(page.locator('.sidebar-nav a.nav-item', { hasText: 'Operate' })).toBeVisible()
})
test('Build is a single entry that opens the Build hub', async ({ page }) => {
await page.goto('/app')
const build = page.locator('.sidebar-nav a.nav-item', { hasText: 'Build' })
await expect(build).toBeVisible()
await build.click()
await expect(page).toHaveURL(/\/app\/build$/)
const bar = page.locator('.dk-hubtabs')
await expect(bar.locator('[data-hub-tab="overview"]')).toHaveAttribute('aria-current', 'page')
await expect(page.locator('.sidebar-nav a.nav-item', { hasText: 'Build' })).toHaveClass(/active/)
})
test('Operate is a single entry that opens the Operate hub', async ({ page }) => {
await page.goto('/app')
const operate = page.locator('.sidebar-nav a.nav-item', { hasText: 'Operate' })
await expect(operate).toBeVisible()
await operate.click()
await expect(page).toHaveURL(/\/app\/operate$/)
await expect(page.locator('.dk-hubtabs [data-hub-tab="status"]')).toHaveAttribute('aria-current', 'page')
})
test('Build hub lists its tools as tabs', async ({ page }) => {
await page.goto('/app/agents')
const bar = page.locator('.dk-hubtabs')
await expect(bar).toBeVisible()
for (const id of ['overview', 'agents', 'skills', 'memory', 'jobs', 'import']) {
await expect(bar.locator(`[data-hub-tab="${id}"]`)).toBeVisible()
}
await expect(bar.locator('[data-hub-tab="fine-tune"], [data-hub-tab="quantize"]')).toHaveCount(0)
await expect(bar.locator('[data-hub-tab="faces"]')).toHaveCount(0)
await expect(bar.locator('[data-hub-tab="agents"]')).toHaveAttribute('aria-current', 'page')
})
test('the Build overview lists the tools with a line each', async ({ page }) => {
// The Fine-tuning tile is shown when the server has the switch on.
await page.route('**/api/features', async route => {
const real = await (await route.fetch()).json()
return route.fulfill({ json: { ...real, fine_tuning: true } })
})
await page.goto('/app/build')
const list = page.getByRole('list', { name: 'Build tools' })
// Each tool is a row with its sentence and an Open link.
const row = (path) => list.locator('li.bt-tool', { has: page.locator(`a[href="${path}"]`) })
await expect(row('/app/agents')).toContainText('Create and run agents')
await expect(list.locator('a[href="/app/fine-tune"]')).toBeVisible()
})
})