The landing page, download pages, invite page, assetlinks and installers existed in two or three places; only site/ and the Forgejo feed are served. - apps/api-server/wwwroot: delete the stale site build, download/invite pages, .well-known copy, legacy static admin and 1.0.0 binaries. The API no longer serves static files (UseStaticFiles/fallbacks and the apk/zip blocker removed); the Next admin is the only admin UI. - Delete 19 tracked installers/packages (~568 MiB) under site/public/releases, apps/web/public/releases and wwwroot/releases; .gitignore blocks them. - apps/web: delete the download/releases pages, desktop-release.ts, the download.html and assetlinks copies, and the accept-invite page (invites are only issued to the site's /accept-invite/). e2e specs call the /app base path and check the /download redirect instead. - scripts: delete the retired release/NAS site scripts, drop the web target from sync-version, and check assetlinks in site/public only. - Delete the unused Dockerfile.admin (apps/admin/Dockerfile is used). Policy: docs/REFACTOR_POLICY.md Wave 3, W3-5 and W3-6.
112 lines
4.2 KiB
TypeScript
112 lines
4.2 KiB
TypeScript
// tests/e2e/system-verification.spec.ts
|
|
// E2E Verification Script for C# .NET API Server, Auth, LLM Proxy, Usage Costing, and BackOffice
|
|
|
|
import { test, expect } from '@playwright/test'
|
|
|
|
const API_BASE = 'http://localhost:5000'
|
|
|
|
test.describe('D3RO Voice E2E Architecture Verification', () => {
|
|
let authToken = ''
|
|
const testEmail = `e2e_user_${Date.now()}@d3ro.ai`
|
|
const testPassword = 'Password123!'
|
|
|
|
test('1. API Server Health & Initial Endpoints', async ({ request }) => {
|
|
const response = await request.get(`${API_BASE}/api/admin/stats`)
|
|
expect(response.status()).toBe(200)
|
|
|
|
const stats = await response.json()
|
|
expect(stats).toHaveProperty('totalUsers')
|
|
expect(stats).toHaveProperty('serverUptimeSeconds')
|
|
expect(stats).toHaveProperty('totalCost')
|
|
console.log('✓ Stats verified:', stats)
|
|
})
|
|
|
|
test('2. User Registration & Login (Mandatory Online Auth)', async ({ request }) => {
|
|
// Register
|
|
const regRes = await request.post(`${API_BASE}/api/auth/register`, {
|
|
data: { email: testEmail, password: testPassword }
|
|
})
|
|
expect(regRes.status()).toBe(200)
|
|
const regData = await regRes.json()
|
|
expect(regData).toHaveProperty('token')
|
|
expect(regData.email).toBe(testEmail)
|
|
console.log('✓ User Registration successful:', regData.email)
|
|
|
|
// Login
|
|
const loginRes = await request.post(`${API_BASE}/api/auth/login`, {
|
|
data: { email: testEmail, password: testPassword }
|
|
})
|
|
expect(loginRes.status()).toBe(200)
|
|
const loginData = await loginRes.json()
|
|
expect(loginData).toHaveProperty('token')
|
|
authToken = loginData.token
|
|
console.log('✓ User Login successful, JWT issued.')
|
|
})
|
|
|
|
test('3. Dynamic Model Endpoint Management (Admin)', async ({ request }) => {
|
|
const newModel = {
|
|
modelId: `e2e-custom-model-${Date.now()}`,
|
|
modelName: 'E2E Dynamic Custom LLM',
|
|
provider: 'CustomProvider',
|
|
endpointUrl: 'https://api.openai.com/v1/chat/completions',
|
|
apiKey: 'sk-e2e-test-key',
|
|
costPer1kPromptTokens: 0.00025,
|
|
costPer1kCompletionTokens: 0.00085
|
|
}
|
|
|
|
const createRes = await request.post(`${API_BASE}/api/admin/endpoints`, {
|
|
data: newModel
|
|
})
|
|
expect(createRes.status()).toBe(200)
|
|
const created = await createRes.json()
|
|
expect(created.modelId).toBe(newModel.modelId)
|
|
console.log('✓ Dynamic Model Endpoint added:', created.modelId)
|
|
|
|
const listRes = await request.get(`${API_BASE}/api/admin/endpoints`)
|
|
expect(listRes.status()).toBe(200)
|
|
const list = await listRes.json()
|
|
expect(list.some((m: any) => m.modelId === newModel.modelId)).toBe(true)
|
|
})
|
|
|
|
test('4. AI Generation & Usage Cost Calculation', async ({ request }) => {
|
|
// Login to get token
|
|
const loginRes = await request.post(`${API_BASE}/api/auth/login`, {
|
|
data: { email: testEmail, password: testPassword }
|
|
})
|
|
const loginData = await loginRes.json()
|
|
const token = loginData.token
|
|
|
|
// Unauthenticated request MUST fail (401)
|
|
const unauthRes = await request.post(`${API_BASE}/api/llm/generate`, {
|
|
data: { prompt: 'Test' }
|
|
})
|
|
expect(unauthRes.status()).toBe(401)
|
|
console.log('✓ Mandatory Login Guard verified: Unauthenticated request rejected (401)')
|
|
|
|
// Authenticated request
|
|
const genRes = await request.post(`${API_BASE}/api/llm/generate`, {
|
|
headers: { Authorization: `Bearer ${token}` },
|
|
data: {
|
|
prompt: 'Self-verification test prompt for D3RO Voice E2E',
|
|
model: 'd3ro-gpt4o-mini'
|
|
}
|
|
})
|
|
expect(genRes.status()).toBe(200)
|
|
const genData = await genRes.json()
|
|
expect(genData).toHaveProperty('text')
|
|
expect(genData).toHaveProperty('cost')
|
|
expect(genData.cost).toBeGreaterThan(0)
|
|
console.log('✓ AI Generation & Cost Calculation verified:', genData)
|
|
})
|
|
|
|
test('5. BackOffice Usage & Cost Analytics Report', async ({ request }) => {
|
|
const reportRes = await request.get(`${API_BASE}/api/admin/usage`)
|
|
expect(reportRes.status()).toBe(200)
|
|
|
|
const report = await reportRes.json()
|
|
expect(report).toHaveProperty('totalRequests')
|
|
expect(report).toHaveProperty('totalCost')
|
|
expect(report.userSummaries.length).toBeGreaterThan(0)
|
|
console.log('✓ BackOffice Usage & Cost Analytics verified:', report)
|
|
})
|
|
})
|