Merge pull request #2700 from langbot-app/test/quality-workspace-ui-oracles-20261017

test(web): replace Workspace source checks with runtime assertions
This commit is contained in:
huanghuoguoguo
2026-10-17 20:13:11 +08:00
committed by GitHub
8 changed files with 412 additions and 171 deletions
+23 -35
View File
@@ -2,6 +2,7 @@ import assert from 'node:assert/strict';
import fs from 'node:fs';
import path from 'node:path';
import test from 'node:test';
import ts from 'typescript';
const root = process.cwd();
const dialogPath = path.join(
@@ -12,43 +13,30 @@ const localeDir = path.join(root, 'src/i18n/locales');
const backendUrlPath = path.join(root, 'src/app/infra/http/backendUrl.ts');
const dialogSource = fs.readFileSync(dialogPath, 'utf8');
const backendUrlSource = fs.readFileSync(backendUrlPath, 'utf8');
const { resolveBackendBaseUrl } = await import(
`data:text/javascript;base64,${Buffer.from(
ts.transpileModule(fs.readFileSync(backendUrlPath, 'utf8'), {
compilerOptions: {
module: ts.ModuleKind.ESNext,
target: ts.ScriptTarget.ES2022,
},
}).outputText,
).toString('base64')}`
);
test('QR login resolves a proxy-root API base against the current origin', () => {
assert.match(dialogSource, /const baseUrl = getBackendBaseUrl\(\)/);
assert.match(backendUrlSource, /!configured \|\| configured === '\/'/);
assert.match(backendUrlSource, /return normalizedOrigin/);
assert.doesNotMatch(
dialogSource,
/import\.meta\.env\.VITE_API_BASE_URL \|\| window\.location\.origin/,
);
});
test('QR credential exchanges preserve the active Workspace scope', () => {
assert.match(dialogSource, /getActiveWorkspaceUuid/);
assert.match(
dialogSource,
/sessionWorkspaceUuidRef\.current = workspaceUuid/,
);
assert.match(
dialogSource,
/const workspaceUuid = sessionWorkspaceUuidRef\.current/,
);
assert.match(dialogSource, /sessionApiBaseRef\.current = cfg\.apiBase/);
assert.match(
dialogSource,
/`\$\{baseUrlRef\.current\}\$\{sessionApiBaseRef\.current\}\/\$\{sessionIdRef\.current\}`/,
);
assert.match(dialogSource, /'X-Workspace-Id': workspaceUuid/);
const workspaceHeaderUses = dialogSource.match(
/'X-Workspace-Id': workspaceUuid/g,
);
assert.equal(
workspaceHeaderUses?.length,
4,
'start, poll, expiry cleanup, and dialog cleanup must all retain Workspace scope',
);
for (const [configured, expected] of [
[undefined, 'https://core.example'],
['', 'https://core.example'],
['/', 'https://core.example'],
['/proxy/', 'https://core.example/proxy'],
['proxy', 'https://core.example/proxy'],
['https://api.example/root/', 'https://api.example/root'],
])
assert.equal(
resolveBackendBaseUrl(configured, 'https://core.example///'),
expected,
);
});
test('WeChat QR login never reuses Feishu progress copy', () => {
@@ -1,24 +0,0 @@
import assert from 'node:assert/strict';
import fs from 'node:fs';
import test from 'node:test';
const source = fs.readFileSync(
new URL('../../src/app/auth/space/callback/page.tsx', import.meta.url),
'utf8',
);
test('direct launch assertion is fragment-only and removed before exchange', () => {
assert.doesNotMatch(source, /searchParams\.get\(['"]launch_assertion['"]\)/);
const readIndex = source.indexOf("fragmentParams.get('launch_assertion')");
const clearIndex = source.indexOf('window.history.replaceState');
const exchangeIndex = source.indexOf('handleOAuthCallback(', clearIndex);
assert.ok(readIndex >= 0, 'fragment assertion read is missing');
assert.ok(
clearIndex > readIndex,
'URL fragment is not cleared after copying the assertion',
);
assert.ok(
exchangeIndex > clearIndex,
'assertion exchange starts before the fragment is cleared',
);
});
@@ -1,24 +0,0 @@
import assert from 'node:assert/strict';
import { readFile } from 'node:fs/promises';
import test from 'node:test';
const panelSource = await readFile(
new URL(
'../../src/app/home/components/workspace-settings/WorkspaceSettingsPanel.tsx',
import.meta.url,
),
'utf8',
);
const entitySource = await readFile(
new URL('../../src/app/infra/entities/workspace.ts', import.meta.url),
'utf8',
);
test('workspace member rows show display name, email, and role', () => {
assert.match(entitySource, /display_name:\s*string/);
assert.match(panelSource, /\{member\.display_name\}/);
assert.match(
panelSource,
/<ItemDescription[^>]*>[\s\S]*?\{member\.email\}[\s\S]*?workspace\.roles\.\$\{member\.role\}[\s\S]*?<\/ItemDescription>/,
);
});
@@ -18,103 +18,15 @@ const homeSidebarSource = readSource(
const workspaceSettingsPanelSource = readSource(
'src/app/home/components/workspace-settings/WorkspaceSettingsPanel.tsx',
);
const workspaceSwitcherSource = readSource(
'src/app/home/components/workspace-settings/WorkspaceSwitcher.tsx',
);
test('renders WorkspaceSwitcher only from HomeSidebar', () => {
assert.doesNotMatch(homeLayoutSource, /<WorkspaceSwitcher\b/);
assert.doesNotMatch(workspaceSettingsPanelSource, /<WorkspaceSwitcher\b/);
assert.equal(homeSidebarSource.match(/<WorkspaceSwitcher\b/g)?.length, 1);
});
test('places WorkspaceSwitcher between the sidebar header and Home navigation', () => {
const headerEnd = homeSidebarSource.indexOf('</SidebarHeader>');
const switcher = homeSidebarSource.indexOf('<WorkspaceSwitcher');
const contentStart = homeSidebarSource.indexOf('<SidebarContent');
const homeGroup = homeSidebarSource.indexOf(
"<SidebarGroupLabel>{t('sidebar.home')}</SidebarGroupLabel>",
);
assert.notEqual(headerEnd, -1);
assert.notEqual(switcher, -1);
assert.notEqual(contentStart, -1);
assert.notEqual(homeGroup, -1);
assert.ok(
headerEnd < switcher,
'WorkspaceSwitcher must follow SidebarHeader',
);
assert.ok(
switcher < contentStart && switcher < homeGroup,
'WorkspaceSwitcher must precede SidebarContent and the Home group',
);
});
test('hides WorkspaceSwitcher for the singleton local OSS workspace and keeps it for Cloud or multiple workspaces', () => {
assert.match(
workspaceSwitcherSource,
/if \(!currentWorkspace\) return null;/,
);
assert.match(
homeSidebarSource,
/const workspaces = useWorkspaceBootstrap\(\);/,
);
assert.match(
homeSidebarSource,
/const showWorkspaceSwitcher\s*=\s*workspaces\.length\s*>\s*1\s*\|\|\s*currentWorkspace\?\.workspace\.source\s*===\s*'cloud_projection'/,
);
assert.match(
homeSidebarSource,
/\{showWorkspaceSwitcher\s*&&\s*\(\s*<div className="px-2[^>]*>[\s\S]*?<WorkspaceSwitcher/,
);
});
test('keeps Cloud workspace member management in Workspace Settings', () => {
assert.match(workspaceSettingsPanelSource, /workspace\.inviteMember/);
assert.doesNotMatch(workspaceSettingsPanelSource, /#workspace-members/);
assert.doesNotMatch(workspaceSettingsPanelSource, /cloudMembersURL/);
assert.doesNotMatch(workspaceSettingsPanelSource, /canManageCloudMembers/);
});
test('keeps workspace plan and settings controls on the workspace row', () => {
assert.match(workspaceSwitcherSource, /entry\.plan_name/);
assert.match(
workspaceSwitcherSource,
/aria-label=\{t\('workspace\.settings'\)\}/,
);
assert.match(workspaceSwitcherSource, /className="size-8"/);
assert.doesNotMatch(workspaceSwitcherSource, /workspace\.currentPlan/);
assert.doesNotMatch(workspaceSwitcherSource, /workspace\.upgradePlan/);
assert.doesNotMatch(workspaceSwitcherSource, /workspace\.roles/);
assert.doesNotMatch(workspaceSwitcherSource, /entry\.membership\.role/);
});
test('moves Cloud plan upgrades into Workspace Settings', () => {
assert.match(workspaceSettingsPanelSource, /cloudPlans\.title/);
assert.match(workspaceSettingsPanelSource, /<CloudPlansDialog/);
assert.match(workspaceSettingsPanelSource, /systemInfo\.cloud_service_url/);
});
test('aligns the workspace trigger with navigation entries on both sides and truncates long names', () => {
assert.match(
homeSidebarSource,
/<div className="px-2[^>]*>[\s\S]*<WorkspaceSwitcher className="w-full/,
);
assert.doesNotMatch(
homeSidebarSource,
/WorkspaceSwitcher className="[^"]*w-4\/5/,
);
assert.match(workspaceSwitcherSource, /h-9/);
assert.match(workspaceSwitcherSource, /w-64/);
assert.doesNotMatch(workspaceSwitcherSource, /min-w-80/);
assert.match(workspaceSwitcherSource, /max-w-\[7rem\][^>]*truncate/);
});
test('uses an infrastructure-level Box health endpoint in monitoring', () => {
const statusCardSource = readSource(
'src/app/home/monitoring/components/overview-cards/SystemStatusCards.tsx',
);
const backendClientSource = readSource('src/app/infra/http/BackendClient.ts');
assert.match(backendClientSource, /getBoxRuntimeStatus/);
assert.match(statusCardSource, /getBoxRuntimeStatus/);
});