Skip to content

Commit 0c22b9b

Browse files
committed
test(agent-workspace): add language rerender stability evidence
1 parent 15c1fb8 commit 0c22b9b

4 files changed

Lines changed: 171 additions & 0 deletions

File tree

docs/brainstorms/2026-04-16-mainline-ci-stabilization-and-m7-direction-requirements.md

Lines changed: 20 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -194,6 +194,26 @@ Deliverables:
194194
- `docs/diataxis-map.json` mapping,
195195
- EN/ZH dashboard and roadmap references.
196196

197+
### M7.4 (Now): Language Rerender Stability Evidence (R8 Closure)
198+
199+
Deliverables:
200+
201+
- add explicit runtime behavior evidence for language rerender stability in agent workspace pane lifecycle context.
202+
- prove language switch keeps capability-card labels and pane labels coherent without introducing implementation-lane coupling.
203+
204+
#### M7.4 Progress Note (2026-04-16)
205+
206+
- [Done] expanded `src/agent_workspace.runtime.behavior.test.ts` with language-rerender regression scenario.
207+
- [Done] asserted language-change rerender for:
208+
- input placeholder text,
209+
- path fullscreen label in enter/exit fullscreen states,
210+
- knowledge-point card title tooltip and score label,
211+
- capability action label sourced via `labelKey`.
212+
- [Done] bounded change scope to test evidence only (no runtime logic mutation) to keep M7 reliability lane low-risk.
213+
- [Done] verification evidence:
214+
- `npm test -- src/agent_workspace.runtime.behavior.test.ts --runInBand`
215+
- `npm run test:agent-workspace:contracts`
216+
197217
## Success Criteria
198218

199219
- CI failure mode that previously blocked the three agent-workspace suites is eliminated on mainline.

docs/diataxis/en/explanation/development-progress-dashboard.md

Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -283,6 +283,21 @@ Execution anchor:
283283
- `npm run docs:diataxis:check && npm run docs:site:build`
284284
- Updated docs navigation and Diataxis map for stable web visibility.
285285

286+
## Latest Mainline Increment (2026-04-16 M7.4 Language Rerender Stability Lane)
287+
288+
- Added runtime behavior regression coverage for language-change rerender stability:
289+
- file: `src/agent_workspace.runtime.behavior.test.ts`
290+
- scope: focus/path pane coexistence context with active workspace cards.
291+
- Added explicit assertions for language-switch rerender targets:
292+
- agent input placeholder text,
293+
- path fullscreen button label in both fullscreen and non-fullscreen states,
294+
- knowledge point card affordances (card title tooltip, score label),
295+
- capability action label resolved by `labelKey`.
296+
- Kept implementation boundary unchanged (test-only increment) to avoid lane coupling while closing M7 `R8` evidence depth.
297+
- Verification evidence:
298+
- `npm test -- src/agent_workspace.runtime.behavior.test.ts --runInBand`
299+
- `npm run test:agent-workspace:contracts`
300+
286301
## Mainline vs Working-Branch Snapshot (2026-04-14)
287302

288303
| Capability Slice | Working Branch (`feat/learning-multi-tutor-adapter`) | Mainline (`origin/main`) | Integration Status |

docs/diataxis/zh/explanation/development-progress-dashboard.md

Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -285,6 +285,21 @@
285285
- `npm run docs:diataxis:check && npm run docs:site:build`
286286
- 已同步导航与 Diataxis 映射,保证文档页面稳定可访问。
287287

288+
## 主线最新增量(2026-04-16 M7.4 多语言重渲染稳定性链路)
289+
290+
- 已新增语言切换重渲染稳定性回归覆盖:
291+
- 文件:`src/agent_workspace.runtime.behavior.test.ts`
292+
- 场景:focus/path 并排上下文下的 agent workspace 卡片与 pane 标签重渲染。
293+
- 已新增语言切换后的关键断言:
294+
- 输入框 placeholder 文案重渲染,
295+
- path fullscreen 按钮在普通/全屏两态下的文案重渲染,
296+
- 知识点卡片可交互文案(title tooltip、score 标签)重渲染,
297+
- 基于 `labelKey` 的 capability action 文案重渲染。
298+
- 本增量保持实现边界不变(仅补测试证据),避免与其他 lane 耦合,同时补齐 M7 `R8` 证据面。
299+
- 验证证据:
300+
- `npm test -- src/agent_workspace.runtime.behavior.test.ts --runInBand`
301+
- `npm run test:agent-workspace:contracts`
302+
288303
## 主线 vs 工作分支快照(2026-04-14)
289304

290305
| 能力切片 | 工作分支(`feat/learning-multi-tutor-adapter`| 主线(`origin/main`| 集成状态 |

src/agent_workspace.runtime.behavior.test.ts

Lines changed: 121 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1361,4 +1361,125 @@ describe('agent workspace runtime behavior', () => {
13611361
const messages = document.getElementById('agent-workspace-messages') as HTMLElement;
13621362
expect(messages.textContent || '').toContain('read');
13631363
});
1364+
1365+
test('re-renders pane labels and capability cards on language change', async () => {
1366+
let language = 'en';
1367+
const languageListeners: Array<() => void> = [];
1368+
const dictionaries: Record<string, Record<string, string>> = {
1369+
en: {
1370+
'agentWorkspace.placeholders.input': 'Ask in English',
1371+
'agentWorkspace.actions.pathFullscreen': 'Path Fullscreen EN',
1372+
'agentWorkspace.actions.exitPathFullscreen': 'Exit Path Fullscreen EN',
1373+
'agentWorkspace.messages.clickPointToFocus': 'Click to focus EN',
1374+
'agentWorkspace.labels.score': 'Score EN',
1375+
'agentWorkspace.actions.openLearningPath': 'Open Learning Path EN',
1376+
},
1377+
zh: {
1378+
'agentWorkspace.placeholders.input': '请用中文提问',
1379+
'agentWorkspace.actions.pathFullscreen': '路径全屏 ZH',
1380+
'agentWorkspace.actions.exitPathFullscreen': '退出路径全屏 ZH',
1381+
'agentWorkspace.messages.clickPointToFocus': '点击进入专注 ZH',
1382+
'agentWorkspace.labels.score': '分数 ZH',
1383+
'agentWorkspace.actions.openLearningPath': '打开学习路径 ZH',
1384+
},
1385+
};
1386+
const i18nMock = {
1387+
t: jest.fn((key: string, params?: Record<string, unknown>) => {
1388+
const template = dictionaries[language]?.[key];
1389+
if (!template) {
1390+
return key;
1391+
}
1392+
return template.replace(/\{(\w+)\}/g, (_match, token) => {
1393+
const value = params && Object.prototype.hasOwnProperty.call(params, token)
1394+
? params[token]
1395+
: '';
1396+
return value == null ? '' : String(value);
1397+
});
1398+
}),
1399+
onLanguageChange: jest.fn((listener: () => void) => {
1400+
languageListeners.push(listener);
1401+
}),
1402+
};
1403+
(global as unknown as Record<string, unknown>).i18n = i18nMock;
1404+
((global as unknown as { window: { i18n?: unknown } }).window).i18n = i18nMock;
1405+
1406+
const fetchMock = jest.fn().mockResolvedValue({
1407+
ok: true,
1408+
status: 200,
1409+
json: async () => ({
1410+
success: true,
1411+
result: {
1412+
userId: 'agent_user_default',
1413+
message: 'Found 1 local knowledge point(s).',
1414+
knowledgePoints: [
1415+
{
1416+
atomId: 'atom-i18n-1',
1417+
title: 'I18N Candidate',
1418+
snippet: 'Language rerender coverage.',
1419+
score: 0.905,
1420+
capabilities: [
1421+
{
1422+
actionId: 'open_learning_path',
1423+
label: 'Learning Path',
1424+
labelKey: 'agentWorkspace.actions.openLearningPath',
1425+
request: {
1426+
userId: 'agent_user_default',
1427+
atomId: 'atom-i18n-1',
1428+
},
1429+
execution: {
1430+
kind: 'knowledge_operation',
1431+
operationId: 'build_learning_path',
1432+
resultPresentation: 'learning_path_card',
1433+
},
1434+
},
1435+
],
1436+
},
1437+
],
1438+
},
1439+
}),
1440+
});
1441+
(global as unknown as Record<string, unknown>).fetch = fetchMock;
1442+
1443+
const runtime = runtimeModule.createAgentWorkspaceRuntime({ defaultUserId: 'agent_user_default' });
1444+
runtime.init();
1445+
expect(i18nMock.onLanguageChange).toHaveBeenCalledTimes(1);
1446+
1447+
const input = document.getElementById('agent-workspace-input') as HTMLTextAreaElement;
1448+
const form = document.getElementById('agent-workspace-form') as HTMLFormElement;
1449+
input.value = 'language rerender';
1450+
form.dispatchEvent(new dom!.window.Event('submit', { bubbles: true, cancelable: true }));
1451+
await flushAsync();
1452+
1453+
runtime.openLearningPathDock('atom-i18n-1');
1454+
await flushAsync();
1455+
1456+
const pathFullscreenButton = document.getElementById('agent-workspace-path-fullscreen') as HTMLButtonElement;
1457+
expect(input.placeholder).toBe('Ask in English');
1458+
expect(pathFullscreenButton.textContent).toBe('Path Fullscreen EN');
1459+
runtime.togglePathFullscreen();
1460+
expect(pathFullscreenButton.textContent).toBe('Exit Path Fullscreen EN');
1461+
1462+
const pointCardEn = document.querySelector('.agent-workspace-point-card') as HTMLElement;
1463+
const pointMetaEn = document.querySelector('.agent-workspace-point-meta') as HTMLElement;
1464+
const actionButtonEn = document.querySelector('.agent-workspace-action-button') as HTMLButtonElement;
1465+
expect(pointCardEn.title).toBe('Click to focus EN');
1466+
expect(pointMetaEn.textContent || '').toContain('Score EN: 0.905');
1467+
expect(actionButtonEn.textContent).toBe('Open Learning Path EN');
1468+
1469+
language = 'zh';
1470+
languageListeners.forEach((listener) => listener());
1471+
await flushAsync();
1472+
1473+
const pointCardZh = document.querySelector('.agent-workspace-point-card') as HTMLElement;
1474+
const pointMetaZh = document.querySelector('.agent-workspace-point-meta') as HTMLElement;
1475+
const actionButtonZh = document.querySelector('.agent-workspace-action-button') as HTMLButtonElement;
1476+
expect(input.placeholder).toBe('请用中文提问');
1477+
expect(pathFullscreenButton.textContent).toBe('退出路径全屏 ZH');
1478+
expect(pointCardZh.title).toBe('点击进入专注 ZH');
1479+
expect(pointMetaZh.textContent || '').toContain('分数 ZH: 0.905');
1480+
expect(actionButtonZh.textContent).toBe('打开学习路径 ZH');
1481+
1482+
runtime.togglePathFullscreen();
1483+
expect(pathFullscreenButton.textContent).toBe('路径全屏 ZH');
1484+
});
13641485
});

0 commit comments

Comments
 (0)