1import { describe, expect, it } from "vite-plus/test";
2
3import {
4 isBaseThreadRoute,
5 resolveFileSelectionNavigationAction,
6 resolveThreadSelectionNavigationAction,
7 resolveThreadSelectionOverlayState,
8} from "./adaptive-navigation";
9
10describe("isBaseThreadRoute", () => {
11 it("recognizes only the thread detail route", () => {
12 expect(isBaseThreadRoute("/threads/environment/thread")).toBe(true);
13 expect(isBaseThreadRoute("/threads/environment/thread/")).toBe(true);
14 expect(isBaseThreadRoute("/threads/environment/thread/files")).toBe(false);
15 expect(isBaseThreadRoute("/threads/environment/thread/review")).toBe(false);
16 });
17});
18
19describe("resolveThreadSelectionNavigationAction", () => {
20 it("updates params when a persistent sidebar selects a peer thread", () => {
21 expect(
22 resolveThreadSelectionNavigationAction({
23 usesSplitView: true,
24 pathname: "/threads/environment/thread",
25 }),
26 ).toBe("set-params");
27 });
28
29 it("replaces nested thread content when a persistent sidebar selects a peer", () => {
30 expect(
31 resolveThreadSelectionNavigationAction({
32 usesSplitView: true,
33 pathname: "/threads/environment/thread/files/path",
34 }),
35 ).toBe("replace");
36 });
37
38 it("pushes from Home so the back stack survives collapsing to compact", () => {
39 expect(
40 resolveThreadSelectionNavigationAction({
41 usesSplitView: true,
42 pathname: "/",
43 }),
44 ).toBe("push");
45 });
46
47 it("pushes compact list selections onto the native stack", () => {
48 expect(
49 resolveThreadSelectionNavigationAction({
50 usesSplitView: false,
51 pathname: "/threads/environment/thread",
52 }),
53 ).toBe("push");
54 });
55});
56
57describe("resolveFileSelectionNavigationAction", () => {
58 it("replaces the wide file browser with the selected preview", () => {
59 expect(resolveFileSelectionNavigationAction({ hasPersistentFileInspector: true })).toBe(
60 "replace",
61 );
62 });
63
64 it("pushes a preview above the compact file browser", () => {
65 expect(resolveFileSelectionNavigationAction({ hasPersistentFileInspector: false })).toBe(
66 "push",
67 );
68 });
69});
70
71describe("resolveThreadSelectionOverlayState", () => {
72 const stack = {
73 key: "workspace",
74 type: "stack",
75 stale: false as const,
76 routeNames: ["Home", "Thread", "ThreadFiles", "SettingsSheet", "SettingsLegal"],
77 };
78 const home = { key: "home", name: "Home" };
79 const thread = {
80 key: "thread",
81 name: "Thread",
82 params: { environmentId: "environment", threadId: "old-thread" },
83 };
84 const files = { key: "files", name: "ThreadFiles", params: thread.params };
85 const settings = { key: "settings", name: "SettingsSheet" };
86 const params = { environmentId: "environment", threadId: "new-thread" };
87
88 it("replaces the underlying file route and dismisses every overlay above it", () => {
89 expect(
90 resolveThreadSelectionOverlayState({
91 state: {
92 ...stack,
93 index: 4,
94 routes: [home, thread, files, settings, { key: "legal", name: "SettingsLegal" }],
95 },
96 workspaceRouteKey: files.key,
97 action: "replace",
98 params,
99 }),
100 ).toEqual({ ...stack, index: 2, routes: [home, thread, { name: "Thread", params }] });
101 });
102
103 it("dismisses an overlay when selecting the current thread without replacing its route key", () => {
104 expect(
105 resolveThreadSelectionOverlayState({
106 state: { ...stack, index: 2, routes: [home, thread, settings] },
107 workspaceRouteKey: thread.key,
108 action: "set-params",
109 params: thread.params,
110 }),
111 ).toEqual({ ...stack, index: 1, routes: [home, thread] });
112 });
113
114 it.each([home, files])(
115 "keeps $name in the back stack when pushing from beneath a sheet",
116 (route) => {
117 expect(
118 resolveThreadSelectionOverlayState({
119 state: { ...stack, index: 1, routes: [route, settings] },
120 workspaceRouteKey: route.key,
121 action: "push",
122 params,
123 }),
124 ).toEqual({ ...stack, index: 1, routes: [route, { name: "Thread", params }] });
125 },
126 );
127
128 it("leaves ordinary thread selection alone when no overlay is present", () => {
129 expect(
130 resolveThreadSelectionOverlayState({
131 state: { ...stack, index: 2, routes: [home, thread, files] },
132 workspaceRouteKey: files.key,
133 action: "replace",
134 params,
135 }),
136 ).toBeNull();
137 });
138});