agenticTable.test.ts5.0 KBView on GitHub /**
* "Agentic Table" — the /agent home pill that creates something.
*
* The thing under test is that NOTHING the user sees waits on the network. The click used to
* block on two sequential writes (~3.5s measured) before a pixel moved; now the id is minted
* client-side and the whole visible result lands synchronously while one write goes out behind
* it. So these assertions run BEFORE the create promise is allowed to settle — that is the
* point, not an accident of the harness.
*/
import { useCedarStore } from '@/modules/store';
import {
NEW_CHAT_ARTIFACT_INTROS,
type CreatedChatNode,
} from '@/modules/files/chat/newChatArtifact';
import {
AGENTIC_TABLE_NAME,
startAgenticTable,
} from '@/modules/home/components/agentic-table';
/** The server's row, as the create route returns it. */
function serverNode(id: string, over: Partial<CreatedChatNode> = {}): CreatedChatNode {
return {
id,
orgId: 'org_1',
userId: 'user_1',
parentId: 'folder_1',
documentType: 'table',
path: 'user/chats/t/untitled-table',
title: AGENTIC_TABLE_NAME,
description: null,
content: '',
lastEditedBy: 'human',
version: 1,
wordCount: null,
lastOpened: null,
createdAt: new Date(),
updatedAt: new Date(),
...over,
};
}
/** A create that never settles, so every assertion below is about the synchronous tick. */
function pendingCreate() {
const calls: Array<Record<string, unknown>> = [];
const createTable = jest.fn(async (input: Record<string, unknown>) => {
calls.push(input);
return new Promise<CreatedChatNode>(() => {});
});
return { createTable, calls };
}
beforeEach(() => {
const store = useCedarStore.getState();
store.createThread('thread-before', 'Before');
store.switchThread('thread-before');
});
describe('startAgenticTable', () => {
it('opens the chat, the table and the intro without awaiting anything', () => {
const { createTable } = pendingCreate();
const before = useCedarStore.getState().mainThreadId;
const { documentId, threadId } = startAgenticTable({ createTable, onFailed: jest.fn() });
const state = useCedarStore.getState();
// A NEW thread, looking at the new table — and the chat the user came from untouched.
expect(state.mainThreadId).toBe(threadId);
expect(state.mainThreadId).not.toBe(before);
expect(state.threadMap[threadId]?.selectedArtifact).toEqual({ kind: 'file', id: documentId });
expect(state.threadMap[before]?.selectedArtifact).toBeFalsy();
// The intro is the thread's first message.
const messages = state.threadMap[threadId]?.messages ?? [];
expect(messages).toHaveLength(1);
expect(messages[0]).toMatchObject({ role: 'assistant', type: 'text' });
expect(messages[0]!.content).toBe(NEW_CHAT_ARTIFACT_INTROS.table);
// Still in flight — nothing above waited for it.
expect(createTable).toHaveBeenCalledTimes(1);
});
it('registers the document as a TABLE up front, so the panel never mounts the prose editor', () => {
const { createTable } = pendingCreate();
const { documentId, threadId } = startAgenticTable({ createTable, onFailed: jest.fn() });
const meta = useCedarStore.getState().getDocumentMeta(documentId);
expect(meta?.documentType).toBe('table');
// `isOptimistic` is what holds the grid back until the row is real — without it the grid's
// Y provider seeds from a 404 and leaves a blank, unsavable table.
expect(meta?.isOptimistic).toBe(true);
expect(meta?.path).toBe(`user/chats/${threadId}/${AGENTIC_TABLE_NAME}`);
});
it('sends the client-minted id and the thread it belongs to, in one call', () => {
const { createTable, calls } = pendingCreate();
const { documentId, threadId } = startAgenticTable({ createTable, onFailed: jest.fn() });
expect(calls).toHaveLength(1);
expect(calls[0]).toMatchObject({ id: documentId, threadId, name: AGENTIC_TABLE_NAME });
});
it('drops the optimistic document and reports when the write fails', async () => {
const onFailed = jest.fn();
const createTable = jest.fn(async () => {
throw new Error('nope');
});
const { documentId, created } = startAgenticTable({ createTable, onFailed });
// Present the moment the click happens...
expect(useCedarStore.getState().getDocumentMeta(documentId)).toBeDefined();
await created;
// ...and gone once the write is known to have failed, rather than left as a grid whose
// every edit would retry forever against a row that does not exist.
expect(useCedarStore.getState().getDocumentMeta(documentId)).toBeUndefined();
expect(onFailed).toHaveBeenCalledWith(expect.any(Error));
});
it('replaces the placeholder with the server row on success', async () => {
const createTable = jest.fn(async (input: { id: string }) => serverNode(input.id));
const { documentId, created } = startAgenticTable({ createTable, onFailed: jest.fn() });
await created;
expect(useCedarStore.getState().getDocumentMeta(documentId)?.isOptimistic).toBe(false);
});
});