@aaronshaf/plane 0.1.2 → 0.1.5

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -1,167 +1,200 @@
1
- import { afterAll, afterEach, beforeAll, beforeEach, describe, expect, it, mock } from "bun:test"
2
- import { Effect } from "effect"
3
- import { http, HttpResponse } from "msw"
4
- import { setupServer } from "msw/node"
5
- import { _clearProjectCache } from "@/resolve"
6
-
7
- const BASE = "http://act-test.local"
8
- const WS = "testws"
9
-
10
- const PROJECTS = [{ id: "proj-acme", identifier: "ACME", name: "Acme Project" }]
11
- const ISSUES = [{ id: "i1", sequence_id: 29, name: "Migrate Button", priority: "high", state: "s1" }]
1
+ import {
2
+ afterAll,
3
+ afterEach,
4
+ beforeAll,
5
+ beforeEach,
6
+ describe,
7
+ expect,
8
+ it,
9
+ mock,
10
+ } from "bun:test";
11
+ import { Effect } from "effect";
12
+ import { http, HttpResponse } from "msw";
13
+ import { setupServer } from "msw/node";
14
+ import { _clearProjectCache } from "@/resolve";
15
+
16
+ const BASE = "http://act-test.local";
17
+ const WS = "testws";
18
+
19
+ const PROJECTS = [
20
+ { id: "proj-acme", identifier: "ACME", name: "Acme Project" },
21
+ ];
22
+ const ISSUES = [
23
+ {
24
+ id: "i1",
25
+ sequence_id: 29,
26
+ name: "Migrate Button",
27
+ priority: "high",
28
+ state: "s1",
29
+ },
30
+ ];
12
31
  const ACTIVITIES = [
13
- {
14
- id: "act1",
15
- actor_detail: { display_name: "Aaron" },
16
- field: "state",
17
- old_value: "Backlog",
18
- new_value: "In Progress",
19
- verb: "updated",
20
- created_at: "2025-01-15T10:30:00Z",
21
- },
22
- {
23
- id: "act2",
24
- actor_detail: { display_name: "Bea" },
25
- field: null,
26
- old_value: null,
27
- new_value: null,
28
- verb: "created",
29
- created_at: "2025-01-14T08:00:00Z",
30
- },
31
- ]
32
+ {
33
+ id: "act1",
34
+ actor_detail: { display_name: "Aaron" },
35
+ field: "state",
36
+ old_value: "Backlog",
37
+ new_value: "In Progress",
38
+ verb: "updated",
39
+ created_at: "2025-01-15T10:30:00Z",
40
+ },
41
+ {
42
+ id: "act2",
43
+ actor_detail: { display_name: "Bea" },
44
+ field: null,
45
+ old_value: null,
46
+ new_value: null,
47
+ verb: "created",
48
+ created_at: "2025-01-14T08:00:00Z",
49
+ },
50
+ ];
32
51
 
33
52
  const server = setupServer(
34
- http.get(`${BASE}/api/v1/workspaces/${WS}/projects/`, () =>
35
- HttpResponse.json({ results: PROJECTS }),
36
- ),
37
- http.get(`${BASE}/api/v1/workspaces/${WS}/projects/proj-acme/issues/`, () =>
38
- HttpResponse.json({ results: ISSUES }),
39
- ),
40
- http.get(`${BASE}/api/v1/workspaces/${WS}/projects/proj-acme/issues/i1/activities/`, () =>
41
- HttpResponse.json({ results: ACTIVITIES }),
42
- ),
43
- )
44
-
45
- beforeAll(() => server.listen({ onUnhandledRequest: "error" }))
46
- afterAll(() => server.close())
53
+ http.get(`${BASE}/api/v1/workspaces/${WS}/projects/`, () =>
54
+ HttpResponse.json({ results: PROJECTS }),
55
+ ),
56
+ http.get(`${BASE}/api/v1/workspaces/${WS}/projects/proj-acme/issues/`, () =>
57
+ HttpResponse.json({ results: ISSUES }),
58
+ ),
59
+ http.get(
60
+ `${BASE}/api/v1/workspaces/${WS}/projects/proj-acme/issues/i1/activities/`,
61
+ () => HttpResponse.json({ results: ACTIVITIES }),
62
+ ),
63
+ );
64
+
65
+ beforeAll(() => server.listen({ onUnhandledRequest: "error" }));
66
+ afterAll(() => server.close());
47
67
 
48
68
  beforeEach(() => {
49
- _clearProjectCache()
50
- process.env["PLANE_HOST"] = BASE
51
- process.env["PLANE_WORKSPACE"] = WS
52
- process.env["PLANE_API_TOKEN"] = "test-token"
53
- })
69
+ _clearProjectCache();
70
+ process.env["PLANE_HOST"] = BASE;
71
+ process.env["PLANE_WORKSPACE"] = WS;
72
+ process.env["PLANE_API_TOKEN"] = "test-token";
73
+ });
54
74
 
55
75
  afterEach(() => {
56
- server.resetHandlers()
57
- delete process.env["PLANE_HOST"]
58
- delete process.env["PLANE_WORKSPACE"]
59
- delete process.env["PLANE_API_TOKEN"]
60
- })
76
+ server.resetHandlers();
77
+ delete process.env["PLANE_HOST"];
78
+ delete process.env["PLANE_WORKSPACE"];
79
+ delete process.env["PLANE_API_TOKEN"];
80
+ });
61
81
 
62
82
  describe("issueActivity command handler", () => {
63
- it("fetches and formats activity with field changes", async () => {
64
- const { issueActivity } = await import("@/commands/issue")
65
- const logs: string[] = []
66
- const originalLog = console.log
67
- console.log = (...args: unknown[]) => logs.push(args.join(" "))
68
-
69
- try {
70
- await Effect.runPromise(
71
- (issueActivity as any).handler({ ref: "ACME-29" }),
72
- )
73
- } finally {
74
- console.log = originalLog
75
- }
76
-
77
- const output = logs.join("\n")
78
- expect(output).toContain("Aaron")
79
- expect(output).toContain("state")
80
- expect(output).toContain("Backlog")
81
- expect(output).toContain("In Progress")
82
- })
83
-
84
- it("shows 'No activity found' when empty", async () => {
85
- server.use(
86
- http.get(`${BASE}/api/v1/workspaces/${WS}/projects/proj-acme/issues/i1/activities/`, () =>
87
- HttpResponse.json({ results: [] }),
88
- ),
89
- )
90
-
91
- const { issueActivity } = await import("@/commands/issue")
92
- const logs: string[] = []
93
- const originalLog = console.log
94
- console.log = (...args: unknown[]) => logs.push(args.join(" "))
95
-
96
- try {
97
- await Effect.runPromise(
98
- (issueActivity as any).handler({ ref: "ACME-29" }),
99
- )
100
- } finally {
101
- console.log = originalLog
102
- }
103
-
104
- expect(logs.join("\n")).toContain("No activity found")
105
- })
106
-
107
- it("formats activity without field (verb-only)", async () => {
108
- server.use(
109
- http.get(`${BASE}/api/v1/workspaces/${WS}/projects/proj-acme/issues/i1/activities/`, () =>
110
- HttpResponse.json({
111
- results: [
112
- {
113
- id: "act3",
114
- actor_detail: { display_name: "Bea" },
115
- verb: "created",
116
- created_at: "2025-01-14T08:00:00Z",
117
- },
118
- ],
119
- }),
120
- ),
121
- )
122
-
123
- const { issueActivity } = await import("@/commands/issue")
124
- const logs: string[] = []
125
- const originalLog = console.log
126
- console.log = (...args: unknown[]) => logs.push(args.join(" "))
127
-
128
- try {
129
- await Effect.runPromise(
130
- (issueActivity as any).handler({ ref: "ACME-29" }),
131
- )
132
- } finally {
133
- console.log = originalLog
134
- }
135
-
136
- const output = logs.join("\n")
137
- expect(output).toContain("Bea")
138
- expect(output).toContain("created")
139
- })
140
-
141
- it("handles missing actor_detail gracefully", async () => {
142
- server.use(
143
- http.get(`${BASE}/api/v1/workspaces/${WS}/projects/proj-acme/issues/i1/activities/`, () =>
144
- HttpResponse.json({
145
- results: [{ id: "act4", field: "priority", old_value: "low", new_value: "high", created_at: "2025-01-15T10:30:00Z" }],
146
- }),
147
- ),
148
- )
149
-
150
- const { issueActivity } = await import("@/commands/issue")
151
- const logs: string[] = []
152
- const originalLog = console.log
153
- console.log = (...args: unknown[]) => logs.push(args.join(" "))
154
-
155
- try {
156
- await Effect.runPromise(
157
- (issueActivity as any).handler({ ref: "ACME-29" }),
158
- )
159
- } finally {
160
- console.log = originalLog
161
- }
162
-
163
- const output = logs.join("\n")
164
- expect(output).toContain("priority")
165
- expect(output).toContain("?") // fallback for missing actor
166
- })
167
- })
83
+ it("fetches and formats activity with field changes", async () => {
84
+ const { issueActivity } = await import("@/commands/issue");
85
+ const logs: string[] = [];
86
+ const originalLog = console.log;
87
+ console.log = (...args: unknown[]) => logs.push(args.join(" "));
88
+
89
+ try {
90
+ await Effect.runPromise(
91
+ (issueActivity as any).handler({ ref: "ACME-29" }),
92
+ );
93
+ } finally {
94
+ console.log = originalLog;
95
+ }
96
+
97
+ const output = logs.join("\n");
98
+ expect(output).toContain("Aaron");
99
+ expect(output).toContain("state");
100
+ expect(output).toContain("Backlog");
101
+ expect(output).toContain("In Progress");
102
+ });
103
+
104
+ it("shows 'No activity found' when empty", async () => {
105
+ server.use(
106
+ http.get(
107
+ `${BASE}/api/v1/workspaces/${WS}/projects/proj-acme/issues/i1/activities/`,
108
+ () => HttpResponse.json({ results: [] }),
109
+ ),
110
+ );
111
+
112
+ const { issueActivity } = await import("@/commands/issue");
113
+ const logs: string[] = [];
114
+ const originalLog = console.log;
115
+ console.log = (...args: unknown[]) => logs.push(args.join(" "));
116
+
117
+ try {
118
+ await Effect.runPromise(
119
+ (issueActivity as any).handler({ ref: "ACME-29" }),
120
+ );
121
+ } finally {
122
+ console.log = originalLog;
123
+ }
124
+
125
+ expect(logs.join("\n")).toContain("No activity found");
126
+ });
127
+
128
+ it("formats activity without field (verb-only)", async () => {
129
+ server.use(
130
+ http.get(
131
+ `${BASE}/api/v1/workspaces/${WS}/projects/proj-acme/issues/i1/activities/`,
132
+ () =>
133
+ HttpResponse.json({
134
+ results: [
135
+ {
136
+ id: "act3",
137
+ actor_detail: { display_name: "Bea" },
138
+ verb: "created",
139
+ created_at: "2025-01-14T08:00:00Z",
140
+ },
141
+ ],
142
+ }),
143
+ ),
144
+ );
145
+
146
+ const { issueActivity } = await import("@/commands/issue");
147
+ const logs: string[] = [];
148
+ const originalLog = console.log;
149
+ console.log = (...args: unknown[]) => logs.push(args.join(" "));
150
+
151
+ try {
152
+ await Effect.runPromise(
153
+ (issueActivity as any).handler({ ref: "ACME-29" }),
154
+ );
155
+ } finally {
156
+ console.log = originalLog;
157
+ }
158
+
159
+ const output = logs.join("\n");
160
+ expect(output).toContain("Bea");
161
+ expect(output).toContain("created");
162
+ });
163
+
164
+ it("handles missing actor_detail gracefully", async () => {
165
+ server.use(
166
+ http.get(
167
+ `${BASE}/api/v1/workspaces/${WS}/projects/proj-acme/issues/i1/activities/`,
168
+ () =>
169
+ HttpResponse.json({
170
+ results: [
171
+ {
172
+ id: "act4",
173
+ field: "priority",
174
+ old_value: "low",
175
+ new_value: "high",
176
+ created_at: "2025-01-15T10:30:00Z",
177
+ },
178
+ ],
179
+ }),
180
+ ),
181
+ );
182
+
183
+ const { issueActivity } = await import("@/commands/issue");
184
+ const logs: string[] = [];
185
+ const originalLog = console.log;
186
+ console.log = (...args: unknown[]) => logs.push(args.join(" "));
187
+
188
+ try {
189
+ await Effect.runPromise(
190
+ (issueActivity as any).handler({ ref: "ACME-29" }),
191
+ );
192
+ } finally {
193
+ console.log = originalLog;
194
+ }
195
+
196
+ const output = logs.join("\n");
197
+ expect(output).toContain("priority");
198
+ expect(output).toContain("?"); // fallback for missing actor
199
+ });
200
+ });