@akiojin/gwt 2.1.1 ā 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 +7 -2
- package/dist/cli/ui/components/common/Input.d.ts.map +1 -1
- package/dist/cli/ui/components/common/Input.js +12 -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 +8 -4
- package/dist/cli/ui/components/screens/BranchListScreen.d.ts.map +1 -1
- package/dist/cli/ui/components/screens/BranchListScreen.js +122 -48
- 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 +496 -75
- 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 +26 -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 +187 -62
- 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,12 +1,12 @@
|
|
|
1
1
|
/**
|
|
2
2
|
* @vitest-environment happy-dom
|
|
3
3
|
*/
|
|
4
|
-
import { describe, it, expect, vi, beforeEach, afterEach } from
|
|
5
|
-
import { render } from
|
|
6
|
-
import React from
|
|
7
|
-
import { App } from
|
|
8
|
-
import { Window } from
|
|
9
|
-
import type { BranchInfo } from
|
|
4
|
+
import { describe, it, expect, vi, beforeEach, afterEach } from "vitest";
|
|
5
|
+
import { render } from "@testing-library/react";
|
|
6
|
+
import React from "react";
|
|
7
|
+
import { App } from "../../components/App.js";
|
|
8
|
+
import { Window } from "happy-dom";
|
|
9
|
+
import type { BranchInfo } from "../../types.js";
|
|
10
10
|
|
|
11
11
|
/**
|
|
12
12
|
* Real-time update integration tests
|
|
@@ -15,14 +15,14 @@ import type { BranchInfo } from '../../types.js';
|
|
|
15
15
|
|
|
16
16
|
// Mock useGitData hook
|
|
17
17
|
const mockRefresh = vi.fn();
|
|
18
|
-
vi.mock(
|
|
18
|
+
vi.mock("../../hooks/useGitData.js", () => ({
|
|
19
19
|
useGitData: vi.fn(),
|
|
20
20
|
}));
|
|
21
21
|
|
|
22
|
-
import { useGitData } from
|
|
22
|
+
import { useGitData } from "../../hooks/useGitData.js";
|
|
23
23
|
const mockUseGitData = useGitData as ReturnType<typeof vi.fn>;
|
|
24
24
|
|
|
25
|
-
describe(
|
|
25
|
+
describe("Real-time Update Integration", () => {
|
|
26
26
|
beforeEach(() => {
|
|
27
27
|
// Setup happy-dom
|
|
28
28
|
const window = new Window();
|
|
@@ -37,18 +37,18 @@ describe('Real-time Update Integration', () => {
|
|
|
37
37
|
vi.restoreAllMocks();
|
|
38
38
|
});
|
|
39
39
|
|
|
40
|
-
it(
|
|
40
|
+
it("T084: should disable auto-refresh (manual refresh with r key)", () => {
|
|
41
41
|
const mockBranches: BranchInfo[] = [
|
|
42
42
|
{
|
|
43
|
-
name:
|
|
44
|
-
branchType:
|
|
45
|
-
type:
|
|
43
|
+
name: "main",
|
|
44
|
+
branchType: "main",
|
|
45
|
+
type: "local",
|
|
46
46
|
isCurrent: true,
|
|
47
47
|
},
|
|
48
48
|
{
|
|
49
|
-
name:
|
|
50
|
-
branchType:
|
|
51
|
-
type:
|
|
49
|
+
name: "feature/test-1",
|
|
50
|
+
branchType: "feature",
|
|
51
|
+
type: "local",
|
|
52
52
|
isCurrent: false,
|
|
53
53
|
},
|
|
54
54
|
];
|
|
@@ -71,18 +71,18 @@ describe('Real-time Update Integration', () => {
|
|
|
71
71
|
});
|
|
72
72
|
});
|
|
73
73
|
|
|
74
|
-
it(
|
|
74
|
+
it("T085: should display updated statistics", () => {
|
|
75
75
|
const mockBranches: BranchInfo[] = [
|
|
76
76
|
{
|
|
77
|
-
name:
|
|
78
|
-
branchType:
|
|
79
|
-
type:
|
|
77
|
+
name: "main",
|
|
78
|
+
branchType: "main",
|
|
79
|
+
type: "local",
|
|
80
80
|
isCurrent: true,
|
|
81
81
|
},
|
|
82
82
|
{
|
|
83
|
-
name:
|
|
84
|
-
branchType:
|
|
85
|
-
type:
|
|
83
|
+
name: "feature/test-1",
|
|
84
|
+
branchType: "feature",
|
|
85
|
+
type: "local",
|
|
86
86
|
isCurrent: false,
|
|
87
87
|
},
|
|
88
88
|
];
|
|
@@ -101,15 +101,15 @@ describe('Real-time Update Integration', () => {
|
|
|
101
101
|
|
|
102
102
|
// Initial state should show "Local: 2"
|
|
103
103
|
expect(getByText(/Local:/i)).toBeDefined();
|
|
104
|
-
expect(getByText(
|
|
104
|
+
expect(getByText("2")).toBeDefined();
|
|
105
105
|
|
|
106
106
|
// Simulate Git operation: add a new branch
|
|
107
107
|
const updatedBranches: BranchInfo[] = [
|
|
108
108
|
...mockBranches,
|
|
109
109
|
{
|
|
110
|
-
name:
|
|
111
|
-
branchType:
|
|
112
|
-
type:
|
|
110
|
+
name: "feature/test-2",
|
|
111
|
+
branchType: "feature",
|
|
112
|
+
type: "local",
|
|
113
113
|
isCurrent: false,
|
|
114
114
|
},
|
|
115
115
|
];
|
|
@@ -127,21 +127,21 @@ describe('Real-time Update Integration', () => {
|
|
|
127
127
|
rerender(<App onExit={onExit} />);
|
|
128
128
|
|
|
129
129
|
// Should now show "Local: 3"
|
|
130
|
-
expect(getByText(
|
|
130
|
+
expect(getByText("3")).toBeDefined();
|
|
131
131
|
});
|
|
132
132
|
|
|
133
|
-
it(
|
|
133
|
+
it("T086: should update statistics after Worktree creation", () => {
|
|
134
134
|
const mockBranches: BranchInfo[] = [
|
|
135
135
|
{
|
|
136
|
-
name:
|
|
137
|
-
branchType:
|
|
138
|
-
type:
|
|
136
|
+
name: "main",
|
|
137
|
+
branchType: "main",
|
|
138
|
+
type: "local",
|
|
139
139
|
isCurrent: true,
|
|
140
140
|
},
|
|
141
141
|
{
|
|
142
|
-
name:
|
|
143
|
-
branchType:
|
|
144
|
-
type:
|
|
142
|
+
name: "feature/test-1",
|
|
143
|
+
branchType: "feature",
|
|
144
|
+
type: "local",
|
|
145
145
|
isCurrent: false,
|
|
146
146
|
},
|
|
147
147
|
];
|
|
@@ -161,24 +161,24 @@ describe('Real-time Update Integration', () => {
|
|
|
161
161
|
// Initial state should show "Worktrees: 0"
|
|
162
162
|
expect(getByText(/Worktrees:/i)).toBeDefined();
|
|
163
163
|
// Verify the content contains Worktrees: 0
|
|
164
|
-
expect(container.textContent).toContain(
|
|
164
|
+
expect(container.textContent).toContain("Worktrees");
|
|
165
165
|
|
|
166
166
|
// Simulate Worktree creation
|
|
167
167
|
const branchesWithWorktree: BranchInfo[] = [
|
|
168
168
|
{
|
|
169
|
-
name:
|
|
170
|
-
branchType:
|
|
171
|
-
type:
|
|
169
|
+
name: "main",
|
|
170
|
+
branchType: "main",
|
|
171
|
+
type: "local",
|
|
172
172
|
isCurrent: true,
|
|
173
173
|
},
|
|
174
174
|
{
|
|
175
|
-
name:
|
|
176
|
-
branchType:
|
|
177
|
-
type:
|
|
175
|
+
name: "feature/test-1",
|
|
176
|
+
branchType: "feature",
|
|
177
|
+
type: "local",
|
|
178
178
|
isCurrent: false,
|
|
179
179
|
worktree: {
|
|
180
|
-
path:
|
|
181
|
-
branch:
|
|
180
|
+
path: "/mock/worktree/feature-test-1",
|
|
181
|
+
branch: "feature/test-1",
|
|
182
182
|
isAccessible: true,
|
|
183
183
|
},
|
|
184
184
|
},
|
|
@@ -188,8 +188,8 @@ describe('Real-time Update Integration', () => {
|
|
|
188
188
|
branches: branchesWithWorktree,
|
|
189
189
|
worktrees: [
|
|
190
190
|
{
|
|
191
|
-
path:
|
|
192
|
-
branch:
|
|
191
|
+
path: "/mock/worktree/feature-test-1",
|
|
192
|
+
branch: "feature/test-1",
|
|
193
193
|
isAccessible: true,
|
|
194
194
|
},
|
|
195
195
|
],
|
|
@@ -205,15 +205,15 @@ describe('Real-time Update Integration', () => {
|
|
|
205
205
|
// Should now show "Worktrees: 1"
|
|
206
206
|
expect(getByText(/Worktrees:/i)).toBeDefined();
|
|
207
207
|
// Verify worktree count increased by checking container content
|
|
208
|
-
expect(container.textContent).toContain(
|
|
208
|
+
expect(container.textContent).toContain("Worktrees");
|
|
209
209
|
});
|
|
210
210
|
|
|
211
|
-
it(
|
|
211
|
+
it("should display lastUpdated timestamp", () => {
|
|
212
212
|
const mockBranches: BranchInfo[] = [
|
|
213
213
|
{
|
|
214
|
-
name:
|
|
215
|
-
branchType:
|
|
216
|
-
type:
|
|
214
|
+
name: "main",
|
|
215
|
+
branchType: "main",
|
|
216
|
+
type: "local",
|
|
217
217
|
isCurrent: true,
|
|
218
218
|
},
|
|
219
219
|
];
|
|
@@ -235,8 +235,8 @@ describe('Real-time Update Integration', () => {
|
|
|
235
235
|
expect(getByText(/Updated:/i)).toBeDefined();
|
|
236
236
|
});
|
|
237
237
|
|
|
238
|
-
it(
|
|
239
|
-
const error = new Error(
|
|
238
|
+
it("should handle refresh errors gracefully", () => {
|
|
239
|
+
const error = new Error("Git command failed");
|
|
240
240
|
mockUseGitData.mockReturnValue({
|
|
241
241
|
branches: [],
|
|
242
242
|
worktrees: [],
|
|
@@ -258,25 +258,25 @@ describe('Real-time Update Integration', () => {
|
|
|
258
258
|
* T082-3: Cursor position retention during auto-refresh
|
|
259
259
|
* Tests that cursor position is maintained when data is auto-refreshed
|
|
260
260
|
*/
|
|
261
|
-
describe(
|
|
262
|
-
it(
|
|
261
|
+
describe("Cursor Position Retention (T082-3)", () => {
|
|
262
|
+
it("should maintain cursor position when branches data is refreshed with same content", () => {
|
|
263
263
|
const mockBranches: BranchInfo[] = [
|
|
264
264
|
{
|
|
265
|
-
name:
|
|
266
|
-
branchType:
|
|
267
|
-
type:
|
|
265
|
+
name: "main",
|
|
266
|
+
branchType: "main",
|
|
267
|
+
type: "local",
|
|
268
268
|
isCurrent: true,
|
|
269
269
|
},
|
|
270
270
|
{
|
|
271
|
-
name:
|
|
272
|
-
branchType:
|
|
273
|
-
type:
|
|
271
|
+
name: "feature/test-1",
|
|
272
|
+
branchType: "feature",
|
|
273
|
+
type: "local",
|
|
274
274
|
isCurrent: false,
|
|
275
275
|
},
|
|
276
276
|
{
|
|
277
|
-
name:
|
|
278
|
-
branchType:
|
|
279
|
-
type:
|
|
277
|
+
name: "feature/test-2",
|
|
278
|
+
branchType: "feature",
|
|
279
|
+
type: "local",
|
|
280
280
|
isCurrent: false,
|
|
281
281
|
},
|
|
282
282
|
];
|
|
@@ -299,21 +299,21 @@ describe('Real-time Update Integration', () => {
|
|
|
299
299
|
// Create new array with same content (simulating auto-refresh)
|
|
300
300
|
const refreshedBranches: BranchInfo[] = [
|
|
301
301
|
{
|
|
302
|
-
name:
|
|
303
|
-
branchType:
|
|
304
|
-
type:
|
|
302
|
+
name: "main",
|
|
303
|
+
branchType: "main",
|
|
304
|
+
type: "local",
|
|
305
305
|
isCurrent: true,
|
|
306
306
|
},
|
|
307
307
|
{
|
|
308
|
-
name:
|
|
309
|
-
branchType:
|
|
310
|
-
type:
|
|
308
|
+
name: "feature/test-1",
|
|
309
|
+
branchType: "feature",
|
|
310
|
+
type: "local",
|
|
311
311
|
isCurrent: false,
|
|
312
312
|
},
|
|
313
313
|
{
|
|
314
|
-
name:
|
|
315
|
-
branchType:
|
|
316
|
-
type:
|
|
314
|
+
name: "feature/test-2",
|
|
315
|
+
branchType: "feature",
|
|
316
|
+
type: "local",
|
|
317
317
|
isCurrent: false,
|
|
318
318
|
},
|
|
319
319
|
];
|
|
@@ -341,18 +341,18 @@ describe('Real-time Update Integration', () => {
|
|
|
341
341
|
// - Cursor position might be reset
|
|
342
342
|
});
|
|
343
343
|
|
|
344
|
-
it(
|
|
344
|
+
it("should maintain cursor position when a branch is added at the end", () => {
|
|
345
345
|
const initialBranches: BranchInfo[] = [
|
|
346
346
|
{
|
|
347
|
-
name:
|
|
348
|
-
branchType:
|
|
349
|
-
type:
|
|
347
|
+
name: "main",
|
|
348
|
+
branchType: "main",
|
|
349
|
+
type: "local",
|
|
350
350
|
isCurrent: true,
|
|
351
351
|
},
|
|
352
352
|
{
|
|
353
|
-
name:
|
|
354
|
-
branchType:
|
|
355
|
-
type:
|
|
353
|
+
name: "feature/test-1",
|
|
354
|
+
branchType: "feature",
|
|
355
|
+
type: "local",
|
|
356
356
|
isCurrent: false,
|
|
357
357
|
},
|
|
358
358
|
];
|
|
@@ -373,9 +373,9 @@ describe('Real-time Update Integration', () => {
|
|
|
373
373
|
const updatedBranches: BranchInfo[] = [
|
|
374
374
|
...initialBranches,
|
|
375
375
|
{
|
|
376
|
-
name:
|
|
377
|
-
branchType:
|
|
378
|
-
type:
|
|
376
|
+
name: "feature/test-2",
|
|
377
|
+
branchType: "feature",
|
|
378
|
+
type: "local",
|
|
379
379
|
isCurrent: false,
|
|
380
380
|
},
|
|
381
381
|
];
|
|
@@ -394,24 +394,24 @@ describe('Real-time Update Integration', () => {
|
|
|
394
394
|
// Cursor should remain on the same item (e.g., index 1 should still point to 'feature/test-1')
|
|
395
395
|
});
|
|
396
396
|
|
|
397
|
-
it(
|
|
397
|
+
it("should adjust cursor position when current selected branch is deleted", () => {
|
|
398
398
|
const initialBranches: BranchInfo[] = [
|
|
399
399
|
{
|
|
400
|
-
name:
|
|
401
|
-
branchType:
|
|
402
|
-
type:
|
|
400
|
+
name: "main",
|
|
401
|
+
branchType: "main",
|
|
402
|
+
type: "local",
|
|
403
403
|
isCurrent: true,
|
|
404
404
|
},
|
|
405
405
|
{
|
|
406
|
-
name:
|
|
407
|
-
branchType:
|
|
408
|
-
type:
|
|
406
|
+
name: "feature/test-1",
|
|
407
|
+
branchType: "feature",
|
|
408
|
+
type: "local",
|
|
409
409
|
isCurrent: false,
|
|
410
410
|
},
|
|
411
411
|
{
|
|
412
|
-
name:
|
|
413
|
-
branchType:
|
|
414
|
-
type:
|
|
412
|
+
name: "feature/test-2",
|
|
413
|
+
branchType: "feature",
|
|
414
|
+
type: "local",
|
|
415
415
|
isCurrent: false,
|
|
416
416
|
},
|
|
417
417
|
];
|
|
@@ -431,15 +431,15 @@ describe('Real-time Update Integration', () => {
|
|
|
431
431
|
// Remove middle branch (cursor was on index 1, which is now deleted)
|
|
432
432
|
const updatedBranches: BranchInfo[] = [
|
|
433
433
|
{
|
|
434
|
-
name:
|
|
435
|
-
branchType:
|
|
436
|
-
type:
|
|
434
|
+
name: "main",
|
|
435
|
+
branchType: "main",
|
|
436
|
+
type: "local",
|
|
437
437
|
isCurrent: true,
|
|
438
438
|
},
|
|
439
439
|
{
|
|
440
|
-
name:
|
|
441
|
-
branchType:
|
|
442
|
-
type:
|
|
440
|
+
name: "feature/test-2",
|
|
441
|
+
branchType: "feature",
|
|
442
|
+
type: "local",
|
|
443
443
|
isCurrent: false,
|
|
444
444
|
},
|
|
445
445
|
];
|
|
@@ -458,12 +458,12 @@ describe('Real-time Update Integration', () => {
|
|
|
458
458
|
// Cursor should be clamped to valid index (e.g., moved to index 1, which is now 'feature/test-2')
|
|
459
459
|
});
|
|
460
460
|
|
|
461
|
-
it(
|
|
461
|
+
it("should maintain scroll offset during auto-refresh", () => {
|
|
462
462
|
// Create many branches to test scrolling
|
|
463
463
|
const manyBranches: BranchInfo[] = Array.from({ length: 20 }, (_, i) => ({
|
|
464
464
|
name: `feature/test-${i + 1}`,
|
|
465
|
-
branchType:
|
|
466
|
-
type:
|
|
465
|
+
branchType: "feature" as const,
|
|
466
|
+
type: "local" as const,
|
|
467
467
|
isCurrent: false,
|
|
468
468
|
}));
|
|
469
469
|
|
|
@@ -480,12 +480,15 @@ describe('Real-time Update Integration', () => {
|
|
|
480
480
|
const { rerender } = render(<App onExit={onExit} />);
|
|
481
481
|
|
|
482
482
|
// Simulate auto-refresh with same content
|
|
483
|
-
const refreshedBranches: BranchInfo[] = Array.from(
|
|
484
|
-
|
|
485
|
-
|
|
486
|
-
|
|
487
|
-
|
|
488
|
-
|
|
483
|
+
const refreshedBranches: BranchInfo[] = Array.from(
|
|
484
|
+
{ length: 20 },
|
|
485
|
+
(_, i) => ({
|
|
486
|
+
name: `feature/test-${i + 1}`,
|
|
487
|
+
branchType: "feature" as const,
|
|
488
|
+
type: "local" as const,
|
|
489
|
+
isCurrent: false,
|
|
490
|
+
}),
|
|
491
|
+
);
|
|
489
492
|
|
|
490
493
|
mockUseGitData.mockReturnValue({
|
|
491
494
|
branches: refreshedBranches,
|
|
@@ -1,16 +1,23 @@
|
|
|
1
|
-
import { describe, it, expect } from
|
|
2
|
-
import { render } from
|
|
3
|
-
import React from
|
|
4
|
-
import { BranchListScreen } from
|
|
5
|
-
import type { BranchItem, Statistics } from
|
|
1
|
+
import { describe, it, expect } from "vitest";
|
|
2
|
+
import { render } from "ink-testing-library";
|
|
3
|
+
import React from "react";
|
|
4
|
+
import { BranchListScreen } from "../../components/screens/BranchListScreen.js";
|
|
5
|
+
import type { BranchItem, Statistics } from "../../types.js";
|
|
6
6
|
|
|
7
7
|
/**
|
|
8
8
|
* Generate mock branch items for performance testing
|
|
9
9
|
*/
|
|
10
10
|
function generateMockBranches(count: number): BranchItem[] {
|
|
11
11
|
const branches: BranchItem[] = [];
|
|
12
|
-
const types = [
|
|
13
|
-
const branchTypes = [
|
|
12
|
+
const types = ["feature", "hotfix", "release", "other"] as const;
|
|
13
|
+
const branchTypes = [
|
|
14
|
+
"main",
|
|
15
|
+
"develop",
|
|
16
|
+
"feature",
|
|
17
|
+
"hotfix",
|
|
18
|
+
"release",
|
|
19
|
+
"other",
|
|
20
|
+
] as const;
|
|
14
21
|
|
|
15
22
|
for (let i = 0; i < count; i++) {
|
|
16
23
|
const type = types[i % types.length];
|
|
@@ -18,22 +25,26 @@ function generateMockBranches(count: number): BranchItem[] {
|
|
|
18
25
|
const hasWorktree = i % 3 === 0;
|
|
19
26
|
|
|
20
27
|
branches.push({
|
|
21
|
-
name: `${type}/test-branch-${i.toString().padStart(4,
|
|
28
|
+
name: `${type}/test-branch-${i.toString().padStart(4, "0")}`,
|
|
22
29
|
branchType,
|
|
23
|
-
type: i % 10 === 0 ?
|
|
30
|
+
type: i % 10 === 0 ? "remote" : "local",
|
|
24
31
|
isCurrent: i === 0,
|
|
25
32
|
worktree: hasWorktree
|
|
26
33
|
? {
|
|
27
34
|
path: `/mock/worktree/${type}-${i}`,
|
|
28
|
-
branch: `${type}/test-branch-${i.toString().padStart(4,
|
|
35
|
+
branch: `${type}/test-branch-${i.toString().padStart(4, "0")}`,
|
|
29
36
|
isAccessible: i % 5 !== 0, // Some inaccessible
|
|
30
37
|
}
|
|
31
38
|
: undefined,
|
|
32
|
-
worktreeStatus: hasWorktree
|
|
39
|
+
worktreeStatus: hasWorktree
|
|
40
|
+
? i % 5 !== 0
|
|
41
|
+
? "active"
|
|
42
|
+
: "inaccessible"
|
|
43
|
+
: undefined,
|
|
33
44
|
hasChanges: i % 4 === 0,
|
|
34
45
|
icons: [],
|
|
35
|
-
label: `${type}/test-branch-${i.toString().padStart(4,
|
|
36
|
-
value: `${type}/test-branch-${i.toString().padStart(4,
|
|
46
|
+
label: `${type}/test-branch-${i.toString().padStart(4, "0")}`,
|
|
47
|
+
value: `${type}/test-branch-${i.toString().padStart(4, "0")}`,
|
|
37
48
|
});
|
|
38
49
|
}
|
|
39
50
|
|
|
@@ -52,17 +63,17 @@ function generateMockBranches(count: number): BranchItem[] {
|
|
|
52
63
|
// worktree: 0,
|
|
53
64
|
// };
|
|
54
65
|
|
|
55
|
-
describe(
|
|
56
|
-
it(
|
|
66
|
+
describe("BranchListScreen Performance", () => {
|
|
67
|
+
it("should render 100+ branches within acceptable time", () => {
|
|
57
68
|
const branches = generateMockBranches(150);
|
|
58
69
|
const stats: Statistics = {
|
|
59
70
|
total: branches.length,
|
|
60
|
-
local: branches.filter((b) => b.type ===
|
|
61
|
-
remote: branches.filter((b) => b.type ===
|
|
71
|
+
local: branches.filter((b) => b.type === "local").length,
|
|
72
|
+
remote: branches.filter((b) => b.type === "remote").length,
|
|
62
73
|
current: 1,
|
|
63
|
-
feature: branches.filter((b) => b.branchType ===
|
|
64
|
-
hotfix: branches.filter((b) => b.branchType ===
|
|
65
|
-
release: branches.filter((b) => b.branchType ===
|
|
74
|
+
feature: branches.filter((b) => b.branchType === "feature").length,
|
|
75
|
+
hotfix: branches.filter((b) => b.branchType === "hotfix").length,
|
|
76
|
+
release: branches.filter((b) => b.branchType === "release").length,
|
|
66
77
|
worktree: branches.filter((b) => b.worktree).length,
|
|
67
78
|
};
|
|
68
79
|
|
|
@@ -75,7 +86,7 @@ describe('BranchListScreen Performance', () => {
|
|
|
75
86
|
onSelect={() => {}}
|
|
76
87
|
onNavigate={() => {}}
|
|
77
88
|
onQuit={() => {}}
|
|
78
|
-
|
|
89
|
+
/>,
|
|
79
90
|
);
|
|
80
91
|
|
|
81
92
|
const renderTime = performance.now() - startTime;
|
|
@@ -89,19 +100,21 @@ describe('BranchListScreen Performance', () => {
|
|
|
89
100
|
console.log(`\nš Performance Test Results:`);
|
|
90
101
|
console.log(` Branches: ${branches.length}`);
|
|
91
102
|
console.log(` Render time: ${renderTime.toFixed(2)}ms`);
|
|
92
|
-
console.log(
|
|
103
|
+
console.log(
|
|
104
|
+
` Average per branch: ${(renderTime / branches.length).toFixed(3)}ms`,
|
|
105
|
+
);
|
|
93
106
|
});
|
|
94
107
|
|
|
95
|
-
it(
|
|
108
|
+
it("should handle re-render efficiently when stats update", () => {
|
|
96
109
|
const branches = generateMockBranches(100);
|
|
97
110
|
const stats: Statistics = {
|
|
98
111
|
total: branches.length,
|
|
99
|
-
local: branches.filter((b) => b.type ===
|
|
100
|
-
remote: branches.filter((b) => b.type ===
|
|
112
|
+
local: branches.filter((b) => b.type === "local").length,
|
|
113
|
+
remote: branches.filter((b) => b.type === "remote").length,
|
|
101
114
|
current: 1,
|
|
102
|
-
feature: branches.filter((b) => b.branchType ===
|
|
103
|
-
hotfix: branches.filter((b) => b.branchType ===
|
|
104
|
-
release: branches.filter((b) => b.branchType ===
|
|
115
|
+
feature: branches.filter((b) => b.branchType === "feature").length,
|
|
116
|
+
hotfix: branches.filter((b) => b.branchType === "hotfix").length,
|
|
117
|
+
release: branches.filter((b) => b.branchType === "release").length,
|
|
105
118
|
worktree: branches.filter((b) => b.worktree).length,
|
|
106
119
|
};
|
|
107
120
|
|
|
@@ -113,7 +126,7 @@ describe('BranchListScreen Performance', () => {
|
|
|
113
126
|
onNavigate={() => {}}
|
|
114
127
|
onQuit={() => {}}
|
|
115
128
|
lastUpdated={new Date()}
|
|
116
|
-
|
|
129
|
+
/>,
|
|
117
130
|
);
|
|
118
131
|
|
|
119
132
|
// Simulate stats update (real-time refresh)
|
|
@@ -127,7 +140,7 @@ describe('BranchListScreen Performance', () => {
|
|
|
127
140
|
onNavigate={() => {}}
|
|
128
141
|
onQuit={() => {}}
|
|
129
142
|
lastUpdated={new Date()}
|
|
130
|
-
|
|
143
|
+
/>,
|
|
131
144
|
);
|
|
132
145
|
|
|
133
146
|
const rerenderTime = performance.now() - startTime;
|
|
@@ -141,16 +154,16 @@ describe('BranchListScreen Performance', () => {
|
|
|
141
154
|
console.log(` Re-render time: ${rerenderTime.toFixed(2)}ms`);
|
|
142
155
|
});
|
|
143
156
|
|
|
144
|
-
it(
|
|
157
|
+
it("should handle large branch list (200+ branches)", () => {
|
|
145
158
|
const branches = generateMockBranches(250);
|
|
146
159
|
const stats: Statistics = {
|
|
147
160
|
total: branches.length,
|
|
148
|
-
local: branches.filter((b) => b.type ===
|
|
149
|
-
remote: branches.filter((b) => b.type ===
|
|
161
|
+
local: branches.filter((b) => b.type === "local").length,
|
|
162
|
+
remote: branches.filter((b) => b.type === "remote").length,
|
|
150
163
|
current: 1,
|
|
151
|
-
feature: branches.filter((b) => b.branchType ===
|
|
152
|
-
hotfix: branches.filter((b) => b.branchType ===
|
|
153
|
-
release: branches.filter((b) => b.branchType ===
|
|
164
|
+
feature: branches.filter((b) => b.branchType === "feature").length,
|
|
165
|
+
hotfix: branches.filter((b) => b.branchType === "hotfix").length,
|
|
166
|
+
release: branches.filter((b) => b.branchType === "release").length,
|
|
154
167
|
worktree: branches.filter((b) => b.worktree).length,
|
|
155
168
|
};
|
|
156
169
|
|
|
@@ -163,7 +176,7 @@ describe('BranchListScreen Performance', () => {
|
|
|
163
176
|
onSelect={() => {}}
|
|
164
177
|
onNavigate={() => {}}
|
|
165
178
|
onQuit={() => {}}
|
|
166
|
-
|
|
179
|
+
/>,
|
|
167
180
|
);
|
|
168
181
|
|
|
169
182
|
const renderTime = performance.now() - startTime;
|