Skip to content

Commit 3ba1438

Browse files
mudlerlocalai-org-maint-bot
authored andcommitted
test(ui): e2e specs for merged Cluster page and old-route redirects
Signed-off-by: Ettore Di Giacinto <mudler@localai.io>
1 parent 85577f7 commit 3ba1438

3 files changed

Lines changed: 101 additions & 18 deletions

File tree

Lines changed: 37 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,37 @@
1+
import { test, expect } from './coverage-fixtures.js'
2+
3+
// The Cluster page composes two capability sections: "Distributed (NATS)" (the
4+
// former Nodes page) and "Swarm (p2p)" (the former P2P page). Each section only
5+
// mounts when its mode is enabled — distributed when /api/nodes answers OK, swarm
6+
// when a non-empty p2p network token is present. We mock those probes so the page
7+
// renders against the standalone ui-test-server without NATS / p2p running.
8+
9+
async function mockDistributedOnly(page) {
10+
await page.route('**/api/nodes', (route) => {
11+
route.fulfill({ status: 200, contentType: 'application/json', body: '[]' })
12+
})
13+
await page.route('**/api/nodes/scheduling', (route) => {
14+
route.fulfill({ status: 200, contentType: 'application/json', body: '[]' })
15+
})
16+
// Swarm disabled: token probe fails, so the swarm section stays hidden.
17+
await page.route('**/api/p2p/token', (route) => {
18+
route.fulfill({ status: 503, contentType: 'text/plain', body: '' })
19+
})
20+
}
21+
22+
test.describe('Cluster page', () => {
23+
test('shows the page title', async ({ page }) => {
24+
await mockDistributedOnly(page)
25+
await page.goto('/app/cluster')
26+
await expect(page).toHaveURL(/\/app\/cluster$/)
27+
await expect(page.getByRole('heading', { name: /Cluster/i })).toBeVisible()
28+
})
29+
30+
test('shows the distributed section when /api/nodes responds', async ({ page }) => {
31+
await mockDistributedOnly(page)
32+
await page.goto('/app/cluster')
33+
await expect(page).toHaveURL(/\/app\/cluster$/)
34+
// The distributed capability section is titled "Distributed (NATS)".
35+
await expect(page.getByText(/Distributed \(NATS\)/i)).toBeVisible()
36+
})
37+
})

core/http/react-ui/e2e/navigation.spec.js

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -53,4 +53,11 @@ test.describe('Navigation', () => {
5353
await expect(rail.locator('a.nav-item[href="/app/fine-tune"]')).toBeVisible()
5454
await expect(rail.locator('a.nav-item[href="/app/face"]')).toBeVisible()
5555
})
56+
57+
test('old cluster routes redirect to /app/cluster', async ({ page }) => {
58+
await page.goto('/app/p2p')
59+
await expect(page).toHaveURL(/\/app\/cluster$/)
60+
await page.goto('/app/nodes')
61+
await expect(page).toHaveURL(/\/app\/cluster$/)
62+
})
5663
})

core/http/react-ui/e2e/p2p.spec.js

Lines changed: 57 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -1,26 +1,65 @@
11
import { test, expect } from './coverage-fixtures.js'
22

3-
// P2P (Swarm) admin page — renders in the no-auth test harness (isAdmin).
4-
test.describe('P2P page', () => {
5-
test.beforeEach(async ({ page }) => {
6-
await page.goto('/app/p2p')
3+
// The standalone P2P (Swarm) page was merged into the Cluster page: /app/p2p now
4+
// redirects to /app/cluster, and the p2p content lives under the "Swarm (p2p)"
5+
// section. That section only mounts when p2p is enabled (a network token is
6+
// present), so we mock /api/p2p/token to return a non-empty token and assert the
7+
// swarm content renders under the cluster page.
8+
const P2P_TOKEN = 'test-network-token'
9+
10+
async function mockSwarmEnabled(page) {
11+
await page.route('**/api/p2p/token', (route) => {
12+
route.fulfill({
13+
status: 200,
14+
contentType: 'text/plain',
15+
body: P2P_TOKEN,
16+
})
17+
})
18+
await page.route('**/api/p2p/workers', (route) => {
19+
route.fulfill({ status: 200, contentType: 'application/json', body: '{"nodes":[]}' })
20+
})
21+
await page.route('**/api/p2p/federation', (route) => {
22+
route.fulfill({ status: 200, contentType: 'application/json', body: '{"nodes":[]}' })
23+
})
24+
await page.route('**/api/p2p/stats', (route) => {
25+
route.fulfill({
26+
status: 200,
27+
contentType: 'application/json',
28+
body: JSON.stringify({
29+
llama_cpp_workers: { online: 0, total: 0 },
30+
federated: { online: 0, total: 0 },
31+
mlx_workers: { online: 0, total: 0 },
32+
}),
33+
})
734
})
35+
// The cluster page also probes /api/nodes for the distributed section; keep it
36+
// failing (distributed disabled) so only the swarm section renders here.
37+
await page.route('**/api/nodes', (route) => {
38+
route.fulfill({ status: 503, contentType: 'application/json', body: '{}' })
39+
})
40+
}
841

9-
test('renders the P2P distribution overview and capability cards', async ({ page }) => {
10-
await expect(page).toHaveURL(/\/app\/p2p$/)
11-
await expect(page.getByRole('heading', { name: /P2P Distribution Not Enabled/i })).toBeVisible()
12-
await expect(page.getByRole('heading', { name: 'Instance Federation' })).toBeVisible()
13-
await expect(page.getByRole('heading', { name: 'Model Sharding' })).toBeVisible()
14-
await expect(page.getByRole('heading', { name: 'Resource Sharing' })).toBeVisible()
15-
await expect(page.getByRole('heading', { name: /How to Enable P2P/i })).toBeVisible()
42+
test.describe('P2P (Swarm) section on the Cluster page', () => {
43+
test('the old /app/p2p route lands on the cluster page', async ({ page }) => {
44+
await mockSwarmEnabled(page)
45+
// /app/p2p redirects to /app/cluster.
46+
await page.goto('/app/p2p')
47+
await expect(page).toHaveURL(/\/app\/cluster$/)
48+
await expect(page.getByRole('heading', { name: /Cluster/i })).toBeVisible()
1649
})
1750

18-
test('hardware selector offers build targets and responds to selection', async ({ page }) => {
19-
const cpu = page.getByRole('button').filter({ hasText: /^CPU$/ })
20-
const cuda = page.getByRole('button').filter({ hasText: /^CUDA 12$/ })
21-
await expect(cpu).toBeVisible()
22-
await expect(cuda).toBeVisible()
23-
await cuda.click() // selecting a build target must not break the page
24-
await expect(page.getByRole('heading', { name: /How to Enable P2P/i })).toBeVisible()
51+
test('renders the Swarm (p2p) section when p2p is enabled', async ({ page }) => {
52+
await mockSwarmEnabled(page)
53+
await page.goto('/app/cluster')
54+
await expect(page).toHaveURL(/\/app\/cluster$/)
55+
56+
// The collapsible swarm section is titled "Swarm (p2p)".
57+
await expect(page.getByText(/Swarm \(p2p\)/i)).toBeVisible()
58+
59+
// The enabled p2p content (Network Token panel + the federation / sharding
60+
// tabs) is rendered inside the swarm section.
61+
await expect(page.getByRole('heading', { name: /Network Token/i })).toBeVisible()
62+
await expect(page.getByText('Federation', { exact: true })).toBeVisible()
63+
await expect(page.getByText('Model Sharding', { exact: true })).toBeVisible()
2564
})
2665
})

0 commit comments

Comments
 (0)