mirror of
https://github.com/nexu-io/open-design.git
synced 2026-06-01 03:14:35 +07:00
* feat(web): queue chat sends * feat(web): render code comment directives * feat(web): add preview comments and manual edits * fix(web): polish shared chrome controls * fix(web): align queued send loading state * feat(web): open primary project artifacts * fix(web): keep queued sends and tests aligned * fix(web): restore docked comment tools layout * fix(web): align preview comment toolbar * fix(web): place local cli beside handoff * fix(web): move agent menu beside handoff * fix(web): make project instructions a direct header action * fix(web): compact handoff and toolbar labels * fix(web): clarify handoff menu and annotation label * fix(web): restore compact cursor handoff trigger * fix(web): align agent menu trigger with handoff * fix(web): add draw toolbar close action * fix(web): move inspect editing into edit mode * fix(web): avoid reserving comment sidebar in annotation mode * fix(web): float preview comments panel * fix(web): keep edit canvas full width * fix(web): polish preview annotation tools * fix(web): highlight active preview comments * fix(web): open comments panel after annotation save * fix(web): polish comment handoff controls * fix(web): remove palette preview tool * fix(web): simplify draw annotation toolbar * fix(web): restore queued tasks into composer * fix(web): restore queued send strip styling * fix(web): hide internal comment target ids * fix(web): align manual edit panel header * test(web): cover visual interaction contracts * fix(web): address PR feedback regressions * fix(web): preserve artifact chrome state * fix(daemon): restore project raw file routes --------- Co-authored-by: chaoxiaoche <chaoxiaoche@chaoxiaochedeMacBook-Pro.local> Co-authored-by: mrcfps <mrc@powerformer.com>
86 lines
2.6 KiB
TypeScript
86 lines
2.6 KiB
TypeScript
// @vitest-environment jsdom
|
||
|
||
import { cleanup, fireEvent, render, screen, within } from '@testing-library/react';
|
||
import { afterEach, describe, expect, it, vi } from 'vitest';
|
||
|
||
import { BoardComposerPopover } from '../../src/components/BoardComposerPopover';
|
||
import type { PreviewCommentSnapshot } from '../../src/comments';
|
||
import type { PreviewCommentMember } from '../../src/types';
|
||
|
||
afterEach(() => {
|
||
cleanup();
|
||
});
|
||
|
||
function member(elementId: string, label = elementId): PreviewCommentMember {
|
||
return {
|
||
elementId,
|
||
selector: `#${elementId}`,
|
||
label,
|
||
text: '',
|
||
position: { x: 0, y: 0, width: 10, height: 10 },
|
||
htmlHint: '',
|
||
};
|
||
}
|
||
|
||
function podTarget(members: PreviewCommentMember[]): PreviewCommentSnapshot {
|
||
return {
|
||
filePath: 'index.html',
|
||
elementId: 'pod-1',
|
||
selector: '',
|
||
label: 'Pod',
|
||
text: '',
|
||
position: { x: 0, y: 0, width: 100, height: 60 },
|
||
htmlHint: '',
|
||
selectionKind: 'pod',
|
||
memberCount: members.length,
|
||
podMembers: members,
|
||
};
|
||
}
|
||
|
||
function renderPopover(overrides: {
|
||
target: PreviewCommentSnapshot;
|
||
onRemoveMember: (elementId: string) => void;
|
||
}) {
|
||
return render(
|
||
<BoardComposerPopover
|
||
target={overrides.target}
|
||
existing={null}
|
||
draft=""
|
||
notes={[]}
|
||
onDraft={() => {}}
|
||
onAddDraft={() => {}}
|
||
onRemoveQueuedNote={() => {}}
|
||
onClose={() => {}}
|
||
onSaveComment={() => {}}
|
||
onSendBatch={() => {}}
|
||
onRemoveMember={overrides.onRemoveMember}
|
||
sending={false}
|
||
t={((key: string) => String(key)) as never}
|
||
/>,
|
||
);
|
||
}
|
||
|
||
describe('BoardComposerPopover captured-component removal', () => {
|
||
it('calls onRemoveMember with the chip elementId when the chip × is clicked', () => {
|
||
const onRemoveMember = vi.fn();
|
||
renderPopover({
|
||
target: podTarget([member('alpha', 'Alpha'), member('beta', 'Beta')]),
|
||
onRemoveMember,
|
||
});
|
||
|
||
const alphaChip = screen.getByText('Alpha').closest('.board-pod-chip');
|
||
if (!alphaChip) throw new Error('Alpha chip not rendered');
|
||
fireEvent.click(within(alphaChip as HTMLElement).getByRole('button'));
|
||
|
||
expect(onRemoveMember).toHaveBeenCalledTimes(1);
|
||
expect(onRemoveMember).toHaveBeenCalledWith('alpha');
|
||
});
|
||
|
||
it('renders every captured chip so members beyond the sixth stay reachable', () => {
|
||
const members = Array.from({ length: 10 }, (_, i) => member(`m${i}`, `Member ${i}`));
|
||
renderPopover({ target: podTarget(members), onRemoveMember: () => {} });
|
||
|
||
expect(document.querySelectorAll('.board-pod-chip')).toHaveLength(10);
|
||
expect(screen.queryByText('Member 9')).not.toBeNull();
|
||
});
|
||
});
|