Files
deer-flow/frontend/tests/unit/core/threads/thread-search-query.test.ts
T
Ryker_FengandGitHub 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

74 lines
2.0 KiB
TypeScript

import { expect, test, rs } from "@rstest/core";
import {
buildThreadsSearchQueryOptions,
DEFAULT_THREAD_SEARCH_PARAMS,
THREAD_SEARCH_REFETCH_INTERVAL_MS,
} from "@/core/threads/thread-search-query";
import type { AgentThread } from "@/core/threads/types";
function makeThread(
threadId: string,
metadata: Record<string, unknown> = {},
): AgentThread {
return {
thread_id: threadId,
created_at: "2025-01-01T00:00:00Z",
updated_at: "2025-01-01T00:00:00Z",
metadata,
status: "idle",
values: { title: threadId, messages: [] },
} as unknown as AgentThread;
}
test("thread search query refreshes so IM-created sessions appear in the sidebar", () => {
const search = rs.fn();
const options = buildThreadsSearchQueryOptions(
{ threads: { search } },
DEFAULT_THREAD_SEARCH_PARAMS,
);
expect(options.refetchInterval).toBe(THREAD_SEARCH_REFETCH_INTERVAL_MS);
expect(options.refetchIntervalInBackground).toBe(false);
expect(options.refetchOnWindowFocus).toBe(false);
});
test("thread search hides sidecar threads from primary lists by default", async () => {
const search = rs
.fn()
.mockResolvedValue([
makeThread("primary-1"),
makeThread("sidecar-1", { deerflow_sidecar: true }),
makeThread("primary-2"),
]);
const options = buildThreadsSearchQueryOptions(
{ threads: { search } },
DEFAULT_THREAD_SEARCH_PARAMS,
);
await expect(options.queryFn()).resolves.toEqual([
makeThread("primary-1"),
makeThread("primary-2"),
]);
});
test("thread search can explicitly include sidecar threads for parent lookup", async () => {
const sidecar = makeThread("sidecar-1", {
deerflow_sidecar: true,
parent_thread_id: "parent-1",
});
const search = rs.fn().mockResolvedValue([sidecar]);
const options = buildThreadsSearchQueryOptions(
{ threads: { search } },
{
...DEFAULT_THREAD_SEARCH_PARAMS,
metadata: {
deerflow_sidecar: true,
parent_thread_id: "parent-1",
},
},
);
await expect(options.queryFn()).resolves.toEqual([sidecar]);
});