WeKnora deployment source with the reviewed wiki identity, summary and recovery fixes
Anydoc / anydoc parser engine (push) Canceled after 0s
App / Format, vet, test, and build (push) Canceled after 0s
CLI / test (macos-latest / go 1.26) (push) Canceled after 0s
CLI / test (ubuntu-latest / go 1.26) (push) Canceled after 0s
CLI / test (windows-latest / go 1.26) (push) Canceled after 0s
Build and Push Docker Image / build-ui (push) Canceled after 0s
Build and Push Docker Image / build-docreader (push) Canceled after 0s
Build and Push Docker Image / build-sandbox (push) Canceled after 0s
Build and Push Docker Image / build-app (amd64, linux/amd64, ubuntu-latest) (push) Canceled after 0s
Build and Push Docker Image / build-app (arm64, linux/arm64, ubuntu-24.04-arm) (push) Canceled after 0s
DocReader / Python tests and Go client tests (push) Canceled after 0s
Build & Publish (dsh-weknora) / Typecheck, test, pack (push) Canceled after 0s
Build & Publish (dsh-weknora) / End-to-end inside dsh (pinned) (push) Canceled after 0s
Build & Publish (dsh-weknora) / End-to-end inside dsh (latest, advisory) (push) Canceled after 0s
Frontend / Test, type-check, and build (push) Canceled after 0s
Go Lint Cache / warm lint cache (.) (push) Canceled after 0s
Go Lint Cache / warm lint cache (cli) (push) Canceled after 0s
Go Lint Cache / warm lint cache (client) (push) Canceled after 0s
Build & Publish (mcp-server) / Test (Python 3.10) (push) Canceled after 0s
Build & Publish (mcp-server) / Test (Python 3.11) (push) Canceled after 0s
Build & Publish (mcp-server) / Test (Python 3.12) (push) Canceled after 0s
Build & Publish (mcp-server) / Test (Python 3.13) (push) Canceled after 0s
Build and Push Docker Image / merge (push) Canceled after 0s
Build & Publish (dsh-weknora) / Publish to npm (push) Canceled after 0s
Build & Publish (mcp-server) / Build sdist + wheel (push) Canceled after 0s
Build & Publish (mcp-server) / Publish to PyPI (push) Canceled after 0s
Anydoc / anydoc parser engine (push) Canceled after 0s
App / Format, vet, test, and build (push) Canceled after 0s
CLI / test (macos-latest / go 1.26) (push) Canceled after 0s
CLI / test (ubuntu-latest / go 1.26) (push) Canceled after 0s
CLI / test (windows-latest / go 1.26) (push) Canceled after 0s
Build and Push Docker Image / build-ui (push) Canceled after 0s
Build and Push Docker Image / build-docreader (push) Canceled after 0s
Build and Push Docker Image / build-sandbox (push) Canceled after 0s
Build and Push Docker Image / build-app (amd64, linux/amd64, ubuntu-latest) (push) Canceled after 0s
Build and Push Docker Image / build-app (arm64, linux/arm64, ubuntu-24.04-arm) (push) Canceled after 0s
DocReader / Python tests and Go client tests (push) Canceled after 0s
Build & Publish (dsh-weknora) / Typecheck, test, pack (push) Canceled after 0s
Build & Publish (dsh-weknora) / End-to-end inside dsh (pinned) (push) Canceled after 0s
Build & Publish (dsh-weknora) / End-to-end inside dsh (latest, advisory) (push) Canceled after 0s
Frontend / Test, type-check, and build (push) Canceled after 0s
Go Lint Cache / warm lint cache (.) (push) Canceled after 0s
Go Lint Cache / warm lint cache (cli) (push) Canceled after 0s
Go Lint Cache / warm lint cache (client) (push) Canceled after 0s
Build & Publish (mcp-server) / Test (Python 3.10) (push) Canceled after 0s
Build & Publish (mcp-server) / Test (Python 3.11) (push) Canceled after 0s
Build & Publish (mcp-server) / Test (Python 3.12) (push) Canceled after 0s
Build & Publish (mcp-server) / Test (Python 3.13) (push) Canceled after 0s
Build and Push Docker Image / merge (push) Canceled after 0s
Build & Publish (dsh-weknora) / Publish to npm (push) Canceled after 0s
Build & Publish (mcp-server) / Build sdist + wheel (push) Canceled after 0s
Build & Publish (mcp-server) / Publish to PyPI (push) Canceled after 0s
This commit is contained in:
@@ -0,0 +1,89 @@
|
||||
const assert = require('node:assert/strict')
|
||||
const fs = require('node:fs')
|
||||
const { chromium } = require('/Users/macclaw/.cache/codex-runtimes/codex-primary-runtime/dependencies/node/node_modules/playwright')
|
||||
|
||||
const directory = '/Volumes/Extreme SSD/yawan-storage/weknora/acceptance'
|
||||
const origin = process.env.VERIFY_FRONTEND_ORIGIN || 'http://127.0.0.1:15173'
|
||||
const apiOrigin = process.env.VERIFY_API_ORIGIN || 'http://127.0.0.1:18080'
|
||||
const outputName = process.env.VERIFY_REPORT_NAME || 'navigation-parity-checks'
|
||||
assert.match(outputName, /^[a-zA-Z0-9_-]+$/)
|
||||
const startedAt = new Date().toISOString()
|
||||
const checks = [], failures = []
|
||||
let browser
|
||||
function writeReport(complete) {
|
||||
const report = { started_at: startedAt, checked_at: new Date().toISOString(), origin, api_origin: apiOrigin, checks, failures,
|
||||
passed: complete && checks.length === 21 && checks.every(c => c.passed) && failures.length === 0 }
|
||||
fs.writeFileSync(`${directory}/${outputName}.json`, JSON.stringify(report, null, 2))
|
||||
return report
|
||||
}
|
||||
|
||||
async function main() {
|
||||
writeReport(false)
|
||||
const credentials = JSON.parse(fs.readFileSync(`${directory}/super-admin-login.json`, 'utf8'))
|
||||
const response = await fetch(`${apiOrigin}/api/v1/auth/login`, {method: 'POST', headers: {'Content-Type': 'application/json'}, body: JSON.stringify({email: credentials.email, password: credentials.password}), signal: AbortSignal.timeout(30000)})
|
||||
assert.equal(response.status, 200)
|
||||
const auth = await response.json()
|
||||
browser = await chromium.launch({headless: true, channel: 'chrome'})
|
||||
try {
|
||||
const context = await browser.newContext({viewport: {width: 1440, height: 1000}})
|
||||
await context.addInitScript(a => {
|
||||
const values = {weknora_user: JSON.stringify({...a.user, tenant_id: String(a.user.tenant_id)}), weknora_tenant: JSON.stringify({...a.active_tenant, id: '10059'}), weknora_token: a.token, weknora_refresh_token: a.refresh_token, weknora_memberships: JSON.stringify(a.memberships)}
|
||||
for (const [key, value] of Object.entries(values)) localStorage.setItem(key, value)
|
||||
localStorage.setItem('weknora:new-user-guide-done:v1', '1')
|
||||
}, auth)
|
||||
const routes = ['/platform/workbench/content?tab=tasks', '/platform/workbench/content?tab=maps', '/platform/workbench/flows', '/platform/digital-humans', '/platform/knowledge-bases', '/platform/agents', '/platform/agents?tab=skills', '/platform/agents?tab=memory', '/platform/workbench/access', '/platform/workbench/resource-versions', '/platform/help', ...['balance', 'usage', 'audit', 'system'].map(tab => `/platform/workbench/operations/${tab}`), ...['models', 'members', 'memory', 'system-audit-log', 'runtime-queues', 'tenant'].map(section => `/platform/settings?section=${section}`)]
|
||||
for (const route of routes) {
|
||||
const page = await context.newPage(), failures = [], started = Date.now(), requests = [], requestedPaths = [], failedRequests = []
|
||||
const pendingRequests = new Map()
|
||||
page.on('request', request => { requestedPaths.push(new URL(request.url()).pathname); pendingRequests.set(request, Date.now()) })
|
||||
page.on('pageerror', () => failures.push('javascript_error'))
|
||||
page.on('response', r => { if (r.status() >= 400 && new URL(r.url()).pathname.startsWith('/api/')) failures.push(`HTTP ${r.status()} ${new URL(r.url()).pathname}`) })
|
||||
page.on('requestfinished', request => {
|
||||
pendingRequests.delete(request)
|
||||
const timing = request.timing()
|
||||
if (timing.responseEnd >= 1000) requests.push({ path: new URL(request.url()).pathname, duration_ms: timing.responseEnd, first_byte_ms: timing.responseStart })
|
||||
})
|
||||
page.on('requestfailed', request => {
|
||||
pendingRequests.delete(request)
|
||||
const error = request.failure()?.errorText || ''
|
||||
failedRequests.push({ path: new URL(request.url()).pathname, error })
|
||||
if (error !== 'net::ERR_ABORTED') failures.push(`Request failed: ${new URL(request.url()).pathname} ${error}`)
|
||||
})
|
||||
try {
|
||||
await page.goto(`${origin}${route}`)
|
||||
await page.waitForLoadState('networkidle', {timeout: 15000})
|
||||
assert.ok(new URL(page.url()).pathname !== '/login')
|
||||
assert.ok((await page.locator('body').innerText()).length > 100)
|
||||
const section = new URL(route, origin).searchParams.get('section')
|
||||
if (section === 'models' || section === 'members') {
|
||||
assert.ok(await page.locator(section === 'models' ? '.model-settings' : '.tenant-members').isVisible(), 'Selected settings section must render')
|
||||
assert.ok(!requestedPaths.some(path => /\/(?:IntegrationSettingsSection|SandboxSkillsPanel|AgentStreamDisplay)-[^/]+\.js$/.test(path)), 'Unopened settings must not load integration or skill modules')
|
||||
}
|
||||
assert.equal(await page.locator('[data-guide="nav-workbench/resource-versions"]').count(), 0)
|
||||
if (route.endsWith('/resource-versions')) {
|
||||
assert.notEqual(new URL(page.url()).pathname, '/platform/workbench/resource-versions', 'Retired resource versions must redirect')
|
||||
}
|
||||
if (route.endsWith('/operations/usage')) {
|
||||
assert.equal(await page.getByRole('cell', {name: 'document_summary', exact: true}).count(), 0)
|
||||
await page.screenshot({path: `${directory}/${outputName}-desktop.png`, animations: 'disabled'})
|
||||
}
|
||||
} catch (e) { failures.push(`${e.name}: ${e.message}`) }
|
||||
checks.push({route, duration_ms: Date.now() - started, passed: failures.length === 0, failures,
|
||||
pending_requests: [...pendingRequests].map(([request, requestedAt]) => ({ path: new URL(request.url()).pathname, duration_ms: Date.now() - requestedAt })),
|
||||
failed_requests: failedRequests,
|
||||
slow_requests: requests.sort((a, b) => b.duration_ms - a.duration_ms).slice(0, 10)})
|
||||
await page.close()
|
||||
writeReport(false)
|
||||
console.log(JSON.stringify(checks.at(-1)))
|
||||
}
|
||||
} finally {
|
||||
await browser.close().catch(error => failures.push(`Browser cleanup: ${error.name}`))
|
||||
browser = undefined
|
||||
}
|
||||
}
|
||||
main().catch(error => { failures.push(`${error.name}: ${error.message}`) }).finally(async () => {
|
||||
if (browser) await browser.close().catch(error => failures.push(`Browser cleanup: ${error.name}`))
|
||||
const report = writeReport(true)
|
||||
console.log(JSON.stringify(report))
|
||||
if (!report.passed) process.exitCode = 1
|
||||
})
|
||||
Reference in New Issue
Block a user