Files
Artemis-Eapil/apps/showcase_ui/src/app/components/plugin-tool-result/plugin-tool-result.component.spec.ts
T
chenmingxuan fac4ccb760 feat: prepare 2.2.0 with UI and execution fixes
Add dark theme, richer Markdown and readable plugin results.
Improve Android input evidence, response integrity and diagnostics.
Unify lifecycle, guidance receipts and evidence sources across clients.
Keep direct action dispatch without an added AI quota approval layer.
Align version metadata at 2.2.0 and bundle Helper 1.2.2.

Validation: 3063 backend tests before the version bump; 44 after.
Frontend: 317 tests and production build passed.
2026-10-26 00:44:13 +08:00

69 lines
3.5 KiB
TypeScript
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
import { TestBed } from '@angular/core/testing';
import { PluginToolResultComponent } from './plugin-tool-result.component';
import { PluginToolView } from '../../utils/plugin-tool-view.util';
describe('readable plugin receipts', () => {
const makeView = (result: string): PluginToolView => ({
title: '观察电脑窗口', kind: '辅助观察', auxiliary: true, status: '已执行', args: [],
result, rawResult: JSON.stringify({ result, call_id: 'original-call' }, null, 2),
facts: [{ key: '窗口', value: 'Demo' }, { key: '截图', value: '1280 × 720' }]
});
const mount = async (view: PluginToolView) => {
await TestBed.configureTestingModule({ imports: [PluginToolResultComponent] }).compileComponents();
const fixture = TestBed.createComponent(PluginToolResultComponent);
fixture.componentRef.setInput('view', view);
fixture.detectChanges();
return fixture;
};
it('keeps a long control tree and the original payload folded and fully accessible', async () => {
const fullText = Array.from({ length: 200 }, (_, i) => `- [${i}] Button "Item ${i}"`).join('\n');
const view = makeView(fullText);
const fixture = await mount(view);
const root: HTMLElement = fixture.nativeElement;
expect(root.querySelector('dl')!.textContent).toContain('1280 × 720');
expect(root.querySelector('.receipt-preview')!.textContent!.length).toBeLessThan(1100);
const textDetails = root.querySelector<HTMLDetailsElement>('.receipt-text')!;
const rawDetails = root.querySelector<HTMLDetailsElement>('.receipt-raw')!;
expect(textDetails.open).toBeFalse();
expect(rawDetails.open).toBeFalse();
textDetails.querySelector('summary')!.click();
expect(textDetails.open).toBeTrue();
expect(textDetails.querySelector('pre')!.textContent).toBe(fullText);
expect(rawDetails.querySelector('pre')!.textContent).toBe(view.rawResult);
});
it('renders untrusted tool text as text and keeps short results readable', async () => {
const text = '<img src=x onerror="alert(1)">\n已观察,未验证业务结果';
const fixture = await mount(makeView(text));
const root: HTMLElement = fixture.nativeElement;
expect(root.querySelector('.receipt-preview')!.textContent).toBe(text);
expect(root.querySelector('img')).toBeNull();
expect(root.querySelector('.receipt-text')).toBeNull();
});
it('reflects a new receipt without resetting an open raw payload', async () => {
const fixture = await mount(makeView('执行中'));
const raw = fixture.nativeElement.querySelector('.receipt-raw') as HTMLDetailsElement;
raw.querySelector('summary')!.click();
fixture.componentRef.setInput('view', makeView('已返回新的窗口观察'));
fixture.detectChanges();
expect(raw.open).toBeTrue();
expect(fixture.nativeElement.querySelector('.receipt-preview').textContent).toBe('已返回新的窗口观察');
expect(raw.querySelector('pre')!.textContent).toContain('已返回新的窗口观察');
});
it('keeps long window labels and unbroken receipt text inside a narrow container', async () => {
const view = makeView('long-unbroken-result'.repeat(200));
view.facts[0].value = 'VeryLongWindowTitle'.repeat(30);
const fixture = await mount(view);
const root = fixture.nativeElement as HTMLElement;
root.style.width = '240px';
fixture.detectChanges();
expect(root.clientWidth).toBe(240);
expect(root.scrollWidth).toBeLessThanOrEqual(root.clientWidth);
const label = root.querySelector('dd')!;
expect(label.scrollWidth).toBeLessThanOrEqual(label.clientWidth);
});
});