openAgentAndFileContext.test.tsx3.9 KBView on GitHub import React from 'react';
import { render, screen } from '@testing-library/react';
import { ContextBadgeRow } from '@/modules/cedar-os/src/cedar-os-components/chatInput/ContextBadgeRow';
import { useCedarStore } from '@/modules/cedar-os/src/store/CedarStore';
/**
* The two things the chat had no way of knowing: WHICH agent workspace is on screen, and
* WHICH file is open inside it.
*
* Before this, opening a file from a file browser (the agent's Output tab, a deal's Files
* tab, the Brain explorer) published nothing at all, and an agent workspace published
* nothing anywhere — so a question asked while looking at both arrived with neither.
*/
function seed(over: Record<string, unknown> = {}) {
useCedarStore.setState((state) => ({
...state,
activeConversationId: null,
conversationSelection: [],
conversations: {},
isThreadOpen: false,
isConversationOpen: false,
selectedThreadId: null,
threadData: {},
mainThreadId: 'main',
threadMap: { main: { id: 'main', name: 'Main', messages: [] } },
additionalContext: {},
chatContextVisibility: {},
excludedManualContextKeys: new Set<string>(),
docSelectedText: null,
openChannelThread: null,
teachModeAgentContext: null,
activeCanvasId: null,
currentConversationList: [],
openAgent: { agentId: 'agent_1', name: 'Meeting prep', avatar: null },
activeDoc: {
path: 'user/agent-agent_1/overview',
documentId: 'doc_1',
title: 'Overview',
documentType: 'document',
},
...over,
}));
}
const wire = () =>
useCedarStore.getState().buildMergedContextForMailSendMessage() as unknown as Record<
string,
{ data: unknown } | undefined
>;
describe('the open agent and the open file, as context', () => {
it('puts both on the wire as pointers', () => {
seed();
const ctx = wire();
expect(ctx.openAgentId).toEqual({ data: 'agent_1' });
expect(ctx.openAgentName).toEqual({ data: 'Meeting prep' });
expect(ctx.activeDocPath).toEqual({ data: 'user/agent-agent_1/overview' });
// The id is what `manage-context` attaches a file by — a path is not an id.
expect(ctx.activeDocId).toEqual({ data: 'doc_1' });
expect(ctx.activeDocTitle).toEqual({ data: 'Overview' });
expect(ctx.activeDocDocumentType).toEqual({ data: 'document' });
});
it('draws a badge for each, the agent ahead of the file it contains', () => {
seed();
render(<ContextBadgeRow />);
const agent = screen.getByLabelText('Selected agent Meeting prep');
const file = screen.getByLabelText('Selected document Overview');
// Reading order matches the nesting on screen: the file is inside the agent.
expect(agent.compareDocumentPosition(file) & Node.DOCUMENT_POSITION_FOLLOWING).toBeTruthy();
});
it('falls back to the path when the surface knows no title', () => {
seed({ activeDoc: { path: 'user/files/q3-pipeline.md' } });
render(<ContextBadgeRow />);
expect(screen.getByLabelText('Selected document Q3 Pipeline')).toBeInTheDocument();
});
it('dismissing a badge takes its context off the wire too', () => {
seed();
useCedarStore.getState().setBadgeVisible('agent', false);
useCedarStore.getState().setBadgeVisible('document', false);
const ctx = wire();
expect(ctx.openAgentId).toBeUndefined();
expect(ctx.activeDocPath).toBeUndefined();
});
it('stands the file badge down once the file is committed to the thread', () => {
seed({
threadMap: {
main: {
id: 'main',
name: 'Main',
messages: [],
chatContext: { items: [{ kind: 'file', id: 'doc_1', label: 'Overview' }] },
},
},
});
render(<ContextBadgeRow />);
// ChatContextRow already draws it, hydrated in full — one file, one chip.
expect(screen.queryByLabelText('Selected document Overview')).toBeNull();
expect(screen.getByLabelText('Selected agent Meeting prep')).toBeInTheDocument();
});
});