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.
69 lines
3.5 KiB
TypeScript
69 lines
3.5 KiB
TypeScript
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);
|
||
});
|
||
});
|