1690 lines
126 KiB
JavaScript
1690 lines
126 KiB
JavaScript
import test from "node:test";
|
||
import assert from "node:assert/strict";
|
||
import fs from "node:fs";
|
||
import path from "node:path";
|
||
|
||
const ROOT = path.resolve(process.cwd(), "web/storyforge-web-v4");
|
||
const HTML = fs.readFileSync(path.join(ROOT, "index.html"), "utf8");
|
||
const APP = fs.readFileSync(path.join(ROOT, "assets/app.js"), "utf8");
|
||
const CSS = fs.readFileSync(path.join(ROOT, "assets/styles.css"), "utf8");
|
||
|
||
function extractBetween(source, startToken, endToken) {
|
||
const start = source.indexOf(startToken);
|
||
assert.notEqual(start, -1, `Missing token: ${startToken}`);
|
||
const end = source.indexOf(endToken, start);
|
||
assert.notEqual(end, -1, `Missing token: ${endToken}`);
|
||
return source.slice(start, end);
|
||
}
|
||
|
||
test("settings navigation and screen are real routes", () => {
|
||
assert.match(HTML, /data-screen-target="settings"/);
|
||
assert.match(HTML, /data-screen="settings"/);
|
||
assert.match(APP, /function renderSettingsScreen\(/);
|
||
assert.match(APP, /screenMap\.settings\.innerHTML = renderSettingsScreen\(\);/);
|
||
assert.match(APP, /window\.addEventListener\("hashchange"/);
|
||
});
|
||
|
||
test("mobile shell includes a native-like header, drawer toggle, and bottom tab bar", () => {
|
||
assert.match(HTML, /<meta name="viewport" content="width=device-width, initial-scale=1, viewport-fit=cover"/);
|
||
assert.match(HTML, /class="mobile-shell-bar"/);
|
||
assert.match(HTML, /class="mobile-workspace-strip"/);
|
||
assert.match(HTML, /data-role="mobile-workspace-project"/);
|
||
assert.match(HTML, /data-role="mobile-workspace-platforms"/);
|
||
assert.match(HTML, /data-action="open-mobile-sidebar"/);
|
||
assert.match(HTML, /class="mobile-tabbar"/);
|
||
assert.match(HTML, /class="mobile-sidebar-backdrop"/);
|
||
assert.match(HTML, /data-screen-target="dashboard"[\s\S]*mobile-tabbar-item/);
|
||
assert.match(HTML, /data-screen-target="intake"[\s\S]*mobile-tabbar-item/);
|
||
assert.match(HTML, /data-screen-target="discovery"[\s\S]*mobile-tabbar-item/);
|
||
assert.match(HTML, /data-screen-target="production"[\s\S]*mobile-tabbar-item/);
|
||
assert.match(HTML, /data-screen-target="playbook"[\s\S]*mobile-tabbar-item/);
|
||
});
|
||
|
||
test("mobile shell styling uses safe-area padding, drawer navigation, and fixed bottom navigation", () => {
|
||
assert.match(CSS, /padding-top:\s*max\(12px,\s*env\(safe-area-inset-top\)\)/);
|
||
assert.match(CSS, /\.mobile-shell-bar\s*\{[\s\S]*position:\s*sticky/);
|
||
assert.match(CSS, /\.mobile-tabbar\s*\{[\s\S]*position:\s*fixed/);
|
||
assert.match(CSS, /\.mobile-sidebar-backdrop\s*\{[\s\S]*position:\s*fixed/);
|
||
assert.match(CSS, /\.mobile-sidebar-backdrop\s*\{[\s\S]*z-index:\s*46/);
|
||
assert.match(CSS, /\.mobile-sidebar-open\s+\.sidebar\s*\{[\s\S]*transform:\s*translateX\(0\)/);
|
||
assert.match(CSS, /@media \(max-width: 760px\)[\s\S]*\.sidebar\s*\{[\s\S]*z-index:\s*47/);
|
||
assert.match(CSS, /@media \(max-width: 760px\)[\s\S]*\.mobile-sidebar-open \.mobile-tabbar,[\s\S]*\.mobile-sidebar-open \.mobile-shell-bar\s*\{[\s\S]*pointer-events:\s*none/);
|
||
assert.match(CSS, /\.content\s*\{[\s\S]*padding-bottom:\s*calc\(110px \+ env\(safe-area-inset-bottom\)\)/);
|
||
assert.match(CSS, /\.oneliner-fab\s*\{[\s\S]*bottom:\s*calc\(96px \+ env\(safe-area-inset-bottom\)\)/);
|
||
assert.match(CSS, /@media \(max-width: 760px\)[\s\S]*\.mobile-workspace-strip\s*\{[\s\S]*display:\s*grid/);
|
||
assert.match(CSS, /@media \(max-width: 760px\)[\s\S]*\.workspace-switch span\s*\{[\s\S]*display:\s*none/);
|
||
assert.match(CSS, /@media \(max-width: 760px\)[\s\S]*\.auth-status\s*\{[\s\S]*display:\s*none/);
|
||
assert.match(CSS, /@media \(max-width: 760px\)[\s\S]*\.oneliner-fab-text\s*\{[\s\S]*display:\s*none/);
|
||
});
|
||
|
||
test("mobile shell javascript syncs drawer state and active labels with the current screen", () => {
|
||
const shell = extractBetween(APP, "function renderAuthUi()", "function openAuthModal()");
|
||
const clicks = extractBetween(APP, "document.addEventListener(\"click\", async (event) => {", "document.addEventListener(\"submit\", async (event) => {");
|
||
|
||
assert.match(APP, /function setMobileSidebarOpen\(next\)/);
|
||
assert.match(APP, /function getScreenLabel\(screenId = appState\.screen\)/);
|
||
assert.match(APP, /function syncMobileShell\(\)/);
|
||
assert.match(APP, /const mobileWorkspaceProject = document\.querySelector\('\[data-role="mobile-workspace-project"\]'\)/);
|
||
assert.match(APP, /const mobileWorkspacePlatforms = document\.querySelector\('\[data-role="mobile-workspace-platforms"\]'\)/);
|
||
assert.match(shell, /syncMobileShell\(\);/);
|
||
assert.match(APP, /setMobileSidebarOpen\(false\);[\s\S]*appState\.screen = resolvedId;/);
|
||
assert.match(clicks, /name === "open-mobile-sidebar"/);
|
||
assert.match(clicks, /name === "close-mobile-sidebar"/);
|
||
assert.match(clicks, /action\.closest\("\.sidebar"\)/);
|
||
});
|
||
|
||
test("mobile workspace strip stays available for project and platform switching", () => {
|
||
const topbar = extractBetween(APP, "function renderTopbar()", "function syncRoleGatedNav()");
|
||
|
||
assert.match(topbar, /data-role="mobile-workspace-project"/);
|
||
assert.match(topbar, /data-role="mobile-workspace-platforms"/);
|
||
assert.match(topbar, /mobileWorkspaceProject\.dataset\.action = "open-dashboard-project-switcher"/);
|
||
assert.match(topbar, /data-action="select-platform"/);
|
||
assert.match(CSS, /@media \(max-width: 760px\)[\s\S]*\.mobile-workspace-strip\s*\{[\s\S]*display:\s*grid/);
|
||
});
|
||
|
||
test("mobile layout turns screen actions and page tabs into native-like horizontal rails", () => {
|
||
assert.match(CSS, /@media \(max-width: 760px\)[\s\S]*\.action-row\s*\{[\s\S]*flex-wrap:\s*nowrap/);
|
||
assert.match(CSS, /@media \(max-width: 760px\)[\s\S]*\.action-row\s*\{[\s\S]*overflow-x:\s*auto/);
|
||
assert.match(CSS, /@media \(max-width: 760px\)[\s\S]*\.page-detail-tabs\s*\{[\s\S]*overflow-x:\s*auto/);
|
||
assert.match(CSS, /@media \(max-width: 760px\)[\s\S]*\.page-detail-tabs\s*\{[\s\S]*scroll-snap-type:\s*x proximity/);
|
||
assert.match(CSS, /@media \(max-width: 760px\)[\s\S]*\.page-detail-tabs \.tab\s*\{[\s\S]*flex:\s*0 0 auto/);
|
||
});
|
||
|
||
test("mobile shell removes duplicated desktop topbar and collapses the main agent fab", () => {
|
||
assert.match(CSS, /@media \(max-width: 760px\)[\s\S]*\.topbar\s*\{[\s\S]*display:\s*none/);
|
||
assert.match(CSS, /@media \(max-width: 760px\)[\s\S]*\.oneliner-fab\s*\{[\s\S]*width:\s*52px/);
|
||
assert.match(CSS, /@media \(max-width: 760px\)[\s\S]*\.oneliner-fab\s*\{[\s\S]*justify-content:\s*center/);
|
||
assert.match(CSS, /@media \(max-width: 760px\)[\s\S]*\.oneliner-fab-text\s*\{[\s\S]*display:\s*none/);
|
||
});
|
||
|
||
test("mobile action sheets and oneliner runtime behave like bottom sheets", () => {
|
||
assert.match(APP, /class="sheet-handle"/);
|
||
assert.match(APP, /document\.body\.classList\.add\("sheet-open", "auth-sheet-open"\)/);
|
||
assert.match(APP, /document\.body\.classList\.remove\("sheet-open", "auth-sheet-open"\)/);
|
||
assert.match(APP, /document\.body\.classList\.add\("sheet-open", "action-sheet-open"\)/);
|
||
assert.match(APP, /document\.body\.classList\.remove\("sheet-open", "action-sheet-open"\)/);
|
||
assert.match(APP, /document\.body\.classList\.add\("sheet-open", "oneliner-open"\)/);
|
||
assert.match(APP, /document\.body\.classList\.remove\("sheet-open", "oneliner-open"\)/);
|
||
assert.match(CSS, /\.sheet-handle\s*\{/);
|
||
assert.match(CSS, /\.sheet-open \.mobile-tabbar\s*\{[\s\S]*opacity:\s*0/);
|
||
assert.match(CSS, /\.oneliner-open \.oneliner-fab\s*\{[\s\S]*opacity:\s*0/);
|
||
assert.match(CSS, /body\.sheet-open,\s*body\.mobile-sidebar-open\s*\{[\s\S]*overflow:\s*hidden/);
|
||
assert.match(CSS, /@media \(max-width: 760px\)[\s\S]*\.auth-modal,\s*[\s\S]*\.action-modal,\s*[\s\S]*\.oneliner-panel\s*\{[\s\S]*border-radius:\s*24px 24px 0 0/);
|
||
assert.match(CSS, /@media \(max-width: 760px\)[\s\S]*\.auth-actions\s*\{[\s\S]*position:\s*sticky/);
|
||
assert.match(CSS, /@media \(max-width: 760px\)[\s\S]*\.oneliner-composer\s*\{[\s\S]*position:\s*sticky/);
|
||
});
|
||
|
||
test("opening OneLiner clears the transient loading state after the panel is hydrated", () => {
|
||
const actions = extractBetween(APP, "document.addEventListener(\"click\", async (event) => {", "document.addEventListener(\"submit\", async (event) => {");
|
||
assert.match(actions, /name === "open-oneliner"[\s\S]*setBusy\(true,\s*"正在打开 OneLiner\.\.\."\)/);
|
||
assert.match(actions, /name === "open-oneliner"[\s\S]*finally \{[\s\S]*setBusy\(false,\s*""\);[\s\S]*renderAll\(\);[\s\S]*\}/);
|
||
});
|
||
|
||
test("project creation and switching use in-app sheets instead of browser prompts", () => {
|
||
const createProject = extractBetween(APP, "async function createProject()", "function openPreferredModelAction()");
|
||
const projectSwitcher = extractBetween(APP, "function openDashboardProjectSwitcher()", "function openDashboardActionReasonAction(");
|
||
assert.match(createProject, /openActionModal\(\{/);
|
||
assert.doesNotMatch(createProject, /window\.prompt/);
|
||
assert.doesNotMatch(createProject, /alert\(/);
|
||
assert.match(projectSwitcher, /type: "html"/);
|
||
assert.match(projectSwitcher, /最近任务/);
|
||
assert.match(projectSwitcher, /切换到这个项目/);
|
||
});
|
||
|
||
test("mobile project sheets support direct project picking and zoom-safe form controls", () => {
|
||
const projectSwitcher = extractBetween(APP, "function openDashboardProjectSwitcher()", "function openDashboardActionReasonAction(");
|
||
const applySelectedProject = extractBetween(APP, "async function applySelectedProject(projectId = \"\")", "function openDashboardProjectSwitcher()");
|
||
const clickHandler = extractBetween(APP, "document.addEventListener(\"click\", async (event) => {", "document.addEventListener(\"submit\", async (event) => {");
|
||
const createProject = extractBetween(APP, "async function createProject()", "function openPreferredModelAction()");
|
||
assert.match(APP, /async function applySelectedProject\(projectId = ""\)/);
|
||
assert.match(APP, /function focusDashboardWorkspace\(anchorId = "dashboard-workspace-anchor"\)/);
|
||
assert.match(projectSwitcher, /data-project-choice=/);
|
||
assert.match(projectSwitcher, /hidden:\s*isMobileViewport/);
|
||
assert.match(projectSwitcher, /onOpen:\s*\(/);
|
||
assert.match(projectSwitcher, /select\.value = nextProjectId/);
|
||
assert.match(projectSwitcher, /window\.matchMedia\?\.\("\(max-width: 760px\)"\)\?\.matches/);
|
||
assert.match(projectSwitcher, /submit\.hidden = true/);
|
||
assert.match(projectSwitcher, /closeActionModal\(\);/);
|
||
assert.match(projectSwitcher, /await applySelectedProject\(nextProjectId\);/);
|
||
assert.match(APP, /if \(field\.hidden\) \{\s*return "";/);
|
||
assert.match(applySelectedProject, /loadStorageStatus\(appState\.selectedProjectId \|\| ""\)/);
|
||
assert.match(applySelectedProject, /loadAgentControlSurfaces\(appState\.selectedProjectId \|\| ""\)/);
|
||
assert.match(applySelectedProject, /focusDashboardWorkspace\("dashboard-workspace-anchor"\)/);
|
||
assert.match(clickHandler, /name === "select-project"[\s\S]*await applySelectedProject\(action\.dataset\.projectId \|\| ""\)/);
|
||
assert.match(APP, /id="dashboard-workspace-anchor"/);
|
||
assert.match(createProject, /onOpen:\s*\(/);
|
||
assert.match(CSS, /@media \(max-width: 760px\)[\s\S]*\.field-stack input,\s*[\s\S]*\.field-stack textarea,\s*[\s\S]*\.field-stack select\s*\{[\s\S]*min-height:\s*46px/);
|
||
assert.match(CSS, /@media \(max-width: 760px\)[\s\S]*\.field-stack input,\s*[\s\S]*\.field-stack textarea,\s*[\s\S]*\.field-stack select\s*\{[\s\S]*font-size:\s*16px/);
|
||
});
|
||
|
||
test("mobile touch targets raise tappable buttons, tabs, and action tags closer to native sizes", () => {
|
||
assert.match(CSS, /@media \(max-width: 760px\)[\s\S]*\.btn,\s*[\s\S]*\.tab,\s*[\s\S]*\.tag\.clickable-tag\s*\{[\s\S]*min-height:\s*44px/);
|
||
assert.match(CSS, /@media \(max-width: 760px\)[\s\S]*\.btn,\s*[\s\S]*\.tab,\s*[\s\S]*\.tag\.clickable-tag\s*\{[\s\S]*display:\s*inline-flex/);
|
||
});
|
||
|
||
test("mobile compact summaries scroll horizontally instead of stacking into a second row", () => {
|
||
assert.match(CSS, /@media \(max-width: 760px\)[\s\S]*\.compact-summary-row\s*\{[\s\S]*flex-wrap:\s*nowrap/);
|
||
assert.match(CSS, /@media \(max-width: 760px\)[\s\S]*\.compact-summary-row\s*\{[\s\S]*overflow-x:\s*auto/);
|
||
assert.match(CSS, /@media \(max-width: 760px\)[\s\S]*\.compact-summary-row::-webkit-scrollbar\s*\{[\s\S]*display:\s*none/);
|
||
assert.match(CSS, /@media \(max-width: 760px\)[\s\S]*\.compact-summary-row \.tag\s*\{[\s\S]*flex:\s*0 0 auto/);
|
||
});
|
||
|
||
test("action tags render interactive controls as buttons instead of passive spans", () => {
|
||
const actionTagSource = extractBetween(APP, "function actionTag(", "function renderPipelineButton(");
|
||
assert.match(actionTagSource, /if \(targetAction\) \{/);
|
||
assert.match(actionTagSource, /<button/);
|
||
assert.match(actionTagSource, /type="button"/);
|
||
assert.match(actionTagSource, /<span/);
|
||
});
|
||
|
||
test("mobile screen heads split the first action into a primary rail and keep the rest in a secondary strip", () => {
|
||
assert.match(APP, /function splitPrimaryAction\(actionsHtml\)/);
|
||
assert.match(APP, /class="action-row-primary"/);
|
||
assert.match(APP, /class="action-row-secondary"/);
|
||
assert.match(CSS, /@media \(max-width: 760px\)[\s\S]*\.action-row\s*\{[\s\S]*display:\s*grid/);
|
||
assert.match(CSS, /@media \(max-width: 760px\)[\s\S]*\.action-row-primary\s+\.btn\s*\{[\s\S]*width:\s*100%/);
|
||
assert.match(CSS, /@media \(max-width: 760px\)[\s\S]*\.action-row-secondary\s*\{[\s\S]*overflow-x:\s*auto/);
|
||
});
|
||
|
||
test("mobile screens with a focus card collapse the secondary action rail", () => {
|
||
assert.match(APP, /const hasMobileFocusCard = body\.includes\("mobile-flow-focus-card"\)/);
|
||
assert.match(APP, /screen-head-has-mobile-focus/);
|
||
assert.match(CSS, /@media \(max-width: 760px\)[\s\S]*\.screen-head\.screen-head-has-mobile-focus \.action-row-secondary\s*\{[\s\S]*display:\s*none/);
|
||
assert.match(CSS, /@media \(max-width: 760px\)[\s\S]*\.screen-head\.screen-head-has-mobile-focus p\s*\{[\s\S]*-webkit-line-clamp:\s*1/);
|
||
});
|
||
|
||
test("mobile bottom navigation stays highlighted for grouped related screens", () => {
|
||
assert.match(APP, /function getMobileTabGroup\(screenId = appState\.screen\)/);
|
||
assert.match(APP, /tracking:\s*"discovery"/);
|
||
assert.match(APP, /review:\s*"production"/);
|
||
assert.match(APP, /strategy:\s*"playbook"/);
|
||
assert.match(APP, /credits:\s*"dashboard"/);
|
||
assert.match(APP, /button\.classList\.toggle\("is-active", active \|\| mobileGroupActive\)/);
|
||
});
|
||
|
||
test("detail tab buttons expose the active state for touch navigation", () => {
|
||
const detailTabs = extractBetween(APP, "function renderDetailTabs(stateKey, tabs) {", "function renderDiscoveryOverviewSection(");
|
||
assert.match(detailTabs, /aria-pressed="\$\{tab\.value === active \? "true" : "false"\}"/);
|
||
});
|
||
|
||
test("strategy navigation and screen are real routes", () => {
|
||
assert.match(HTML, /data-screen-target="strategy"/);
|
||
assert.match(HTML, /data-screen="strategy"/);
|
||
assert.match(APP, /function renderStrategyScreen\(/);
|
||
assert.match(APP, /screenMap\.strategy\.innerHTML = renderStrategyScreen\(\);/);
|
||
});
|
||
|
||
test("strategy screen exposes a compact mobile summary for current governance state", () => {
|
||
const source = extractBetween(APP, "function renderStrategyScreen()", "function renderCreditsScreen()");
|
||
assert.match(source, /mobile-only compact-summary-row/);
|
||
assert.match(source, /mobile-only mobile-flow-focus-card/);
|
||
assert.match(source, /当前策略任务/);
|
||
assert.match(source, /当前生效/);
|
||
assert.match(source, /平台策略/);
|
||
});
|
||
|
||
test("automation screen stays user-facing and excludes admin-only panels", () => {
|
||
const source = extractBetween(APP, "function renderAutomationScreen()", "function renderOwnedScreen()");
|
||
assert.doesNotMatch(source, /renderTenantQuotaPanel\(/);
|
||
assert.doesNotMatch(source, /renderOneLinerActionRegistryPanel\(/);
|
||
assert.doesNotMatch(source, /renderAdminOpsPanel\(/);
|
||
assert.match(source, /renderDetailTabs\("automationDetailTab"/);
|
||
});
|
||
|
||
test("agent screen excludes quota and registry panels and uses page tabs", () => {
|
||
const source = extractBetween(APP, "function renderPlaybookScreen()", "function renderProductionScreen()");
|
||
assert.doesNotMatch(source, /renderTenantQuotaPanel\(/);
|
||
assert.doesNotMatch(source, /renderOneLinerActionRegistryPanel\(/);
|
||
assert.match(source, /renderDetailTabs\("playbookDetailTab"/);
|
||
assert.match(source, /mobile-only compact-summary-row/);
|
||
assert.match(source, /mobile-only mobile-flow-focus-card/);
|
||
assert.match(source, /当前 Agent 任务/);
|
||
assert.match(source, /renderGovernanceSummaryCard\(/);
|
||
assert.match(source, /open-user-global-policy/);
|
||
assert.match(source, /open-user-platform-policy/);
|
||
assert.match(source, /active_admin_override_notice/);
|
||
});
|
||
|
||
test("discovery, production, and admin screens use page tabs for heavy content", () => {
|
||
const discovery = extractBetween(APP, "function renderDiscoveryScreen()", "function renderTrackingScreen()");
|
||
const production = extractBetween(APP, "function renderProductionScreen()", "function renderReviewScreen()");
|
||
const admin = extractBetween(APP, "function renderAdminWorkbenchScreen()", "function renderDashboardScreen()");
|
||
const strategy = extractBetween(APP, "function renderStrategyScreen()", "function renderCreditsScreen()");
|
||
|
||
assert.match(discovery, /renderDetailTabs\("discoveryDetailTab"/);
|
||
assert.match(production, /renderDetailTabs\("productionDetailTab"/);
|
||
assert.match(production, /value: "recorder", label: "视频录制"/);
|
||
assert.match(admin, /renderDetailTabs\("adminWorkbenchTab"/);
|
||
assert.match(admin, /value: "model_access", label: "模型与接入"/);
|
||
assert.match(admin, /renderAdminModelAccessPanel\(/);
|
||
assert.match(admin, /renderAdminGovernanceSummaryPanel\(/);
|
||
assert.match(admin, /覆盖与审计/);
|
||
assert.match(strategy, /renderDetailTabs\("strategyDetailTab"/);
|
||
assert.match(strategy, /renderPolicyAuditFeed\(/);
|
||
});
|
||
|
||
test("admin workbench exposes a dedicated model access workspace and actions", () => {
|
||
const admin = extractBetween(APP, "function renderAdminModelRuntimePanel()", "function renderDashboardScreen()");
|
||
const loadControls = extractBetween(APP, "async function loadAgentControlSurfaces(", "async function loadOneLinerMessages(");
|
||
const clickActions = extractBetween(APP, "document.addEventListener(\"click\", async (event) => {", "document.addEventListener(\"submit\", async (event) => {");
|
||
assert.match(APP, /adminModelAccess:\s*null/);
|
||
assert.match(APP, /function focusAdminModelAccessWorkspace\(anchorId = "admin-model-access-anchor"\)/);
|
||
assert.match(loadControls, /\/v2\/admin\/model-access\/overview/);
|
||
assert.match(admin, /运行时接入/);
|
||
assert.match(admin, /系统模型/);
|
||
assert.match(admin, /视频模型服务/);
|
||
assert.match(admin, /open-admin-runtime-config/);
|
||
assert.match(admin, /open-admin-system-model/);
|
||
assert.match(admin, /open-admin-huobao-ai-config/);
|
||
assert.match(clickActions, /name === "open-admin-runtime-config"/);
|
||
assert.match(clickActions, /name === "open-admin-system-model"/);
|
||
assert.match(clickActions, /name === "open-admin-huobao-ai-config"/);
|
||
});
|
||
|
||
test("governance and quota panels use real empty-state language instead of backend-sync placeholders", () => {
|
||
const actionRegistry = extractBetween(APP, "function renderOneLinerActionRegistryPanel()", "function renderTenantQuotaPanel()");
|
||
const tenantQuota = extractBetween(APP, "function renderTenantQuotaPanel()", "function policyScopeTagLabel(");
|
||
const platformAgents = extractBetween(APP, "function renderPlatformAgentPanel()", "function renderTrackingScreen()");
|
||
|
||
assert.doesNotMatch(actionRegistry, /等 <code>\/v2\/oneliner\/action-registry<\/code> 可用后/);
|
||
assert.match(actionRegistry, /当前项目还没有单独动作配置/);
|
||
|
||
assert.doesNotMatch(tenantQuota, /等 live collector 同步 `\/v2\/tenant\/quota` 和 `\/v2\/tenant\/usage` 后/);
|
||
assert.match(tenantQuota, /当前项目还没有额度配置/);
|
||
assert.match(tenantQuota, /data-action="open-tenant-quota"/);
|
||
|
||
assert.doesNotMatch(platformAgents, /等 live collector 同步 `\/v2\/platform-agents` 后/);
|
||
assert.match(platformAgents, /当前项目还没有平台 Agent 配置/);
|
||
assert.match(platformAgents, /open-platform-agent-profile/);
|
||
});
|
||
|
||
test("platform agent surfaces recent execution feedback from main agent runs", () => {
|
||
const platformAgents = extractBetween(APP, "function renderPlatformAgentPanel()", "function renderAdminOpsPanel()");
|
||
const detail = extractBetween(APP, "async function openPlatformAgentDetailAction(platform)", "function openPlatformSkillReviewAction(platform, skillId, accepted)");
|
||
const actions = extractBetween(APP, "document.addEventListener(\"click\", async (event) => {", "document.addEventListener(\"submit\", async (event) => {");
|
||
|
||
assert.match(platformAgents, /recent_execution/);
|
||
assert.match(platformAgents, /最近执行/);
|
||
assert.match(platformAgents, /配置 v/);
|
||
assert.match(platformAgents, /open-oneliner-run-result/);
|
||
assert.match(platformAgents, /open-oneliner-run-context/);
|
||
assert.match(detail, /最近执行/);
|
||
assert.match(detail, /recent_execution/);
|
||
assert.match(detail, /open-oneliner-run-result/);
|
||
assert.match(detail, /open-oneliner-run-context/);
|
||
assert.match(actions, /name === "open-oneliner-run-context"[\s\S]*openOneLinerRunContextAction/);
|
||
});
|
||
|
||
test("quota and review screens foreground live next-step guidance", () => {
|
||
const tenantQuota = extractBetween(APP, "function renderTenantQuotaPanel()", "function policyScopeTagLabel(");
|
||
const credits = extractBetween(APP, "function renderCreditsScreen()", "function renderSettingsScreen()");
|
||
const quotaAction = extractBetween(APP, "function openTenantQuotaAction()", "function openCreateAssistantAction()");
|
||
const review = extractBetween(APP, "function renderReviewScreen()", "function renderStrategyScreen()");
|
||
const storage = extractBetween(APP, "function renderStorageStatusPanel()", "function renderAutomationScreen()");
|
||
|
||
assert.match(tenantQuota, /先处理存储超限|先恢复额度保护|先补项目额度策略|先检查本周期消耗|先跑出第一条计量/);
|
||
assert.match(tenantQuota, /主要消耗/);
|
||
assert.match(tenantQuota, /周期 /);
|
||
assert.match(tenantQuota, /计量 /);
|
||
|
||
assert.doesNotMatch(review, /复盘能力暂未接入|还缺 \/v2\/reviews/);
|
||
assert.match(review, /先把最近完成任务写成复盘|先回看高频结论|先跑出第一条可复盘任务/);
|
||
assert.match(review, /高频结论/);
|
||
assert.match(review, /已发布/);
|
||
assert.doesNotMatch(storage, /后端暂未提供 \/v2\/storage\/status/);
|
||
assert.match(storage, /当前实例没有返回存储策略时/);
|
||
assert.doesNotMatch(credits, /后续再接真实套餐/);
|
||
assert.doesNotMatch(credits, /后端尚未完全接入真实预算/);
|
||
assert.doesNotMatch(credits, /当前先按文案、AI 视频、实拍剪辑三类动作池展示/);
|
||
assert.match(credits, /当前项目还没有独立额度策略/);
|
||
assert.match(credits, /文案、AI 视频和实拍剪辑会按动作池分开管理/);
|
||
assert.match(credits, /按最近动作量和成本信号建立可执行的预算基线|按项目阶段配置试用、增长或规模套餐/);
|
||
assert.match(credits, /预算、动作池和项目阶段绑定成正式套餐/);
|
||
assert.match(tenantQuota, /套餐档位/);
|
||
assert.match(tenantQuota, /预警阈值|预警 80%/);
|
||
assert.match(APP, /const TENANT_QUOTA_PACKAGE_PRESETS =/);
|
||
assert.match(APP, /function getTenantQuotaForecastValues\(values = \{\}, usage = null\)/);
|
||
assert.match(APP, /function renderTenantQuotaForecastTags\(values, usage = null\)/);
|
||
assert.match(APP, /function getTenantQuotaPackageRecommendation\(values = \{\}, usage = null\)/);
|
||
assert.match(APP, /renderTenantQuotaForecastTags\(currentValues\)/);
|
||
assert.match(APP, /function renderTenantQuotaPackagePreview\(label, values = null, usage = null\)/);
|
||
assert.match(tenantQuota, /renderTenantQuotaForecastTags\(quota \|\| \{\}, usage\)/);
|
||
assert.match(tenantQuota, /packageRecommendation\.title/);
|
||
assert.match(credits, /renderTenantQuotaForecastTags\(quota \|\| \{\}, usage\)/);
|
||
assert.match(credits, /const packageRecommendation = getTenantQuotaPackageRecommendation\(/);
|
||
assert.match(credits, /<h4>套餐建议<\/h4>/);
|
||
assert.match(credits, /packageRecommendation\.summary/);
|
||
assert.match(credits, /剩余 \${escapeHtml\(formatNumber\(forecast\.remainingBudgetCents \/ 100\)\)} 元/);
|
||
assert.match(credits, /文案剩余 \${formatNumber\(forecast\.remainingCopyQuota\)}/);
|
||
assert.match(quotaAction, /const usage = appState\.tenantUsage \|\| \{\}/);
|
||
assert.match(quotaAction, /renderTenantQuotaPackagePreview\(quotaConfig\.package_label \|\| "custom", defaultDraft, usage\)/);
|
||
assert.match(quotaAction, /renderTenantQuotaPackagePreview\("custom", currentCustomDraft, usage\)/);
|
||
assert.match(APP, /预设已锁定|支持自定义/);
|
||
assert.match(quotaAction, /input\.disabled = Boolean\(preset\)/);
|
||
assert.match(quotaAction, /name: "packageLabel"/);
|
||
assert.match(quotaAction, /name: "warnThreshold"/);
|
||
assert.match(quotaAction, /package_label/);
|
||
assert.match(quotaAction, /warn_threshold/);
|
||
});
|
||
|
||
test("tracking refresh and top-video analysis flows expose async feedback inside the workbench", () => {
|
||
const tracking = extractBetween(APP, "function renderTrackingScreen()", "function renderAutomationScreen()");
|
||
const discovery = extractBetween(APP, "function renderDiscoveryOverviewSection(", "function renderDiscoveryRelationsSection(");
|
||
const accountWorkspaceLoad = extractBetween(APP, "async function loadPlatformAccount(", "async function bootstrap()");
|
||
const bootstrapSource = extractBetween(APP, "async function bootstrap()", "async function markTrackingDigestRead()");
|
||
const oneLinerHydrate = extractBetween(APP, "async function hydrateSelectedOneLinerRun()", "async function loadAgentControlSurfaces(");
|
||
const controlSurfaces = extractBetween(APP, "async function loadAgentControlSurfaces(", "async function loadOneLinerMessages(");
|
||
const oneLinerMessages = extractBetween(APP, "async function loadOneLinerMessages(", "async function ensureOneLinerSession(");
|
||
const trackingActions = extractBetween(APP, "async function markTrackingDigestRead()", "function createEmptyTrackingDigest(");
|
||
const oneLinerSession = extractBetween(APP, "async function ensureOneLinerSession()", "async function submitOneLinerMessage(");
|
||
const oneLinerRun = extractBetween(APP, "async function createOneLinerRun(", "async function confirmOneLinerRun(");
|
||
const oneLinerAction = extractBetween(APP, "async function executeOneLinerAction(", "function openCurrentOneLinerRunResultAction(");
|
||
const skillReview = extractBetween(APP, "function openPlatformSkillReviewAction(", "function openPlatformSkillRollbackAction(");
|
||
const agentDetail = extractBetween(APP, "async function openPlatformAgentDetailAction(", "function openPlatformSkillReviewAction(");
|
||
const topVideoAction = extractBetween(APP, "function openAnalyzeTopVideosAction()", "function openSimilaritySearchAction()");
|
||
const jobRecoverability = extractBetween(APP, "function getJobRecoverability(job) {", "function getJobRecoveryRequest(job) {");
|
||
const recoveryAction = extractBetween(APP, "async function recoverJobAction(", "function getRecoverableFailedJobs()");
|
||
const clickActions = extractBetween(APP, "document.addEventListener(\"click\", async (event) => {", "document.addEventListener(\"submit\", async (event) => {");
|
||
|
||
assert.match(APP, /function summarizeTrackingRefreshPayload\(/);
|
||
assert.match(APP, /function rememberTrackingRefreshNotice\(/);
|
||
assert.match(APP, /function isMissingBackendCapability\(/);
|
||
assert.match(tracking, /批量同步已排队|单账号同步已排队|后台同步状态/);
|
||
assert.match(tracking, /去生产中心/);
|
||
assert.doesNotMatch(tracking, /这套后端还没有接入.*跟踪接口/);
|
||
|
||
assert.match(APP, /function getSelectedTopVideoAnalysisResult\(/);
|
||
assert.match(discovery, /最近高分拆解/);
|
||
assert.match(discovery, /这批结果已经回流到当前账号页/);
|
||
assert.doesNotMatch(trackingActions, /当前后端暂不支持.*跟踪已读游标|当前后端暂不支持.*批量跟踪同步|当前后端暂不支持.*单账号跟踪同步/s);
|
||
assert.doesNotMatch(accountWorkspaceLoad, /supportsAccountVideos|supportsAccountSnapshots|supportsCreatorFields|supportsAnalysisReports/);
|
||
assert.ok(!bootstrapSource.includes('backendSupports("/v2/integrations/health")'));
|
||
assert.ok(!bootstrapSource.includes('backendSupports("/v2/live-recorder/sources")'));
|
||
assert.ok(!oneLinerHydrate.includes('backendSupports("/v2/oneliner/runs/{run_id}")'));
|
||
assert.ok(!oneLinerMessages.includes('backendSupports("/v2/oneliner/sessions/{session_id}/messages")'));
|
||
assert.ok(!controlSurfaces.includes('backendSupports("/v2/oneliner/profile")'));
|
||
assert.ok(!controlSurfaces.includes('backendSupports("/v2/platform-agents")'));
|
||
assert.doesNotMatch(oneLinerSession, /当前后端还没有接入 OneLiner 会话接口/);
|
||
assert.doesNotMatch(oneLinerRun, /当前后端还没有接入主 Agent 运行层/);
|
||
assert.doesNotMatch(oneLinerAction, /当前后端还没有接入 OneLiner 动作执行器/);
|
||
assert.doesNotMatch(skillReview, /当前后端还没有接入平台技能验收接口/);
|
||
assert.ok(!agentDetail.includes('backendSupports("/v2/platform-agents/{platform}/skills/{skill_id}/versions")'));
|
||
assert.doesNotMatch(topVideoAction, /当前后端暂不支持.*高分作品批量分析/s);
|
||
assert.doesNotMatch(topVideoAction, /当前实例未提供/);
|
||
assert.doesNotMatch(jobRecoverability, /暂时无法自动恢复/);
|
||
assert.doesNotMatch(jobRecoverability, /当前链路没有可自动恢复的模板/);
|
||
assert.ok(!jobRecoverability.includes('backendSupports("/v2/explore/jobs/{job_id}/retry") && uploadedPath'));
|
||
assert.doesNotMatch(recoveryAction, /暂不支持自动恢复|暂不支持恢复/);
|
||
assert.ok(!recoveryAction.includes('if (backendSupports("/v2/explore/jobs/{job_id}/retry"))'));
|
||
assert.ok(!clickActions.includes('else if (backendSupports("/v2/oneliner/sessions"))'));
|
||
});
|
||
|
||
test("job detail and follow-up flows use direct generate-copy execution and persist recent copy results", () => {
|
||
const jobDetail = extractBetween(APP, "function openJobDetailAction(jobId) {", "function openRecoverJobAction(");
|
||
const clickActions = extractBetween(APP, "document.addEventListener(\"click\", async (event) => {", "document.addEventListener(\"submit\", async (event) => {");
|
||
|
||
assert.match(APP, /function cacheGeneratedCopyResult\(payload, options = \{\}\)/);
|
||
assert.match(jobDetail, /actionTag\("用摘要写文案", "direct-generate-copy"/);
|
||
assert.match(clickActions, /name === "open-generated-copy-results"[\s\S]*focusRecentGeneratedCopy\(\)/);
|
||
assert.match(clickActions, /name === "direct-generate-copy"[\s\S]*runDirectWorkbenchAction\("generate-copy"/);
|
||
assert.match(clickActions, /name === "direct-generate-copy"[\s\S]*followRecommendedAction:\s*false/);
|
||
assert.match(clickActions, /name === "direct-generate-copy"[\s\S]*cacheGeneratedCopyResult\(result,\s*\{\s*brief\s*\}\)/);
|
||
assert.match(clickActions, /name === "direct-generate-copy"[\s\S]*focusRecentGeneratedCopy\(\)/);
|
||
assert.match(clickActions, /name === "job-to-generate-copy"[\s\S]*runDirectWorkbenchAction\("generate-copy"/);
|
||
});
|
||
|
||
test("ai video provider hint links super admins into the huobao video config workspace", () => {
|
||
const hintSource = extractBetween(APP, "function renderAiVideoProviderHintHtml(provider = \"doubao\") {", "function renderAiVideoProviderMemoryHtml(");
|
||
const clickActions = extractBetween(APP, "document.addEventListener(\"click\", async (event) => {", "document.addEventListener(\"submit\", async (event) => {");
|
||
assert.match(hintSource, /打开视频引擎配置/);
|
||
assert.match(hintSource, /focus-huobao-video-config/);
|
||
assert.match(clickActions, /name === "focus-huobao-video-config"[\s\S]*focusAdminModelAccessWorkspace\("admin-model-video-anchor"\)/);
|
||
});
|
||
|
||
test("pipeline follow-up tags route source-job actions through direct execute handlers", () => {
|
||
const pipelineGuards = extractBetween(APP, "const PIPELINE_GUARDS = {", "const ONELINER_INTENT_LABELS = {");
|
||
const clickActions = extractBetween(APP, "document.addEventListener(\"click\", async (event) => {", "document.addEventListener(\"submit\", async (event) => {");
|
||
|
||
assert.match(pipelineGuards, /openAction:\s*"open-ai-video"/);
|
||
assert.match(pipelineGuards, /openAction:\s*"open-real-cut"/);
|
||
assert.match(pipelineGuards, /jobAction:\s*"direct-create-ai-video"/);
|
||
assert.match(pipelineGuards, /jobAction:\s*"direct-create-real-cut"/);
|
||
assert.match(clickActions, /name === "direct-create-ai-video"[\s\S]*if \(action\.dataset\.jobId\) \{[\s\S]*closeActionModal\(\);/);
|
||
assert.match(clickActions, /name === "direct-create-real-cut"[\s\S]*if \(action\.dataset\.jobId\) \{[\s\S]*closeActionModal\(\);/);
|
||
});
|
||
|
||
test("discovery and production screens expose compact mobile flow summaries", () => {
|
||
const discovery = extractBetween(APP, "function renderDiscoveryScreen()", "function renderTrackingScreen()");
|
||
const production = extractBetween(APP, "function renderProductionScreen()", "function renderReviewScreen()");
|
||
|
||
assert.match(discovery, /mobile-only compact-summary-row/);
|
||
assert.match(discovery, /当前对标/);
|
||
assert.match(discovery, /已接入/);
|
||
assert.match(production, /mobile-only compact-summary-row/);
|
||
assert.match(production, /处理中/);
|
||
assert.match(production, /失败/);
|
||
});
|
||
|
||
test("workbench copy uses direct live language instead of future-placeholder wording", () => {
|
||
assert.doesNotMatch(APP, /可选,不填则后续再补/);
|
||
assert.match(APP, /可选,可先留空,后面随时补充/);
|
||
assert.match(APP, /文案生成、对标绑定和复盘都会优先使用这里选中的 Agent/);
|
||
assert.match(APP, /导入分析、市场调研和风格学习都会优先使用这里设置的模型/);
|
||
assert.match(APP, /系统会自动生成更新日报/);
|
||
assert.match(APP, /把完成任务写成一条可追踪复盘,可按项目累计/);
|
||
assert.match(APP, /先绑定执行 Agent,再完善任务目标和方法论/);
|
||
assert.match(APP, /先看真实作品,再继续整理文档与成片/);
|
||
assert.match(APP, /等待配置探测地址/);
|
||
});
|
||
|
||
test("discovery and production screens expose mobile focus cards with next-step actions", () => {
|
||
const discovery = extractBetween(APP, "function renderDiscoveryScreen()", "function renderTrackingScreen()");
|
||
const production = extractBetween(APP, "function renderProductionScreen()", "function renderReviewScreen()");
|
||
const cssMobile = extractBetween(CSS, "@media (max-width: 760px) {", "@media (max-width: 560px) {");
|
||
|
||
assert.match(discovery, /mobile-only mobile-flow-focus-card/);
|
||
assert.match(discovery, /class="filters mobile-priority-filters"/);
|
||
assert.match(discovery, /下一步先做/);
|
||
assert.match(discovery, /导入当前对标/);
|
||
assert.match(discovery, /查相似/);
|
||
assert.match(production, /mobile-only mobile-flow-focus-card/);
|
||
assert.match(APP, /function renderProductionMobileTaskDeck\(/);
|
||
assert.match(APP, /mobile-only production-mobile-task-deck/);
|
||
assert.match(APP, /当前要先处理/);
|
||
assert.match(production, /当前工作流/);
|
||
assert.match(production, /批量恢复/);
|
||
assert.match(cssMobile, /\.mobile-flow-focus-card/);
|
||
assert.match(cssMobile, /\.production-mobile-task-deck/);
|
||
});
|
||
|
||
test("mobile discovery and production simplify duplicated top-level actions", () => {
|
||
const discovery = extractBetween(APP, "function renderDiscoveryScreen()", "function renderTrackingScreen()");
|
||
const production = extractBetween(APP, "function renderProductionScreen()", "function renderReviewScreen()");
|
||
const clickActions = extractBetween(APP, "document.addEventListener(\"click\", async (event) => {", "navButtons.forEach((button) => {");
|
||
|
||
assert.match(APP, /function isMobileViewport\(\)/);
|
||
assert.match(discovery, /const isMobileUi = isMobileViewport\(\);/);
|
||
assert.match(discovery, /const discoveryActionsHtml = isMobileUi/);
|
||
assert.match(discovery, /button\("导入主页", "open-import-homepage"\)/);
|
||
assert.match(discovery, /button\("导入当前对标", "direct-import-selected-account"/);
|
||
assert.match(discovery, /button\("查相似", "direct-search-similar"/);
|
||
assert.match(discovery, /saveBenchmarkActionName = similarCandidates\.length \? "direct-save-benchmark-link" : "open-benchmark-link"/);
|
||
assert.match(production, /const isMobileUi = isMobileViewport\(\);/);
|
||
assert.match(production, /const productionActionsHtml = isMobileUi/);
|
||
assert.match(production, /button\("导入主页", "open-import-homepage"\)/);
|
||
assert.match(production, /button\("导入作品", "open-import-video-link"/);
|
||
assert.match(production, /button\("导入文本", "open-import-text"\)/);
|
||
assert.match(production, /button\("上传视频", "open-upload-video"\)/);
|
||
assert.match(production, /button\("视频录制", "focus-live-recorder-maintenance", "secondary"\)/);
|
||
assert.match(production, /button\("交给主 Agent", "handoff-to-main-agent"/);
|
||
assert.match(production, /button\("去复盘", "goto-review", "primary"\)/);
|
||
assert.match(clickActions, /name === "focus-live-recorder-maintenance"[\s\S]*captureMainAgentLandingContext\(action,\s*"goto-production"\);[\s\S]*focusLiveRecorderMaintenance\(\)/);
|
||
});
|
||
|
||
test("production queue promotes intake entrypoints so import flows are reachable without leaving production", () => {
|
||
const production = extractBetween(APP, "function renderProductionScreen()", "function renderReviewScreen()");
|
||
const mobileDeck = extractBetween(APP, "function renderProductionMobileTaskDeck(", "function renderProductionScreen()");
|
||
assert.match(production, /const intakeEntryActionsHtml =/);
|
||
assert.match(production, /<h4>接入素材<\/h4>/);
|
||
assert.match(production, /把主页、作品链接、文本素材或本地视频先接进项目/);
|
||
assert.match(production, /先从导入主页、作品、文本或上传视频开始接入素材/);
|
||
assert.match(production, /<h4>接入与录制<\/h4>/);
|
||
assert.match(production, /同步 .* 条 · 录制源 .* 个/);
|
||
assert.match(production, /录制 \${escapeHtml\(formatNumber\(recorderSourceCount\)\)}/);
|
||
assert.match(production, /actionTag\("导入作品", "open-import-video-link"\)/);
|
||
assert.match(production, /actionTag\("上传视频", "open-upload-video"\)/);
|
||
assert.match(mobileDeck, /<h4>接入与录制<\/h4>/);
|
||
assert.match(mobileDeck, /actionTag\("导入主页", "open-import-homepage"\)/);
|
||
assert.match(mobileDeck, /actionTag\("视频录制", "focus-live-recorder-maintenance"\)/);
|
||
});
|
||
|
||
test("discovery page promotes selected-account actions into direct execute flows", () => {
|
||
const discovery = extractBetween(APP, "function renderDiscoveryScreen()", "function renderTrackingScreen()");
|
||
const discoveryOverview = extractBetween(APP, "function renderDiscoveryOverviewSection(", "function renderDiscoveryRelationsSection(");
|
||
assert.match(APP, /async function runDirectDiscoveryAction\(executorKey, payload, options = \{\}\)/);
|
||
assert.match(APP, /async function followRecommendedActionResult\(payload, options = \{\}\)/);
|
||
assert.match(discoveryOverview, /direct-import-selected-account/);
|
||
assert.match(discoveryOverview, /direct-track-selected-account/);
|
||
assert.match(discovery, /actionTag\("导入当前对标", "direct-import-selected-account"\)/);
|
||
assert.match(discovery, /actionTag\("账号分析", "direct-analyze-selected-account"\)/);
|
||
assert.match(discovery, /actionTag\("查相似", "direct-search-similar"\)/);
|
||
assert.match(APP, /if \(name === "direct-import-selected-account"\)/);
|
||
assert.match(APP, /if \(name === "direct-track-selected-account"\)/);
|
||
assert.match(APP, /if \(name === "direct-analyze-selected-account"\)/);
|
||
assert.match(APP, /if \(name === "direct-analyze-top-videos"\)/);
|
||
assert.match(APP, /if \(name === "direct-search-similar"\)/);
|
||
assert.match(APP, /if \(name === "direct-save-benchmark-link"\)/);
|
||
});
|
||
|
||
test("direct discovery analysis actions gracefully fall back to forms when no account is selected", () => {
|
||
assert.match(APP, /if \(name === "direct-analyze-selected-account"\)[\s\S]*const account = getSelectedAccount\(\);/);
|
||
assert.match(APP, /if \(name === "direct-analyze-selected-account"\)[\s\S]*openAnalyzeSelectedAccountAction\(\);/);
|
||
assert.match(APP, /if \(name === "direct-analyze-top-videos"\)[\s\S]*const account = getSelectedAccount\(\);/);
|
||
assert.match(APP, /if \(name === "direct-analyze-top-videos"\)[\s\S]*openAnalyzeTopVideosAction\(\);/);
|
||
});
|
||
|
||
test("mobile discovery prioritizes the selected-account task flow before the scrollable account list", () => {
|
||
const discovery = extractBetween(APP, "function renderDiscoveryScreen()", "function renderTrackingScreen()");
|
||
assert.match(discovery, /mobile-discovery-priority/);
|
||
assert.match(discovery, /mobile-discovery-selected-summary/);
|
||
assert.match(discovery, /mobile-account-list/);
|
||
assert.match(discovery, /mobile-discovery-priority[\s\S]*mobile-account-list/);
|
||
});
|
||
|
||
test("mobile heavy screens mark redundant desktop metric blocks for compact hiding", () => {
|
||
const discovery = extractBetween(APP, "function renderDiscoveryScreen()", "function renderTrackingScreen()");
|
||
const tracking = extractBetween(APP, "function renderTrackingScreen()", "function renderAutomationScreen()");
|
||
const automation = extractBetween(APP, "function renderAutomationScreen()", "function renderOwnedScreen()");
|
||
const owned = extractBetween(APP, "function renderOwnedScreen()", "function renderPlaybookScreen()");
|
||
const projects = extractBetween(APP, "function renderProjectsScreen()", "function getActiveDetailTab(");
|
||
const production = extractBetween(APP, "function renderProductionScreen()", "function renderReviewScreen()");
|
||
const review = extractBetween(APP, "function renderReviewScreen()", "function renderStrategyScreen()");
|
||
const playbook = extractBetween(APP, "function renderPlaybookScreen()", "function renderProductionScreen()");
|
||
const strategy = extractBetween(APP, "function renderStrategyScreen()", "function renderCreditsScreen()");
|
||
const cssMobile = extractBetween(CSS, "@media (max-width: 760px) {", "@media (max-width: 560px) {");
|
||
|
||
assert.match(discovery, /discovery-selected-hero mobile-secondary-card/);
|
||
assert.match(tracking, /hero-card mobile-secondary-card/);
|
||
assert.match(automation, /hero-card mobile-secondary-card/);
|
||
assert.match(owned, /hero-card mobile-secondary-card/);
|
||
assert.match(projects, /hero-card mobile-secondary-card/);
|
||
assert.match(production, /production-queue-grid/);
|
||
assert.match(review, /hero-card mobile-secondary-card/);
|
||
assert.match(playbook, /hero-card mobile-secondary-card/);
|
||
assert.match(strategy, /hero-card mobile-secondary-card/);
|
||
assert.match(cssMobile, /\.discovery-selected-hero \.mini-grid/);
|
||
assert.match(cssMobile, /\.production-queue-grid/);
|
||
assert.match(cssMobile, /\.mobile-priority-filters \.filter:nth-child\(n\+3\)/);
|
||
assert.match(cssMobile, /\.mobile-secondary-card/);
|
||
});
|
||
|
||
test("remaining mobile workbench screens expose focus cards and compact summaries", () => {
|
||
const projects = extractBetween(APP, "function renderProjectsScreen()", "function getActiveDetailTab(");
|
||
const tracking = extractBetween(APP, "function renderTrackingScreen()", "function renderAutomationScreen()");
|
||
const automation = extractBetween(APP, "function renderAutomationScreen()", "function renderOwnedScreen()");
|
||
const owned = extractBetween(APP, "function renderOwnedScreen()", "function renderPlaybookScreen()");
|
||
const review = extractBetween(APP, "function renderReviewScreen()", "function renderStrategyScreen()");
|
||
const credits = extractBetween(APP, "function renderCreditsScreen()", "function renderSettingsScreen()");
|
||
const settings = extractBetween(APP, "function renderSettingsScreen()", "function renderTopbar()");
|
||
|
||
assert.match(projects, /mobile-only mobile-flow-focus-card/);
|
||
assert.match(projects, /当前项目任务/);
|
||
assert.match(projects, /mobile-only compact-summary-row/);
|
||
assert.match(projects, /当前项目/);
|
||
|
||
assert.match(tracking, /mobile-only mobile-flow-focus-card/);
|
||
assert.match(tracking, /当前跟踪任务/);
|
||
assert.match(tracking, /mobile-only compact-summary-row/);
|
||
assert.match(tracking, /日报/);
|
||
|
||
assert.match(automation, /mobile-only mobile-flow-focus-card/);
|
||
assert.match(automation, /当前自动流程任务/);
|
||
assert.match(automation, /mobile-only compact-summary-row/);
|
||
assert.match(automation, /AI 视频/);
|
||
|
||
assert.match(owned, /mobile-only mobile-flow-focus-card/);
|
||
assert.match(owned, /当前账号任务/);
|
||
assert.match(owned, /mobile-only compact-summary-row/);
|
||
assert.match(owned, /当前项目/);
|
||
|
||
assert.match(review, /mobile-only mobile-flow-focus-card/);
|
||
assert.match(review, /当前复盘任务/);
|
||
assert.match(review, /mobile-only compact-summary-row/);
|
||
assert.match(review, /已保存/);
|
||
|
||
assert.match(credits, /mobile-only mobile-flow-focus-card/);
|
||
assert.match(credits, /当前额度任务/);
|
||
assert.match(credits, /mobile-only compact-summary-row/);
|
||
assert.match(credits, /预算/);
|
||
|
||
assert.match(settings, /mobile-only mobile-flow-focus-card/);
|
||
assert.match(settings, /当前设置任务/);
|
||
assert.match(settings, /mobile-only compact-summary-row/);
|
||
assert.match(settings, /已自动连接/);
|
||
});
|
||
|
||
test("projects screen uses an adaptive project grid instead of a fixed three-column squeeze", () => {
|
||
const projects = extractBetween(APP, "function renderProjectsScreen()", "function getActiveDetailTab(");
|
||
assert.match(projects, /project-status-grid/);
|
||
assert.match(CSS, /\.project-status-grid\s*\{[\s\S]*repeat\(auto-fit,\s*minmax\(260px,\s*1fr\)\)/);
|
||
assert.match(CSS, /\.entity-card\.pad\s*\{[\s\S]*padding:\s*15px/);
|
||
});
|
||
|
||
test("ai video action exposes seedance provider controls and sends provider metadata", () => {
|
||
const source = extractBetween(APP, "function openCreateAiVideoAction(defaults = {})", "function openCreateRealCutAction(");
|
||
assert.match(source, /视频引擎/);
|
||
assert.match(source, /seedance2/);
|
||
assert.match(source, /seedance-2\.0-pro/);
|
||
assert.match(source, /cameraLanguage/);
|
||
assert.match(source, /motionRhythm/);
|
||
assert.match(source, /visualGuardrails/);
|
||
assert.match(source, /video_provider:\s*values\.videoProvider/);
|
||
assert.match(source, /video_model:\s*values\.videoModel/);
|
||
});
|
||
|
||
test("mobile typography clamps subtitles and dense card copy on small screens", () => {
|
||
assert.match(CSS, /@media \(max-width: 760px\)[\s\S]*\.panel-subtitle\s*\{[\s\S]*-webkit-line-clamp:\s*2/);
|
||
assert.match(CSS, /@media \(max-width: 760px\)[\s\S]*\.task-item p,[\s\S]*\.review-card p\s*\{[\s\S]*-webkit-line-clamp:\s*3/);
|
||
});
|
||
|
||
test("dashboard and project screens distinguish auto-connecting from truly disconnected", () => {
|
||
const dashboard = extractBetween(APP, "function renderDashboardScreen()", "function renderProjectsScreen()");
|
||
const projects = extractBetween(APP, "function renderProjectsScreen()", "function getActiveDetailTab(");
|
||
const helper = extractBetween(APP, "function isAutoConnectionPending()", "async function refreshFromAuthModal()");
|
||
|
||
assert.match(APP, /function isAutoConnectionPending\(\)/);
|
||
assert.match(APP, /function renderAutoConnectingScreen\(/);
|
||
assert.match(helper, /正在自动连接工作区/);
|
||
assert.match(dashboard, /isAutoConnectionPending\(\)/);
|
||
assert.match(dashboard, /renderAutoConnectingScreen\("项目总台"/);
|
||
assert.match(projects, /isAutoConnectionPending\(\)/);
|
||
assert.match(projects, /renderAutoConnectingScreen\("我的项目"/);
|
||
});
|
||
|
||
test("ensureAutoSession re-renders immediately when auto-connect starts", () => {
|
||
const source = extractBetween(APP, "async function ensureAutoSession(options = {})", "async function refreshFromAuthModal()");
|
||
assert.match(source, /appState\.autoConnectAttempted = true;/);
|
||
assert.match(source, /renderAll\(\);/);
|
||
});
|
||
|
||
test("bootstrap does not trust a stored session from a different backend", () => {
|
||
const helpers = extractBetween(APP, "function loadStoredSession()", "function compareDateDesc(");
|
||
const ensure = extractBetween(APP, "async function ensureAutoSession(options = {})", "async function refreshFromAuthModal()");
|
||
const bootstrap = extractBetween(APP, "async function bootstrap()", "async function markTrackingDigestRead()");
|
||
|
||
assert.match(helpers, /function normalizeBackendUrlValue\(/);
|
||
assert.match(helpers, /function hasSessionBackendMismatch\(/);
|
||
assert.match(ensure, /const backendMismatch = hasSessionBackendMismatch\(backendUrl\);/);
|
||
assert.match(ensure, /persistSession\(null\);/);
|
||
assert.match(bootstrap, /const backendMismatch = hasSessionBackendMismatch\(\);/);
|
||
assert.match(bootstrap, /await ensureAutoSession\(\{ force: backendMismatch \}\);/);
|
||
});
|
||
|
||
test("bootstrap renders the workspace shell before heavy hydration completes", () => {
|
||
const statusHelpers = extractBetween(APP, "function setBusy(next, message = \"\")", "function getScreenLabel(");
|
||
const bootstrap = extractBetween(APP, "async function bootstrap()", "async function markTrackingDigestRead()");
|
||
const hydration = extractBetween(APP, "async function hydrateWorkbenchDataAfterBootstrap(", "async function bootstrap()");
|
||
|
||
assert.match(APP, /workspaceHydrating:\s*false/);
|
||
assert.match(APP, /let bootstrapHydrationToken = 0;/);
|
||
assert.match(APP, /function isWorkspaceBusy\(\)/);
|
||
assert.match(statusHelpers, /function isWorkspaceBusy\(\)/);
|
||
assert.match(APP, /mobileShellStatus\.textContent = isWorkspaceBusy\(\)/);
|
||
assert.match(APP, /status\.textContent = isWorkspaceBusy\(\)/);
|
||
assert.match(bootstrap, /appState\.workspaceHydrating = true;/);
|
||
assert.match(bootstrap, /setBusy\(false,\s*""\);[\s\S]*renderAll\(\);[\s\S]*void hydrateWorkbenchDataAfterBootstrap\(dashboard,\s*preferredPlatform,\s*requestToken\);/);
|
||
assert.doesNotMatch(bootstrap, /await loadStorageStatus\(appState\.selectedProjectId \|\| ""\)/);
|
||
assert.doesNotMatch(bootstrap, /await loadAgentControlSurfaces\(appState\.selectedProjectId \|\| ""\)/);
|
||
assert.doesNotMatch(bootstrap, /await loadPlatformAccount\(/);
|
||
assert.match(hydration, /void Promise\.all\(\[\s*loadStorageStatus\(appState\.selectedProjectId \|\| ""\),\s*loadAgentControlSurfaces\(appState\.selectedProjectId \|\| ""\)\s*\]\)/);
|
||
assert.match(hydration, /void loadPlatformAccount\(getAccountPlatform\(nextAccount\), nextAccountId\)/);
|
||
});
|
||
|
||
test("bootstrap fetches me and dashboard in parallel before entering the workspace shell", () => {
|
||
const bootstrap = extractBetween(APP, "async function bootstrap()", "async function markTrackingDigestRead()");
|
||
assert.match(bootstrap, /const \[me, dashboard\] = await Promise\.all\(\[\s*storyforgeFetch\("\/v2\/me"\),\s*storyforgeFetch\("\/v2\/me\/dashboard"\)\s*\]\);/);
|
||
assert.match(bootstrap, /appState\.me = me;/);
|
||
assert.match(bootstrap, /appState\.dashboard = dashboard;/);
|
||
});
|
||
|
||
test("bootstrap only loads live recorder runtime endpoints when the integration is reachable", () => {
|
||
const hydration = extractBetween(APP, "async function hydrateWorkbenchDataAfterBootstrap(", "async function bootstrap()");
|
||
assert.match(hydration, /const liveRecorderIntegration = integrationHealth\?\.live_recorder \|\| null/);
|
||
assert.match(hydration, /const canLoadLiveRecorderRuntime = Boolean\(liveRecorderIntegration\?\.reachable\)/);
|
||
assert.doesNotMatch(hydration, /supportsLiveRecorderStatus|supportsLiveRecorderFiles|supportsLiveRecorderHealth/);
|
||
assert.match(hydration, /canLoadLiveRecorderRuntime \? storyforgeFetch\("\/v2\/live-recorder\/status"\)/);
|
||
assert.match(hydration, /canLoadLiveRecorderRuntime \? storyforgeFetch\("\/v2\/live-recorder\/files\?limit=16"\)/);
|
||
assert.match(hydration, /canLoadLiveRecorderRuntime \? storyforgeFetch\("\/v2\/live-recorder\/health"\)/);
|
||
});
|
||
|
||
test("oneliner submit failures stay inside the app instead of using a browser alert", () => {
|
||
assert.doesNotMatch(APP, /alert\("OneLiner 调度失败:/);
|
||
assert.match(APP, /presentActionFailure\(error,\s*"OneLiner 调度失败"\)/);
|
||
});
|
||
|
||
test("agent control surfaces load governance endpoints for user and admin summaries", () => {
|
||
const source = extractBetween(APP, "async function loadAgentControlSurfaces(projectId = \"\")", "async function loadOneLinerMessages(sessionId)");
|
||
assert.match(source, /\/v2\/oneliner\/governance\/effective/);
|
||
assert.match(source, /\/v2\/oneliner\/runs/);
|
||
assert.match(APP, /function hydrateSelectedOneLinerRun\(\)/);
|
||
assert.match(APP, /\/v2\/oneliner\/runs\/\$\{encodeURIComponent\(runId\)\}/);
|
||
assert.match(source, /\/v2\/oneliner\/governance\/user\/global/);
|
||
assert.match(source, /\/v2\/oneliner\/governance\/user\/platforms\/\$\{encodeURIComponent\(governancePlatform\)\}/);
|
||
assert.match(source, /\/v2\/admin\/oneliner\/governance\/system\/main-agent/);
|
||
assert.match(source, /\/v2\/admin\/oneliner\/governance\/system\/platforms\/\$\{encodeURIComponent\(item\.value\)\}/);
|
||
assert.match(source, /\/v2\/admin\/oneliner\/governance\/directory/);
|
||
assert.match(source, /\/v2\/admin\/oneliner\/governance\/overrides/);
|
||
assert.match(source, /Object\.prototype\.hasOwnProperty\.call\(existingTarget, "targetProjectId"\)/);
|
||
assert.match(source, /const requestedProjectId = hasExistingProjectTarget/);
|
||
assert.match(source, /const targetProjectId = requestedProjectId === ""/);
|
||
});
|
||
|
||
test("oneliner panel includes a dedicated runtime header for agent runs", () => {
|
||
const source = extractBetween(APP, "function ensureOneLinerUi()", "function renderOneLinerSessionTabs()");
|
||
const runtime = extractBetween(APP, "function renderOneLinerRunsHtml()", "function renderOneLinerMessagesHtml()");
|
||
assert.match(source, /data-role="oneliner-runs"/);
|
||
assert.match(runtime, /confirm-oneliner-run/);
|
||
assert.match(runtime, /cancel-oneliner-run/);
|
||
assert.match(runtime, /当前计划/);
|
||
assert.match(runtime, /recommended_preview_action/);
|
||
assert.match(runtime, /renderOneLinerExecutionPayloadHtml\(currentRun\.result\)/);
|
||
assert.match(runtime, /open-oneliner-run-result/);
|
||
assert.match(runtime, /recommended_action/);
|
||
});
|
||
|
||
test("confirm-oneliner-run opens a dedicated confirmation sheet before execution", () => {
|
||
const confirmSheet = extractBetween(APP, "function openConfirmOneLinerRunAction(runId = \"\")", "async function loadPlatformAccount(");
|
||
const actions = extractBetween(APP, "document.addEventListener(\"click\", async (event) => {", "document.addEventListener(\"submit\", async (event) => {");
|
||
|
||
assert.match(confirmSheet, /确认主 Agent 执行计划/);
|
||
assert.match(confirmSheet, /当前计划/);
|
||
assert.match(confirmSheet, /预计落点/);
|
||
assert.match(confirmSheet, /submitLabel: "确认执行"/);
|
||
assert.match(confirmSheet, /reason/);
|
||
assert.match(confirmSheet, /confirmOneLinerRun\(run\.id,\s*values\.reason/);
|
||
assert.match(actions, /openConfirmOneLinerRunAction\(action\.dataset\.runId \|\| ""\)/);
|
||
});
|
||
|
||
test("oneliner meta and action handlers expose governance entry points", () => {
|
||
const meta = extractBetween(APP, "function renderOneLinerUi()", "function openOneLinerPanel()");
|
||
const messages = extractBetween(APP, "function renderOneLinerMessagesHtml()", "function renderOneLinerUi()");
|
||
const actions = extractBetween(APP, "document.addEventListener(\"click\", async (event) => {", "document.addEventListener(\"submit\", async (event) => {");
|
||
const runs = extractBetween(APP, "function renderOneLinerRunsHtml()", "function renderOneLinerMessagesHtml()");
|
||
assert.match(meta, /open-user-global-policy/);
|
||
assert.match(meta, /配置 v/);
|
||
assert.match(meta, /renderOneLinerRunsHtml\(\)/);
|
||
assert.match(meta, /policyScopeTagLabel/);
|
||
assert.match(messages, /active_admin_override_notice/);
|
||
assert.match(messages, /oneliner_profile_version/);
|
||
assert.match(runs, /oneliner_profile_version/);
|
||
assert.match(runs, /open-oneliner-profile-history/);
|
||
assert.match(actions, /name === "open-user-global-policy"/);
|
||
assert.match(actions, /name === "open-system-main-policy"/);
|
||
assert.match(actions, /name === "handoff-to-main-agent"/);
|
||
assert.match(actions, /name === "confirm-oneliner-run"/);
|
||
assert.match(actions, /name === "open-oneliner-run-result"/);
|
||
});
|
||
|
||
test("oneliner runtime remembers completed runs exactly once after hydration", () => {
|
||
const hydrate = extractBetween(APP, "async function hydrateSelectedOneLinerRun()", "async function loadAgentControlSurfaces(projectId = \"\")");
|
||
const state = extractBetween(APP, "const appState = {", "};\n\nlet PLATFORM_RUNTIME");
|
||
assert.match(state, /lastCompletedOnelinerRunId/);
|
||
assert.match(hydrate, /detail\.run_status === "done"/);
|
||
assert.match(hydrate, /appState\.lastCompletedOnelinerRunId !== detail\.id/);
|
||
assert.match(hydrate, /rememberAction\("主 Agent 已完成本轮"/);
|
||
});
|
||
|
||
test("system governance saves refresh control surfaces after persisting", () => {
|
||
const profile = extractBetween(APP, "function openOneLinerProfileAction()", "async function openOneLinerProfileHistoryAction(preferredVersionId = \"\")");
|
||
const userGlobal = extractBetween(APP, "function openUserGlobalPolicyAction()", "function openUserPlatformPolicyAction(platform)");
|
||
const userPlatform = extractBetween(APP, "function openUserPlatformPolicyAction(platform)", "function openSystemMainPolicyAction()");
|
||
const main = extractBetween(APP, "function openSystemMainPolicyAction()", "function openSystemPlatformPolicyAction(platform)");
|
||
const platform = extractBetween(APP, "function openSystemPlatformPolicyAction(platform)", "function openPlatformAgentProfileAction(platform)");
|
||
|
||
assert.match(profile, /renderPolicyVersionSummary\(profile/);
|
||
assert.match(profile, /name: "reason"/);
|
||
assert.match(profile, /appState\.onelinerProfile = saved;/);
|
||
assert.match(profile, /await loadAgentControlSurfaces\(project\.id\);/);
|
||
assert.match(profile, /saved\.current_version\?\.version_no/);
|
||
|
||
assert.match(userGlobal, /appState\.userGlobalPolicy = saved;/);
|
||
assert.match(userGlobal, /await loadAgentControlSurfaces\(project\.id\);/);
|
||
|
||
assert.match(userPlatform, /appState\.userCurrentPlatformPolicy = saved;/);
|
||
assert.match(userPlatform, /await loadAgentControlSurfaces\(project\.id\);/);
|
||
|
||
assert.match(main, /const projectId = getOneLinerProjectId\(\);/);
|
||
assert.match(main, /appState\.adminSystemMainPolicy = saved;/);
|
||
assert.match(main, /await loadAgentControlSurfaces\(projectId\);/);
|
||
|
||
assert.match(platform, /const projectId = getOneLinerProjectId\(\);/);
|
||
assert.match(platform, /appState\.adminSystemPlatformPolicies = safeArray\(appState\.adminSystemPlatformPolicies\)/);
|
||
assert.match(platform, /await loadAgentControlSurfaces\(projectId\);/);
|
||
});
|
||
|
||
test("oneliner profile history exposes rollback and audit entrypoints", () => {
|
||
const playbookFocusHelper = extractBetween(APP, "function focusPlaybookOneLinerWorkspace(anchorId = \"oneliner-profile-anchor\") {", "function openOneLinerProfileAction() {");
|
||
const profile = extractBetween(APP, "function openOneLinerProfileAction()", "function resolvePreferredVersionId(history, preferredVersionId = \"\")");
|
||
const profileHistory = extractBetween(APP, "async function openOneLinerProfileHistoryAction(preferredVersionId = \"\")", "function parsePolicyJsonField(rawValue, label = \"策略 JSON\")");
|
||
const playbook = extractBetween(APP, "function renderPlaybookScreen()", "function renderProductionScreen()");
|
||
const actions = extractBetween(APP, "document.addEventListener(\"click\", async (event) => {", "document.addEventListener(\"submit\", async (event) => {");
|
||
|
||
assert.match(playbookFocusHelper, /appState\.playbookDetailTab = "workspace"/);
|
||
assert.match(playbookFocusHelper, /setScreen\("playbook"\)/);
|
||
assert.match(playbookFocusHelper, /scrollIntoView/);
|
||
assert.match(profile, /focusPlaybookOneLinerWorkspace\("oneliner-profile-anchor"\)/);
|
||
assert.match(APP, /function resolvePreferredVersionId\(history, preferredVersionId = ""\)/);
|
||
assert.match(profileHistory, /\/v2\/oneliner\/profile\/versions/);
|
||
assert.match(profileHistory, /\/v2\/oneliner\/profile\/audits/);
|
||
assert.match(profileHistory, /\/v2\/oneliner\/profile\/rollback/);
|
||
assert.match(profileHistory, /resolvePreferredVersionId\(history, preferredVersionId\)/);
|
||
assert.match(profileHistory, /hideSubmit:\s*!selectedVersionId/);
|
||
assert.match(profileHistory, /focusPlaybookOneLinerWorkspace\("oneliner-profile-anchor"\)/);
|
||
assert.match(playbook, /open-oneliner-profile-history/);
|
||
assert.match(playbook, /id="oneliner-profile-anchor"/);
|
||
assert.match(actions, /name === "open-oneliner-profile-history"/);
|
||
assert.match(actions, /openOneLinerProfileHistoryAction\(action\.dataset\.versionId \|\| ""\)/);
|
||
});
|
||
|
||
test("governance UI exposes admin override target picker and history rollback entrypoints", () => {
|
||
const admin = extractBetween(APP, "function renderAdminGovernanceSummaryPanel()", "function renderPlatformAgentPanel()");
|
||
const targetPicker = extractBetween(APP, "async function openAdminOverrideTargetAction()", "function openAdminOverridePolicyAction()");
|
||
const actions = extractBetween(APP, "document.addEventListener(\"click\", async (event) => {", "document.addEventListener(\"submit\", async (event) => {");
|
||
|
||
assert.match(admin, /open-admin-override-target/);
|
||
assert.match(admin, /open-admin-override-policy/);
|
||
assert.match(admin, /open-admin-override-history/);
|
||
assert.match(admin, /open-system-main-policy-history/);
|
||
assert.match(admin, /open-system-platform-policy-history/);
|
||
assert.match(APP, /function syncAdminOverrideProjectOptions\(/);
|
||
assert.match(targetPicker, /onOpen: \(\) => \{/);
|
||
assert.match(targetPicker, /userSelect\.addEventListener\("change"/);
|
||
assert.match(targetPicker, /syncAdminOverrideProjectOptions\(userSelect\.value, ""\)/);
|
||
|
||
assert.match(actions, /name === "open-admin-override-target"/);
|
||
assert.match(actions, /name === "open-admin-override-policy"/);
|
||
assert.match(actions, /name === "open-admin-override-history"/);
|
||
assert.match(actions, /name === "open-system-main-policy-history"/);
|
||
assert.match(actions, /name === "open-system-platform-policy-history"/);
|
||
});
|
||
|
||
test("admin governance history actions stay read-only when there are no versions yet", () => {
|
||
const overrideHistory = extractBetween(APP, "async function openAdminOverrideHistoryAction(preferredVersionId = \"\")", "async function openSystemMainPolicyHistoryAction(preferredVersionId = \"\")");
|
||
const systemMainHistory = extractBetween(APP, "async function openSystemMainPolicyHistoryAction(preferredVersionId = \"\")", "async function openSystemPlatformPolicyHistoryAction(platform, preferredVersionId = \"\")");
|
||
const systemPlatformHistory = extractBetween(APP, "async function openSystemPlatformPolicyHistoryAction(platform, preferredVersionId = \"\")", "function openPlatformAgentProfileAction(platform)");
|
||
|
||
assert.match(overrideHistory, /hideSubmit:\s*!selectedVersionId/);
|
||
assert.match(systemMainHistory, /hideSubmit:\s*!selectedVersionId/);
|
||
assert.match(systemPlatformHistory, /hideSubmit:\s*!selectedVersionId/);
|
||
assert.match(overrideHistory, /\.\.\.\(selectedVersionId \? \[/);
|
||
assert.match(systemMainHistory, /\.\.\.\(selectedVersionId \? \[/);
|
||
assert.match(systemPlatformHistory, /\.\.\.\(selectedVersionId \? \[/);
|
||
});
|
||
|
||
test("admin governance actions apply local permission and empty-directory guards before mutating", () => {
|
||
const helpers = extractBetween(APP, "function ensureAdminGovernanceAccess()", "function openUserGlobalPolicyAction()");
|
||
const adminFocusHelper = extractBetween(APP, "function focusAdminGovernanceAgentsWorkspace(anchorId = \"admin-governance-anchor\") {", "function openSystemMainPolicyAction() {");
|
||
const targetPicker = extractBetween(APP, "async function openAdminOverrideTargetAction()", "function openAdminOverridePolicyAction()");
|
||
const systemMain = extractBetween(APP, "function openSystemMainPolicyAction()", "function openSystemPlatformPolicyAction(platform)");
|
||
const systemPlatform = extractBetween(APP, "function openSystemPlatformPolicyAction(platform)", "async function openAdminOverrideTargetAction()");
|
||
const systemMainHistory = extractBetween(APP, "async function openSystemMainPolicyHistoryAction(preferredVersionId = \"\")", "async function openSystemPlatformPolicyHistoryAction(platform, preferredVersionId = \"\")");
|
||
const systemPlatformHistory = extractBetween(APP, "async function openSystemPlatformPolicyHistoryAction(platform, preferredVersionId = \"\")", "function reopenPlatformAgentDetailSoon(platform)");
|
||
const actionRegistry = extractBetween(APP, "function openActionRegistryEditAction(actionKey)", "function openTenantQuotaAction()");
|
||
|
||
assert.match(helpers, /function ensureAdminGovernanceAccess\(\)/);
|
||
assert.match(helpers, /function ensureAdminOverrideTargetReady\(target\)/);
|
||
assert.match(adminFocusHelper, /appState\.adminWorkbenchTab = "agents"/);
|
||
assert.match(adminFocusHelper, /setScreen\("admin-workbench"\)/);
|
||
assert.match(adminFocusHelper, /scrollIntoView/);
|
||
assert.match(targetPicker, /hideSubmit:\s*!directoryItems\.length/);
|
||
assert.match(targetPicker, /focusAdminGovernanceAuditWorkspace\("admin-override-audit-anchor"\)/);
|
||
assert.match(systemMain, /if \(!ensureAdminGovernanceAccess\(\)\) return;/);
|
||
assert.match(systemPlatform, /if \(!ensureAdminGovernanceAccess\(\)\) return;/);
|
||
assert.match(systemMain, /focusAdminGovernanceAgentsWorkspace\("admin-governance-anchor"\)/);
|
||
assert.match(systemPlatform, /focusAdminGovernanceAgentsWorkspace\("admin-governance-anchor"\)/);
|
||
assert.match(systemMainHistory, /focusAdminGovernanceAgentsWorkspace\("admin-governance-anchor"\)/);
|
||
assert.match(systemPlatformHistory, /focusAdminGovernanceAgentsWorkspace\("admin-governance-anchor"\)/);
|
||
assert.match(actionRegistry, /focusAdminGovernanceAgentsWorkspace\("admin-action-registry-anchor"\)/);
|
||
});
|
||
|
||
test("user governance UI exposes personal history and rollback entrypoints", () => {
|
||
const helpers = extractBetween(APP, "function ensureAdminGovernanceAccess()", "function openSystemMainPolicyAction() {");
|
||
const playbook = extractBetween(APP, "function renderPlaybookScreen()", "function renderProductionScreen()");
|
||
const strategy = extractBetween(APP, "function renderStrategyScreen()", "function renderCreditsScreen()");
|
||
const automation = extractBetween(APP, "function renderAutomationScreen()", "function renderOwnedScreen()");
|
||
const actions = extractBetween(APP, "document.addEventListener(\"click\", async (event) => {", "document.addEventListener(\"submit\", async (event) => {");
|
||
const userGlobal = extractBetween(APP, "function openUserGlobalPolicyAction()", "function openUserPlatformPolicyAction(platform) {");
|
||
const userPlatform = extractBetween(APP, "function openUserPlatformPolicyAction(platform)", "async function openUserGlobalPolicyHistoryAction(preferredVersionId = \"\")");
|
||
const userGlobalHistory = extractBetween(APP, "async function openUserGlobalPolicyHistoryAction(preferredVersionId = \"\")", "async function openUserPlatformPolicyHistoryAction(platform, preferredVersionId = \"\")");
|
||
const userPlatformHistory = extractBetween(APP, "async function openUserPlatformPolicyHistoryAction(platform, preferredVersionId = \"\")", "function focusAdminGovernanceAgentsWorkspace(anchorId = \"admin-governance-anchor\") {");
|
||
|
||
assert.match(helpers, /function focusUserGovernanceWorkspace\(tab = "effective", anchorId = "strategy-governance-anchor"\)/);
|
||
assert.match(helpers, /appState\.strategyDetailTab = tab/);
|
||
assert.match(helpers, /setScreen\("strategy"\)/);
|
||
assert.match(playbook, /open-user-global-policy-history/);
|
||
assert.match(playbook, /open-user-platform-policy-history/);
|
||
assert.match(playbook, /handoff-to-main-agent/);
|
||
assert.match(playbook, /playbook-main-agent-handoff/);
|
||
assert.match(strategy, /active_admin_override_notice/);
|
||
assert.match(strategy, /管理员覆盖生效中/);
|
||
assert.match(strategy, /handoff-to-main-agent/);
|
||
assert.match(strategy, /strategy-main-agent-handoff/);
|
||
assert.match(strategy, /id="strategy-governance-anchor"/);
|
||
assert.match(automation, /handoff-to-main-agent/);
|
||
assert.match(automation, /automation-main-agent-handoff/);
|
||
assert.match(userGlobal, /focusUserGovernanceWorkspace\("global", "strategy-governance-anchor"\)/);
|
||
assert.match(userPlatform, /focusUserGovernanceWorkspace\("platform", "strategy-governance-anchor"\)/);
|
||
assert.match(userGlobalHistory, /focusUserGovernanceWorkspace\("global", "strategy-governance-anchor"\)/);
|
||
assert.match(userPlatformHistory, /focusUserGovernanceWorkspace\("platform", "strategy-governance-anchor"\)/);
|
||
|
||
assert.match(actions, /name === "open-user-global-policy-history"/);
|
||
assert.match(actions, /name === "open-user-platform-policy-history"/);
|
||
});
|
||
|
||
test("admin override actions guard against missing governance targets", () => {
|
||
const override = extractBetween(APP, "function openAdminOverridePolicyAction()", "async function openAdminOverrideHistoryAction(preferredVersionId = \"\")");
|
||
const overrideHistory = extractBetween(APP, "async function openAdminOverrideHistoryAction(preferredVersionId = \"\")", "async function openSystemMainPolicyHistoryAction(preferredVersionId = \"\")");
|
||
const helpers = extractBetween(APP, "function ensureAdminGovernanceAccess()", "function openUserGlobalPolicyAction()");
|
||
|
||
assert.match(helpers, /function ensureAdminOverrideTargetReady\(target\)/);
|
||
assert.match(helpers, /当前治理目录里还没有可选用户/);
|
||
assert.match(helpers, /function focusAdminGovernanceAuditWorkspace\(anchorId = "admin-override-audit-anchor"\)/);
|
||
assert.match(override, /if \(!ensureAdminOverrideTargetReady\(target\)\) return;/);
|
||
assert.match(overrideHistory, /if \(!ensureAdminOverrideTargetReady\(target\)\) return;/);
|
||
assert.match(override, /focusAdminGovernanceAuditWorkspace\("admin-override-audit-anchor"\)/);
|
||
assert.match(overrideHistory, /focusAdminGovernanceAuditWorkspace\("admin-override-audit-anchor"\)/);
|
||
});
|
||
|
||
test("main agent result rendering offers a direct route back into the recommended screen", () => {
|
||
const execution = extractBetween(APP, "function renderOneLinerExecutionPayloadHtml(payload)", "function parseOneLinerActionPayloadValue(value)");
|
||
const lastAction = extractBetween(APP, "function renderLastActionCard()", "function getJobRecoveryCategory(job)");
|
||
const landing = extractBetween(APP, "function resolveMainAgentLandingScreen(target)", "function captureMainAgentLandingContext(action, targetScreen)");
|
||
assert.match(execution, /recommended_action/);
|
||
assert.match(execution, /result_sections/);
|
||
assert.match(execution, /当前焦点/);
|
||
assert.match(execution, /detail-grid/);
|
||
assert.match(execution, /本轮平台 Agent/);
|
||
assert.match(execution, /platform_agent_profile/);
|
||
assert.match(execution, /data-action="\$\{escapeHtml\(payload\.recommended_action\.action\)\}"/);
|
||
assert.match(lastAction, /open-oneliner-run-result/);
|
||
assert.match(lastAction, /recommended_action/);
|
||
assert.match(landing, /"goto-admin-workbench": "admin-workbench"/);
|
||
});
|
||
|
||
test("direct oneliner execution results preserve structured follow-up attrs", () => {
|
||
const helpers = extractBetween(APP, "function extractGeneratedCopy(payload)", "function renderLastActionCard()");
|
||
const execution = extractBetween(APP, "function renderOneLinerExecutionPayloadHtml(payload)", "function parseOneLinerActionPayloadValue(value)");
|
||
const lastAction = extractBetween(APP, "function renderLastActionCard()", "function getJobRecoveryCategory(job)");
|
||
assert.match(helpers, /function buildRecommendedActionAttrs\(recommendedAction, landing = \{\}\)/);
|
||
assert.match(helpers, /job_id: "data-job-id"/);
|
||
assert.match(helpers, /review_id: "data-review-id"/);
|
||
assert.match(helpers, /platform: "data-platform"/);
|
||
assert.match(helpers, /account_id: "data-account-id"/);
|
||
assert.match(helpers, /tracked_account_id: "data-tracked-account-id"/);
|
||
assert.match(helpers, /assistant_id: "data-assistant-id"/);
|
||
assert.match(helpers, /source_id: "data-source-id"/);
|
||
assert.match(execution, /const recommendedAction = payload\.recommended_action/);
|
||
assert.match(execution, /buildRecommendedActionAttrs\(recommendedAction/);
|
||
assert.match(execution, /actionTag\(recommendedAction\.label \|\| "看任务详情"/);
|
||
assert.match(execution, /actionTag\(recommendedAction\.label \|\| "打开复盘"/);
|
||
assert.match(execution, /actionTag\(recommendedAction\.label \|\| "打开录制控制"/);
|
||
assert.match(execution, /actionTag\(recommendedAction\.label \|\| "查看平台 Agent"/);
|
||
assert.match(lastAction, /buildRecommendedActionAttrs\(recommendedAction/);
|
||
assert.match(lastAction, /actionTag\(recommendedAction\.label \|\| "回到对应页面"/);
|
||
});
|
||
|
||
test("main agent runtime and platform recent execution preserve structured follow-up attrs", () => {
|
||
const runtime = extractBetween(APP, "function renderOneLinerRunsHtml()", "function renderOneLinerMessagesHtml()");
|
||
const execution = extractBetween(APP, "function renderOneLinerExecutionPayloadHtml(payload)", "function parseOneLinerActionPayloadValue(value)");
|
||
const playbook = extractBetween(APP, "function renderPlatformAgentPanel()", "function renderAdminOpsPanel()");
|
||
const detail = extractBetween(APP, "async function openPlatformAgentDetailAction(platform)", "function openPlatformSkillReviewAction(platform, skillId, accepted)");
|
||
assert.match(runtime, /const resultLandingAttrs = buildRecommendedActionAttrs\(recommendedAction/);
|
||
assert.match(runtime, /const doneLandingAttrs = buildRecommendedActionAttrs\(doneAction/);
|
||
assert.match(execution, /const landingAttrs = buildRecommendedActionAttrs\(payload\.recommended_action/);
|
||
assert.match(playbook, /buildRecommendedActionAttrs\(item\.recent_execution\.recommended_action/);
|
||
assert.match(detail, /buildRecommendedActionAttrs\(profile\.recent_execution\.recommended_action/);
|
||
});
|
||
|
||
test("platform agent profiles expose history, rollback, and execution version context", () => {
|
||
const actions = extractBetween(APP, "document.addEventListener(\"click\", async (event) => {", "document.addEventListener(\"submit\", async (event) => {");
|
||
const reopenHelper = extractBetween(APP, "function reopenPlatformAgentDetailSoon(platform) {", "function openPlatformAgentProfileAction(platform) {");
|
||
const profileEditor = extractBetween(APP, "function openPlatformAgentProfileAction(platform)", "async function openPlatformAgentProfileHistoryAction(platform, preferredVersionId = \"\")");
|
||
const profileHistory = extractBetween(APP, "async function openPlatformAgentProfileHistoryAction(platform, preferredVersionId = \"\")", "function openPlatformAgentMemoryAction(platform)");
|
||
const memoryEditor = extractBetween(APP, "function openPlatformAgentMemoryAction(platform)", "function openPlatformAgentSkillAction(platform)");
|
||
const skillEditor = extractBetween(APP, "function openPlatformAgentSkillAction(platform)", "async function openPlatformAgentDetailAction(platform)");
|
||
const panel = extractBetween(APP, "function renderPlatformAgentPanel()", "function renderAdminOpsPanel()");
|
||
const detail = extractBetween(APP, "async function openPlatformAgentDetailAction(platform)", "function openPlatformSkillReviewAction(platform, skillId, accepted)");
|
||
const skillReview = extractBetween(APP, "function openPlatformSkillReviewAction(platform, skillId, accepted)", "function openPlatformSkillRollbackAction(platform, skillId, versionId)");
|
||
const skillRollback = extractBetween(APP, "function openPlatformSkillRollbackAction(platform, skillId, versionId)", "function openActionRegistryEditAction(actionKey)");
|
||
const execution = extractBetween(APP, "function renderOneLinerExecutionPayloadHtml(payload)", "function parseOneLinerActionPayloadValue(value)");
|
||
|
||
assert.match(reopenHelper, /setTimeout/);
|
||
assert.match(reopenHelper, /openPlatformAgentDetailAction/);
|
||
assert.match(profileEditor, /renderPolicyVersionSummary\(current,/);
|
||
assert.match(profileEditor, /name: "reason"/);
|
||
assert.match(profileEditor, /saved\.current_version\?\.version_no/);
|
||
assert.match(profileEditor, /reopenPlatformAgentDetailSoon\(platform\)/);
|
||
|
||
assert.match(profileHistory, /\/v2\/platform-agents\/\$\{encodeURIComponent\(normalizedPlatform\)\}\/profile\/versions/);
|
||
assert.match(profileHistory, /\/v2\/platform-agents\/\$\{encodeURIComponent\(normalizedPlatform\)\}\/profile\/audits/);
|
||
assert.match(profileHistory, /\/v2\/platform-agents\/\$\{encodeURIComponent\(normalizedPlatform\)\}\/profile\/rollback/);
|
||
assert.match(profileHistory, /renderPolicyVersionsHtml/);
|
||
assert.match(profileHistory, /renderPolicyAuditsHtml/);
|
||
assert.match(profileHistory, /reopenPlatformAgentDetailSoon\(normalizedPlatform\)/);
|
||
assert.match(memoryEditor, /reopenPlatformAgentDetailSoon\(platform\)/);
|
||
assert.match(skillEditor, /reopenPlatformAgentDetailSoon\(platform\)/);
|
||
assert.match(skillReview, /reopenPlatformAgentDetailSoon\(normalizedPlatform\)/);
|
||
assert.match(skillRollback, /reopenPlatformAgentDetailSoon\(normalizedPlatform\)/);
|
||
|
||
assert.match(panel, /open-platform-agent-profile-history/);
|
||
assert.match(detail, /open-platform-agent-profile-history/);
|
||
assert.match(panel, /data-version-id="\$\{escapeHtml\(item\.recent_execution\.platform_agent_profile_version_id \|\| ""\)\}"/);
|
||
assert.match(detail, /data-version-id="\$\{escapeHtml\(profile\.recent_execution\.platform_agent_profile_version_id \|\| ""\)\}"/);
|
||
assert.match(panel, /platform_agent_profile_version_no/);
|
||
assert.match(panel, /recent_execution\.recommended_action\?\.action/);
|
||
assert.match(panel, /recent_execution\.workstream_label/);
|
||
assert.match(detail, /platform_agent_profile_version_no/);
|
||
assert.match(detail, /recent_execution\.recommended_action\?\.action/);
|
||
assert.match(detail, /recent_execution\.workstream_label/);
|
||
assert.match(execution, /platformAgentProfile\.version_no/);
|
||
assert.match(actions, /name === "open-platform-agent-profile-history"/);
|
||
assert.match(actions, /openPlatformAgentProfileHistoryAction\(action\.dataset\.platform \|\| "", action\.dataset\.versionId \|\| ""\)/);
|
||
});
|
||
|
||
test("platform agent recent execution highlights when newer configs exist", () => {
|
||
const detail = extractBetween(APP, "async function openPlatformAgentDetailAction(platform)", "function openPlatformSkillReviewAction(platform, skillId, accepted)");
|
||
const panel = extractBetween(APP, "function renderPlatformAgentPanel()", "function renderAdminOpsPanel()");
|
||
assert.match(detail, /recentExecutionOnelinerConfigStale/);
|
||
assert.match(detail, /recentExecutionPlatformConfigStale/);
|
||
assert.match(detail, /主配置已更新/);
|
||
assert.match(detail, /Agent 已更新/);
|
||
assert.match(panel, /recentExecutionOnelinerConfigStale/);
|
||
assert.match(panel, /recentExecutionPlatformConfigStale/);
|
||
});
|
||
|
||
test("platform agent recent execution surfaces title, platform scope, and delivery mode", () => {
|
||
const detail = extractBetween(APP, "async function openPlatformAgentDetailAction(platform)", "function openPlatformSkillReviewAction(platform, skillId, accepted)");
|
||
const panel = extractBetween(APP, "function renderPlatformAgentPanel()", "function renderAdminOpsPanel()");
|
||
assert.match(detail, /recent_execution\.title/);
|
||
assert.match(detail, /recent_execution\.platform_scope/);
|
||
assert.match(detail, /recent_execution\.delivery_mode/);
|
||
assert.match(panel, /recent_execution\.title/);
|
||
assert.match(panel, /recent_execution\.platform_scope/);
|
||
assert.match(panel, /recent_execution\.delivery_mode/);
|
||
});
|
||
|
||
test("main agent route actions keep landing context and destination screens render a notice", () => {
|
||
const execution = extractBetween(APP, "function renderOneLinerExecutionPayloadHtml(payload)", "function parseOneLinerActionPayloadValue(value)");
|
||
const actions = extractBetween(APP, "document.addEventListener(\"click\", async (event) => {", "document.addEventListener(\"submit\", async (event) => {");
|
||
const landingActions = extractBetween(APP, "function renderMainAgentLandingQuickActions(screenKey)", "function renderMainAgentLandingNotice(screenKey)");
|
||
const strategy = extractBetween(APP, "function renderStrategyScreen()", "function renderCreditsScreen()");
|
||
const landing = extractBetween(APP, "function renderMainAgentLandingNotice(screenKey)", "function renderEmptyState(title, description)");
|
||
const production = extractBetween(APP, "function renderProductionScreen()", "function renderReviewScreen()");
|
||
assert.match(execution, /buildRecommendedActionAttrs\(payload\.recommended_action/);
|
||
assert.match(actions, /captureMainAgentLandingContext\(action,\s*"goto-production"/);
|
||
assert.match(actions, /captureMainAgentLandingContext\(action,\s*"goto-strategy"/);
|
||
assert.match(actions, /name === "dismiss-main-agent-landing"/);
|
||
assert.match(landingActions, /open-user-global-policy/);
|
||
assert.match(landingActions, /refresh-tracking/);
|
||
assert.match(landing, /result_sections/);
|
||
assert.match(landing, /renderMainAgentLandingQuickActions\(screenKey\)/);
|
||
assert.match(landing, /detail-grid/);
|
||
assert.match(strategy, /renderMainAgentLandingNotice\("strategy"\)/);
|
||
assert.match(production, /renderMainAgentLandingNotice\("production"\)/);
|
||
});
|
||
|
||
test("main agent landing quick actions prefer direct execute flows where executors already exist", () => {
|
||
const landingActions = extractBetween(APP, "function renderMainAgentLandingQuickActions(screenKey)", "function renderMainAgentLandingNotice(screenKey)");
|
||
assert.match(landingActions, /direct-analyze-top-videos/);
|
||
assert.match(landingActions, /direct-search-similar/);
|
||
assert.match(landingActions, /direct-create-assistant/);
|
||
assert.match(landingActions, /direct-review-draft/);
|
||
assert.match(landingActions, /direct-create-ai-video/);
|
||
assert.match(landingActions, /direct-create-real-cut/);
|
||
assert.match(APP, /if \(name === "direct-create-assistant"\)/);
|
||
assert.match(APP, /if \(name === "direct-review-draft"\)/);
|
||
assert.match(APP, /if \(name === "direct-create-ai-video"\)/);
|
||
assert.match(APP, /if \(name === "direct-create-real-cut"\)/);
|
||
assert.match(APP, /async function runDirectWorkbenchAction\(executorKey, options = \{\}\)/);
|
||
});
|
||
|
||
test("playbook and review high-frequency actions now reuse direct execute handlers", () => {
|
||
const playbook = extractBetween(APP, "function renderPlaybookScreen()", "function renderProductionScreen()");
|
||
const review = extractBetween(APP, "function renderReviewScreen()", "function renderStrategyScreen()");
|
||
const clickActions = extractBetween(APP, "document.addEventListener(\"click\", async (event) => {", "document.addEventListener(\"submit\", async (event) => {");
|
||
const openAiVideoBlock = extractBetween(clickActions, 'if (name === "open-ai-video") {', 'if (name === "direct-create-ai-video") {');
|
||
const openRealCutBlock = extractBetween(clickActions, 'if (name === "open-real-cut") {', 'if (name === "direct-create-real-cut") {');
|
||
assert.match(playbook, /direct-create-assistant/);
|
||
assert.match(review, /direct-review-draft/);
|
||
assert.match(APP, /payload: action\.dataset\.jobId \? \{ source_job_id: action\.dataset\.jobId \} : \{\}/);
|
||
assert.match(clickActions, /name === "open-create-review"[\s\S]*const fallbackJob = getLatestCompletedProjectJob\(\)/);
|
||
assert.match(clickActions, /name === "open-create-review"[\s\S]*runDirectWorkbenchAction\("review-draft"/);
|
||
assert.match(clickActions, /name === "open-create-review"[\s\S]*openReviewAction\(\)/);
|
||
assert.match(clickActions, /name === "open-generate-copy"[\s\S]*const fallbackJob = getLatestCompletedProjectJob\(\)/);
|
||
assert.match(clickActions, /name === "open-generate-copy"[\s\S]*runDirectWorkbenchAction\("generate-copy"/);
|
||
assert.match(clickActions, /name === "open-generate-copy"[\s\S]*openGenerateCopyAction\(\)/);
|
||
assert.match(clickActions, /name === "open-review-from-job"[\s\S]*runDirectWorkbenchAction\("review-draft"/);
|
||
assert.match(clickActions, /name === "open-review-from-job"[\s\S]*payload: \{ source_job_id: jobId \}/);
|
||
assert.match(openAiVideoBlock, /const fallbackJob = getLatestCompletedProjectJob\(\)/);
|
||
assert.match(openAiVideoBlock, /openCreateAiVideoAction\(/);
|
||
assert.doesNotMatch(openAiVideoBlock, /runDirectWorkbenchAction\("create-ai-video"/);
|
||
assert.match(openRealCutBlock, /const fallbackJob = getLatestCompletedProjectJob\(\)/);
|
||
assert.match(openRealCutBlock, /openCreateRealCutAction\(/);
|
||
assert.doesNotMatch(openRealCutBlock, /runDirectWorkbenchAction\("create-real-cut"/);
|
||
assert.match(clickActions, /name === "open-create-assistant"[\s\S]*const project = getSelectedProject\(\)/);
|
||
assert.match(clickActions, /name === "open-create-assistant"[\s\S]*runDirectWorkbenchAction\("create-assistant"/);
|
||
assert.match(clickActions, /name === "open-create-assistant"[\s\S]*openCreateAssistantAction\(\)/);
|
||
assert.match(clickActions, /name === "open-import-homepage"[\s\S]*const selectedAccount = getSelectedAccountRow\(\)/);
|
||
assert.match(clickActions, /name === "open-import-homepage"[\s\S]*runDirectDiscoveryAction\("import-homepage"/);
|
||
assert.match(clickActions, /name === "open-import-homepage"[\s\S]*openImportHomepageAction\(\)/);
|
||
});
|
||
|
||
test("ai video form explains where Seedance 火山配置 lives", () => {
|
||
const clickActions = extractBetween(
|
||
APP,
|
||
'document.addEventListener("click", async (event) => {',
|
||
'navButtons.forEach((button) => {'
|
||
);
|
||
assert.match(APP, /function renderAiVideoProviderHintHtml\(provider = "doubao"\)/);
|
||
assert.match(APP, /Seedance 2\.0 走火山视频配置/);
|
||
assert.match(APP, /\/settings\/ai-config/);
|
||
assert.match(APP, /视频 -> 火山引擎/);
|
||
assert.match(APP, /HUOBAO_VIDEO_API_KEY/);
|
||
assert.match(APP, /data-action="focus-huobao-video-config"/);
|
||
assert.match(APP, /id="integration-\$\{escapeHtml\(item\.key\)\}-anchor"/);
|
||
assert.match(APP, /function focusAutomationHealthWorkspace\(anchorId = "integration-huobao-anchor"\)/);
|
||
assert.match(APP, /function bindAiVideoProviderRecommendations\(fields, options = \{\}\)/);
|
||
assert.match(APP, /const AI_VIDEO_DEFAULTS_KEY = STORAGE_KEY \+ ":ai-video-defaults"/);
|
||
assert.match(APP, /function getAiVideoPreferences\(projectId = ""\)/);
|
||
assert.match(APP, /function saveAiVideoPreferences\(projectId = "", values = \{\}\)/);
|
||
assert.match(APP, /function renderAiVideoProviderMemoryHtml\(projectId = "", preferences = \{\}\)/);
|
||
assert.match(APP, /const persistedDefaults = getAiVideoPreferences\(project\.id\)/);
|
||
assert.match(APP, /label: "最近使用", type: "html", html: renderAiVideoProviderMemoryHtml\(project\.id, persistedDefaults\)/);
|
||
assert.match(APP, /当前项目最近视频引擎/);
|
||
assert.match(APP, /上次创建 AI 视频时使用的是/);
|
||
assert.match(APP, /modelInput\.placeholder = provider === "seedance2" \? "例如:seedance-2\.0-pro" : "留空则沿用当前默认视频模型"/);
|
||
assert.match(APP, /bindAiVideoProviderRecommendations\(fields, \{ seedanceModel: defaultVideoModel \|\| "seedance-2\.0-pro" \}\)/);
|
||
assert.match(APP, /saveAiVideoPreferences\(project\.id, \{/);
|
||
assert.match(clickActions, /name === "focus-huobao-video-config"[\s\S]*focusAutomationHealthWorkspace\("integration-huobao-anchor"\)/);
|
||
});
|
||
|
||
test("main agent landing notices expose a compact mobile follow-up strip", () => {
|
||
const landing = extractBetween(APP, "function renderMainAgentLandingNotice(screenKey)", "function renderEmptyState(title, description)");
|
||
assert.match(landing, /mobile-only compact-summary-row/);
|
||
assert.match(landing, /mobile-only mobile-flow-focus-card/);
|
||
assert.match(landing, /主 Agent 结果/);
|
||
assert.match(landing, /继续处理/);
|
||
});
|
||
|
||
test("key workbench screens expose contextual handoff-to-main-agent actions", () => {
|
||
const discovery = extractBetween(APP, "function renderDiscoveryScreen()", "function renderTrackingScreen()");
|
||
const tracking = extractBetween(APP, "function renderTrackingScreen()", "function renderAutomationScreen()");
|
||
const projects = extractBetween(APP, "function renderProjectsScreen()", "function getActiveDetailTab(");
|
||
const production = extractBetween(APP, "function renderProductionScreen()", "function renderReviewScreen()");
|
||
const review = extractBetween(APP, "function renderReviewScreen()", "function renderStrategyScreen()");
|
||
|
||
assert.match(discovery, /buildMainAgentHandoffAttrs\(\{/);
|
||
assert.match(discovery, /button\("交给主 Agent", "handoff-to-main-agent"/);
|
||
assert.match(discovery, /sourceScreen: "discovery"/);
|
||
|
||
assert.match(tracking, /buildMainAgentHandoffAttrs\(\{/);
|
||
assert.match(tracking, /button\("交给主 Agent", "handoff-to-main-agent"/);
|
||
assert.match(tracking, /sourceScreen: "tracking"/);
|
||
|
||
assert.match(projects, /buildMainAgentHandoffAttrs\(\{/);
|
||
assert.match(projects, /button\("交给主 Agent", "handoff-to-main-agent"/);
|
||
assert.match(projects, /sourceScreen: "intake"/);
|
||
|
||
assert.match(production, /buildMainAgentHandoffAttrs\(\{/);
|
||
assert.match(production, /button\("交给主 Agent", "handoff-to-main-agent"/);
|
||
assert.match(production, /sourceScreen: "production"/);
|
||
|
||
assert.match(review, /buildMainAgentHandoffAttrs\(\{/);
|
||
assert.match(review, /button\("交给主 Agent", "handoff-to-main-agent"/);
|
||
assert.match(review, /sourceScreen: "review"/);
|
||
});
|
||
|
||
test("tracked-account refresh opens the created sync task when the backend returns one", () => {
|
||
const refresh = extractBetween(APP, "async function refreshTrackedAccountAction(trackedAccountId)", "function getSelectedProject()");
|
||
assert.match(refresh, /sync_job_id/);
|
||
assert.match(refresh, /openJobDetailAction\(payload\.sync_job_id\)/);
|
||
});
|
||
|
||
test("job-creating workbench actions jump straight into the created job detail", () => {
|
||
const importHomepage = extractBetween(APP, "function openImportHomepageAction()", "function openImportSelectedAccountAction()");
|
||
const importSelected = extractBetween(APP, "function openImportSelectedAccountAction()", "function openTrackSelectedAccountAction()");
|
||
const importVideo = extractBetween(APP, "function openImportVideoLinkAction()", "function openImportTextAction()");
|
||
const importText = extractBetween(APP, "function openImportTextAction()", "function openUploadVideoAction()");
|
||
const uploadVideo = extractBetween(APP, "function openUploadVideoAction()", "function openOneLinerProfileAction()");
|
||
const aiVideo = extractBetween(APP, "function openCreateAiVideoAction(defaults = {})", "function openCreateRealCutAction(defaults = {})");
|
||
const realCut = extractBetween(APP, "function openCreateRealCutAction(defaults = {})", "function openLiveRecorderAction()");
|
||
assert.match(importHomepage, /runDirectWorkbenchAction\("import-homepage"/);
|
||
assert.match(importSelected, /runDirectDiscoveryAction\("import-homepage"/);
|
||
assert.match(importVideo, /runDirectWorkbenchAction\("import-video-link"/);
|
||
assert.match(importText, /runDirectWorkbenchAction\("import-text"/);
|
||
assert.match(uploadVideo, /if \(job\?\.id\) \{\s*openJobDetailAction\(job\.id\);/);
|
||
assert.match(aiVideo, /if \(job\?\.id\) \{\s*openJobDetailAction\(job\.id\);/);
|
||
assert.match(realCut, /if \(job\?\.id\) \{\s*openJobDetailAction\(job\.id\);/);
|
||
});
|
||
|
||
test("import and tracking sheets submit through direct execute handlers", () => {
|
||
const importHomepage = extractBetween(APP, "function openImportHomepageAction()", "function openImportSelectedAccountAction()");
|
||
const importSelected = extractBetween(APP, "function openImportSelectedAccountAction()", "function openTrackSelectedAccountAction()");
|
||
const trackSelected = extractBetween(APP, "function openTrackSelectedAccountAction()", "function openImportVideoLinkAction()");
|
||
const importVideo = extractBetween(APP, "function openImportVideoLinkAction()", "function openImportTextAction()");
|
||
const importText = extractBetween(APP, "function openImportTextAction()", "function openUploadVideoAction()");
|
||
assert.match(importHomepage, /runDirectWorkbenchAction\("import-homepage"/);
|
||
assert.match(importHomepage, /assistant_id:\s*values\.assistantId \|\| ""/);
|
||
assert.doesNotMatch(importHomepage, /storyforgeFetch\("\/v2\/content-sources"/);
|
||
assert.doesNotMatch(importHomepage, /storyforgeFetch\("\/v2\/pipelines\/content-source-sync"/);
|
||
assert.match(importSelected, /runDirectDiscoveryAction\("import-homepage"/);
|
||
assert.match(importSelected, /assistant_id:\s*values\.assistantId \|\| ""/);
|
||
assert.doesNotMatch(importSelected, /storyforgeFetch\("\/v2\/content-sources"/);
|
||
assert.doesNotMatch(importSelected, /storyforgeFetch\("\/v2\/pipelines\/content-source-sync"/);
|
||
assert.match(trackSelected, /runDirectDiscoveryAction\("track-account"/);
|
||
assert.match(trackSelected, /assistant_id:\s*values\.assistantId \|\| ""/);
|
||
assert.doesNotMatch(trackSelected, /storyforgeFetch\(trackingAccountsPath/);
|
||
assert.match(importVideo, /runDirectWorkbenchAction\("import-video-link"/);
|
||
assert.doesNotMatch(importVideo, /storyforgeFetch\("\/v2\/explore\/video-link"/);
|
||
assert.match(importText, /runDirectWorkbenchAction\("import-text"/);
|
||
assert.doesNotMatch(importText, /storyforgeFetch\("\/v2\/explore\/text"/);
|
||
});
|
||
|
||
test("input-heavy intake sheets surface current context and smarter defaults", () => {
|
||
const importHomepage = extractBetween(APP, "function openImportHomepageAction()", "function openImportSelectedAccountAction()");
|
||
const importSelected = extractBetween(APP, "function openImportSelectedAccountAction()", "function openTrackSelectedAccountAction()");
|
||
const trackSelected = extractBetween(APP, "function openTrackSelectedAccountAction()", "function openImportVideoLinkAction()");
|
||
const importVideo = extractBetween(APP, "function openImportVideoLinkAction()", "function openImportTextAction()");
|
||
const importText = extractBetween(APP, "function openImportTextAction()", "function openUploadVideoAction()");
|
||
const uploadVideo = extractBetween(APP, "function openUploadVideoAction()", "function focusPlaybookOneLinerWorkspace(");
|
||
const generateCopy = extractBetween(APP, "function openGenerateCopyAction(defaults = {})", "function openCreateAiVideoAction(defaults = {})");
|
||
const createAiVideo = extractBetween(APP, "function openCreateAiVideoAction(defaults = {})", "function openCreateRealCutAction(defaults = {})");
|
||
const createRealCut = extractBetween(APP, "function openCreateRealCutAction(defaults = {})", "function openLiveRecorderAction()");
|
||
const liveRecorderCreate = extractBetween(APP, "function openLiveRecorderCreateAction()", "function openLiveRecorderSourceAction(sourceId)");
|
||
const liveRecorderSource = extractBetween(APP, "function openLiveRecorderSourceAction(sourceId)", "function openLiveRecorderImportAction()");
|
||
const liveRecorderImport = extractBetween(APP, "function openLiveRecorderImportAction()", "async function toggleLiveRecorderSourceAction(");
|
||
const reviewAction = extractBetween(APP, "function openReviewAction(defaults = {})", "document.addEventListener(\"click\", async (event) => {");
|
||
assert.match(APP, /function renderIntakeActionContextHtml\(/);
|
||
assert.match(APP, /function renderSourceJobContextHtml\(job\)/);
|
||
assert.match(APP, /function recommendAudienceForPlatform\(platform\)/);
|
||
assert.match(APP, /function recommendAspectRatioForPlatform\(platform\)/);
|
||
assert.match(APP, /function recommendCreativeStyle\(sourceJob\)/);
|
||
assert.match(APP, /function recommendRealCutDuration\(sourceJob\)/);
|
||
assert.match(APP, /function recommendAiVideoShotDuration\(sourceJob\)/);
|
||
assert.match(APP, /function recommendDerivativeJobTitle\(sourceJob, suffix, fallback\)/);
|
||
assert.match(APP, /function recommendRealCutObjective\(sourceJob\)/);
|
||
assert.match(APP, /function recommendLiveRecorderTitle\(project, platform\)/);
|
||
assert.match(APP, /function recommendLiveRecorderImportSamples\(platform\)/);
|
||
assert.match(APP, /function recommendManualIntakeTitle\(project, platform, kind\)/);
|
||
assert.match(APP, /function bindManualIntakeTitleRecommendation\(fields, kind, options = \{\}\)/);
|
||
assert.match(APP, /function bindActionContextRecommendation\(fields, options = \{\}\)/);
|
||
assert.match(APP, /function bindAssistantSheetRecommendations\(fields, options = \{\}\)/);
|
||
assert.match(APP, /function bindCreativeSourceJobRecommendations\(fields, options = \{\}\)/);
|
||
assert.match(APP, /const contextHtml = fields\.querySelector\('\[data-action-field="context"] \.sheet-html'\);/);
|
||
assert.match(APP, /const assistantSelect = fields\.querySelector\('\[data-action-field="assistantId"]'\);/);
|
||
assert.match(APP, /registerManagedField\(assistantSelect, \(job\) => \{/);
|
||
assert.match(APP, /contextHtml\.innerHTML = renderIntakeActionContextHtml\(projectId, assistantId\);/);
|
||
assert.match(APP, /function bindLiveRecorderSheetRecommendations\(fields, options = \{\}\)/);
|
||
assert.match(importHomepage, /label: "当前上下文", type: "html"/);
|
||
assert.match(importHomepage, /const defaultAssistantId = getSelectedAssistant\(\)\?\.id \|\| assistants\[0\]\?\.value \|\| ""/);
|
||
assert.match(importHomepage, /const defaultPlatform = normalizePlatformValue\(getPreferredPlatform\(\), "douyin"\)/);
|
||
assert.match(importHomepage, /const titlePlaceholder = recommendManualIntakeTitle\(project, defaultPlatform, "主页对标"\)/);
|
||
assert.match(importHomepage, /renderIntakeActionContextHtml\(project\.id, defaultAssistantId\)/);
|
||
assert.match(importHomepage, /value: defaultPlatform/);
|
||
assert.match(importHomepage, /placeholder: titlePlaceholder/);
|
||
assert.match(importHomepage, /bindActionContextRecommendation\(fields, \{ defaultAssistantId \}\);/);
|
||
assert.match(importHomepage, /onOpen:\s*\(\{ fields \}\) => \{\s*bindManualIntakeTitleRecommendation\(fields, "主页对标", \{ defaultPlatform: "douyin" \}\);/);
|
||
assert.match(importSelected, /label: "当前上下文", type: "html"/);
|
||
assert.match(importSelected, /const defaultAssistantId = getSelectedAssistant\(\)\?\.id \|\| assistants\[0\]\?\.value \|\| ""/);
|
||
assert.match(importSelected, /renderIntakeActionContextHtml\(project\.id, defaultAssistantId\)/);
|
||
assert.match(importSelected, /bindActionContextRecommendation\(fields, \{ defaultAssistantId \}\);/);
|
||
assert.match(trackSelected, /label: "当前上下文", type: "html"/);
|
||
assert.match(trackSelected, /const defaultAssistantId = trackedItem\?\.assistant_id \|\| getSelectedAssistant\(\)\?\.id \|\| assistants\[0\]\?\.value \|\| ""/);
|
||
assert.match(trackSelected, /renderIntakeActionContextHtml\(project\.id, defaultAssistantId\)/);
|
||
assert.match(trackSelected, /bindActionContextRecommendation\(fields, \{ defaultAssistantId, projectField: "" \}\);/);
|
||
assert.match(importVideo, /label: "当前上下文", type: "html"/);
|
||
assert.match(importVideo, /const defaultAssistantId = getSelectedAssistant\(\)\?\.id \|\| assistants\[0\]\?\.value \|\| ""/);
|
||
assert.match(importVideo, /const defaultPlatform = normalizePlatformValue\(getPreferredPlatform\(\), "douyin"\)/);
|
||
assert.match(importVideo, /const titlePlaceholder = recommendManualIntakeTitle\(project, defaultPlatform, "单条作品"\)/);
|
||
assert.match(importVideo, /renderIntakeActionContextHtml\(project\.id, defaultAssistantId\)/);
|
||
assert.match(importVideo, /placeholder: titlePlaceholder/);
|
||
assert.match(importVideo, /bindActionContextRecommendation\(fields, \{ defaultAssistantId \}\);/);
|
||
assert.match(importVideo, /onOpen:\s*\(\{ fields \}\) => \{\s*bindManualIntakeTitleRecommendation\(fields, "单条作品", \{ defaultPlatform: "douyin" \}\);/);
|
||
assert.match(importText, /label: "当前上下文", type: "html"/);
|
||
assert.match(importText, /const defaultAssistantId = getSelectedAssistant\(\)\?\.id \|\| assistants\[0\]\?\.value \|\| ""/);
|
||
assert.match(importText, /const defaultPlatform = normalizePlatformValue\(getPreferredPlatform\(\), "douyin"\)/);
|
||
assert.match(importText, /const titlePlaceholder = recommendManualIntakeTitle\(project, defaultPlatform, "文本素材"\)/);
|
||
assert.match(importText, /renderIntakeActionContextHtml\(project\.id, defaultAssistantId\)/);
|
||
assert.match(importText, /placeholder: titlePlaceholder/);
|
||
assert.match(importText, /bindActionContextRecommendation\(fields, \{ defaultAssistantId \}\);/);
|
||
assert.match(importText, /onOpen:\s*\(\{ fields \}\) => \{\s*bindManualIntakeTitleRecommendation\(fields, "文本素材", \{ defaultPlatform: "douyin" \}\);/);
|
||
assert.match(uploadVideo, /label: "当前上下文", type: "html"/);
|
||
assert.match(uploadVideo, /const defaultAssistantId = getSelectedAssistant\(\)\?\.id \|\| assistants\[0\]\?\.value \|\| ""/);
|
||
assert.match(uploadVideo, /const defaultPlatform = normalizePlatformValue\(getPreferredPlatform\(\), "douyin"\)/);
|
||
assert.match(uploadVideo, /const titlePlaceholder = recommendManualIntakeTitle\(project, defaultPlatform, "本地视频"\)/);
|
||
assert.match(uploadVideo, /renderIntakeActionContextHtml\(project\.id, defaultAssistantId\)/);
|
||
assert.match(uploadVideo, /placeholder: titlePlaceholder/);
|
||
assert.match(uploadVideo, /bindActionContextRecommendation\(fields, \{ defaultAssistantId \}\);/);
|
||
assert.match(uploadVideo, /onOpen:\s*\(\{ fields \}\) => \{\s*bindManualIntakeTitleRecommendation\(fields, "本地视频", \{ defaultPlatform: "douyin" \}\);/);
|
||
assert.match(generateCopy, /label: "当前上下文", type: "html"/);
|
||
assert.match(generateCopy, /renderIntakeActionContextHtml\(project\?\.id \|\| "", assistant\.id\)/);
|
||
assert.match(generateCopy, /sourceJob \? \[\{ name: "sourceJobContext", label: "来源任务", type: "html", html: renderSourceJobContextHtml\(sourceJob\) \}\] : \[\]/);
|
||
assert.match(generateCopy, /const defaultPlatform = normalizePlatformValue\(defaults\.platform \|\| sourceJob\?\.platform \|\| "douyin"\)/);
|
||
assert.match(generateCopy, /value: defaults\.audience \|\| recommendAudienceForPlatform\(defaultPlatform\)/);
|
||
assert.match(generateCopy, /onOpen:\s*\(\{ fields \}\) => \{\s*bindCreativeSourceJobRecommendations\(fields, \{/);
|
||
assert.match(createAiVideo, /label: "当前上下文", type: "html"/);
|
||
assert.match(createAiVideo, /const defaultAssistantId = assistant\?\.id \|\| ""/);
|
||
assert.match(createAiVideo, /const defaultPlatform = normalizePlatformValue\(defaults\.platform \|\| sourceJob\?\.platform \|\| "douyin"\)/);
|
||
assert.match(createAiVideo, /renderIntakeActionContextHtml\(project\.id, defaultAssistantId\)/);
|
||
assert.match(createAiVideo, /sourceJob \? \[\{ name: "sourceJobContext", label: "来源任务", type: "html", html: renderSourceJobContextHtml\(sourceJob\) \}\] : \[\]/);
|
||
assert.match(createAiVideo, /value: defaults\.title \|\| recommendDerivativeJobTitle\(sourceJob, "AI 视频", ""\)/);
|
||
assert.match(createAiVideo, /value: defaults\.style \|\| recommendCreativeStyle\(sourceJob\)/);
|
||
assert.match(createAiVideo, /recommendAspectRatioForPlatform\(defaultPlatform\)/);
|
||
assert.match(createAiVideo, /value: defaults\.duration \|\| recommendAiVideoShotDuration\(sourceJob\)/);
|
||
assert.match(createAiVideo, /onOpen:\s*\(\{ fields \}\) => \{\s*bindCreativeSourceJobRecommendations\(fields, \{/);
|
||
assert.match(createRealCut, /label: "当前上下文", type: "html"/);
|
||
assert.match(createRealCut, /const defaultPlatform = normalizePlatformValue\(defaults\.platform \|\| sourceJob\?\.platform \|\| "douyin"\)/);
|
||
assert.match(createRealCut, /renderIntakeActionContextHtml\(project\.id, assistant\?\.id \|\| ""\)/);
|
||
assert.match(createRealCut, /sourceJob \? \[\{ name: "sourceJobContext", label: "来源任务", type: "html", html: renderSourceJobContextHtml\(sourceJob\) \}\] : \[\]/);
|
||
assert.match(createRealCut, /value: defaults\.title \|\| recommendDerivativeJobTitle\(sourceJob, "实拍剪辑", ""\)/);
|
||
assert.match(createRealCut, /value: defaults\.targetDurationSec \|\| recommendRealCutDuration\(sourceJob\)/);
|
||
assert.match(createRealCut, /recommendAspectRatioForPlatform\(defaultPlatform\)/);
|
||
assert.match(createRealCut, /value: defaults\.objective \|\| recommendRealCutObjective\(sourceJob\)/);
|
||
assert.match(createRealCut, /onOpen:\s*\(\{ fields \}\) => \{\s*bindCreativeSourceJobRecommendations\(fields, \{/);
|
||
assert.match(liveRecorderCreate, /label: "当前上下文", type: "html"/);
|
||
assert.match(liveRecorderCreate, /const defaultAssistantId = getSelectedAssistant\(\)\?\.id \|\| assistants\[0\]\?\.value \|\| ""/);
|
||
assert.match(liveRecorderCreate, /const defaultPlatform = normalizePlatformValue\(getPreferredPlatform\(\), "kuaishou"\)/);
|
||
assert.match(liveRecorderCreate, /const defaultTitle = recommendLiveRecorderTitle\(project, defaultPlatform\)/);
|
||
assert.match(liveRecorderCreate, /renderIntakeActionContextHtml\(project\?\.id \|\| "", defaultAssistantId\)/);
|
||
assert.match(liveRecorderCreate, /value: defaultTitle, placeholder: defaultTitle/);
|
||
assert.match(liveRecorderCreate, /onOpen:\s*\(\{ fields \}\) => \{\s*bindLiveRecorderSheetRecommendations\(fields, \{/);
|
||
assert.match(liveRecorderSource, /label: "当前上下文", type: "html"/);
|
||
assert.match(liveRecorderSource, /const defaultAssistantId = source\.assistant_id \|\| getSelectedAssistant\(\)\?\.id \|\| assistants\[0\]\?\.value \|\| ""/);
|
||
assert.match(liveRecorderSource, /const titlePlaceholder = recommendLiveRecorderTitle\(currentProject, source\.platform \|\| "kuaishou"\)/);
|
||
assert.match(liveRecorderSource, /renderIntakeActionContextHtml\(currentProject\?\.id \|\| source\.project_id \|\| "", defaultAssistantId\)/);
|
||
assert.match(liveRecorderSource, /placeholder: titlePlaceholder/);
|
||
assert.match(liveRecorderSource, /onOpen:\s*\(\{ fields \}\) => \{\s*bindLiveRecorderSheetRecommendations\(fields, \{/);
|
||
assert.match(liveRecorderImport, /label: "当前上下文", type: "html"/);
|
||
assert.match(liveRecorderImport, /const defaultAssistantId = getSelectedAssistant\(\)\?\.id \|\| assistants\[0\]\?\.value \|\| ""/);
|
||
assert.match(liveRecorderImport, /const defaultPlatform = normalizePlatformValue\(getPreferredPlatform\(\), "kuaishou"\)/);
|
||
assert.match(liveRecorderImport, /const samples = recommendLiveRecorderImportSamples\(defaultPlatform\)/);
|
||
assert.match(liveRecorderImport, /renderIntakeActionContextHtml\(project\?\.id \|\| "", defaultAssistantId\)/);
|
||
assert.match(liveRecorderImport, /按行粘贴\$\{platformLabel\(defaultPlatform\)\}直播源/);
|
||
assert.match(liveRecorderImport, /onOpen:\s*\(\{ fields, description \}\) => \{\s*bindLiveRecorderSheetRecommendations\(fields, \{/);
|
||
assert.match(reviewAction, /label: "当前上下文", type: "html"/);
|
||
assert.match(reviewAction, /const defaultAssistantId = getSelectedAssistant\(\)\?\.id \|\| assistants\[0\]\?\.value \|\| ""/);
|
||
assert.match(reviewAction, /renderIntakeActionContextHtml\(project\.id, defaultAssistantId\)/);
|
||
assert.match(reviewAction, /sourceJob \? \[\{ name: "sourceJobContext", label: "来源任务", type: "html", html: renderSourceJobContextHtml\(sourceJob\) \}\] : \[\]/);
|
||
assert.match(reviewAction, /value: existingReview\?\.title \|\| defaults\.title \|\| recommendDerivativeJobTitle\(sourceJob, "复盘", ""\)/);
|
||
assert.match(reviewAction, /normalizePlatformValue\(existingReview\?\.platform \|\| defaults\.platform \|\| sourceJob\?\.platform \|\| "douyin"\)/);
|
||
assert.match(reviewAction, /onOpen:\s*\(\{ fields \}\) => \{\s*bindCreativeSourceJobRecommendations\(fields, \{/);
|
||
assert.match(reviewAction, /projectId:\s*project\.id/);
|
||
assert.match(reviewAction, /defaultAssistantId:\s*existingReview\?\.assistant_id \|\| defaultAssistantId/);
|
||
});
|
||
|
||
test("discovery analysis actions focus the most relevant detail tab after success", () => {
|
||
const analyzeAccount = extractBetween(APP, "function openAnalyzeSelectedAccountAction()", "function openAnalyzeTopVideosAction()");
|
||
const analyzeTopVideos = extractBetween(APP, "function openAnalyzeTopVideosAction()", "function openSimilaritySearchAction()");
|
||
const similaritySearch = extractBetween(APP, "function openSimilaritySearchAction()", "function openBenchmarkLinkAction(defaults = {})");
|
||
assert.match(APP, /function focusDiscoveryDetailTab\(tabValue\)/);
|
||
assert.match(APP, /function focusDiscoveryInsights\(\)/);
|
||
assert.match(APP, /function focusDiscoveryTopVideoInsights\(\)/);
|
||
assert.match(APP, /function focusDiscoveryRelations\(\)/);
|
||
assert.match(analyzeAccount, /focusDiscoveryInsights\(\)/);
|
||
assert.match(analyzeTopVideos, /focusDiscoveryTopVideoInsights\(\)/);
|
||
assert.match(similaritySearch, /focusDiscoveryRelations\(\)/);
|
||
});
|
||
|
||
test("tracking and benchmark actions land on the most relevant workbench area after success", () => {
|
||
const trackSelected = extractBetween(APP, "function openTrackSelectedAccountAction()", "function openImportVideoLinkAction()");
|
||
const saveCandidate = extractBetween(APP, "async function saveCandidateAsBenchmark(candidateIndex, relationType = \"benchmark\")", "function screenShell(title, subtitle, actionsHtml, bodyHtml)");
|
||
const openBenchmark = extractBetween(APP, "function openBenchmarkLinkAction(defaults = {})", "async function scanAdminOpsAction()");
|
||
const clickHandler = extractBetween(APP, "document.addEventListener(\"click\", async (event) => {", "document.addEventListener(\"submit\", async (event) => {");
|
||
assert.match(APP, /function focusTrackingWorkspace\(\)/);
|
||
assert.match(APP, /function focusDiscoveryRelations\(\)/);
|
||
assert.match(trackSelected, /runDirectDiscoveryAction\("track-account"/);
|
||
assert.match(saveCandidate, /focusDiscoveryRelations\(\)/);
|
||
assert.match(openBenchmark, /focusDiscoveryRelations\(\)/);
|
||
assert.match(clickHandler, /name === "mark-tracking-read"[\s\S]*focusTrackingWorkspace\(\)/);
|
||
});
|
||
|
||
test("recovery and copy actions continue into the most useful result view", () => {
|
||
const singleRecover = extractBetween(APP, "function openRecoverJobAction(jobId)", "function openBatchRecoverJobsAction()");
|
||
const batchRecover = extractBetween(APP, "function openBatchRecoverJobsAction()", "function openGenerateCopyAction(defaults = {})");
|
||
const generateCopy = extractBetween(APP, "function openGenerateCopyAction(defaults = {})", "function openCreateAiVideoAction(defaults = {})");
|
||
const recoveryGuide = extractBetween(APP, "function getRecoverJobGuidance(job, recovery) {", "function getJobRecoveryRequest(job) {");
|
||
assert.match(APP, /function focusProductionDetailTab\(tabValue\)/);
|
||
assert.match(APP, /function focusRecentGeneratedCopy\(\)/);
|
||
assert.match(singleRecover, /if \(result\?\.created\?\.id\) \{\s*openJobDetailAction\(result\.created\.id\);/);
|
||
assert.match(singleRecover, /focusProductionDetailTab\("recovery"\)/);
|
||
assert.match(singleRecover, /失败任务处理建议/);
|
||
assert.match(singleRecover, /getRecoverJobGuidance\(job, recovery\)/);
|
||
assert.match(singleRecover, /renderRecoverJobGuidanceHtml\(job, recovery, guidance\)/);
|
||
assert.match(singleRecover, /sheet-html/);
|
||
assert.match(singleRecover, /先补信息,再继续推进/);
|
||
assert.match(recoveryGuide, /state === "blocked"/);
|
||
assert.match(recoveryGuide, /upload_video/);
|
||
assert.match(recoveryGuide, /real_cut/);
|
||
assert.match(recoveryGuide, /ai_video/);
|
||
assert.match(recoveryGuide, /content_source_sync/);
|
||
assert.match(recoveryGuide, /text/);
|
||
assert.match(recoveryGuide, /video_link/);
|
||
assert.match(recoveryGuide, /去导入主页/);
|
||
assert.match(recoveryGuide, /交给主 Agent/);
|
||
assert.match(recoveryGuide, /recover-job-handoff/);
|
||
assert.match(batchRecover, /if \(successes\[0\]\?\.result\?\.created\?\.id\) \{\s*openJobDetailAction\(successes\[0\]\.result\.created\.id\);/);
|
||
assert.match(batchRecover, /focusProductionDetailTab\("recovery"\)/);
|
||
assert.match(generateCopy, /focusRecentGeneratedCopy\(\)/);
|
||
});
|
||
|
||
test("review actions return to the review workspace with the saved review in focus", () => {
|
||
const reviewAction = extractBetween(APP, "function openReviewAction(defaults = {})", "document.addEventListener(\"click\", async (event) => {");
|
||
assert.match(APP, /function focusReviewWorkspace\(reviewId = ""\)/);
|
||
assert.match(reviewAction, /focusReviewWorkspace\(review\.id\)/);
|
||
assert.match(APP, /id="review-workspace-anchor"/);
|
||
assert.match(APP, /data-review-id="\$\{escapeHtml\(review\.id\)\}"/);
|
||
});
|
||
|
||
test("quota and admin ops mutations refocus the user into the most relevant workbench area", () => {
|
||
const quota = extractBetween(APP, "function openTenantQuotaAction()", "function openCreateAssistantAction()");
|
||
const scanOps = extractBetween(APP, "async function scanAdminOpsAction()", "function openAdminIncidentReviewAction(incidentId)");
|
||
const reviewIncident = extractBetween(APP, "function openAdminIncidentReviewAction(incidentId)", "function openAdminRepairPlanAction(incidentId)");
|
||
const repairPlan = extractBetween(APP, "function openAdminRepairPlanAction(incidentId)", "function openAdminFixRunDetailAction(runId)");
|
||
const auditFixRun = extractBetween(APP, "function openAdminFixRunAuditAction(runId)", "function openJobDetailAction(jobId)");
|
||
|
||
assert.match(APP, /function focusCreditsWorkspace\(anchorId = "credits-quota-anchor"\)/);
|
||
assert.match(APP, /function focusAdminOpsWorkspace\(anchorId = "admin-ops-anchor"\)/);
|
||
assert.match(APP, /id="credits-quota-anchor"/);
|
||
assert.match(APP, /id="admin-ops-anchor"/);
|
||
assert.match(quota, /focusCreditsWorkspace\("credits-quota-anchor"\)/);
|
||
assert.match(scanOps, /focusAdminOpsWorkspace\("admin-ops-anchor"\)/);
|
||
assert.match(reviewIncident, /focusAdminOpsWorkspace\("admin-ops-anchor"\)/);
|
||
assert.match(repairPlan, /focusAdminOpsWorkspace\("admin-ops-anchor"\)/);
|
||
assert.match(auditFixRun, /focusAdminOpsWorkspace\("admin-ops-anchor"\)/);
|
||
});
|
||
|
||
test("assistant actions return to the playbook workspace with the saved assistant in focus", () => {
|
||
const createAssistant = extractBetween(APP, "function openCreateAssistantAction()", "function openEditAssistantAction(assistantId = \"\")");
|
||
const editAssistant = extractBetween(APP, "function openEditAssistantAction(assistantId = \"\")", "function openAnalyzeSelectedAccountAction()");
|
||
const clickHandler = extractBetween(APP, "document.addEventListener(\"click\", async (event) => {", "document.addEventListener(\"submit\", async (event) => {");
|
||
assert.match(APP, /function focusPlaybookWorkspace\(assistantId = ""\)/);
|
||
assert.match(createAssistant, /label: "当前上下文", type: "html"/);
|
||
assert.match(createAssistant, /label: "默认知识库", type: "select"/);
|
||
assert.match(createAssistant, /bindAssistantSheetRecommendations\(fields, \{ defaultProjectId: project\.id, defaultKnowledgeBaseId: kbOptions\[0\]\?\.value \|\| "" \}\);/);
|
||
assert.match(createAssistant, /fields\.querySelector\('\[data-action-field="name"\]'\)\?\.focus\(\);/);
|
||
assert.match(createAssistant, /focusPlaybookWorkspace\(assistant\.id\)/);
|
||
assert.match(editAssistant, /label: "当前上下文", type: "html"/);
|
||
assert.match(editAssistant, /label: "默认知识库", type: "select"/);
|
||
assert.match(editAssistant, /bindAssistantSheetRecommendations\(fields, \{/);
|
||
assert.match(editAssistant, /knowledge_base_ids:\s*values\.knowledgeBaseId \? \[values\.knowledgeBaseId\] : \[\]/);
|
||
assert.match(editAssistant, /focusPlaybookWorkspace\(updated\.id\)/);
|
||
assert.match(clickHandler, /name === "select-assistant"[\s\S]*focusPlaybookWorkspace\(appState\.selectedAssistantId\)/);
|
||
assert.match(APP, /id="current-agent-anchor"/);
|
||
assert.match(APP, /data-assistant-id="\$\{escapeHtml\(assistant\.id\)\}"/);
|
||
});
|
||
|
||
test("live recorder mutations return to the recorder maintenance panel after success", () => {
|
||
const createSource = extractBetween(APP, "function openLiveRecorderCreateAction()", "function openLiveRecorderSourceAction(sourceId)");
|
||
const editSource = extractBetween(APP, "function openLiveRecorderSourceAction(sourceId)", "function openLiveRecorderImportAction()");
|
||
const importSource = extractBetween(APP, "function openLiveRecorderImportAction()", "async function toggleLiveRecorderSourceAction(sourceId, nextEnabled)");
|
||
const toggleSource = extractBetween(APP, "async function toggleLiveRecorderSourceAction(sourceId, nextEnabled)", "async function deleteLiveRecorderSourceAction(sourceId)");
|
||
const deleteSource = extractBetween(APP, "async function deleteLiveRecorderSourceAction(sourceId)", "async function openLiveRecorderFileAction(fileId)");
|
||
assert.match(APP, /function focusLiveRecorderMaintenance\(\)/);
|
||
assert.match(createSource, /focusLiveRecorderMaintenance\(\)/);
|
||
assert.match(editSource, /focusLiveRecorderMaintenance\(\)/);
|
||
assert.match(importSource, /focusLiveRecorderMaintenance\(\)/);
|
||
assert.match(toggleSource, /focusLiveRecorderMaintenance\(\)/);
|
||
assert.match(deleteSource, /focusLiveRecorderMaintenance\(\)/);
|
||
});
|
||
|
||
test("main agent execution cards can jump to oneliner and platform profile history", () => {
|
||
const messages = extractBetween(APP, "function renderOneLinerMessagesHtml()", "function renderAutoConnectingScreen(screenTitle, nextStepText)");
|
||
const runtime = extractBetween(APP, "function renderOneLinerRunsHtml()", "function renderOneLinerMessagesHtml()");
|
||
const execution = extractBetween(APP, "function renderOneLinerExecutionPayloadHtml(payload)", "function parseOneLinerActionPayloadValue(value)");
|
||
assert.match(messages, /const buildOnelinerActionAttrs = \(item\) =>/);
|
||
assert.match(messages, /actions\.map\(\(item\) => actionTag\(/);
|
||
assert.match(messages, /item\.label \|\| item\.executor_label \|\| item\.key \|\| "执行动作"/);
|
||
assert.match(messages, /buildOnelinerActionAttrs\(item\)/);
|
||
assert.doesNotMatch(messages, /actions\.map\(\(item\) => `<span class="tag clickable-tag" data-action="\$\{escapeHtml\(item\.key\)\}">\$\{escapeHtml\(item\.label\)\}<\/span>`\)/);
|
||
assert.match(messages, /data-action="open-oneliner-profile-history"/);
|
||
assert.match(messages, /data-action="open-platform-agent-profile-history"/);
|
||
assert.match(messages, /data-version-id="\$\{escapeHtml\(profileVersion\.version_id \|\| ""\)\}"/);
|
||
assert.match(messages, /data-version-id="\$\{escapeHtml\(platformAgentProfile\.version_id \|\| ""\)\}"/);
|
||
assert.match(messages, /actionTag\(\s*primaryAction\.label \|\| "执行下一步"/);
|
||
assert.match(messages, /buildOnelinerActionAttrs\(primaryAction\)/);
|
||
assert.match(runtime, /data-version-id="\$\{escapeHtml\(currentRunConfigVersion\.version_id \|\| ""\)\}"/);
|
||
assert.match(execution, /data-version-id="\$\{escapeHtml\(configVersion\.version_id \|\| ""\)\}"/);
|
||
assert.match(execution, /data-version-id="\$\{escapeHtml\(platformAgentProfile\.version_id \|\| ""\)\}"/);
|
||
});
|
||
|
||
test("oneliner runtime shows grouped run health summary above the current run card", () => {
|
||
const runtime = extractBetween(APP, "function renderOneLinerRunsHtml()", "function renderOneLinerMessagesHtml()");
|
||
assert.match(runtime, /近期运行概况/);
|
||
assert.match(runtime, /待确认/);
|
||
assert.match(runtime, /执行中/);
|
||
assert.match(runtime, /已完成/);
|
||
assert.match(runtime, /异常/);
|
||
assert.match(runtime, /最近完成/);
|
||
assert.match(runtime, /recentCompletedRuns/);
|
||
assert.match(runtime, /select-oneliner-run-filter/);
|
||
assert.match(runtime, /重点运行/);
|
||
assert.match(runtime, /已完成/);
|
||
assert.match(runtime, /异常运行/);
|
||
assert.match(runtime, /全部/);
|
||
assert.match(runtime, /problemRunCount/);
|
||
assert.match(runtime, /safeArray\(runs\)\.filter\(\(item\) => item\.run_status === "needs_confirmation"\)\.length/);
|
||
});
|
||
|
||
test("oneliner runtime exposes a compact mobile task strip for the current run", () => {
|
||
const runtime = extractBetween(APP, "function renderOneLinerRunsHtml()", "function renderOneLinerMessagesHtml()");
|
||
assert.match(runtime, /mobile-only compact-summary-row/);
|
||
assert.match(runtime, /mobile-only mobile-flow-focus-card/);
|
||
assert.match(runtime, /当前运行/);
|
||
assert.match(runtime, /继续这个任务/);
|
||
});
|
||
|
||
test("opening a main agent run result keeps that run selected in the floating runtime", () => {
|
||
const resultAction = extractBetween(APP, "function openCurrentOneLinerRunResultAction(runId = \"\")", "function openConfirmOneLinerRunAction(runId = \"\")");
|
||
assert.match(resultAction, /appState\.selectedOnelinerRunId = currentRun\.id/);
|
||
assert.match(resultAction, /appState\.onelinerRunFilter = currentRun\.run_status === "done" \? "done" : appState\.onelinerRunFilter/);
|
||
});
|
||
|
||
test("oneliner runtime exposes retry for retryable runs and wires the action handler", () => {
|
||
const runtime = extractBetween(APP, "function renderOneLinerRunsHtml()", "function renderOneLinerMessagesHtml()");
|
||
const actions = extractBetween(APP, "document.addEventListener(\"click\", async (event) => {", "document.addEventListener(\"submit\", async (event) => {");
|
||
assert.match(runtime, /retry-oneliner-run/);
|
||
assert.match(actions, /name === "retry-oneliner-run"/);
|
||
assert.match(actions, /await retryOneLinerRun\(action\.dataset\.runId \|\| "", "user requested retry"\)/);
|
||
});
|
||
|
||
test("oneliner runtime highlights stale configuration versions and suggests rerunning with current config", () => {
|
||
const runtime = extractBetween(APP, "function renderOneLinerRunsHtml()", "function renderOneLinerMessagesHtml()");
|
||
assert.match(APP, /function getVersionIdentity\(version = \{\}\)/);
|
||
assert.match(APP, /function isConfigurationVersionStale\(runVersion, currentVersion\)/);
|
||
assert.match(runtime, /currentRunOnelinerConfigStale/);
|
||
assert.match(runtime, /currentRunPlatformAgentConfigStale/);
|
||
assert.match(runtime, /主配置已更新/);
|
||
assert.match(runtime, /平台 Agent 已更新/);
|
||
assert.match(runtime, /按当前配置重跑/);
|
||
});
|
||
|
||
test("oneliner panel auto-polls active runs while the floating panel stays open", () => {
|
||
const render = extractBetween(APP, "function renderOneLinerUi()", "function openOneLinerPanel()");
|
||
const open = extractBetween(APP, "function openOneLinerPanel()", "function closeOneLinerPanel()");
|
||
const close = extractBetween(APP, "function closeOneLinerPanel()", "function readActionForm()");
|
||
|
||
assert.match(APP, /let onelinerRunPollTimer = null;/);
|
||
assert.match(APP, /function clearOneLinerRunPollTimer\(\)/);
|
||
assert.match(APP, /function syncOneLinerRunPolling\(\)/);
|
||
assert.match(render, /syncOneLinerRunPolling\(\);/);
|
||
assert.match(open, /syncOneLinerRunPolling\(\);/);
|
||
assert.match(close, /clearOneLinerRunPollTimer\(\);/);
|
||
assert.match(APP, /setTimeout\(async \(\) => \{/);
|
||
assert.match(APP, /await hydrateSelectedOneLinerRun\(\);/);
|
||
});
|
||
|
||
test("workbench interaction flow avoids browser alerts and keeps failures inside the product shell", () => {
|
||
const clicks = extractBetween(APP, "document.addEventListener(\"click\", async (event) => {", "document.addEventListener(\"submit\", async (event) => {");
|
||
assert.doesNotMatch(APP, /alert\(/);
|
||
assert.doesNotMatch(APP, /confirm\(/);
|
||
assert.match(clicks, /name === "show-disabled-reason"[\s\S]*rememberAction\("动作已拦截"/);
|
||
assert.match(clicks, /name === "auth-refresh" \|\| name === "refresh-data"[\s\S]*presentActionFailure\(error, "刷新数据失败"\)/);
|
||
});
|
||
|
||
test("live recorder delete uses an in-app confirmation sheet instead of browser confirm", () => {
|
||
const removeSource = extractBetween(APP, "async function deleteLiveRecorderSourceAction(sourceId)", "async function openLiveRecorderFileAction(fileId)");
|
||
assert.match(removeSource, /openActionModal\(\{/);
|
||
assert.match(removeSource, /title:\s*"确认删除录制源"/);
|
||
assert.match(removeSource, /submitLabel:\s*"确认删除"/);
|
||
assert.doesNotMatch(removeSource, /window\.confirm/);
|
||
});
|
||
|
||
test("live-first workbench flows no longer advertise stale missing-capability placeholders for active routes", () => {
|
||
assert.doesNotMatch(APP, /当前实例还没有开放 OneLiner 会话接口/);
|
||
assert.doesNotMatch(APP, /当前实例还没有开放主 Agent 运行层/);
|
||
assert.doesNotMatch(APP, /当前实例还没有开放 OneLiner 动作执行器/);
|
||
assert.doesNotMatch(APP, /当前实例还没有开放平台技能验收接口/);
|
||
assert.doesNotMatch(APP, /当前实例未提供/);
|
||
assert.doesNotMatch(APP, /等待接入重点对象/);
|
||
assert.doesNotMatch(APP, /动作待接入/);
|
||
assert.match(APP, /先挑一个重点对象开始跟进/);
|
||
assert.match(APP, /暂未识别当前动作/);
|
||
});
|
||
|
||
test("integration cards surface ASR runtime mode and model details", () => {
|
||
const detailSource = extractBetween(APP, "function getIntegrationDetail(key) {", "function isFnosTunnelCutvideo");
|
||
const statusSource = extractBetween(APP, "function getIntegrationStatus(detail) {", "function describeIntegrationFailure");
|
||
const cardsSource = extractBetween(APP, "function getIntegrationCards()", "function renderLiveRecorderSummaryHtml()");
|
||
|
||
assert.match(APP, /function getAsrRuntimeBadge\(/);
|
||
assert.match(detailSource, /runtimeDeviceMode:/);
|
||
assert.match(detailSource, /runtimeComputeTypeMode:/);
|
||
assert.match(detailSource, /activeDevice:/);
|
||
assert.match(detailSource, /activeComputeType:/);
|
||
assert.match(detailSource, /languageMode:/);
|
||
assert.match(detailSource, /modelName:/);
|
||
assert.match(detailSource, /deploymentScope:/);
|
||
assert.match(detailSource, /deploymentLabel:/);
|
||
assert.match(statusSource, /detail\.key === "asr"/);
|
||
assert.match(statusSource, /在线 ·/);
|
||
assert.match(cardsSource, /部署:/);
|
||
assert.match(cardsSource, /当前转写:/);
|
||
assert.match(cardsSource, /当前模型:/);
|
||
});
|
||
|
||
test("smart discovery entrypoints prefer direct execute before falling back to forms", () => {
|
||
const clicks = extractBetween(APP, "document.addEventListener(\"click\", async (event) => {", "document.addEventListener(\"submit\", async (event) => {");
|
||
assert.match(clicks, /name === "open-similar-search"[\s\S]*const account = getSelectedAccount\(\);/);
|
||
assert.match(clicks, /name === "open-similar-search"[\s\S]*runDirectDiscoveryAction\("search-similar-accounts"/);
|
||
assert.match(clicks, /name === "open-similar-search"[\s\S]*openSimilaritySearchAction\(\);/);
|
||
assert.match(clicks, /name === "open-benchmark-link"[\s\S]*const candidate = safeArray\(appState\.lastSimilaritySearch\?\.candidates\)\[0\] \|\| null;/);
|
||
assert.match(clicks, /name === "open-benchmark-link"[\s\S]*runDirectDiscoveryAction\("save-benchmark-link"/);
|
||
assert.match(clicks, /name === "open-benchmark-link"[\s\S]*openBenchmarkLinkAction\(\);/);
|
||
assert.match(clicks, /name === "open-import-selected-account"[\s\S]*const currentSource = getCurrentProjectSourcesForAccount\(account, project\.id\)\[0\];/);
|
||
assert.match(clicks, /name === "open-import-selected-account"[\s\S]*runDirectDiscoveryAction\("import-homepage"/);
|
||
assert.match(clicks, /name === "open-import-selected-account"[\s\S]*openImportSelectedAccountAction\(\);/);
|
||
assert.match(clicks, /name === "open-track-selected-account"[\s\S]*const trackedItem = account\?\.id/);
|
||
assert.match(clicks, /name === "open-track-selected-account"[\s\S]*runDirectDiscoveryAction\("track-account"/);
|
||
assert.match(clicks, /name === "open-track-selected-account"[\s\S]*openTrackSelectedAccountAction\(\);/);
|
||
});
|
||
|
||
test("direct discovery relation actions gracefully fall back to forms when context is incomplete", () => {
|
||
const clicks = extractBetween(APP, "document.addEventListener(\"click\", async (event) => {", "document.addEventListener(\"submit\", async (event) => {");
|
||
assert.match(clicks, /name === "direct-search-similar"[\s\S]*const account = getSelectedAccount\(\);/);
|
||
assert.match(clicks, /name === "direct-search-similar"[\s\S]*if \(!account\?\.id\) \{[\s\S]*openSimilaritySearchAction\(\);[\s\S]*return;[\s\S]*\}/);
|
||
assert.match(clicks, /name === "direct-search-similar"[\s\S]*runDirectDiscoveryAction\("search-similar-accounts"/);
|
||
assert.match(clicks, /name === "direct-save-benchmark-link"[\s\S]*const account = getSelectedAccount\(\);/);
|
||
assert.match(clicks, /name === "direct-save-benchmark-link"[\s\S]*if \(!account\?\.id\) \{[\s\S]*openBenchmarkLinkAction\(\);[\s\S]*return;[\s\S]*\}/);
|
||
assert.match(clicks, /name === "direct-save-benchmark-link"[\s\S]*if \(!candidate\) \{[\s\S]*openBenchmarkLinkAction\(\);[\s\S]*return;[\s\S]*\}/);
|
||
assert.match(clicks, /name === "direct-save-benchmark-link"[\s\S]*runDirectDiscoveryAction\("save-benchmark-link"/);
|
||
});
|
||
|
||
test("declared static workbench actions are wired into explicit handlers", () => {
|
||
const declared = new Set([...APP.matchAll(/data-action="([a-zA-Z0-9_-]+)"/g)].map((match) => match[1]));
|
||
const clickHandled = new Set([...APP.matchAll(/if \(name === "([a-zA-Z0-9_-]+)"\)/g)].map((match) => match[1]));
|
||
const knownNonClick = new Set(["submit-auth", "submit-oneliner", "submit-sheet", "close-sheet", "close-auth", "close-oneliner", "discovery-query", "refresh-data"]);
|
||
const missing = [...declared].filter((name) => !clickHandled.has(name) && !knownNonClick.has(name)).sort();
|
||
assert.deepEqual(missing, []);
|
||
});
|