Files
LocalAI/core/http/react-ui/e2e/chrome-audit.spec.js
T
mudler-agentandEttore Di Giacinto 60254e582d refactor(ui): remove the built-in copies of the add-on pages (#12852)
The Face recognition, Voice recognition, Voice library, Fine-tune and
Quantize pages now live only in their add-ons. The router still kept a
built-in copy of each one and showed it when the add-on was not
installed, which meant two pages to maintain for the same job.

Replace the MovedPage wrapper with a plain redirect. The old addresses
(/app/face, /app/voice, /app/voice-library, /app/fine-tune and the
rest) keep working and always open the add-on route. When the add-on is
not installed or not ready, the add-on shell shows its "not available"
page. The model of /app/face/:model and /app/voice/:model still travels
as ?model=.

Delete the six page files, the components, styles and helpers only they
used, the biometrics translation namespace, and the end-to-end specs
that tested the built-in copies. Drop the two add-on parity tests that
compared the add-on page with the deleted core page. Server APIs and
feature flags are unchanged.


Assisted-by: Claude:claude-sonnet-5-5 [Claude Code]

Signed-off-by: Ettore Di Giacinto <mudler@localai.io>
Co-authored-by: Ettore Di Giacinto <mudler@localai.io>
2026-10-23 11:54:53 +02:00

59 lines
2.9 KiB
JavaScript

import { test, expect } from './coverage-fixtures.js'
import { installStudioAddons } from './studio-addon.js'
// A standing guard against the two defects an earlier automated edit left
// scattered through the pages: icons that render nothing at all (here, an svg
// whose sprite target is missing or that has no size), and controls left with
// the user agent's own chrome, which is a pale grey button on a dark ground.
const ROUTES = [
'/app', '/app/chat', '/app/models', '/app/studio', '/app/talk',
'/app/agents', '/app/skills', '/app/collections', '/app/agent-jobs',
'/app/models?view=installed', '/app/backends', '/app/activity', '/app/operate',
'/app/settings', '/app/traces', '/app/usage', '/app/nodes', '/app/p2p',
'/app/account',
]
test('no page renders a dead icon or a default-chrome control', async ({ page }) => {
// Studio and Talk are add-ons; /app/studio and /app/talk open them.
await installStudioAddons(page)
// One test walks every route, so its budget has to scale with the list rather
// than sit on Playwright's per-test default of 30s. At 25 routes that default
// allows ~1.2s per navigation, which holds on a developer machine and does
// not on a loaded CI runner: the suite went red on the commit that added this
// spec, timing out mid-loop at waitForTimeout rather than at any single goto,
// which is what cumulative slowness looks like as opposed to one hung route.
// Six seconds a route absorbs a slow runner and still fails promptly if a
// route really does hang.
test.setTimeout(ROUTES.length * 6_000)
const findings = []
for (const route of ROUTES) {
await page.goto(route)
await page.waitForTimeout(400)
const found = await page.evaluate(() => {
const out = []
for (const el of document.querySelectorAll('button, a')) {
if (el.getBoundingClientRect().width === 0) continue
const cs = getComputedStyle(el)
if (cs.borderTopStyle === 'outset' || cs.backgroundColor === 'rgb(239, 239, 239)') {
out.push(`default-chrome: "${(el.textContent || '').trim().slice(0, 24)}" [${el.className}]`)
}
}
for (const svg of document.querySelectorAll('svg[data-icon]')) {
const use = svg.querySelector('use')
const target = use && document.querySelector(use.getAttribute('href'))
const box = svg.getBoundingClientRect()
if (use && !target) out.push(`dead-icon: no sprite symbol for [${svg.dataset.icon}]`)
if (box.width > 0 && (box.width < 4 || box.height < 4)) out.push(`dead-icon: [${svg.dataset.icon}] is ${box.width}x${box.height}`)
}
// A leftover icon-font element draws nothing now that the font is gone.
for (const i of document.querySelectorAll('i[class*="fa-"], .fas, .far, .fab')) {
out.push(`dead-icon: font class left on [${i.className}]`)
}
return [...new Set(out)]
})
for (const f of found) findings.push(`${route} — ${f}`)
}
expect(findings).toEqual([])
})