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,160 @@
|
||||
const assert = require('node:assert/strict')
|
||||
const fs = require('node:fs')
|
||||
const path = require('node:path')
|
||||
const { pathToFileURL } = require('node:url')
|
||||
const { chromium } = require('/Users/macclaw/.cache/codex-runtimes/codex-primary-runtime/dependencies/node/node_modules/playwright')
|
||||
|
||||
async function main() {
|
||||
const directory = '/Volumes/Extreme SSD/yawan-storage/weknora/acceptance'
|
||||
const root = path.resolve(__dirname, '../frontend')
|
||||
const apiOrigin = process.env.VERIFY_API_ORIGIN || 'http://127.0.0.1:18080'
|
||||
const checks = [], requestedAssets = new Set(), unexpectedMutations = [], pageErrors = []
|
||||
const reportPath = path.join(directory, 'lazy-platform-modals-20260919.json')
|
||||
const credentials = JSON.parse(fs.readFileSync(path.join(directory, 'super-admin-login.json'), 'utf8'))
|
||||
const login = await fetch(`${apiOrigin}/api/v1/auth/login`, {
|
||||
method: 'POST', headers: { 'Content-Type': 'application/json' },
|
||||
body: JSON.stringify({ email: credentials.email, password: credentials.password }),
|
||||
})
|
||||
assert.equal(login.status, 200, 'Read-only verification login')
|
||||
const auth = await login.json()
|
||||
process.env.VITE_DEV_PROXY_TARGET = apiOrigin
|
||||
const { preview } = await import(pathToFileURL(path.join(root, 'node_modules/vite/dist/node/index.js')).href)
|
||||
const server = await preview({ root, configFile: path.join(root, 'vite.config.ts'), preview: { host: '127.0.0.1', port: 15174, strictPort: true } })
|
||||
const origin = server.resolvedUrls.local[0].replace(/\/$/, '')
|
||||
let browser
|
||||
async function check(name, fn) {
|
||||
const started = Date.now()
|
||||
try {
|
||||
await fn()
|
||||
checks.push({ name, passed: true, duration_ms: Date.now() - started })
|
||||
console.log(JSON.stringify(checks.at(-1)))
|
||||
} catch (error) {
|
||||
checks.push({ name, passed: false, duration_ms: Date.now() - started, error: error.name, location: error.stack?.split('\n').filter(line => line.trim().startsWith('at ')).slice(0, 3) })
|
||||
console.log(JSON.stringify(checks.at(-1)))
|
||||
throw error
|
||||
}
|
||||
}
|
||||
try {
|
||||
browser = await chromium.launch({ headless: true, channel: 'chrome' })
|
||||
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)
|
||||
for (const key of ['weknora:new-user-guide-done:v1', 'weknora:contextual-guide-kb-list:v2', 'weknora:contextual-guide-kb-create:v3', 'weknora:contextual-guide-tenant-models:v1']) localStorage.setItem(key, '1')
|
||||
}, auth)
|
||||
await context.route('**/api/**', async route => {
|
||||
const request = route.request()
|
||||
if (!['GET', 'HEAD', 'OPTIONS'].includes(request.method())) {
|
||||
unexpectedMutations.push({ method: request.method(), path: new URL(request.url()).pathname })
|
||||
return route.abort('blockedbyclient')
|
||||
}
|
||||
await route.continue()
|
||||
})
|
||||
const page = await context.newPage()
|
||||
page.setDefaultTimeout(20000)
|
||||
page.on('pageerror', error => pageErrors.push({ name: error.name }))
|
||||
page.on('request', request => {
|
||||
const pathname = new URL(request.url()).pathname
|
||||
if (pathname.startsWith('/assets/')) requestedAssets.add(pathname)
|
||||
})
|
||||
const editor = page.locator('.settings-overlay').filter({ has: page.locator('[data-guide="kb-editor-sidebar"]') })
|
||||
const settings = page.locator('.settings-overlay').filter({ has: page.locator('[data-guide="settings-models"]') })
|
||||
const nameInput = editor.locator('[data-guide="kb-create-name"] input')
|
||||
const create = async () => {
|
||||
await page.locator('[data-guide="kb-list-create"]').first().click()
|
||||
await nameInput.waitFor({ state: 'visible' })
|
||||
}
|
||||
const closeEditor = async () => {
|
||||
await editor.locator('.close-btn').click()
|
||||
await editor.waitFor({ state: 'hidden' })
|
||||
}
|
||||
await check('cold_knowledge_list_defers_hidden_modal_chunks', async () => {
|
||||
await page.goto(`${origin}/platform/knowledge-bases`)
|
||||
await page.locator('[data-guide="kb-list-create"]').first().waitFor({ state: 'visible' })
|
||||
await page.waitForLoadState('networkidle')
|
||||
assert.equal([...requestedAssets].filter(asset => /\/(Settings|KnowledgeBaseEditorModal)-.*\.js$/.test(asset)).length, 0)
|
||||
})
|
||||
await check('command_palette_keyboard_shortcut_remains_registered', async () => {
|
||||
await page.keyboard.press('Meta+k')
|
||||
await page.locator('.cmdk').waitFor({ state: 'visible' })
|
||||
await page.keyboard.press('Escape')
|
||||
await page.locator('.cmdk').waitFor({ state: 'hidden' })
|
||||
})
|
||||
await check('first_create_initializes_and_only_loads_editor', async () => {
|
||||
await create()
|
||||
assert.equal(await nameInput.inputValue(), '')
|
||||
assert.ok([...requestedAssets].some(asset => /\/KnowledgeBaseEditorModal-.*\.js$/.test(asset)))
|
||||
assert.equal([...requestedAssets].filter(asset => /\/Settings-.*\.js$/.test(asset)).length, 0)
|
||||
})
|
||||
await check('create_close_reopen_discards_unsaved_form', async () => {
|
||||
await nameInput.fill('UNSAVED_BROWSER_CHECK')
|
||||
await closeEditor()
|
||||
await create()
|
||||
assert.equal(await nameInput.inputValue(), '')
|
||||
})
|
||||
async function openModelsSettings() {
|
||||
await editor.locator('[data-guide="kb-editor-nav-models"]').click()
|
||||
await editor.locator('[data-guide="kb-create-llm"] .model-selector').click()
|
||||
await page.locator('.add-model-option:visible').click()
|
||||
await settings.waitFor({ state: 'visible' })
|
||||
}
|
||||
await check('lazy_settings_opens_models_from_editor', async () => {
|
||||
await openModelsSettings()
|
||||
assert.ok([...requestedAssets].some(asset => /\/Settings-.*\.js$/.test(asset)))
|
||||
assert.equal(await page.locator('.settings-overlay').count(), 2)
|
||||
})
|
||||
await check('settings_escape_closes_and_reopens_without_losing_editor', async () => {
|
||||
await page.keyboard.press('Escape')
|
||||
await settings.waitFor({ state: 'hidden' })
|
||||
assert.ok(await editor.isVisible())
|
||||
await openModelsSettings()
|
||||
await settings.locator('.close-btn').click()
|
||||
await settings.waitFor({ state: 'hidden' })
|
||||
await closeEditor()
|
||||
})
|
||||
await check('existing_knowledge_editor_loads_and_reopens_correct_resource', async () => {
|
||||
const card = page.locator('.kb-card').filter({ has: page.locator('.more-wrap') }).first()
|
||||
await card.waitFor({ state: 'visible' })
|
||||
const expectedName = await card.locator('.card-title').getAttribute('title')
|
||||
const edit = async () => {
|
||||
const settingsItem = page.locator('.card-more-popup:visible .popup-menu-item').filter({ has: page.locator('.t-icon-setting') })
|
||||
if (!await settingsItem.isVisible()) await card.locator('.more-wrap').click()
|
||||
await settingsItem.click()
|
||||
await nameInput.waitFor({ state: 'visible' })
|
||||
const actualName = await nameInput.inputValue()
|
||||
if (actualName !== expectedName) {
|
||||
console.log(JSON.stringify({ diagnostic: 'editor_name_mismatch', expected_length: expectedName?.length, actual_length: actualName.length, blank: !actualName, normalized_match: actualName.trim() === expectedName?.trim() }))
|
||||
}
|
||||
assert.equal(actualName, expectedName)
|
||||
}
|
||||
await edit()
|
||||
await nameInput.fill('UNSAVED_BROWSER_CHECK')
|
||||
await closeEditor()
|
||||
await edit()
|
||||
await closeEditor()
|
||||
})
|
||||
await check('direct_settings_models_route_has_one_initialized_overlay', async () => {
|
||||
await page.goto(`${origin}/platform/settings?section=models`)
|
||||
await settings.waitFor({ state: 'visible' })
|
||||
assert.equal(await page.locator('.settings-overlay').count(), 1)
|
||||
await page.waitForLoadState('networkidle')
|
||||
})
|
||||
await check('no_browser_errors_or_business_mutations', async () => {
|
||||
assert.equal(pageErrors.length, 0)
|
||||
assert.equal(unexpectedMutations.length, 0)
|
||||
})
|
||||
} finally {
|
||||
if (browser) await browser.close()
|
||||
await new Promise((resolve, reject) => server.httpServer.close(error => error ? reject(error) : resolve()))
|
||||
const report = { checked_at: new Date().toISOString(), origin, api_origin: apiOrigin, checks, passed: checks.length === 9 && checks.every(check => check.passed), requested_assets: [...requestedAssets], page_errors: pageErrors, unexpected_mutations: unexpectedMutations }
|
||||
fs.writeFileSync(reportPath, JSON.stringify(report, null, 2))
|
||||
console.log(JSON.stringify({ report: reportPath, passed: report.passed, checks: checks.length }))
|
||||
}
|
||||
}
|
||||
|
||||
main().catch(error => { console.error(error.name); process.exitCode = 1 })
|
||||
Reference in New Issue
Block a user