Open History to see the last commit
1import * as NodeModule from "node:module";
2import { describe, expect, it } from "vite-plus/test";
3import {
4 draftRouteIdentity,
5 isDraftThreadRoute,
6 submittedThreadParams,
7} from "./thread-route-state";
8
9const requireNavigation = NodeModule.createRequire(
10 NodeModule.createRequire(import.meta.url).resolve("@react-navigation/native/package.json"),
11);
12const { StackRouter, CommonActions, StackActions } = requireNavigation(
13 "@react-navigation/routers",
14) as {
15 StackRouter: typeof import("@react-navigation/native").StackRouter;
16 CommonActions: typeof import("@react-navigation/native").CommonActions;
17 StackActions: typeof import("@react-navigation/native").StackActions;
18};
19
20describe("draft thread handoff", () => {
21 it("submits in the existing route and stops suppressing the live thread selection", () => {
22 const router = StackRouter({});
23 const options = { routeNames: ["Home", "Thread"], routeParamList: {}, routeGetIdList: {} };
24 const initial = router.getInitialState(options);
25 const draft = router.getStateForAction(
26 initial,
27 CommonActions.navigate("Thread", { draft: { projectId: "project" } }),
28 options,
29 )!;
30 if (!draft || draft.stale !== false) throw new Error("Draft route was not initialized");
31 expect(isDraftThreadRoute(draft.routes.at(-1))).toBe(true);
32 const submitted = router.getStateForAction(
33 draft,
34 CommonActions.setParams(submittedThreadParams("environment", "thread")),
35 options,
36 )!;
37 expect(submitted.routes.map((route) => route.key)).toEqual(
38 draft.routes.map((route) => route.key),
39 );
40 expect(submitted.index).toBe(draft.index);
41 expect(submitted.routes.at(-1)?.params).toEqual({
42 draft: undefined,
43 environmentId: "environment",
44 threadId: "thread",
45 });
46 expect(isDraftThreadRoute(submitted.routes.at(-1))).toBe(false);
47 });
48});
49
50describe("missing shared-content project recovery", () => {
51 it("replaces the stale draft before selecting the replacement project", () => {
52 const router = StackRouter({});
53 const options = {
54 routeNames: ["Home", "Thread", "NewTaskProject"],
55 routeParamList: {},
56 routeGetIdList: {},
57 };
58 const initial = router.getInitialState(options);
59 const staleDraft = router.getStateForAction(
60 initial,
61 CommonActions.navigate("Thread", {
62 draft: { environmentId: "environment", projectId: "deleted", incomingShareId: "share" },
63 }),
64 options,
65 )!;
66 if (staleDraft.stale !== false) throw new Error("Draft route was not initialized");
67 const picker = router.getStateForAction(
68 staleDraft,
69 StackActions.replace("NewTaskProject", { incomingShareId: "share" }),
70 options,
71 )!;
72 if (picker.stale !== false) throw new Error("Project picker was not initialized");
73 expect(picker.routes.some(isDraftThreadRoute)).toBe(false);
74 expect(picker.routes.at(-1)?.params).toEqual({ incomingShareId: "share" });
75 const recovered = router.getStateForAction(
76 picker,
77 CommonActions.navigate("Thread", {
78 draft: { environmentId: "environment", projectId: "replacement", incomingShareId: "share" },
79 }),
80 options,
81 )!;
82 expect(recovered.routes.filter(isDraftThreadRoute)).toHaveLength(1);
83 expect(recovered.routes.at(-1)?.params).toEqual({
84 draft: { environmentId: "environment", projectId: "replacement", incomingShareId: "share" },
85 });
86 });
87});
88
89describe("draft route identity", () => {
90 it("changes when a reused Thread route selects another draft or starts a new one", () => {
91 const draft = { environmentId: "env", projectId: "project", draftId: "a" };
92 expect(draftRouteIdentity(draft)).not.toBe(draftRouteIdentity({ ...draft, draftId: "b" }));
93 expect(draftRouteIdentity(draft)).not.toBe(
94 draftRouteIdentity({ ...draft, draftId: undefined }),
95 );
96 expect(draftRouteIdentity(draft)).not.toBe(
97 draftRouteIdentity({ ...draft, projectId: "other" }),
98 );
99 expect(draftRouteIdentity(draft)).not.toBe(
100 draftRouteIdentity({ ...draft, incomingShareId: "share" }),
101 );
102 });
103
104 it("normalizes link parameters without resetting for display metadata", () => {
105 expect(
106 draftRouteIdentity({ environmentId: ["env"], projectId: ["project"], title: "Old" }),
107 ).toBe(draftRouteIdentity({ environmentId: "env", projectId: "project", title: "New" }));
108 });
109});
110
111it("starts a fresh controller for repeated new-task requests in the same project", () => {
112 const project = { environmentId: "env", projectId: "project" };
113 expect(draftRouteIdentity({ ...project, requestId: "first" })).not.toBe(
114 draftRouteIdentity({ ...project, requestId: "second" }),
115 );
116});