mirror of
https://github.com/mudler/LocalAI.git
synced 2026-10-28 00:59:28 -04:00
test(ui): stub the pin routes in the add-on e2e fixtures (#12882)
test(ui): stub the add-on routes in the add-on e2e fixtures The add-on owner now runs as its own workload. With no owner running the server reports the add-ons feature off and answers 5xx on /api/addons/builtin and /api/addons/pins. The add-on pages are gated on that flag, and the navigation shell calls both routes, which the browser logs as failed requests. Specs that draw add-on pages assert no console errors, so they failed on master. Stub those routes on the browser context: the feature flag is switched on with the server's other flags kept, and the pin routes answer with an empty set. A spec's own page routes still take precedence. Studio's old-address and 404 specs call the same stub, since they expect add-ons to be on. The server behaviour is unchanged. 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>
This commit is contained in:
1 parent
48478a89cd
commit
b9b5434692
4 files changed
+23
-1
No files matched your search
+17
@@ -44,6 +44,22 @@ export function sessionFor(user, permissions = {}) {
|
||||
const ok = (payload) => ({ status: 200, contentType: 'application/json', body: JSON.stringify({ payload }) })
|
||||
const fail = (status, type, extra = {}) => ({ status, contentType: 'application/json', body: JSON.stringify({ error: { type, message: type, ...extra } }) })
|
||||
|
||||
// Specs that draw add-on pages need add-ons on. With no add-on owner running,
|
||||
// the server reports add-ons off and answers 5xx on the pin routes, and the
|
||||
// browser logs each failed request. These stubs answer the add-on pages with an
|
||||
// empty set. They live on the context, which Playwright matches after the
|
||||
// page's own routes: a spec that sets its own features, builtin or pin list
|
||||
// still gets it.
|
||||
export async function stubAddonRoutes(page) {
|
||||
// The real flags, with add-ons on: the other switches keep what the server says.
|
||||
await page.context().route('**/api/features', async route => {
|
||||
const real = await (await route.fetch()).json()
|
||||
return route.fulfill({ json: { ...real, addons: true } })
|
||||
})
|
||||
await page.context().route('**/api/addons/builtin', route => route.fulfill({ json: { builtin: [] } }))
|
||||
await page.context().route('**/api/addons/pins', route => route.fulfill({ json: [] }))
|
||||
}
|
||||
|
||||
// Installs the routes and returns the mutable state the spec reads and edits.
|
||||
export async function mockAddons(page, options = {}) {
|
||||
const state = {
|
||||
@@ -62,6 +78,7 @@ export async function mockAddons(page, options = {}) {
|
||||
dispatch: options.dispatch || null,
|
||||
}
|
||||
|
||||
await stubAddonRoutes(page)
|
||||
await page.route(/\/api\/addons\/apps\/[^/]+\/icon/, route => route.fulfill({ status: 200, contentType: 'image/png', body: PNG }))
|
||||
await page.route(/\/api\/addons\/apps$/, route => {
|
||||
state.log.appsList += 1
|
||||
|
||||
@@ -1,8 +1,10 @@
|
||||
import { test, expect } from './coverage-fixtures.js'
|
||||
import { mockAccess } from './access-fixtures.js'
|
||||
import { stubAddonRoutes } from './addons-fixtures.js'
|
||||
|
||||
test.describe('404', () => {
|
||||
test('names the address, offers a way home and lists the places the viewer can go', async ({ page }) => {
|
||||
await stubAddonRoutes(page)
|
||||
await page.goto('/app/no-such-page')
|
||||
const nf = page.getByTestId('not-found')
|
||||
await expect(nf.getByRole('heading', { level: 1 })).toHaveText('This page does not exist')
|
||||
|
||||
+2
-1
@@ -6,7 +6,7 @@
|
||||
import fs from 'node:fs'
|
||||
import path from 'node:path'
|
||||
import { fileURLToPath } from 'node:url'
|
||||
import { app, mockAddons } from './addons-fixtures.js'
|
||||
import { app, mockAddons, stubAddonRoutes } from './addons-fixtures.js'
|
||||
|
||||
const addons = path.resolve(path.dirname(fileURLToPath(import.meta.url)), '../../../../addons')
|
||||
const DIGEST = 'e'.repeat(64)
|
||||
@@ -55,6 +55,7 @@ export function packagedApp(id, over = {}) {
|
||||
// Returns the state of mockAddons.
|
||||
export async function installStudioAddons(page, { ids = ['studio', 'talk'], ...options } = {}) {
|
||||
const dirs = await Promise.all(ids.map(build))
|
||||
await stubAddonRoutes(page)
|
||||
await page.route(/\/api\/addons\/(studio|talk|voice)\/assets\//, route => {
|
||||
const parts = new URL(route.request().url()).pathname.split('/')
|
||||
const id = parts[3]
|
||||
|
||||
@@ -1,5 +1,6 @@
|
||||
import { test, expect } from './coverage-fixtures.js'
|
||||
import { installStudioAddons } from './studio-addon.js'
|
||||
import { stubAddonRoutes } from './addons-fixtures.js'
|
||||
import { mockStudio } from './studio-fixtures.js'
|
||||
import { fakeRealtime } from './chat-fixtures.js'
|
||||
|
||||
@@ -66,6 +67,7 @@ test.describe('Studio add-on', () => {
|
||||
})
|
||||
|
||||
test('the old Studio addresses say so plainly when the add-on is not installed', async ({ page }) => {
|
||||
await stubAddonRoutes(page)
|
||||
for (const address of ['/app/studio', '/app/studio/tts', '/app/image', '/app/talk']) {
|
||||
await page.goto(address)
|
||||
await expect(page.getByTestId('addon-unavailable')).toBeVisible({ timeout: 15_000 })
|
||||
|
||||
Reference in new issue
Block a user