fix(coding): preserve renderer recovery state
This commit is contained in:
@@ -194,6 +194,46 @@ describe('coding Conversation store', () => {
|
||||
expect(store.getState().entriesByConversationId['conversation-b'].reducer.invalidation).toBeNull();
|
||||
});
|
||||
|
||||
it('replays target patches that arrive while a gap snapshot is loading', async () => {
|
||||
const recovery = deferred<ConversationSnapshot>();
|
||||
const getSnapshot = vi.fn(() => recovery.promise);
|
||||
const store = createCodingConversationStore({
|
||||
getSnapshot,
|
||||
openEvents: vi.fn(),
|
||||
submitPrompt: vi.fn(),
|
||||
createId: ids(),
|
||||
});
|
||||
store.getState().applySnapshotEvent(snapshotEvent(snapshot('conversation-a')));
|
||||
|
||||
store.getState().applyPatchEvent(patchEvent('conversation-a', 2, {
|
||||
op: 'run.state',
|
||||
run: { status: 'running', runId: 'run-gap' },
|
||||
}));
|
||||
store.getState().applyPatchEvent(patchEvent('conversation-a', 3, {
|
||||
op: 'run.state',
|
||||
run: {
|
||||
status: 'error',
|
||||
runId: 'run-gap',
|
||||
terminalReason: 'failed',
|
||||
},
|
||||
}));
|
||||
recovery.resolve({
|
||||
...snapshot('conversation-a', 1, 2),
|
||||
run: { status: 'running', runId: 'run-gap' },
|
||||
});
|
||||
|
||||
await waitFor(() => {
|
||||
expect(selectCodingConversationSnapshot('conversation-a')(store.getState()))
|
||||
.toMatchObject({
|
||||
cursor: { workerGeneration: 1, seq: 3 },
|
||||
run: { status: 'error', runId: 'run-gap', terminalReason: 'failed' },
|
||||
});
|
||||
});
|
||||
expect(getSnapshot).toHaveBeenCalledTimes(1);
|
||||
expect(store.getState().entriesByConversationId['conversation-a'].reducer.invalidation)
|
||||
.toBeNull();
|
||||
});
|
||||
|
||||
it('uses native EventSource reconnect without reopening or replaying a mutation', async () => {
|
||||
const source = new FakeEventSource();
|
||||
const openEvents = vi.fn(async () => source as unknown as EventSource);
|
||||
@@ -276,6 +316,9 @@ describe('coding Conversation store', () => {
|
||||
await submission;
|
||||
expect(store.getState().requestsByConversationId['conversation-a']['request-1'].status)
|
||||
.toBe('accepted');
|
||||
store.getState().applySnapshotEvent(snapshotEvent(snapshot('conversation-a')));
|
||||
expect(selectCodingConversationSnapshot('conversation-a')(store.getState())?.nodes[0])
|
||||
.toMatchObject({ id: 'node-1', clientRequestId: 'request-1', status: 'optimistic' });
|
||||
store.getState().applyPatchEvent(patchEvent('conversation-a', 1, {
|
||||
op: 'message.upsert',
|
||||
node: {
|
||||
@@ -350,6 +393,7 @@ describe('coding Conversation store', () => {
|
||||
})).rejects.toThrow('Delivery is uncertain');
|
||||
source.fail();
|
||||
source.open();
|
||||
source.emit('snapshot', snapshotEvent(snapshot('conversation-a')));
|
||||
|
||||
expect(store.getState().draftsByConversationId['conversation-a'].text).toBe('Do not replay');
|
||||
expect(store.getState().requestsByConversationId['conversation-a']['request-1'])
|
||||
|
||||
Reference in New Issue
Block a user