@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,13 +1,13 @@
|
|
|
1
1
|
/**
|
|
2
2
|
* @vitest-environment happy-dom
|
|
3
3
|
*/
|
|
4
|
-
import { describe, it, expect, beforeEach, vi } from
|
|
5
|
-
import { render } from
|
|
6
|
-
import React from
|
|
7
|
-
import { ExecutionModeSelectorScreen } from
|
|
8
|
-
import { Window } from
|
|
4
|
+
import { describe, it, expect, beforeEach, vi } from "vitest";
|
|
5
|
+
import { render } from "@testing-library/react";
|
|
6
|
+
import React from "react";
|
|
7
|
+
import { ExecutionModeSelectorScreen } from "../../../components/screens/ExecutionModeSelectorScreen.js";
|
|
8
|
+
import { Window } from "happy-dom";
|
|
9
9
|
|
|
10
|
-
describe(
|
|
10
|
+
describe("ExecutionModeSelectorScreen", () => {
|
|
11
11
|
beforeEach(() => {
|
|
12
12
|
// Setup happy-dom
|
|
13
13
|
const window = new Window();
|
|
@@ -15,21 +15,21 @@ describe('ExecutionModeSelectorScreen', () => {
|
|
|
15
15
|
globalThis.document = window.document as any;
|
|
16
16
|
});
|
|
17
17
|
|
|
18
|
-
it(
|
|
18
|
+
it("should render header with title", () => {
|
|
19
19
|
const onBack = vi.fn();
|
|
20
20
|
const onSelect = vi.fn();
|
|
21
21
|
const { container } = render(
|
|
22
|
-
<ExecutionModeSelectorScreen onBack={onBack} onSelect={onSelect}
|
|
22
|
+
<ExecutionModeSelectorScreen onBack={onBack} onSelect={onSelect} />,
|
|
23
23
|
);
|
|
24
24
|
|
|
25
25
|
expect(container).toBeDefined();
|
|
26
26
|
});
|
|
27
27
|
|
|
28
|
-
it(
|
|
28
|
+
it("should render execution mode options", () => {
|
|
29
29
|
const onBack = vi.fn();
|
|
30
30
|
const onSelect = vi.fn();
|
|
31
31
|
const { getByText } = render(
|
|
32
|
-
<ExecutionModeSelectorScreen onBack={onBack} onSelect={onSelect}
|
|
32
|
+
<ExecutionModeSelectorScreen onBack={onBack} onSelect={onSelect} />,
|
|
33
33
|
);
|
|
34
34
|
|
|
35
35
|
expect(getByText(/Normal/i)).toBeDefined();
|
|
@@ -37,25 +37,25 @@ describe('ExecutionModeSelectorScreen', () => {
|
|
|
37
37
|
expect(getByText(/Resume/i)).toBeDefined();
|
|
38
38
|
});
|
|
39
39
|
|
|
40
|
-
it(
|
|
40
|
+
it("should render footer with actions", () => {
|
|
41
41
|
const onBack = vi.fn();
|
|
42
42
|
const onSelect = vi.fn();
|
|
43
43
|
const { getAllByText } = render(
|
|
44
|
-
<ExecutionModeSelectorScreen onBack={onBack} onSelect={onSelect}
|
|
44
|
+
<ExecutionModeSelectorScreen onBack={onBack} onSelect={onSelect} />,
|
|
45
45
|
);
|
|
46
46
|
|
|
47
47
|
expect(getAllByText(/enter/i).length).toBeGreaterThan(0);
|
|
48
48
|
expect(getAllByText(/esc/i).length).toBeGreaterThan(0);
|
|
49
49
|
});
|
|
50
50
|
|
|
51
|
-
it(
|
|
51
|
+
it("should use terminal height for layout calculation", () => {
|
|
52
52
|
const originalRows = process.stdout.rows;
|
|
53
53
|
process.stdout.rows = 30;
|
|
54
54
|
|
|
55
55
|
const onBack = vi.fn();
|
|
56
56
|
const onSelect = vi.fn();
|
|
57
57
|
const { container } = render(
|
|
58
|
-
<ExecutionModeSelectorScreen onBack={onBack} onSelect={onSelect}
|
|
58
|
+
<ExecutionModeSelectorScreen onBack={onBack} onSelect={onSelect} />,
|
|
59
59
|
);
|
|
60
60
|
|
|
61
61
|
expect(container).toBeDefined();
|
|
@@ -63,22 +63,22 @@ describe('ExecutionModeSelectorScreen', () => {
|
|
|
63
63
|
process.stdout.rows = originalRows;
|
|
64
64
|
});
|
|
65
65
|
|
|
66
|
-
it(
|
|
66
|
+
it("should handle back navigation with ESC key", () => {
|
|
67
67
|
const onBack = vi.fn();
|
|
68
68
|
const onSelect = vi.fn();
|
|
69
69
|
const { container } = render(
|
|
70
|
-
<ExecutionModeSelectorScreen onBack={onBack} onSelect={onSelect}
|
|
70
|
+
<ExecutionModeSelectorScreen onBack={onBack} onSelect={onSelect} />,
|
|
71
71
|
);
|
|
72
72
|
|
|
73
73
|
// Test will verify onBack is called when ESC is pressed
|
|
74
74
|
expect(container).toBeDefined();
|
|
75
75
|
});
|
|
76
76
|
|
|
77
|
-
it(
|
|
77
|
+
it("should handle mode selection", () => {
|
|
78
78
|
const onBack = vi.fn();
|
|
79
79
|
const onSelect = vi.fn();
|
|
80
80
|
const { container } = render(
|
|
81
|
-
<ExecutionModeSelectorScreen onBack={onBack} onSelect={onSelect}
|
|
81
|
+
<ExecutionModeSelectorScreen onBack={onBack} onSelect={onSelect} />,
|
|
82
82
|
);
|
|
83
83
|
|
|
84
84
|
// Test will verify onSelect is called with correct mode
|
|
@@ -87,12 +87,12 @@ describe('ExecutionModeSelectorScreen', () => {
|
|
|
87
87
|
|
|
88
88
|
// TDD: Tests for 2-step selection (mode + skipPermissions)
|
|
89
89
|
// TODO: Implement integration tests with user interaction simulation
|
|
90
|
-
describe.skip(
|
|
91
|
-
it(
|
|
90
|
+
describe.skip("Skip Permissions Selection", () => {
|
|
91
|
+
it("should render skip permissions prompt after mode selection", () => {
|
|
92
92
|
const onBack = vi.fn();
|
|
93
93
|
const onSelect = vi.fn();
|
|
94
94
|
const { getByText } = render(
|
|
95
|
-
<ExecutionModeSelectorScreen onBack={onBack} onSelect={onSelect}
|
|
95
|
+
<ExecutionModeSelectorScreen onBack={onBack} onSelect={onSelect} />,
|
|
96
96
|
);
|
|
97
97
|
|
|
98
98
|
// After selecting a mode, should show skip permissions prompt
|
|
@@ -100,11 +100,11 @@ describe('ExecutionModeSelectorScreen', () => {
|
|
|
100
100
|
expect(getByText(/Skip permission checks/i)).toBeDefined();
|
|
101
101
|
});
|
|
102
102
|
|
|
103
|
-
it(
|
|
103
|
+
it("should show correct flag hints for skipPermissions prompt", () => {
|
|
104
104
|
const onBack = vi.fn();
|
|
105
105
|
const onSelect = vi.fn();
|
|
106
106
|
const { getByText } = render(
|
|
107
|
-
<ExecutionModeSelectorScreen onBack={onBack} onSelect={onSelect}
|
|
107
|
+
<ExecutionModeSelectorScreen onBack={onBack} onSelect={onSelect} />,
|
|
108
108
|
);
|
|
109
109
|
|
|
110
110
|
// Should show both --dangerously-skip-permissions and --yolo hints
|
|
@@ -112,10 +112,12 @@ describe('ExecutionModeSelectorScreen', () => {
|
|
|
112
112
|
expect(getByText(/--yolo/i)).toBeDefined();
|
|
113
113
|
});
|
|
114
114
|
|
|
115
|
-
it(
|
|
115
|
+
it("should call onSelect with mode and skipPermissions=true when Yes is selected", () => {
|
|
116
116
|
const onBack = vi.fn();
|
|
117
117
|
const onSelect = vi.fn();
|
|
118
|
-
render(
|
|
118
|
+
render(
|
|
119
|
+
<ExecutionModeSelectorScreen onBack={onBack} onSelect={onSelect} />,
|
|
120
|
+
);
|
|
119
121
|
|
|
120
122
|
// After selecting mode and Yes for skipPermissions
|
|
121
123
|
// onSelect should be called with { mode: 'normal', skipPermissions: true }
|
|
@@ -124,14 +126,16 @@ describe('ExecutionModeSelectorScreen', () => {
|
|
|
124
126
|
expect.objectContaining({
|
|
125
127
|
mode: expect.any(String),
|
|
126
128
|
skipPermissions: true,
|
|
127
|
-
})
|
|
129
|
+
}),
|
|
128
130
|
);
|
|
129
131
|
});
|
|
130
132
|
|
|
131
|
-
it(
|
|
133
|
+
it("should call onSelect with mode and skipPermissions=false when No is selected", () => {
|
|
132
134
|
const onBack = vi.fn();
|
|
133
135
|
const onSelect = vi.fn();
|
|
134
|
-
render(
|
|
136
|
+
render(
|
|
137
|
+
<ExecutionModeSelectorScreen onBack={onBack} onSelect={onSelect} />,
|
|
138
|
+
);
|
|
135
139
|
|
|
136
140
|
// After selecting mode and No for skipPermissions
|
|
137
141
|
// onSelect should be called with { mode: 'normal', skipPermissions: false }
|
|
@@ -140,21 +144,23 @@ describe('ExecutionModeSelectorScreen', () => {
|
|
|
140
144
|
expect.objectContaining({
|
|
141
145
|
mode: expect.any(String),
|
|
142
146
|
skipPermissions: false,
|
|
143
|
-
})
|
|
147
|
+
}),
|
|
144
148
|
);
|
|
145
149
|
});
|
|
146
150
|
|
|
147
|
-
it(
|
|
151
|
+
it("should default skipPermissions to false", () => {
|
|
148
152
|
const onBack = vi.fn();
|
|
149
153
|
const onSelect = vi.fn();
|
|
150
|
-
render(
|
|
154
|
+
render(
|
|
155
|
+
<ExecutionModeSelectorScreen onBack={onBack} onSelect={onSelect} />,
|
|
156
|
+
);
|
|
151
157
|
|
|
152
158
|
// Default should be No (skipPermissions: false)
|
|
153
159
|
// This test will fail until implementation
|
|
154
160
|
expect(onSelect).toHaveBeenCalledWith(
|
|
155
161
|
expect.objectContaining({
|
|
156
162
|
skipPermissions: false,
|
|
157
|
-
})
|
|
163
|
+
}),
|
|
158
164
|
);
|
|
159
165
|
});
|
|
160
166
|
});
|
|
@@ -1,14 +1,14 @@
|
|
|
1
1
|
/**
|
|
2
2
|
* @vitest-environment happy-dom
|
|
3
3
|
*/
|
|
4
|
-
import { describe, it, expect, beforeEach, vi } from
|
|
5
|
-
import { render } from
|
|
6
|
-
import React from
|
|
7
|
-
import { PRCleanupScreen } from
|
|
8
|
-
import { Window } from
|
|
9
|
-
import type { CleanupTarget } from
|
|
10
|
-
|
|
11
|
-
describe(
|
|
4
|
+
import { describe, it, expect, beforeEach, vi } from "vitest";
|
|
5
|
+
import { render } from "@testing-library/react";
|
|
6
|
+
import React from "react";
|
|
7
|
+
import { PRCleanupScreen } from "../../../components/screens/PRCleanupScreen.js";
|
|
8
|
+
import { Window } from "happy-dom";
|
|
9
|
+
import type { CleanupTarget } from "../../../types.js";
|
|
10
|
+
|
|
11
|
+
describe("PRCleanupScreen", () => {
|
|
12
12
|
beforeEach(() => {
|
|
13
13
|
// Setup happy-dom
|
|
14
14
|
const window = new Window();
|
|
@@ -18,30 +18,30 @@ describe('PRCleanupScreen', () => {
|
|
|
18
18
|
|
|
19
19
|
const mockTargets: CleanupTarget[] = [
|
|
20
20
|
{
|
|
21
|
-
branch:
|
|
22
|
-
cleanupType:
|
|
21
|
+
branch: "feature/add-new-feature",
|
|
22
|
+
cleanupType: "worktree-and-branch",
|
|
23
23
|
pullRequest: {
|
|
24
24
|
number: 123,
|
|
25
|
-
title:
|
|
26
|
-
branch:
|
|
27
|
-
mergedAt:
|
|
28
|
-
author:
|
|
25
|
+
title: "Add new feature",
|
|
26
|
+
branch: "feature/add-new-feature",
|
|
27
|
+
mergedAt: "2025-01-20T10:00:00Z",
|
|
28
|
+
author: "user1",
|
|
29
29
|
},
|
|
30
|
-
worktreePath:
|
|
30
|
+
worktreePath: "/workspace/feature-add-new-feature",
|
|
31
31
|
hasUncommittedChanges: false,
|
|
32
32
|
hasUnpushedCommits: false,
|
|
33
33
|
hasRemoteBranch: true,
|
|
34
34
|
isAccessible: true,
|
|
35
35
|
},
|
|
36
36
|
{
|
|
37
|
-
branch:
|
|
38
|
-
cleanupType:
|
|
37
|
+
branch: "hotfix/fix-bug",
|
|
38
|
+
cleanupType: "branch-only",
|
|
39
39
|
pullRequest: {
|
|
40
40
|
number: 124,
|
|
41
|
-
title:
|
|
42
|
-
branch:
|
|
43
|
-
mergedAt:
|
|
44
|
-
author:
|
|
41
|
+
title: "Fix bug",
|
|
42
|
+
branch: "hotfix/fix-bug",
|
|
43
|
+
mergedAt: "2025-01-21T15:30:00Z",
|
|
44
|
+
author: "user2",
|
|
45
45
|
},
|
|
46
46
|
worktreePath: null,
|
|
47
47
|
hasUncommittedChanges: false,
|
|
@@ -50,7 +50,7 @@ describe('PRCleanupScreen', () => {
|
|
|
50
50
|
},
|
|
51
51
|
];
|
|
52
52
|
|
|
53
|
-
it(
|
|
53
|
+
it("should render header with title", () => {
|
|
54
54
|
const onBack = vi.fn();
|
|
55
55
|
const onCleanup = vi.fn();
|
|
56
56
|
const { getByText } = render(
|
|
@@ -61,13 +61,13 @@ describe('PRCleanupScreen', () => {
|
|
|
61
61
|
onBack={onBack}
|
|
62
62
|
onRefresh={vi.fn()}
|
|
63
63
|
onCleanup={onCleanup}
|
|
64
|
-
|
|
64
|
+
/>,
|
|
65
65
|
);
|
|
66
66
|
|
|
67
67
|
expect(getByText(/Branch Cleanup/i)).toBeDefined();
|
|
68
68
|
});
|
|
69
69
|
|
|
70
|
-
it(
|
|
70
|
+
it("should render PR list", () => {
|
|
71
71
|
const onBack = vi.fn();
|
|
72
72
|
const onCleanup = vi.fn();
|
|
73
73
|
const { getByText } = render(
|
|
@@ -78,14 +78,14 @@ describe('PRCleanupScreen', () => {
|
|
|
78
78
|
onBack={onBack}
|
|
79
79
|
onRefresh={vi.fn()}
|
|
80
80
|
onCleanup={onCleanup}
|
|
81
|
-
|
|
81
|
+
/>,
|
|
82
82
|
);
|
|
83
83
|
|
|
84
84
|
expect(getByText(/feature\/add-new-feature/i)).toBeDefined();
|
|
85
85
|
expect(getByText(/hotfix\/fix-bug/i)).toBeDefined();
|
|
86
86
|
});
|
|
87
87
|
|
|
88
|
-
it(
|
|
88
|
+
it("should render footer with actions", () => {
|
|
89
89
|
const onBack = vi.fn();
|
|
90
90
|
const onCleanup = vi.fn();
|
|
91
91
|
const { getAllByText } = render(
|
|
@@ -96,14 +96,14 @@ describe('PRCleanupScreen', () => {
|
|
|
96
96
|
onBack={onBack}
|
|
97
97
|
onRefresh={vi.fn()}
|
|
98
98
|
onCleanup={onCleanup}
|
|
99
|
-
|
|
99
|
+
/>,
|
|
100
100
|
);
|
|
101
101
|
|
|
102
102
|
expect(getAllByText(/enter/i).length).toBeGreaterThan(0);
|
|
103
103
|
expect(getAllByText(/esc/i).length).toBeGreaterThan(0);
|
|
104
104
|
});
|
|
105
105
|
|
|
106
|
-
it(
|
|
106
|
+
it("should handle empty PR list", () => {
|
|
107
107
|
const onBack = vi.fn();
|
|
108
108
|
const onCleanup = vi.fn();
|
|
109
109
|
const { getByText } = render(
|
|
@@ -114,13 +114,13 @@ describe('PRCleanupScreen', () => {
|
|
|
114
114
|
onBack={onBack}
|
|
115
115
|
onRefresh={vi.fn()}
|
|
116
116
|
onCleanup={onCleanup}
|
|
117
|
-
|
|
117
|
+
/>,
|
|
118
118
|
);
|
|
119
119
|
|
|
120
120
|
expect(getByText(/No cleanup targets found/i)).toBeDefined();
|
|
121
121
|
});
|
|
122
122
|
|
|
123
|
-
it(
|
|
123
|
+
it("should display PR count in stats", () => {
|
|
124
124
|
const onBack = vi.fn();
|
|
125
125
|
const onCleanup = vi.fn();
|
|
126
126
|
const { getByText, getAllByText } = render(
|
|
@@ -131,14 +131,14 @@ describe('PRCleanupScreen', () => {
|
|
|
131
131
|
onBack={onBack}
|
|
132
132
|
onRefresh={vi.fn()}
|
|
133
133
|
onCleanup={onCleanup}
|
|
134
|
-
|
|
134
|
+
/>,
|
|
135
135
|
);
|
|
136
136
|
|
|
137
137
|
expect(getByText(/Total:/i)).toBeDefined();
|
|
138
138
|
expect(getAllByText(/^2$/).length).toBeGreaterThan(0);
|
|
139
139
|
});
|
|
140
140
|
|
|
141
|
-
it(
|
|
141
|
+
it("should use terminal height for layout calculation", () => {
|
|
142
142
|
const originalRows = process.stdout.rows;
|
|
143
143
|
process.stdout.rows = 30;
|
|
144
144
|
|
|
@@ -152,7 +152,7 @@ describe('PRCleanupScreen', () => {
|
|
|
152
152
|
onBack={onBack}
|
|
153
153
|
onRefresh={vi.fn()}
|
|
154
154
|
onCleanup={onCleanup}
|
|
155
|
-
|
|
155
|
+
/>,
|
|
156
156
|
);
|
|
157
157
|
|
|
158
158
|
expect(container).toBeDefined();
|
|
@@ -160,7 +160,7 @@ describe('PRCleanupScreen', () => {
|
|
|
160
160
|
process.stdout.rows = originalRows;
|
|
161
161
|
});
|
|
162
162
|
|
|
163
|
-
it(
|
|
163
|
+
it("should handle back navigation with ESC key", () => {
|
|
164
164
|
const onBack = vi.fn();
|
|
165
165
|
const onCleanup = vi.fn();
|
|
166
166
|
const { container } = render(
|
|
@@ -171,14 +171,14 @@ describe('PRCleanupScreen', () => {
|
|
|
171
171
|
onBack={onBack}
|
|
172
172
|
onRefresh={vi.fn()}
|
|
173
173
|
onCleanup={onCleanup}
|
|
174
|
-
|
|
174
|
+
/>,
|
|
175
175
|
);
|
|
176
176
|
|
|
177
177
|
// Test will verify onBack is called when ESC is pressed
|
|
178
178
|
expect(container).toBeDefined();
|
|
179
179
|
});
|
|
180
180
|
|
|
181
|
-
it(
|
|
181
|
+
it("should render status message when provided", () => {
|
|
182
182
|
const onBack = vi.fn();
|
|
183
183
|
const onCleanup = vi.fn();
|
|
184
184
|
const { getByText } = render(
|
|
@@ -190,13 +190,13 @@ describe('PRCleanupScreen', () => {
|
|
|
190
190
|
onBack={onBack}
|
|
191
191
|
onRefresh={vi.fn()}
|
|
192
192
|
onCleanup={onCleanup}
|
|
193
|
-
|
|
193
|
+
/>,
|
|
194
194
|
);
|
|
195
195
|
|
|
196
196
|
expect(getByText(/Cleanup completed/i)).toBeDefined();
|
|
197
197
|
});
|
|
198
198
|
|
|
199
|
-
it(
|
|
199
|
+
it("should render loading message when loading", () => {
|
|
200
200
|
const onBack = vi.fn();
|
|
201
201
|
const onCleanup = vi.fn();
|
|
202
202
|
const { getByText } = render(
|
|
@@ -207,7 +207,7 @@ describe('PRCleanupScreen', () => {
|
|
|
207
207
|
onBack={onBack}
|
|
208
208
|
onRefresh={vi.fn()}
|
|
209
209
|
onCleanup={onCleanup}
|
|
210
|
-
|
|
210
|
+
/>,
|
|
211
211
|
);
|
|
212
212
|
|
|
213
213
|
expect(getByText(/Loading cleanup targets/i)).toBeDefined();
|
|
@@ -1,13 +1,13 @@
|
|
|
1
1
|
/**
|
|
2
2
|
* @vitest-environment happy-dom
|
|
3
3
|
*/
|
|
4
|
-
import { describe, it, expect, beforeEach, vi } from
|
|
5
|
-
import { render } from
|
|
6
|
-
import React from
|
|
7
|
-
import { SessionSelectorScreen } from
|
|
8
|
-
import { Window } from
|
|
4
|
+
import { describe, it, expect, beforeEach, vi } from "vitest";
|
|
5
|
+
import { render } from "@testing-library/react";
|
|
6
|
+
import React from "react";
|
|
7
|
+
import { SessionSelectorScreen } from "../../../components/screens/SessionSelectorScreen.js";
|
|
8
|
+
import { Window } from "happy-dom";
|
|
9
9
|
|
|
10
|
-
describe(
|
|
10
|
+
describe("SessionSelectorScreen", () => {
|
|
11
11
|
beforeEach(() => {
|
|
12
12
|
// Setup happy-dom
|
|
13
13
|
const window = new Window();
|
|
@@ -15,23 +15,31 @@ describe('SessionSelectorScreen', () => {
|
|
|
15
15
|
globalThis.document = window.document as any;
|
|
16
16
|
});
|
|
17
17
|
|
|
18
|
-
const mockSessions = [
|
|
18
|
+
const mockSessions = ["session-1", "session-2", "session-3"];
|
|
19
19
|
|
|
20
|
-
it(
|
|
20
|
+
it("should render header with title", () => {
|
|
21
21
|
const onBack = vi.fn();
|
|
22
22
|
const onSelect = vi.fn();
|
|
23
23
|
const { getByText } = render(
|
|
24
|
-
<SessionSelectorScreen
|
|
24
|
+
<SessionSelectorScreen
|
|
25
|
+
sessions={mockSessions}
|
|
26
|
+
onBack={onBack}
|
|
27
|
+
onSelect={onSelect}
|
|
28
|
+
/>,
|
|
25
29
|
);
|
|
26
30
|
|
|
27
31
|
expect(getByText(/Session Selection/i)).toBeDefined();
|
|
28
32
|
});
|
|
29
33
|
|
|
30
|
-
it(
|
|
34
|
+
it("should render session list", () => {
|
|
31
35
|
const onBack = vi.fn();
|
|
32
36
|
const onSelect = vi.fn();
|
|
33
37
|
const { getByText } = render(
|
|
34
|
-
<SessionSelectorScreen
|
|
38
|
+
<SessionSelectorScreen
|
|
39
|
+
sessions={mockSessions}
|
|
40
|
+
onBack={onBack}
|
|
41
|
+
onSelect={onSelect}
|
|
42
|
+
/>,
|
|
35
43
|
);
|
|
36
44
|
|
|
37
45
|
expect(getByText(/session-1/i)).toBeDefined();
|
|
@@ -39,46 +47,62 @@ describe('SessionSelectorScreen', () => {
|
|
|
39
47
|
expect(getByText(/session-3/i)).toBeDefined();
|
|
40
48
|
});
|
|
41
49
|
|
|
42
|
-
it(
|
|
50
|
+
it("should render footer with actions", () => {
|
|
43
51
|
const onBack = vi.fn();
|
|
44
52
|
const onSelect = vi.fn();
|
|
45
53
|
const { getAllByText } = render(
|
|
46
|
-
<SessionSelectorScreen
|
|
54
|
+
<SessionSelectorScreen
|
|
55
|
+
sessions={mockSessions}
|
|
56
|
+
onBack={onBack}
|
|
57
|
+
onSelect={onSelect}
|
|
58
|
+
/>,
|
|
47
59
|
);
|
|
48
60
|
|
|
49
61
|
expect(getAllByText(/enter/i).length).toBeGreaterThan(0);
|
|
50
62
|
expect(getAllByText(/esc/i).length).toBeGreaterThan(0);
|
|
51
63
|
});
|
|
52
64
|
|
|
53
|
-
it(
|
|
65
|
+
it("should handle empty session list", () => {
|
|
54
66
|
const onBack = vi.fn();
|
|
55
67
|
const onSelect = vi.fn();
|
|
56
68
|
const { getByText } = render(
|
|
57
|
-
<SessionSelectorScreen
|
|
69
|
+
<SessionSelectorScreen
|
|
70
|
+
sessions={[]}
|
|
71
|
+
onBack={onBack}
|
|
72
|
+
onSelect={onSelect}
|
|
73
|
+
/>,
|
|
58
74
|
);
|
|
59
75
|
|
|
60
76
|
expect(getByText(/No sessions found/i)).toBeDefined();
|
|
61
77
|
});
|
|
62
78
|
|
|
63
|
-
it(
|
|
79
|
+
it("should display session count in stats", () => {
|
|
64
80
|
const onBack = vi.fn();
|
|
65
81
|
const onSelect = vi.fn();
|
|
66
82
|
const { getByText, getAllByText } = render(
|
|
67
|
-
<SessionSelectorScreen
|
|
83
|
+
<SessionSelectorScreen
|
|
84
|
+
sessions={mockSessions}
|
|
85
|
+
onBack={onBack}
|
|
86
|
+
onSelect={onSelect}
|
|
87
|
+
/>,
|
|
68
88
|
);
|
|
69
89
|
|
|
70
90
|
expect(getByText(/Total:/i)).toBeDefined();
|
|
71
91
|
expect(getAllByText(/3/).length).toBeGreaterThan(0);
|
|
72
92
|
});
|
|
73
93
|
|
|
74
|
-
it(
|
|
94
|
+
it("should use terminal height for layout calculation", () => {
|
|
75
95
|
const originalRows = process.stdout.rows;
|
|
76
96
|
process.stdout.rows = 30;
|
|
77
97
|
|
|
78
98
|
const onBack = vi.fn();
|
|
79
99
|
const onSelect = vi.fn();
|
|
80
100
|
const { container } = render(
|
|
81
|
-
<SessionSelectorScreen
|
|
101
|
+
<SessionSelectorScreen
|
|
102
|
+
sessions={mockSessions}
|
|
103
|
+
onBack={onBack}
|
|
104
|
+
onSelect={onSelect}
|
|
105
|
+
/>,
|
|
82
106
|
);
|
|
83
107
|
|
|
84
108
|
expect(container).toBeDefined();
|
|
@@ -86,11 +110,15 @@ describe('SessionSelectorScreen', () => {
|
|
|
86
110
|
process.stdout.rows = originalRows;
|
|
87
111
|
});
|
|
88
112
|
|
|
89
|
-
it(
|
|
113
|
+
it("should handle back navigation with ESC key", () => {
|
|
90
114
|
const onBack = vi.fn();
|
|
91
115
|
const onSelect = vi.fn();
|
|
92
116
|
const { container } = render(
|
|
93
|
-
<SessionSelectorScreen
|
|
117
|
+
<SessionSelectorScreen
|
|
118
|
+
sessions={mockSessions}
|
|
119
|
+
onBack={onBack}
|
|
120
|
+
onSelect={onSelect}
|
|
121
|
+
/>,
|
|
94
122
|
);
|
|
95
123
|
|
|
96
124
|
// Test will verify onBack is called when ESC is pressed
|