Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
5 changes: 4 additions & 1 deletion examples/personal-workspace-browser/goal-suggestions.mjs
Original file line number Diff line number Diff line change
Expand Up @@ -130,7 +130,10 @@ export const goalSuggestionsScenario = {
await other.getByTestId("goal-vitals").waitFor({ state: "visible", timeout: 15_000 });
const vitals = (await other.getByTestId("goal-vitals").innerText()).replace(/\s+/g, " ");
assert.match(vitals, /0 等你决定|可选/, `the lane shows the item as optional: ${vitals}`);
assert.match(vitals, /已列出 5 项中的 0 项/, `the lane shows the partial listing truthfully: ${vitals}; listed: ${(await other.locator(".goal-overview").innerText().catch(() => "")).replace(/\s+/g, " ").slice(0, 400)}`);
// The work vital marks its unknown total; its help carries the partial counts.
await other.getByTestId("goal-vitals").getByRole("button", { name: "工作 · 总数未知", exact: true }).focus();
await other.getByRole("tooltip").getByText(/已列出 5 项中的 0 项/).waitFor();
await other.keyboard.press("Escape");
await other.getByRole("navigation", { name: "Goal 视图" }).getByRole("button", { name: "对话", exact: true }).click();
const otherSummary = other.locator(".personal-composer-tools > summary");
await otherSummary.waitFor({ state: "visible", timeout: 15_000 });
Expand Down
8 changes: 7 additions & 1 deletion examples/personal-workspace-browser/goal-workspace-m2.mjs
Original file line number Diff line number Diff line change
Expand Up @@ -152,7 +152,10 @@ export const goalWorkspaceM2Scenario = {
await page.setViewportSize({width:1440,height:1000});
const expandStart = performance.now();
for (const summary of await now.locator('.goal-work-more > summary').all()) {await summary.focus();await page.keyboard.press('Enter');}
assert.equal(await now.locator('.goal-owner-group [data-todo-id]:visible').count(),200,"All work remains reachable in the original owner order");
// Each toggle renders asynchronously; the budget below covers all of them.
const visibleWork = () => now.locator('.goal-owner-group [data-todo-id]:visible').count();
for (const deadline = Date.now() + 5000; await visibleWork() !== 200 && Date.now() < deadline;) await page.waitForTimeout(50);
assert.equal(await visibleWork(),200,"All work remains reachable in the original owner order");
const expandMs = performance.now() - expandStart;
assert.ok(expandMs < 2000, `Full 200-item expansion exceeded 2s budget: ${expandMs}ms`);
await now.getByRole('button',{name:'关系图',exact:true}).click();
Expand Down Expand Up @@ -257,6 +260,9 @@ async function verifyRemoteSelection(browser, url) {
assert.equal(await observation.getByText('Archived totals have not been independently reconciled.',{exact:true}).count(),0,"Wrong-Goal observations never survive a refresh");
await page.getByRole('button',{name:'Goal 信息',exact:true}).click();
const unavailableDrawer = page.locator('.personal-context-drawer');
// Opening moves focus to the drawer title on the next frame; focusing the
// help first would let that handoff blur and dismiss its tooltip.
await page.waitForFunction(() => document.activeElement?.id === 'personal-drawer-title');
await unavailableDrawer.getByRole('button',{name:'验收观察未获取',exact:true}).focus();
await page.getByRole('tooltip').getByText('验收观测不可用,Goal 是否达成仍未知。',{exact:true}).waitFor();
await page.keyboard.press('Escape');
Expand Down
16 changes: 12 additions & 4 deletions examples/personal-workspace-browser/managed_agent_fixture.py
Original file line number Diff line number Diff line change
Expand Up @@ -2,21 +2,29 @@
from __future__ import annotations

import json
import os
from pathlib import Path
import runpy
import socket
import sys
import tempfile
import threading

import pytest

REPO = Path(__file__).resolve().parents[2]
sys.path[:0] = [str(REPO), str(REPO / "tests/control_plane")]
from canonical_authority_fixture import isolate_sqlite_runtime, promoted_create_fixture
from loopx.chat_server import serve_chat


class ProcessPatch:
"""This fixture owns its process; the browser lane installs no test extras."""
setattr = staticmethod(setattr)

@staticmethod
def setenv(name: str, value: str) -> None:
os.environ[name] = value


class SyntheticManagedSource:
transport_ref = "synthetic-managed"
cancelled = staticmethod(lambda: False)
Expand Down Expand Up @@ -84,8 +92,8 @@ def calls(self):
return [json.loads(line) for line in path.read_text().splitlines()] if path.exists() else []


with tempfile.TemporaryDirectory(prefix="loopx-managed-ui-") as directory, pytest.MonkeyPatch.context() as patch:
root = Path(directory)
with tempfile.TemporaryDirectory(prefix="loopx-managed-ui-") as directory:
root, patch = Path(directory), ProcessPatch
isolate_sqlite_runtime(root, patch)
patch.setenv("CODEX_HOME", str(root / "synthetic-model-home"))
registry, _, _ = promoted_create_fixture(root, provider="sqlite", goal_id="product-release", registered_agents=["worker", "peer"])
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -117,7 +117,10 @@ export const researchFindingReaderScenario = {
assert.equal(await group.locator("h4").innerText(), "合成研究:质量、延迟和未知成本应如何一起判断?");
assert.match(await group.locator("header").innerText(), /20 条决策记录.*已反驳 3.*暂定结论 4/s);
const decisions = group.locator(".research-trail-list button");
if (width === 1440) assert.equal(await decisions.count(), 3, "A question starts with three records, not repeated title cards");
// Returning from an older finding expands its question to that exact
// decision; research-history owns the default three-record view.
if (width === 1440) assert.ok(await decisions.evaluateAll(nodes => nodes.some(node => node === document.activeElement
&& /比较 2:/.test(node.getAttribute("aria-label") ?? ""))), "Returning keeps the decision just read in view and focused");
await group.scrollIntoViewIfNeeded();
await page.screenshot({path: resolve(outputDir, `research-decision-groups-${width}.png`), animations: "disabled"});
const older = decisions.nth(1);
Expand Down
Loading