deer-flow/frontend/tests/unit/core/threads/send-message.test.ts
Ryker_Feng 6a4e5a3bb2
feat(frontend): add side conversations for quoted follow-ups (#3934)
* feat(frontend): add side conversations for quoted follow-ups

* style(frontend): apply prettier formatting to sidecar-chat files

* fix(frontend): surface sidecar cascade cleanup failures via console.warn

Previously deleteSidecarThreadsForParent silently swallowed both
lookup errors and per-thread deletion failures, so parent thread
deletions could succeed while orphaning sidecar threads with no
signal to the caller. Log a warning that includes the parent id
and the failed thread ids/reasons so the leak is discoverable in
telemetry, matching the existing console.warn/error pattern in
this file.

* fix(frontend): address all sidecar review feedback

Resolve every reviewer comment on PR #3934:

- input-box/hooks/sidecar-panel: clear quoted references only via an
  `onSent` callback that fires after the in-flight guard, so a dropped
  send no longer silently discards quotes (willem-bd #3550).
- message-list: flip the selection toolbar below the selection when it
  would clip above the viewport (willem-bd #3551).
- reference-metadata/thread/input-box: keep referenced ids, roles, and
  count arrays 1:1 parallel instead of deduping ids (willem-bd #3552).
- message-list: widen selection containment to the shared assistant-turn
  container and hint when a selection crosses messages (willem-bd #3553).
- sidecar/api: coalesce concurrent sidecar creates for one parent behind
  a single in-flight promise to prevent duplicates (willem-bd #3554).
- sidecar-trigger/context: force-restore on trigger click so a sidecar
  deleted elsewhere self-heals instead of opening a dead thread
  (willem-bd #3555).
- threads/hooks: surface sidecar cascade cleanup failures via
  console.warn for both lookup and per-thread deletes (Copilot).

Add unit + e2e coverage for parallel metadata, atomic create, and
trigger self-healing.
2026-07-05 00:12:16 +08:00

63 lines
1.5 KiB
TypeScript

import type { Message } from "@langchain/langgraph-sdk";
import { expect, test } from "@rstest/core";
import { buildThreadSubmitMessages } from "@/core/threads/hooks";
test("builds thread submit messages with hidden sidecar context before the visible user message", () => {
const hiddenContext = {
type: "human",
content: "Hidden sidecar context",
additional_kwargs: {
hide_from_ui: true,
sidecar_context: true,
},
} as Message;
const messages = buildThreadSubmitMessages({
text: "What should we do next?",
additionalInputMessages: [hiddenContext],
});
expect(messages).toEqual([
hiddenContext,
{
type: "human",
content: [{ type: "text", text: "What should we do next?" }],
additional_kwargs: {},
},
]);
});
test("keeps uploaded files on the visible user message only", () => {
const messages = buildThreadSubmitMessages({
text: "Use this file",
additionalInputMessages: [
{
type: "human",
content: "Hidden sidecar context",
additional_kwargs: { hide_from_ui: true },
} as Message,
],
filesForSubmit: [
{
filename: "report.pdf",
size: 42,
path: "/uploads/report.pdf",
status: "uploaded",
},
],
});
expect(messages[0]?.additional_kwargs).toEqual({ hide_from_ui: true });
expect(messages[1]?.additional_kwargs).toEqual({
files: [
{
filename: "report.pdf",
size: 42,
path: "/uploads/report.pdf",
status: "uploaded",
},
],
});
});