@akiojin/gwt 2.2.0 → 2.3.0
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.
- package/README.ja.md +4 -4
- package/README.md +4 -4
- package/dist/cli/ui/components/App.d.ts +4 -4
- package/dist/cli/ui/components/App.d.ts.map +1 -1
- package/dist/cli/ui/components/App.js +144 -105
- package/dist/cli/ui/components/App.js.map +1 -1
- package/dist/cli/ui/components/common/Confirm.d.ts +1 -1
- package/dist/cli/ui/components/common/Confirm.d.ts.map +1 -1
- package/dist/cli/ui/components/common/Confirm.js +7 -7
- package/dist/cli/ui/components/common/Confirm.js.map +1 -1
- package/dist/cli/ui/components/common/ErrorBoundary.d.ts +1 -1
- package/dist/cli/ui/components/common/ErrorBoundary.d.ts.map +1 -1
- package/dist/cli/ui/components/common/ErrorBoundary.js +4 -4
- package/dist/cli/ui/components/common/ErrorBoundary.js.map +1 -1
- package/dist/cli/ui/components/common/Input.d.ts +2 -2
- package/dist/cli/ui/components/common/Input.d.ts.map +1 -1
- package/dist/cli/ui/components/common/Input.js +4 -4
- package/dist/cli/ui/components/common/Input.js.map +1 -1
- package/dist/cli/ui/components/common/LoadingIndicator.d.ts +1 -1
- package/dist/cli/ui/components/common/LoadingIndicator.d.ts.map +1 -1
- package/dist/cli/ui/components/common/LoadingIndicator.js +4 -4
- package/dist/cli/ui/components/common/LoadingIndicator.js.map +1 -1
- package/dist/cli/ui/components/common/Select.d.ts +1 -1
- package/dist/cli/ui/components/common/Select.d.ts.map +1 -1
- package/dist/cli/ui/components/common/Select.js +11 -12
- package/dist/cli/ui/components/common/Select.js.map +1 -1
- package/dist/cli/ui/components/screens/AIToolSelectorScreen.d.ts +2 -2
- package/dist/cli/ui/components/screens/AIToolSelectorScreen.d.ts.map +1 -1
- package/dist/cli/ui/components/screens/AIToolSelectorScreen.js +11 -11
- package/dist/cli/ui/components/screens/AIToolSelectorScreen.js.map +1 -1
- package/dist/cli/ui/components/screens/BranchCreatorScreen.d.ts +1 -1
- package/dist/cli/ui/components/screens/BranchCreatorScreen.d.ts.map +1 -1
- package/dist/cli/ui/components/screens/BranchCreatorScreen.js +39 -36
- package/dist/cli/ui/components/screens/BranchCreatorScreen.js.map +1 -1
- package/dist/cli/ui/components/screens/BranchListScreen.d.ts +3 -3
- package/dist/cli/ui/components/screens/BranchListScreen.d.ts.map +1 -1
- package/dist/cli/ui/components/screens/BranchListScreen.js +55 -50
- package/dist/cli/ui/components/screens/BranchListScreen.js.map +1 -1
- package/dist/cli/ui/components/screens/ExecutionModeSelectorScreen.d.ts +2 -2
- package/dist/cli/ui/components/screens/ExecutionModeSelectorScreen.d.ts.map +1 -1
- package/dist/cli/ui/components/screens/ExecutionModeSelectorScreen.js +25 -25
- package/dist/cli/ui/components/screens/ExecutionModeSelectorScreen.js.map +1 -1
- package/dist/cli/ui/components/screens/PRCleanupScreen.d.ts +2 -2
- package/dist/cli/ui/components/screens/PRCleanupScreen.js +21 -21
- package/dist/cli/ui/components/screens/SessionSelectorScreen.d.ts +1 -1
- package/dist/cli/ui/components/screens/SessionSelectorScreen.js +8 -8
- package/dist/cli/ui/components/screens/WorktreeManagerScreen.d.ts +1 -1
- package/dist/cli/ui/components/screens/WorktreeManagerScreen.js +8 -8
- package/dist/cli/ui/screens/BranchActionSelectorScreen.d.ts.map +1 -1
- package/dist/cli/ui/screens/BranchActionSelectorScreen.js +7 -4
- package/dist/cli/ui/screens/BranchActionSelectorScreen.js.map +1 -1
- package/dist/cli/ui/types.d.ts.map +1 -1
- package/dist/client/assets/{index-V6hDu9KS.js → index-Difv1Hwu.js} +2 -2
- package/dist/client/index.html +1 -1
- package/dist/config/builtin-tools.d.ts +10 -2
- package/dist/config/builtin-tools.d.ts.map +1 -1
- package/dist/config/builtin-tools.js +40 -4
- package/dist/config/builtin-tools.js.map +1 -1
- package/dist/config/index.d.ts.map +1 -1
- package/dist/config/index.js.map +1 -1
- package/dist/config/tools.d.ts.map +1 -1
- package/dist/config/tools.js +4 -3
- package/dist/config/tools.js.map +1 -1
- package/dist/gemini.d.ts +12 -0
- package/dist/gemini.d.ts.map +1 -0
- package/dist/gemini.js +154 -0
- package/dist/gemini.js.map +1 -0
- package/dist/git.d.ts.map +1 -1
- package/dist/git.js.map +1 -1
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +30 -0
- package/dist/index.js.map +1 -1
- package/dist/qwen.d.ts +12 -0
- package/dist/qwen.d.ts.map +1 -0
- package/dist/qwen.js +154 -0
- package/dist/qwen.js.map +1 -0
- package/dist/services/git.service.d.ts.map +1 -1
- package/dist/services/git.service.js.map +1 -1
- package/dist/web/client/src/components/BranchGraph.d.ts.map +1 -1
- package/dist/web/client/src/components/BranchGraph.js +1 -1
- package/dist/web/client/src/components/BranchGraph.js.map +1 -1
- package/dist/web/client/src/components/EnvEditor.d.ts.map +1 -1
- package/dist/web/client/src/components/EnvEditor.js +7 -4
- package/dist/web/client/src/components/EnvEditor.js.map +1 -1
- package/dist/web/client/src/pages/BranchDetailPage.d.ts.map +1 -1
- package/dist/web/client/src/pages/BranchDetailPage.js +55 -18
- package/dist/web/client/src/pages/BranchDetailPage.js.map +1 -1
- package/dist/web/client/src/pages/BranchListPage.d.ts.map +1 -1
- package/dist/web/client/src/pages/BranchListPage.js +10 -4
- package/dist/web/client/src/pages/BranchListPage.js.map +1 -1
- package/dist/web/client/src/pages/ConfigManagementPage.d.ts.map +1 -1
- package/dist/web/client/src/pages/ConfigManagementPage.js +4 -2
- package/dist/web/client/src/pages/ConfigManagementPage.js.map +1 -1
- package/package.json +2 -1
- package/src/cli/ui/__tests__/acceptance/navigation.acceptance.test.tsx +69 -50
- package/src/cli/ui/__tests__/components/App.protected-branch.test.tsx +67 -45
- package/src/cli/ui/__tests__/components/App.shortcuts.test.tsx +117 -75
- package/src/cli/ui/__tests__/components/App.test.tsx +45 -37
- package/src/cli/ui/__tests__/components/common/Confirm.test.tsx +35 -22
- package/src/cli/ui/__tests__/components/common/ErrorBoundary.test.tsx +22 -22
- package/src/cli/ui/__tests__/components/common/Input.test.tsx +29 -22
- package/src/cli/ui/__tests__/components/common/LoadingIndicator.test.tsx +40 -34
- package/src/cli/ui/__tests__/components/common/Select.memo.test.tsx +57 -66
- package/src/cli/ui/__tests__/components/common/Select.test.tsx +121 -91
- package/src/cli/ui/__tests__/components/parts/Footer.test.tsx +18 -16
- package/src/cli/ui/__tests__/components/parts/Header.test.tsx +13 -13
- package/src/cli/ui/__tests__/components/parts/ScrollableList.test.tsx +20 -20
- package/src/cli/ui/__tests__/components/parts/Stats.test.tsx +38 -26
- package/src/cli/ui/__tests__/components/screens/AIToolSelectorScreen.test.tsx +31 -31
- package/src/cli/ui/__tests__/components/screens/BranchCreatorScreen.test.tsx +73 -37
- package/src/cli/ui/__tests__/components/screens/BranchListScreen.test.tsx +261 -153
- package/src/cli/ui/__tests__/components/screens/ExecutionModeSelectorScreen.test.tsx +38 -32
- package/src/cli/ui/__tests__/components/screens/PRCleanupScreen.test.tsx +39 -39
- package/src/cli/ui/__tests__/components/screens/SessionSelectorScreen.test.tsx +49 -21
- package/src/cli/ui/__tests__/components/screens/WorktreeManagerScreen.test.tsx +52 -28
- package/src/cli/ui/__tests__/integration/edgeCases.test.tsx +84 -48
- package/src/cli/ui/__tests__/integration/navigation.test.tsx +111 -83
- package/src/cli/ui/__tests__/integration/realtimeUpdate.test.tsx +111 -108
- package/src/cli/ui/__tests__/performance/branchList.performance.test.tsx +50 -37
- package/src/cli/ui/__tests__/performance/useMemoOptimization.test.tsx +75 -76
- package/src/cli/ui/components/App.tsx +247 -150
- package/src/cli/ui/components/common/Confirm.tsx +13 -9
- package/src/cli/ui/components/common/ErrorBoundary.tsx +8 -5
- package/src/cli/ui/components/common/Input.tsx +12 -4
- package/src/cli/ui/components/common/LoadingIndicator.tsx +8 -5
- package/src/cli/ui/components/common/Select.tsx +28 -17
- package/src/cli/ui/components/parts/Header.test.tsx +5 -15
- package/src/cli/ui/components/screens/AIToolSelectorScreen.tsx +19 -13
- package/src/cli/ui/components/screens/BranchCreatorScreen.tsx +74 -54
- package/src/cli/ui/components/screens/BranchListScreen.tsx +92 -75
- package/src/cli/ui/components/screens/ExecutionModeSelectorScreen.tsx +35 -28
- package/src/cli/ui/components/screens/PRCleanupScreen.tsx +22 -22
- package/src/cli/ui/components/screens/SessionSelectorScreen.tsx +8 -8
- package/src/cli/ui/components/screens/WorktreeManagerScreen.tsx +8 -8
- package/src/cli/ui/screens/BranchActionSelectorScreen.tsx +9 -4
- package/src/cli/ui/types.ts +8 -1
- package/src/config/builtin-tools.ts +42 -4
- package/src/config/index.ts +2 -12
- package/src/config/tools.ts +16 -6
- package/src/gemini.ts +202 -0
- package/src/git.ts +2 -1
- package/src/index.ts +30 -0
- package/src/qwen.ts +208 -0
- package/src/services/git.service.ts +2 -1
- package/src/web/client/src/components/BranchGraph.tsx +3 -2
- package/src/web/client/src/components/EnvEditor.tsx +44 -11
- package/src/web/client/src/pages/BranchDetailPage.tsx +165 -54
- package/src/web/client/src/pages/BranchListPage.tsx +37 -13
- package/src/web/client/src/pages/ConfigManagementPage.tsx +28 -9
|
@@ -1,19 +1,27 @@
|
|
|
1
1
|
/**
|
|
2
2
|
* @vitest-environment happy-dom
|
|
3
3
|
*/
|
|
4
|
-
import {
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
import
|
|
14
|
-
import
|
|
15
|
-
import
|
|
16
|
-
import
|
|
4
|
+
import {
|
|
5
|
+
describe,
|
|
6
|
+
it,
|
|
7
|
+
expect,
|
|
8
|
+
beforeEach,
|
|
9
|
+
afterEach,
|
|
10
|
+
afterAll,
|
|
11
|
+
vi,
|
|
12
|
+
} from "vitest";
|
|
13
|
+
import { act, render } from "@testing-library/react";
|
|
14
|
+
import React from "react";
|
|
15
|
+
import { Window } from "happy-dom";
|
|
16
|
+
import { App } from "../../components/App.js";
|
|
17
|
+
import type { BranchInfo, BranchItem } from "../../types.js";
|
|
18
|
+
import * as useGitDataModule from "../../hooks/useGitData.js";
|
|
19
|
+
import * as useScreenStateModule from "../../hooks/useScreenState.js";
|
|
20
|
+
import * as BranchListScreenModule from "../../components/screens/BranchListScreen.js";
|
|
21
|
+
import * as BranchActionSelectorScreenModule from "../../screens/BranchActionSelectorScreen.js";
|
|
22
|
+
import * as worktreeModule from "../../../../worktree.ts";
|
|
23
|
+
import * as gitModule from "../../../../git.ts";
|
|
24
|
+
import type { ScreenType } from "../../types.js";
|
|
17
25
|
|
|
18
26
|
const navigateToMock = vi.fn();
|
|
19
27
|
const goBackMock = vi.fn();
|
|
@@ -22,37 +30,47 @@ const resetMock = vi.fn();
|
|
|
22
30
|
const originalUseGitData = useGitDataModule.useGitData;
|
|
23
31
|
const originalUseScreenState = useScreenStateModule.useScreenState;
|
|
24
32
|
const originalBranchListScreen = BranchListScreenModule.BranchListScreen;
|
|
25
|
-
const originalBranchActionSelector =
|
|
33
|
+
const originalBranchActionSelector =
|
|
34
|
+
BranchActionSelectorScreenModule.BranchActionSelectorScreen;
|
|
26
35
|
const originalGetRepositoryRoot = gitModule.getRepositoryRoot;
|
|
27
36
|
|
|
28
|
-
const useGitDataSpy = vi.spyOn(useGitDataModule,
|
|
29
|
-
const useScreenStateSpy = vi.spyOn(useScreenStateModule,
|
|
30
|
-
const branchListScreenSpy = vi.spyOn(
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
37
|
+
const useGitDataSpy = vi.spyOn(useGitDataModule, "useGitData");
|
|
38
|
+
const useScreenStateSpy = vi.spyOn(useScreenStateModule, "useScreenState");
|
|
39
|
+
const branchListScreenSpy = vi.spyOn(
|
|
40
|
+
BranchListScreenModule,
|
|
41
|
+
"BranchListScreen",
|
|
42
|
+
);
|
|
43
|
+
const branchActionSelectorSpy = vi.spyOn(
|
|
44
|
+
BranchActionSelectorScreenModule,
|
|
45
|
+
"BranchActionSelectorScreen",
|
|
46
|
+
);
|
|
47
|
+
const switchToProtectedBranchSpy = vi.spyOn(
|
|
48
|
+
worktreeModule,
|
|
49
|
+
"switchToProtectedBranch",
|
|
50
|
+
);
|
|
51
|
+
const getRepositoryRootSpy = vi.spyOn(gitModule, "getRepositoryRoot");
|
|
34
52
|
|
|
35
53
|
const branchListProps: any[] = [];
|
|
36
54
|
const branchActionProps: any[] = [];
|
|
37
55
|
const aiToolProps: any[] = [];
|
|
38
56
|
let currentScreenState: ScreenType;
|
|
39
57
|
|
|
40
|
-
vi.mock(
|
|
58
|
+
vi.mock("../../components/screens/AIToolSelectorScreen.js", () => {
|
|
41
59
|
return {
|
|
42
60
|
AIToolSelectorScreen: (props: unknown) => {
|
|
43
61
|
aiToolProps.push(props);
|
|
44
|
-
return React.createElement(
|
|
62
|
+
return React.createElement("div");
|
|
45
63
|
},
|
|
46
64
|
};
|
|
47
65
|
});
|
|
48
66
|
|
|
49
|
-
describe(
|
|
67
|
+
describe("App protected branch handling", () => {
|
|
50
68
|
beforeEach(() => {
|
|
51
69
|
const window = new Window();
|
|
52
70
|
globalThis.window = window as any;
|
|
53
71
|
globalThis.document = window.document as any;
|
|
54
72
|
|
|
55
|
-
currentScreenState =
|
|
73
|
+
currentScreenState = "branch-list";
|
|
56
74
|
navigateToMock.mockReset();
|
|
57
75
|
goBackMock.mockReset();
|
|
58
76
|
resetMock.mockReset();
|
|
@@ -73,7 +91,7 @@ describe('App protected branch handling', () => {
|
|
|
73
91
|
goBack: goBackMock,
|
|
74
92
|
reset: () => {
|
|
75
93
|
resetMock();
|
|
76
|
-
currentScreenState =
|
|
94
|
+
currentScreenState = "branch-list";
|
|
77
95
|
},
|
|
78
96
|
}));
|
|
79
97
|
|
|
@@ -85,8 +103,8 @@ describe('App protected branch handling', () => {
|
|
|
85
103
|
branchActionProps.push(props);
|
|
86
104
|
return React.createElement(originalBranchActionSelector, props);
|
|
87
105
|
});
|
|
88
|
-
switchToProtectedBranchSpy.mockResolvedValue(
|
|
89
|
-
getRepositoryRootSpy.mockResolvedValue(
|
|
106
|
+
switchToProtectedBranchSpy.mockResolvedValue("local");
|
|
107
|
+
getRepositoryRootSpy.mockResolvedValue("/repo");
|
|
90
108
|
});
|
|
91
109
|
|
|
92
110
|
afterEach(() => {
|
|
@@ -95,7 +113,9 @@ describe('App protected branch handling', () => {
|
|
|
95
113
|
useScreenStateSpy.mockReset();
|
|
96
114
|
useScreenStateSpy.mockImplementation(originalUseScreenState);
|
|
97
115
|
branchListScreenSpy.mockImplementation(originalBranchListScreen as any);
|
|
98
|
-
branchActionSelectorSpy.mockImplementation(
|
|
116
|
+
branchActionSelectorSpy.mockImplementation(
|
|
117
|
+
originalBranchActionSelector as any,
|
|
118
|
+
);
|
|
99
119
|
switchToProtectedBranchSpy.mockReset();
|
|
100
120
|
getRepositoryRootSpy.mockReset();
|
|
101
121
|
branchActionProps.length = 0;
|
|
@@ -110,18 +130,18 @@ describe('App protected branch handling', () => {
|
|
|
110
130
|
getRepositoryRootSpy.mockRestore();
|
|
111
131
|
});
|
|
112
132
|
|
|
113
|
-
it(
|
|
133
|
+
it("shows protected branch warning and switches root without launching AI tool", async () => {
|
|
114
134
|
const branches: BranchInfo[] = [
|
|
115
135
|
{
|
|
116
|
-
name:
|
|
117
|
-
type:
|
|
118
|
-
branchType:
|
|
136
|
+
name: "main",
|
|
137
|
+
type: "local",
|
|
138
|
+
branchType: "main",
|
|
119
139
|
isCurrent: false,
|
|
120
140
|
},
|
|
121
141
|
{
|
|
122
|
-
name:
|
|
123
|
-
type:
|
|
124
|
-
branchType:
|
|
142
|
+
name: "feature/example",
|
|
143
|
+
type: "local",
|
|
144
|
+
branchType: "feature",
|
|
125
145
|
isCurrent: true,
|
|
126
146
|
},
|
|
127
147
|
];
|
|
@@ -141,15 +161,15 @@ describe('App protected branch handling', () => {
|
|
|
141
161
|
const latestProps = branchListProps.at(-1);
|
|
142
162
|
expect(latestProps).toBeDefined();
|
|
143
163
|
if (!latestProps) {
|
|
144
|
-
throw new Error(
|
|
164
|
+
throw new Error("BranchListScreen props missing");
|
|
145
165
|
}
|
|
146
166
|
|
|
147
167
|
const protectedBranch = (latestProps.branches as BranchItem[]).find(
|
|
148
|
-
(item) => item.name ===
|
|
168
|
+
(item) => item.name === "main",
|
|
149
169
|
);
|
|
150
170
|
expect(protectedBranch).toBeDefined();
|
|
151
171
|
if (!protectedBranch) {
|
|
152
|
-
throw new Error(
|
|
172
|
+
throw new Error("Protected branch item not found");
|
|
153
173
|
}
|
|
154
174
|
|
|
155
175
|
await act(async () => {
|
|
@@ -157,13 +177,15 @@ describe('App protected branch handling', () => {
|
|
|
157
177
|
await Promise.resolve();
|
|
158
178
|
});
|
|
159
179
|
|
|
160
|
-
expect(navigateToMock).toHaveBeenCalledWith(
|
|
180
|
+
expect(navigateToMock).toHaveBeenCalledWith("branch-action-selector");
|
|
161
181
|
expect(branchActionProps).not.toHaveLength(0);
|
|
162
182
|
const actionProps = branchActionProps.at(-1);
|
|
163
|
-
expect(actionProps?.mode).toBe(
|
|
164
|
-
expect(actionProps?.infoMessage).toContain(
|
|
165
|
-
expect(actionProps?.primaryLabel).toBe(
|
|
166
|
-
expect(actionProps?.secondaryLabel).toBe(
|
|
183
|
+
expect(actionProps?.mode).toBe("protected");
|
|
184
|
+
expect(actionProps?.infoMessage).toContain("is a root branch");
|
|
185
|
+
expect(actionProps?.primaryLabel).toBe("Use root branch (no worktree)");
|
|
186
|
+
expect(actionProps?.secondaryLabel).toBe(
|
|
187
|
+
"Create new branch from this branch",
|
|
188
|
+
);
|
|
167
189
|
|
|
168
190
|
await act(async () => {
|
|
169
191
|
actionProps?.onUseExisting();
|
|
@@ -172,12 +194,12 @@ describe('App protected branch handling', () => {
|
|
|
172
194
|
});
|
|
173
195
|
|
|
174
196
|
expect(switchToProtectedBranchSpy).toHaveBeenCalledWith({
|
|
175
|
-
branchName:
|
|
197
|
+
branchName: "main",
|
|
176
198
|
repoRoot: expect.any(String),
|
|
177
199
|
remoteRef: null,
|
|
178
200
|
});
|
|
179
201
|
|
|
180
|
-
expect(navigateToMock).toHaveBeenCalledWith(
|
|
202
|
+
expect(navigateToMock).toHaveBeenCalledWith("ai-tool-selector");
|
|
181
203
|
expect(aiToolProps).not.toHaveLength(0);
|
|
182
204
|
});
|
|
183
205
|
});
|
|
@@ -1,20 +1,28 @@
|
|
|
1
1
|
/**
|
|
2
2
|
* @vitest-environment happy-dom
|
|
3
3
|
*/
|
|
4
|
-
import {
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
import
|
|
14
|
-
import
|
|
15
|
-
import
|
|
16
|
-
import
|
|
17
|
-
import {
|
|
4
|
+
import {
|
|
5
|
+
describe,
|
|
6
|
+
it,
|
|
7
|
+
expect,
|
|
8
|
+
beforeEach,
|
|
9
|
+
afterEach,
|
|
10
|
+
afterAll,
|
|
11
|
+
vi,
|
|
12
|
+
} from "vitest";
|
|
13
|
+
import type { Mock } from "vitest";
|
|
14
|
+
import { render, act, waitFor } from "@testing-library/react";
|
|
15
|
+
import React from "react";
|
|
16
|
+
import type { BranchItem, CleanupTarget } from "../../types.js";
|
|
17
|
+
import { Window } from "happy-dom";
|
|
18
|
+
import * as useGitDataModule from "../../hooks/useGitData.js";
|
|
19
|
+
import * as useScreenStateModule from "../../hooks/useScreenState.js";
|
|
20
|
+
import * as WorktreeManagerScreenModule from "../../components/screens/WorktreeManagerScreen.js";
|
|
21
|
+
import * as BranchCreatorScreenModule from "../../components/screens/BranchCreatorScreen.js";
|
|
22
|
+
import * as BranchListScreenModule from "../../components/screens/BranchListScreen.js";
|
|
23
|
+
import * as worktreeModule from "../../../../worktree.ts";
|
|
24
|
+
import * as gitModule from "../../../../git.ts";
|
|
25
|
+
import { App } from "../../components/App.js";
|
|
18
26
|
|
|
19
27
|
const navigateToMock = vi.fn();
|
|
20
28
|
const goBackMock = vi.fn();
|
|
@@ -26,8 +34,10 @@ const branchListProps: any[] = [];
|
|
|
26
34
|
|
|
27
35
|
const originalUseGitData = useGitDataModule.useGitData;
|
|
28
36
|
const originalUseScreenState = useScreenStateModule.useScreenState;
|
|
29
|
-
const originalWorktreeManagerScreen =
|
|
30
|
-
|
|
37
|
+
const originalWorktreeManagerScreen =
|
|
38
|
+
WorktreeManagerScreenModule.WorktreeManagerScreen;
|
|
39
|
+
const originalBranchCreatorScreen =
|
|
40
|
+
BranchCreatorScreenModule.BranchCreatorScreen;
|
|
31
41
|
const originalBranchListScreen = BranchListScreenModule.BranchListScreen;
|
|
32
42
|
const originalGetMergedPRWorktrees = worktreeModule.getMergedPRWorktrees;
|
|
33
43
|
const originalGenerateWorktreePath = worktreeModule.generateWorktreePath;
|
|
@@ -36,21 +46,36 @@ const originalRemoveWorktree = worktreeModule.removeWorktree;
|
|
|
36
46
|
const originalGetRepositoryRoot = gitModule.getRepositoryRoot;
|
|
37
47
|
const originalDeleteBranch = gitModule.deleteBranch;
|
|
38
48
|
|
|
39
|
-
const useGitDataSpy = vi.spyOn(useGitDataModule,
|
|
40
|
-
const useScreenStateSpy = vi.spyOn(useScreenStateModule,
|
|
41
|
-
const worktreeManagerScreenSpy = vi.spyOn(
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
const
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
const
|
|
50
|
-
|
|
51
|
-
|
|
49
|
+
const useGitDataSpy = vi.spyOn(useGitDataModule, "useGitData");
|
|
50
|
+
const useScreenStateSpy = vi.spyOn(useScreenStateModule, "useScreenState");
|
|
51
|
+
const worktreeManagerScreenSpy = vi.spyOn(
|
|
52
|
+
WorktreeManagerScreenModule,
|
|
53
|
+
"WorktreeManagerScreen",
|
|
54
|
+
);
|
|
55
|
+
const branchCreatorScreenSpy = vi.spyOn(
|
|
56
|
+
BranchCreatorScreenModule,
|
|
57
|
+
"BranchCreatorScreen",
|
|
58
|
+
);
|
|
59
|
+
const branchListScreenSpy = vi.spyOn(
|
|
60
|
+
BranchListScreenModule,
|
|
61
|
+
"BranchListScreen",
|
|
62
|
+
);
|
|
63
|
+
const getMergedPRWorktreesSpy = vi.spyOn(
|
|
64
|
+
worktreeModule,
|
|
65
|
+
"getMergedPRWorktrees",
|
|
66
|
+
);
|
|
67
|
+
const generateWorktreePathSpy = vi.spyOn(
|
|
68
|
+
worktreeModule,
|
|
69
|
+
"generateWorktreePath",
|
|
70
|
+
);
|
|
71
|
+
const createWorktreeSpy = vi.spyOn(worktreeModule, "createWorktree");
|
|
72
|
+
const removeWorktreeSpy = vi.spyOn(worktreeModule, "removeWorktree");
|
|
73
|
+
const getRepositoryRootSpy = vi.spyOn(gitModule, "getRepositoryRoot");
|
|
74
|
+
const deleteBranchSpy = vi.spyOn(gitModule, "deleteBranch");
|
|
75
|
+
|
|
76
|
+
describe("App shortcuts integration", () => {
|
|
52
77
|
beforeEach(() => {
|
|
53
|
-
if (typeof globalThis.document ===
|
|
78
|
+
if (typeof globalThis.document === "undefined") {
|
|
54
79
|
const window = new Window();
|
|
55
80
|
globalThis.window = window as any;
|
|
56
81
|
globalThis.document = window.document as any;
|
|
@@ -65,8 +90,8 @@ describe('App shortcuts integration', () => {
|
|
|
65
90
|
branches: [],
|
|
66
91
|
worktrees: [
|
|
67
92
|
{
|
|
68
|
-
branch:
|
|
69
|
-
path:
|
|
93
|
+
branch: "feature/existing",
|
|
94
|
+
path: "/worktrees/feature-existing",
|
|
70
95
|
isAccessible: true,
|
|
71
96
|
},
|
|
72
97
|
],
|
|
@@ -76,7 +101,7 @@ describe('App shortcuts integration', () => {
|
|
|
76
101
|
lastUpdated: null,
|
|
77
102
|
}));
|
|
78
103
|
useScreenStateSpy.mockImplementation(() => ({
|
|
79
|
-
currentScreen:
|
|
104
|
+
currentScreen: "worktree-manager",
|
|
80
105
|
navigateTo: navigateToMock as _Mock,
|
|
81
106
|
goBack: goBackMock as _Mock,
|
|
82
107
|
reset: resetMock as _Mock,
|
|
@@ -95,42 +120,42 @@ describe('App shortcuts integration', () => {
|
|
|
95
120
|
});
|
|
96
121
|
getMergedPRWorktreesSpy.mockResolvedValue([
|
|
97
122
|
{
|
|
98
|
-
branch:
|
|
99
|
-
cleanupType:
|
|
123
|
+
branch: "feature/add-new-feature",
|
|
124
|
+
cleanupType: "worktree-and-branch",
|
|
100
125
|
pullRequest: {
|
|
101
126
|
number: 123,
|
|
102
|
-
title:
|
|
103
|
-
branch:
|
|
104
|
-
mergedAt:
|
|
105
|
-
author:
|
|
127
|
+
title: "Add new feature",
|
|
128
|
+
branch: "feature/add-new-feature",
|
|
129
|
+
mergedAt: "2025-01-20T10:00:00Z",
|
|
130
|
+
author: "user1",
|
|
106
131
|
},
|
|
107
|
-
worktreePath:
|
|
132
|
+
worktreePath: "/worktrees/feature-add-new-feature",
|
|
108
133
|
hasUncommittedChanges: false,
|
|
109
134
|
hasUnpushedCommits: false,
|
|
110
135
|
hasRemoteBranch: true,
|
|
111
136
|
isAccessible: true,
|
|
112
137
|
},
|
|
113
138
|
{
|
|
114
|
-
branch:
|
|
115
|
-
cleanupType:
|
|
139
|
+
branch: "hotfix/urgent-fix",
|
|
140
|
+
cleanupType: "worktree-and-branch",
|
|
116
141
|
pullRequest: {
|
|
117
142
|
number: 456,
|
|
118
|
-
title:
|
|
119
|
-
branch:
|
|
120
|
-
mergedAt:
|
|
121
|
-
author:
|
|
143
|
+
title: "Urgent fix",
|
|
144
|
+
branch: "hotfix/urgent-fix",
|
|
145
|
+
mergedAt: "2025-01-21T09:00:00Z",
|
|
146
|
+
author: "user2",
|
|
122
147
|
},
|
|
123
|
-
worktreePath:
|
|
148
|
+
worktreePath: "/worktrees/hotfix-urgent-fix",
|
|
124
149
|
hasUncommittedChanges: true,
|
|
125
150
|
hasUnpushedCommits: false,
|
|
126
151
|
hasRemoteBranch: true,
|
|
127
152
|
isAccessible: true,
|
|
128
153
|
},
|
|
129
154
|
] as CleanupTarget[]);
|
|
130
|
-
generateWorktreePathSpy.mockResolvedValue(
|
|
155
|
+
generateWorktreePathSpy.mockResolvedValue("/worktrees/new-branch");
|
|
131
156
|
createWorktreeSpy.mockResolvedValue(undefined);
|
|
132
157
|
removeWorktreeSpy.mockResolvedValue(undefined);
|
|
133
|
-
getRepositoryRootSpy.mockResolvedValue(
|
|
158
|
+
getRepositoryRootSpy.mockResolvedValue("/repo");
|
|
134
159
|
deleteBranchSpy.mockResolvedValue(undefined);
|
|
135
160
|
});
|
|
136
161
|
|
|
@@ -148,18 +173,26 @@ describe('App shortcuts integration', () => {
|
|
|
148
173
|
deleteBranchSpy.mockReset();
|
|
149
174
|
useGitDataSpy.mockImplementation(originalUseGitData);
|
|
150
175
|
useScreenStateSpy.mockImplementation(originalUseScreenState);
|
|
151
|
-
worktreeManagerScreenSpy.mockImplementation(
|
|
152
|
-
|
|
176
|
+
worktreeManagerScreenSpy.mockImplementation(
|
|
177
|
+
originalWorktreeManagerScreen as any,
|
|
178
|
+
);
|
|
179
|
+
branchCreatorScreenSpy.mockImplementation(
|
|
180
|
+
originalBranchCreatorScreen as any,
|
|
181
|
+
);
|
|
153
182
|
branchListScreenSpy.mockImplementation(originalBranchListScreen as any);
|
|
154
|
-
getMergedPRWorktreesSpy.mockImplementation(
|
|
155
|
-
|
|
183
|
+
getMergedPRWorktreesSpy.mockImplementation(
|
|
184
|
+
originalGetMergedPRWorktrees as any,
|
|
185
|
+
);
|
|
186
|
+
generateWorktreePathSpy.mockImplementation(
|
|
187
|
+
originalGenerateWorktreePath as any,
|
|
188
|
+
);
|
|
156
189
|
createWorktreeSpy.mockImplementation(originalCreateWorktree as any);
|
|
157
190
|
removeWorktreeSpy.mockImplementation(originalRemoveWorktree as any);
|
|
158
191
|
getRepositoryRootSpy.mockImplementation(originalGetRepositoryRoot as any);
|
|
159
192
|
deleteBranchSpy.mockImplementation(originalDeleteBranch as any);
|
|
160
193
|
});
|
|
161
194
|
|
|
162
|
-
it(
|
|
195
|
+
it("navigates to AI tool selector when worktree is selected", () => {
|
|
163
196
|
const onExit = vi.fn();
|
|
164
197
|
render(<App onExit={onExit} />);
|
|
165
198
|
|
|
@@ -169,15 +202,15 @@ describe('App shortcuts integration', () => {
|
|
|
169
202
|
|
|
170
203
|
onSelect(worktrees[0]);
|
|
171
204
|
|
|
172
|
-
expect(navigateToMock).toHaveBeenCalledWith(
|
|
205
|
+
expect(navigateToMock).toHaveBeenCalledWith("ai-tool-selector");
|
|
173
206
|
});
|
|
174
207
|
|
|
175
|
-
it(
|
|
208
|
+
it("creates new worktree when branch creator submits", async () => {
|
|
176
209
|
const onExit = vi.fn();
|
|
177
210
|
|
|
178
211
|
// Update screen state mock to branch-creator for this test
|
|
179
212
|
useScreenStateSpy.mockReturnValue({
|
|
180
|
-
currentScreen:
|
|
213
|
+
currentScreen: "branch-creator",
|
|
181
214
|
navigateTo: navigateToMock as _Mock,
|
|
182
215
|
goBack: goBackMock as _Mock,
|
|
183
216
|
reset: resetMock as _Mock,
|
|
@@ -189,19 +222,19 @@ describe('App shortcuts integration', () => {
|
|
|
189
222
|
const { onCreate } = branchCreatorProps[0];
|
|
190
223
|
|
|
191
224
|
await act(async () => {
|
|
192
|
-
await onCreate(
|
|
225
|
+
await onCreate("feature/new-branch");
|
|
193
226
|
});
|
|
194
227
|
|
|
195
228
|
expect(createWorktreeSpy).toHaveBeenCalledWith(
|
|
196
229
|
expect.objectContaining({
|
|
197
|
-
branchName:
|
|
230
|
+
branchName: "feature/new-branch",
|
|
198
231
|
isNewBranch: true,
|
|
199
|
-
})
|
|
232
|
+
}),
|
|
200
233
|
);
|
|
201
|
-
expect(navigateToMock).toHaveBeenCalledWith(
|
|
234
|
+
expect(navigateToMock).toHaveBeenCalledWith("ai-tool-selector");
|
|
202
235
|
});
|
|
203
236
|
|
|
204
|
-
it(
|
|
237
|
+
it("displays per-branch cleanup indicators and waits before clearing results", async () => {
|
|
205
238
|
vi.useFakeTimers();
|
|
206
239
|
|
|
207
240
|
try {
|
|
@@ -214,18 +247,18 @@ describe('App shortcuts integration', () => {
|
|
|
214
247
|
() =>
|
|
215
248
|
new Promise<void>((resolve) => {
|
|
216
249
|
resolveRemoveWorktree = resolve;
|
|
217
|
-
})
|
|
250
|
+
}),
|
|
218
251
|
);
|
|
219
252
|
|
|
220
253
|
deleteBranchSpy.mockImplementationOnce(
|
|
221
254
|
() =>
|
|
222
255
|
new Promise<void>((resolve) => {
|
|
223
256
|
resolveDeleteBranch = resolve;
|
|
224
|
-
})
|
|
257
|
+
}),
|
|
225
258
|
);
|
|
226
259
|
|
|
227
260
|
useScreenStateSpy.mockReturnValue({
|
|
228
|
-
currentScreen:
|
|
261
|
+
currentScreen: "branch-list",
|
|
229
262
|
navigateTo: navigateToMock as _Mock,
|
|
230
263
|
goBack: goBackMock as _Mock,
|
|
231
264
|
reset: resetMock as _Mock,
|
|
@@ -237,7 +270,7 @@ describe('App shortcuts integration', () => {
|
|
|
237
270
|
const initialProps = branchListProps.at(-1);
|
|
238
271
|
expect(initialProps).toBeDefined();
|
|
239
272
|
if (!initialProps) {
|
|
240
|
-
throw new Error(
|
|
273
|
+
throw new Error("BranchListScreen props missing");
|
|
241
274
|
}
|
|
242
275
|
|
|
243
276
|
act(() => {
|
|
@@ -252,8 +285,10 @@ describe('App shortcuts integration', () => {
|
|
|
252
285
|
expect(latestProps?.cleanupUI?.inputLocked).toBe(true);
|
|
253
286
|
expect(latestProps?.cleanupUI?.footerMessage?.text).toBeTruthy();
|
|
254
287
|
expect(latestProps?.cleanupUI?.indicators).toMatchObject({
|
|
255
|
-
|
|
256
|
-
|
|
288
|
+
"feature/add-new-feature": expect.objectContaining({
|
|
289
|
+
icon: expect.stringMatching(/⠋|⠙|⠹|⠸|⠼|⠴|⠦|⠧/),
|
|
290
|
+
}),
|
|
291
|
+
"hotfix/urgent-fix": expect.objectContaining({ icon: "⏳" }),
|
|
257
292
|
});
|
|
258
293
|
|
|
259
294
|
resolveRemoveWorktree?.();
|
|
@@ -265,10 +300,13 @@ describe('App shortcuts integration', () => {
|
|
|
265
300
|
resolveDeleteBranch?.();
|
|
266
301
|
|
|
267
302
|
expect(removeWorktreeSpy).toHaveBeenCalledWith(
|
|
268
|
-
|
|
269
|
-
true
|
|
303
|
+
"/worktrees/feature-add-new-feature",
|
|
304
|
+
true,
|
|
305
|
+
);
|
|
306
|
+
expect(deleteBranchSpy).toHaveBeenCalledWith(
|
|
307
|
+
"feature/add-new-feature",
|
|
308
|
+
true,
|
|
270
309
|
);
|
|
271
|
-
expect(deleteBranchSpy).toHaveBeenCalledWith('feature/add-new-feature', true);
|
|
272
310
|
|
|
273
311
|
// Flush state updates after processing first target
|
|
274
312
|
await act(async () => {
|
|
@@ -277,8 +315,8 @@ describe('App shortcuts integration', () => {
|
|
|
277
315
|
|
|
278
316
|
latestProps = branchListProps.at(-1);
|
|
279
317
|
expect(latestProps?.cleanupUI?.indicators).toMatchObject({
|
|
280
|
-
|
|
281
|
-
|
|
318
|
+
"feature/add-new-feature": { icon: "✅" },
|
|
319
|
+
"hotfix/urgent-fix": { icon: "⏭️" },
|
|
282
320
|
});
|
|
283
321
|
expect(latestProps?.cleanupUI?.inputLocked).toBe(false);
|
|
284
322
|
|
|
@@ -291,7 +329,11 @@ describe('App shortcuts integration', () => {
|
|
|
291
329
|
latestProps = branchListProps.at(-1);
|
|
292
330
|
expect(latestProps?.cleanupUI?.indicators).toEqual({});
|
|
293
331
|
expect(latestProps?.cleanupUI?.inputLocked).toBe(false);
|
|
294
|
-
expect(
|
|
332
|
+
expect(
|
|
333
|
+
latestProps?.branches?.some(
|
|
334
|
+
(branch: BranchItem) => branch.name === "feature/add-new-feature",
|
|
335
|
+
),
|
|
336
|
+
).toBe(false);
|
|
295
337
|
} finally {
|
|
296
338
|
vi.useRealTimers();
|
|
297
339
|
}
|
|
@@ -303,7 +345,7 @@ afterAll(() => {
|
|
|
303
345
|
useScreenStateSpy.mockRestore();
|
|
304
346
|
worktreeManagerScreenSpy.mockRestore();
|
|
305
347
|
branchCreatorScreenSpy.mockRestore();
|
|
306
|
-
|
|
348
|
+
branchListScreenSpy.mockRestore();
|
|
307
349
|
getMergedPRWorktreesSpy.mockRestore();
|
|
308
350
|
generateWorktreePathSpy.mockRestore();
|
|
309
351
|
createWorktreeSpy.mockRestore();
|