Skip to content
Source
Sign inSign up

threadReference.test.ts

115 lines3.9 KB

1import { EnvironmentId, ThreadId, type ThreadPullRequestLink } from "@t3tools/contracts";
2import {
3 decodeComposerContextFragment,
4 encodeComposerContextFragment,
5} from "@t3tools/shared/composerContextClipboard";
6import { threadLinkContextReferences } from "@t3tools/shared/composerContextReferences";
7import { describe, expect, it } from "vite-plus/test";
8​
9import { resolveThreadReferenceCopyTarget } from "./threadReference.ts";
10​
11const thread = {
12 threadRef: { environmentId: EnvironmentId.make("env-1"), threadId: ThreadId.make("thread-1") },
13 title: "Fix the login flow",
14};
15​
16const crossRepositoryPullRequest: ThreadPullRequestLink = {
17 host: "github.com",
18 repository: "other/repo",
19 number: 42,
20 url: "https://github.com/other/repo/pull/42",
21 source: "manual",
22 linkedAt: "2026-01-01T00:00:00.000Z",
23 snapshot: null,
24 stack: null,
25};
26​
27describe("resolveThreadReferenceCopyTarget", () => {
28 it("does not copy another reference while the open panel URL is unavailable", () => {
29 expect(
30 resolveThreadReferenceCopyTarget({
31 ...thread,
32 openPanelPullRequestUrl: null,
33 pullRequests: [crossRepositoryPullRequest],
34 linkedPullRequestUrl: "https://github.com/t3/pr/12",
35 }),
36 ).toBeNull();
37 });
38​
39 it("prefers the open panel pull request over the thread pull request", () => {
40 expect(
41 resolveThreadReferenceCopyTarget({
42 ...thread,
43 openPanelPullRequestUrl: "https://github.com/t3/pr/14",
44 pullRequests: [crossRepositoryPullRequest],
45 linkedPullRequestUrl: "https://github.com/t3/pr/12",
46 }),
47 ).toMatchObject({
48 kind: "pull-request",
49 value: "https://github.com/t3/pr/14",
50 successTitle: "PR link copied",
51 });
52 });
53​
54 it.each([null, "https://github.com/t3/pr/12"])(
55 "copies a native cross-repository link before the fallback URL %s",
56 (linkedPullRequestUrl) => {
57 expect(
58 resolveThreadReferenceCopyTarget({
59 ...thread,
60 pullRequests: [crossRepositoryPullRequest],
61 linkedPullRequestUrl,
62 }),
63 ).toMatchObject({
64 kind: "pull-request",
65 value: crossRepositoryPullRequest.url,
66 });
67 },
68 );
69​
70 it("uses the fallback URL when native links are dismissed", () => {
71 expect(
72 resolveThreadReferenceCopyTarget({
73 ...thread,
74 pullRequests: [{ ...crossRepositoryPullRequest, source: "stack-dismissed" }],
75 linkedPullRequestUrl: "https://github.com/t3/pr/12",
76 }),
77 ).toMatchObject({ kind: "pull-request", value: "https://github.com/t3/pr/12" });
78 });
79​
80 it("copies a thread chip that pastes back as the same thread on its machine", () => {
81 const target = resolveThreadReferenceCopyTarget({ ...thread, linkedPullRequestUrl: null });
82​
83 expect(target).toMatchObject({
84 kind: "thread",
85 description: "Fix the login flow",
86 successTitle: "Thread copied",
87 });
88 const pasted = decodeComposerContextFragment(encodeComposerContextFragment(target!.fragment!));
89 expect(pasted).toEqual({
90 version: 1,
91 source: { environmentId: "env-1" },
92 records: [
93 expect.objectContaining({
94 kind: "thread",
95 environmentId: "env-1",
96 threadId: "thread-1",
97 title: "Fix the login flow",
98 }),
99 ],
100 });
101 // The plain text opens the thread anywhere and pastes back as the copied record's chip.
102 expect(target!.value).toBe("https://app.t3.codes/threads/env-1/thread-1");
103 expect(threadLinkContextReferences(target!.value, pasted!.records, () => undefined)).toEqual({
104 text: `[Fix the login flow](t3-context://v1/thread/${pasted!.records[0]!.contextId})`,
105 records: pasted!.records,
106 });
107 });
108​
109 it("links through the build's hosted app", () => {
110 expect(
111 resolveThreadReferenceCopyTarget({ ...thread, hostedAppUrl: "https://preview.t3.codes" })
112 ?.value,
113 ).toBe("https://preview.t3.codes/threads/env-1/thread-1");
114 });
115});