@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.
Files changed (149) hide show
  1. package/README.ja.md +4 -4
  2. package/README.md +4 -4
  3. package/dist/cli/ui/components/App.d.ts +4 -4
  4. package/dist/cli/ui/components/App.d.ts.map +1 -1
  5. package/dist/cli/ui/components/App.js +144 -105
  6. package/dist/cli/ui/components/App.js.map +1 -1
  7. package/dist/cli/ui/components/common/Confirm.d.ts +1 -1
  8. package/dist/cli/ui/components/common/Confirm.d.ts.map +1 -1
  9. package/dist/cli/ui/components/common/Confirm.js +7 -7
  10. package/dist/cli/ui/components/common/Confirm.js.map +1 -1
  11. package/dist/cli/ui/components/common/ErrorBoundary.d.ts +1 -1
  12. package/dist/cli/ui/components/common/ErrorBoundary.d.ts.map +1 -1
  13. package/dist/cli/ui/components/common/ErrorBoundary.js +4 -4
  14. package/dist/cli/ui/components/common/ErrorBoundary.js.map +1 -1
  15. package/dist/cli/ui/components/common/Input.d.ts +2 -2
  16. package/dist/cli/ui/components/common/Input.d.ts.map +1 -1
  17. package/dist/cli/ui/components/common/Input.js +4 -4
  18. package/dist/cli/ui/components/common/Input.js.map +1 -1
  19. package/dist/cli/ui/components/common/LoadingIndicator.d.ts +1 -1
  20. package/dist/cli/ui/components/common/LoadingIndicator.d.ts.map +1 -1
  21. package/dist/cli/ui/components/common/LoadingIndicator.js +4 -4
  22. package/dist/cli/ui/components/common/LoadingIndicator.js.map +1 -1
  23. package/dist/cli/ui/components/common/Select.d.ts +1 -1
  24. package/dist/cli/ui/components/common/Select.d.ts.map +1 -1
  25. package/dist/cli/ui/components/common/Select.js +11 -12
  26. package/dist/cli/ui/components/common/Select.js.map +1 -1
  27. package/dist/cli/ui/components/screens/AIToolSelectorScreen.d.ts +2 -2
  28. package/dist/cli/ui/components/screens/AIToolSelectorScreen.d.ts.map +1 -1
  29. package/dist/cli/ui/components/screens/AIToolSelectorScreen.js +11 -11
  30. package/dist/cli/ui/components/screens/AIToolSelectorScreen.js.map +1 -1
  31. package/dist/cli/ui/components/screens/BranchCreatorScreen.d.ts +1 -1
  32. package/dist/cli/ui/components/screens/BranchCreatorScreen.d.ts.map +1 -1
  33. package/dist/cli/ui/components/screens/BranchCreatorScreen.js +39 -36
  34. package/dist/cli/ui/components/screens/BranchCreatorScreen.js.map +1 -1
  35. package/dist/cli/ui/components/screens/BranchListScreen.d.ts +3 -3
  36. package/dist/cli/ui/components/screens/BranchListScreen.d.ts.map +1 -1
  37. package/dist/cli/ui/components/screens/BranchListScreen.js +55 -50
  38. package/dist/cli/ui/components/screens/BranchListScreen.js.map +1 -1
  39. package/dist/cli/ui/components/screens/ExecutionModeSelectorScreen.d.ts +2 -2
  40. package/dist/cli/ui/components/screens/ExecutionModeSelectorScreen.d.ts.map +1 -1
  41. package/dist/cli/ui/components/screens/ExecutionModeSelectorScreen.js +25 -25
  42. package/dist/cli/ui/components/screens/ExecutionModeSelectorScreen.js.map +1 -1
  43. package/dist/cli/ui/components/screens/PRCleanupScreen.d.ts +2 -2
  44. package/dist/cli/ui/components/screens/PRCleanupScreen.js +21 -21
  45. package/dist/cli/ui/components/screens/SessionSelectorScreen.d.ts +1 -1
  46. package/dist/cli/ui/components/screens/SessionSelectorScreen.js +8 -8
  47. package/dist/cli/ui/components/screens/WorktreeManagerScreen.d.ts +1 -1
  48. package/dist/cli/ui/components/screens/WorktreeManagerScreen.js +8 -8
  49. package/dist/cli/ui/screens/BranchActionSelectorScreen.d.ts.map +1 -1
  50. package/dist/cli/ui/screens/BranchActionSelectorScreen.js +7 -4
  51. package/dist/cli/ui/screens/BranchActionSelectorScreen.js.map +1 -1
  52. package/dist/cli/ui/types.d.ts.map +1 -1
  53. package/dist/client/assets/{index-V6hDu9KS.js → index-Difv1Hwu.js} +2 -2
  54. package/dist/client/index.html +1 -1
  55. package/dist/config/builtin-tools.d.ts +10 -2
  56. package/dist/config/builtin-tools.d.ts.map +1 -1
  57. package/dist/config/builtin-tools.js +40 -4
  58. package/dist/config/builtin-tools.js.map +1 -1
  59. package/dist/config/index.d.ts.map +1 -1
  60. package/dist/config/index.js.map +1 -1
  61. package/dist/config/tools.d.ts.map +1 -1
  62. package/dist/config/tools.js +4 -3
  63. package/dist/config/tools.js.map +1 -1
  64. package/dist/gemini.d.ts +12 -0
  65. package/dist/gemini.d.ts.map +1 -0
  66. package/dist/gemini.js +154 -0
  67. package/dist/gemini.js.map +1 -0
  68. package/dist/git.d.ts.map +1 -1
  69. package/dist/git.js.map +1 -1
  70. package/dist/index.d.ts.map +1 -1
  71. package/dist/index.js +30 -0
  72. package/dist/index.js.map +1 -1
  73. package/dist/qwen.d.ts +12 -0
  74. package/dist/qwen.d.ts.map +1 -0
  75. package/dist/qwen.js +154 -0
  76. package/dist/qwen.js.map +1 -0
  77. package/dist/services/git.service.d.ts.map +1 -1
  78. package/dist/services/git.service.js.map +1 -1
  79. package/dist/web/client/src/components/BranchGraph.d.ts.map +1 -1
  80. package/dist/web/client/src/components/BranchGraph.js +1 -1
  81. package/dist/web/client/src/components/BranchGraph.js.map +1 -1
  82. package/dist/web/client/src/components/EnvEditor.d.ts.map +1 -1
  83. package/dist/web/client/src/components/EnvEditor.js +7 -4
  84. package/dist/web/client/src/components/EnvEditor.js.map +1 -1
  85. package/dist/web/client/src/pages/BranchDetailPage.d.ts.map +1 -1
  86. package/dist/web/client/src/pages/BranchDetailPage.js +55 -18
  87. package/dist/web/client/src/pages/BranchDetailPage.js.map +1 -1
  88. package/dist/web/client/src/pages/BranchListPage.d.ts.map +1 -1
  89. package/dist/web/client/src/pages/BranchListPage.js +10 -4
  90. package/dist/web/client/src/pages/BranchListPage.js.map +1 -1
  91. package/dist/web/client/src/pages/ConfigManagementPage.d.ts.map +1 -1
  92. package/dist/web/client/src/pages/ConfigManagementPage.js +4 -2
  93. package/dist/web/client/src/pages/ConfigManagementPage.js.map +1 -1
  94. package/package.json +2 -1
  95. package/src/cli/ui/__tests__/acceptance/navigation.acceptance.test.tsx +69 -50
  96. package/src/cli/ui/__tests__/components/App.protected-branch.test.tsx +67 -45
  97. package/src/cli/ui/__tests__/components/App.shortcuts.test.tsx +117 -75
  98. package/src/cli/ui/__tests__/components/App.test.tsx +45 -37
  99. package/src/cli/ui/__tests__/components/common/Confirm.test.tsx +35 -22
  100. package/src/cli/ui/__tests__/components/common/ErrorBoundary.test.tsx +22 -22
  101. package/src/cli/ui/__tests__/components/common/Input.test.tsx +29 -22
  102. package/src/cli/ui/__tests__/components/common/LoadingIndicator.test.tsx +40 -34
  103. package/src/cli/ui/__tests__/components/common/Select.memo.test.tsx +57 -66
  104. package/src/cli/ui/__tests__/components/common/Select.test.tsx +121 -91
  105. package/src/cli/ui/__tests__/components/parts/Footer.test.tsx +18 -16
  106. package/src/cli/ui/__tests__/components/parts/Header.test.tsx +13 -13
  107. package/src/cli/ui/__tests__/components/parts/ScrollableList.test.tsx +20 -20
  108. package/src/cli/ui/__tests__/components/parts/Stats.test.tsx +38 -26
  109. package/src/cli/ui/__tests__/components/screens/AIToolSelectorScreen.test.tsx +31 -31
  110. package/src/cli/ui/__tests__/components/screens/BranchCreatorScreen.test.tsx +73 -37
  111. package/src/cli/ui/__tests__/components/screens/BranchListScreen.test.tsx +261 -153
  112. package/src/cli/ui/__tests__/components/screens/ExecutionModeSelectorScreen.test.tsx +38 -32
  113. package/src/cli/ui/__tests__/components/screens/PRCleanupScreen.test.tsx +39 -39
  114. package/src/cli/ui/__tests__/components/screens/SessionSelectorScreen.test.tsx +49 -21
  115. package/src/cli/ui/__tests__/components/screens/WorktreeManagerScreen.test.tsx +52 -28
  116. package/src/cli/ui/__tests__/integration/edgeCases.test.tsx +84 -48
  117. package/src/cli/ui/__tests__/integration/navigation.test.tsx +111 -83
  118. package/src/cli/ui/__tests__/integration/realtimeUpdate.test.tsx +111 -108
  119. package/src/cli/ui/__tests__/performance/branchList.performance.test.tsx +50 -37
  120. package/src/cli/ui/__tests__/performance/useMemoOptimization.test.tsx +75 -76
  121. package/src/cli/ui/components/App.tsx +247 -150
  122. package/src/cli/ui/components/common/Confirm.tsx +13 -9
  123. package/src/cli/ui/components/common/ErrorBoundary.tsx +8 -5
  124. package/src/cli/ui/components/common/Input.tsx +12 -4
  125. package/src/cli/ui/components/common/LoadingIndicator.tsx +8 -5
  126. package/src/cli/ui/components/common/Select.tsx +28 -17
  127. package/src/cli/ui/components/parts/Header.test.tsx +5 -15
  128. package/src/cli/ui/components/screens/AIToolSelectorScreen.tsx +19 -13
  129. package/src/cli/ui/components/screens/BranchCreatorScreen.tsx +74 -54
  130. package/src/cli/ui/components/screens/BranchListScreen.tsx +92 -75
  131. package/src/cli/ui/components/screens/ExecutionModeSelectorScreen.tsx +35 -28
  132. package/src/cli/ui/components/screens/PRCleanupScreen.tsx +22 -22
  133. package/src/cli/ui/components/screens/SessionSelectorScreen.tsx +8 -8
  134. package/src/cli/ui/components/screens/WorktreeManagerScreen.tsx +8 -8
  135. package/src/cli/ui/screens/BranchActionSelectorScreen.tsx +9 -4
  136. package/src/cli/ui/types.ts +8 -1
  137. package/src/config/builtin-tools.ts +42 -4
  138. package/src/config/index.ts +2 -12
  139. package/src/config/tools.ts +16 -6
  140. package/src/gemini.ts +202 -0
  141. package/src/git.ts +2 -1
  142. package/src/index.ts +30 -0
  143. package/src/qwen.ts +208 -0
  144. package/src/services/git.service.ts +2 -1
  145. package/src/web/client/src/components/BranchGraph.tsx +3 -2
  146. package/src/web/client/src/components/EnvEditor.tsx +44 -11
  147. package/src/web/client/src/pages/BranchDetailPage.tsx +165 -54
  148. package/src/web/client/src/pages/BranchListPage.tsx +37 -13
  149. 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 { describe, it, expect, beforeEach, afterEach, afterAll, vi } from 'vitest';
5
- import { act, 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
- import * as useGitDataModule from '../../hooks/useGitData.js';
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 { App } from "../../components/App.js";
16
+ import { Window } from "happy-dom";
17
+ import type { BranchInfo } from "../../types.js";
18
+ import * as useGitDataModule from "../../hooks/useGitData.js";
11
19
 
12
20
  const mockRefresh = vi.fn();
13
21
  const originalUseGitData = useGitDataModule.useGitData;
14
- const useGitDataSpy = vi.spyOn(useGitDataModule, 'useGitData');
22
+ const useGitDataSpy = vi.spyOn(useGitDataModule, "useGitData");
15
23
 
16
- describe('App', () => {
24
+ describe("App", () => {
17
25
  beforeEach(() => {
18
26
  // Setup happy-dom
19
27
  const window = new Window();
@@ -27,20 +35,20 @@ describe('App', () => {
27
35
 
28
36
  const mockBranches: BranchInfo[] = [
29
37
  {
30
- name: 'main',
31
- type: 'local',
32
- branchType: 'main',
38
+ name: "main",
39
+ type: "local",
40
+ branchType: "main",
33
41
  isCurrent: true,
34
42
  },
35
43
  {
36
- name: 'feature/test',
37
- type: 'local',
38
- branchType: 'feature',
44
+ name: "feature/test",
45
+ type: "local",
46
+ branchType: "feature",
39
47
  isCurrent: false,
40
48
  },
41
49
  ];
42
50
 
43
- it('should render BranchListScreen when data is loaded', () => {
51
+ it("should render BranchListScreen when data is loaded", () => {
44
52
  useGitDataSpy.mockReturnValue({
45
53
  branches: mockBranches,
46
54
  loading: false,
@@ -58,7 +66,7 @@ describe('App', () => {
58
66
  expect(getByText(/feature\/test/)).toBeDefined();
59
67
  });
60
68
 
61
- it('should show loading state initially', async () => {
69
+ it("should show loading state initially", async () => {
62
70
  useGitDataSpy.mockReturnValue({
63
71
  branches: [],
64
72
  loading: true,
@@ -69,7 +77,7 @@ describe('App', () => {
69
77
 
70
78
  const onExit = vi.fn();
71
79
  const { queryByText, getByText } = render(
72
- <App onExit={onExit} loadingIndicatorDelay={10} />
80
+ <App onExit={onExit} loadingIndicatorDelay={10} />,
73
81
  );
74
82
 
75
83
  expect(queryByText(/Loading Git information/i)).toBeNull();
@@ -81,8 +89,8 @@ describe('App', () => {
81
89
  expect(getByText(/Loading Git information/i)).toBeDefined();
82
90
  });
83
91
 
84
- it('should show error state when Git data fails to load', () => {
85
- const error = new Error('Failed to fetch branches');
92
+ it("should show error state when Git data fails to load", () => {
93
+ const error = new Error("Failed to fetch branches");
86
94
  useGitDataSpy.mockReturnValue({
87
95
  branches: [],
88
96
  loading: false,
@@ -98,29 +106,29 @@ describe('App', () => {
98
106
  expect(getByText(/Failed to fetch branches/i)).toBeDefined();
99
107
  });
100
108
 
101
- it('should calculate statistics from branches', () => {
109
+ it("should calculate statistics from branches", () => {
102
110
  const branchesWithWorktree: BranchInfo[] = [
103
111
  {
104
- name: 'main',
105
- type: 'local',
106
- branchType: 'main',
112
+ name: "main",
113
+ type: "local",
114
+ branchType: "main",
107
115
  isCurrent: true,
108
116
  },
109
117
  {
110
- name: 'feature/a',
111
- type: 'local',
112
- branchType: 'feature',
118
+ name: "feature/a",
119
+ type: "local",
120
+ branchType: "feature",
113
121
  isCurrent: false,
114
122
  worktree: {
115
- path: '/path/a',
123
+ path: "/path/a",
116
124
  locked: false,
117
125
  prunable: false,
118
126
  },
119
127
  },
120
128
  {
121
- name: 'origin/main',
122
- type: 'remote',
123
- branchType: 'main',
129
+ name: "origin/main",
130
+ type: "remote",
131
+ branchType: "main",
124
132
  isCurrent: false,
125
133
  },
126
134
  ];
@@ -144,7 +152,7 @@ describe('App', () => {
144
152
  expect(getByText(/Worktrees:/)).toBeDefined();
145
153
  });
146
154
 
147
- it('should call onExit when branch is selected', () => {
155
+ it("should call onExit when branch is selected", () => {
148
156
  useGitDataSpy.mockReturnValue({
149
157
  branches: mockBranches,
150
158
  loading: false,
@@ -161,7 +169,7 @@ describe('App', () => {
161
169
  // which is covered in integration tests
162
170
  });
163
171
 
164
- it('should handle empty branch list', () => {
172
+ it("should handle empty branch list", () => {
165
173
  useGitDataSpy.mockReturnValue({
166
174
  branches: [],
167
175
  loading: false,
@@ -176,7 +184,7 @@ describe('App', () => {
176
184
  expect(getByText(/No branches found/i)).toBeDefined();
177
185
  });
178
186
 
179
- it('should wrap with ErrorBoundary', () => {
187
+ it("should wrap with ErrorBoundary", () => {
180
188
  // This test verifies ErrorBoundary is present
181
189
  // Actual error catching is tested separately
182
190
  useGitDataSpy.mockReturnValue({
@@ -193,7 +201,7 @@ describe('App', () => {
193
201
  expect(container).toBeDefined();
194
202
  });
195
203
 
196
- it('should format branch items with icons', () => {
204
+ it("should format branch items with icons", () => {
197
205
  useGitDataSpy.mockReturnValue({
198
206
  branches: mockBranches,
199
207
  loading: false,
@@ -209,8 +217,8 @@ describe('App', () => {
209
217
  expect(getByText(/⚡/)).toBeDefined();
210
218
  });
211
219
 
212
- describe('BranchActionSelectorScreen integration', () => {
213
- it('should show BranchActionSelectorScreen after branch selection', () => {
220
+ describe("BranchActionSelectorScreen integration", () => {
221
+ it("should show BranchActionSelectorScreen after branch selection", () => {
214
222
  useGitDataSpy.mockReturnValue({
215
223
  branches: mockBranches,
216
224
  loading: false,
@@ -1,13 +1,13 @@
1
1
  /**
2
2
  * @vitest-environment happy-dom
3
3
  */
4
- import { describe, it, expect, beforeEach, vi } from 'vitest';
5
- import { render } from '@testing-library/react';
6
- import React from 'react';
7
- import { Confirm } from '../../../components/common/Confirm.js';
8
- import { Window } from 'happy-dom';
4
+ import { describe, it, expect, beforeEach, vi } from "vitest";
5
+ import { render } from "@testing-library/react";
6
+ import React from "react";
7
+ import { Confirm } from "../../../components/common/Confirm.js";
8
+ import { Window } from "happy-dom";
9
9
 
10
- describe('Confirm', () => {
10
+ describe("Confirm", () => {
11
11
  beforeEach(() => {
12
12
  // Setup happy-dom
13
13
  const window = new Window();
@@ -15,47 +15,60 @@ describe('Confirm', () => {
15
15
  globalThis.document = window.document as any;
16
16
  });
17
17
 
18
- it('should render the message', () => {
18
+ it("should render the message", () => {
19
19
  const onConfirm = vi.fn();
20
- const { getByText } = render(<Confirm message="Are you sure?" onConfirm={onConfirm} />);
20
+ const { getByText } = render(
21
+ <Confirm message="Are you sure?" onConfirm={onConfirm} />,
22
+ );
21
23
 
22
- expect(getByText('Are you sure?')).toBeDefined();
24
+ expect(getByText("Are you sure?")).toBeDefined();
23
25
  });
24
26
 
25
- it('should render Yes and No options', () => {
27
+ it("should render Yes and No options", () => {
26
28
  const onConfirm = vi.fn();
27
- const { getByText } = render(<Confirm message="Continue?" onConfirm={onConfirm} />);
29
+ const { getByText } = render(
30
+ <Confirm message="Continue?" onConfirm={onConfirm} />,
31
+ );
28
32
 
29
- expect(getByText('Yes')).toBeDefined();
30
- expect(getByText('No')).toBeDefined();
33
+ expect(getByText("Yes")).toBeDefined();
34
+ expect(getByText("No")).toBeDefined();
31
35
  });
32
36
 
33
- it('should render custom Yes and No labels', () => {
37
+ it("should render custom Yes and No labels", () => {
34
38
  const onConfirm = vi.fn();
35
39
  const { getByText } = render(
36
- <Confirm message="Delete?" onConfirm={onConfirm} yesLabel="Confirm" noLabel="Cancel" />
40
+ <Confirm
41
+ message="Delete?"
42
+ onConfirm={onConfirm}
43
+ yesLabel="Confirm"
44
+ noLabel="Cancel"
45
+ />,
37
46
  );
38
47
 
39
- expect(getByText('Confirm')).toBeDefined();
40
- expect(getByText('Cancel')).toBeDefined();
48
+ expect(getByText("Confirm")).toBeDefined();
49
+ expect(getByText("Cancel")).toBeDefined();
41
50
  });
42
51
 
43
- it('should default to Yes option', () => {
52
+ it("should default to Yes option", () => {
44
53
  const onConfirm = vi.fn();
45
- const { container } = render(<Confirm message="Continue?" onConfirm={onConfirm} />);
54
+ const { container } = render(
55
+ <Confirm message="Continue?" onConfirm={onConfirm} />,
56
+ );
46
57
 
47
58
  // Verify component renders without error
48
59
  expect(container).toBeDefined();
49
60
  });
50
61
 
51
- it('should accept defaultNo prop to default to No', () => {
62
+ it("should accept defaultNo prop to default to No", () => {
52
63
  const onConfirm = vi.fn();
53
- const { container } = render(<Confirm message="Continue?" onConfirm={onConfirm} defaultNo />);
64
+ const { container } = render(
65
+ <Confirm message="Continue?" onConfirm={onConfirm} defaultNo />,
66
+ );
54
67
 
55
68
  expect(container).toBeDefined();
56
69
  });
57
70
 
58
- it('should call onConfirm with false by default when rendered', () => {
71
+ it("should call onConfirm with false by default when rendered", () => {
59
72
  const onConfirm = vi.fn();
60
73
  render(<Confirm message="Continue?" onConfirm={onConfirm} />);
61
74
 
@@ -1,22 +1,22 @@
1
1
  /**
2
2
  * @vitest-environment happy-dom
3
3
  */
4
- import { describe, it, expect, beforeEach, vi } from 'vitest';
5
- import { render } from '@testing-library/react';
6
- import React from 'react';
7
- import { ErrorBoundary } from '../../../components/common/ErrorBoundary.js';
8
- import { Text, Box } from 'ink';
9
- import { Window } from 'happy-dom';
4
+ import { describe, it, expect, beforeEach, vi } from "vitest";
5
+ import { render } from "@testing-library/react";
6
+ import React from "react";
7
+ import { ErrorBoundary } from "../../../components/common/ErrorBoundary.js";
8
+ import { Text, Box } from "ink";
9
+ import { Window } from "happy-dom";
10
10
 
11
11
  // Component that throws an error
12
12
  const ThrowError = ({ shouldThrow }: { shouldThrow: boolean }) => {
13
13
  if (shouldThrow) {
14
- throw new Error('Test error message');
14
+ throw new Error("Test error message");
15
15
  }
16
16
  return <Text>No error</Text>;
17
17
  };
18
18
 
19
- describe('ErrorBoundary', () => {
19
+ describe("ErrorBoundary", () => {
20
20
  beforeEach(() => {
21
21
  // Setup happy-dom
22
22
  const window = new Window();
@@ -24,31 +24,31 @@ describe('ErrorBoundary', () => {
24
24
  globalThis.document = window.document as any;
25
25
 
26
26
  // Suppress console.error for expected errors in tests
27
- vi.spyOn(console, 'error').mockImplementation(() => {});
27
+ vi.spyOn(console, "error").mockImplementation(() => {});
28
28
  });
29
29
 
30
- it('should render children when no error occurs', () => {
30
+ it("should render children when no error occurs", () => {
31
31
  const { getByText } = render(
32
32
  <ErrorBoundary>
33
33
  <ThrowError shouldThrow={false} />
34
- </ErrorBoundary>
34
+ </ErrorBoundary>,
35
35
  );
36
36
 
37
- expect(getByText('No error')).toBeDefined();
37
+ expect(getByText("No error")).toBeDefined();
38
38
  });
39
39
 
40
- it('should catch errors and display error message', () => {
40
+ it("should catch errors and display error message", () => {
41
41
  const { getByText } = render(
42
42
  <ErrorBoundary>
43
43
  <ThrowError shouldThrow={true} />
44
- </ErrorBoundary>
44
+ </ErrorBoundary>,
45
45
  );
46
46
 
47
47
  expect(getByText(/Error:/)).toBeDefined();
48
48
  expect(getByText(/Test error message/)).toBeDefined();
49
49
  });
50
50
 
51
- it('should display custom fallback when provided', () => {
51
+ it("should display custom fallback when provided", () => {
52
52
  const CustomFallback = ({ error }: { error: Error }) => (
53
53
  <Box>
54
54
  <Text color="red">Custom Error: {error.message}</Text>
@@ -58,18 +58,18 @@ describe('ErrorBoundary', () => {
58
58
  const { getByText } = render(
59
59
  <ErrorBoundary fallback={CustomFallback}>
60
60
  <ThrowError shouldThrow={true} />
61
- </ErrorBoundary>
61
+ </ErrorBoundary>,
62
62
  );
63
63
 
64
64
  expect(getByText(/Custom Error:/)).toBeDefined();
65
65
  expect(getByText(/Test error message/)).toBeDefined();
66
66
  });
67
67
 
68
- it('should reset error state when children change', () => {
68
+ it("should reset error state when children change", () => {
69
69
  const { rerender, getByText } = render(
70
70
  <ErrorBoundary>
71
71
  <ThrowError shouldThrow={true} />
72
- </ErrorBoundary>
72
+ </ErrorBoundary>,
73
73
  );
74
74
 
75
75
  // Error is shown
@@ -79,14 +79,14 @@ describe('ErrorBoundary', () => {
79
79
  rerender(
80
80
  <ErrorBoundary>
81
81
  <ThrowError shouldThrow={false} />
82
- </ErrorBoundary>
82
+ </ErrorBoundary>,
83
83
  );
84
84
 
85
85
  // Original children should be rendered
86
- expect(getByText('No error')).toBeDefined();
86
+ expect(getByText("No error")).toBeDefined();
87
87
  });
88
88
 
89
- it('should handle errors with no message', () => {
89
+ it("should handle errors with no message", () => {
90
90
  const ThrowNoMessage = () => {
91
91
  throw new Error();
92
92
  };
@@ -94,7 +94,7 @@ describe('ErrorBoundary', () => {
94
94
  const { getByText } = render(
95
95
  <ErrorBoundary>
96
96
  <ThrowNoMessage />
97
- </ErrorBoundary>
97
+ </ErrorBoundary>,
98
98
  );
99
99
 
100
100
  expect(getByText(/Error:/)).toBeDefined();
@@ -1,13 +1,13 @@
1
1
  /**
2
2
  * @vitest-environment happy-dom
3
3
  */
4
- import { describe, it, expect, beforeEach, vi } from 'vitest';
5
- import { render } from '@testing-library/react';
6
- import React from 'react';
7
- import { Input } from '../../../components/common/Input.js';
8
- import { Window } from 'happy-dom';
4
+ import { describe, it, expect, beforeEach, vi } from "vitest";
5
+ import { render } from "@testing-library/react";
6
+ import React from "react";
7
+ import { Input } from "../../../components/common/Input.js";
8
+ import { Window } from "happy-dom";
9
9
 
10
- describe('Input', () => {
10
+ describe("Input", () => {
11
11
  beforeEach(() => {
12
12
  // Setup happy-dom
13
13
  const window = new Window();
@@ -15,35 +15,42 @@ describe('Input', () => {
15
15
  globalThis.document = window.document as any;
16
16
  });
17
17
 
18
- it('should render with value', () => {
18
+ it("should render with value", () => {
19
19
  const onChange = vi.fn();
20
20
  const onSubmit = vi.fn();
21
- const { container } = render(<Input value="test" onChange={onChange} onSubmit={onSubmit} />);
21
+ const { container } = render(
22
+ <Input value="test" onChange={onChange} onSubmit={onSubmit} />,
23
+ );
22
24
 
23
25
  expect(container).toBeDefined();
24
26
  });
25
27
 
26
- it('should render with placeholder', () => {
28
+ it("should render with placeholder", () => {
27
29
  const onChange = vi.fn();
28
30
  const onSubmit = vi.fn();
29
31
  const { getByText } = render(
30
- <Input value="" onChange={onChange} onSubmit={onSubmit} placeholder="Enter text..." />
32
+ <Input
33
+ value=""
34
+ onChange={onChange}
35
+ onSubmit={onSubmit}
36
+ placeholder="Enter text..."
37
+ />,
31
38
  );
32
39
 
33
- expect(getByText('Enter text...')).toBeDefined();
40
+ expect(getByText("Enter text...")).toBeDefined();
34
41
  });
35
42
 
36
- it('should render with label', () => {
43
+ it("should render with label", () => {
37
44
  const onChange = vi.fn();
38
45
  const onSubmit = vi.fn();
39
46
  const { getByText } = render(
40
- <Input value="" onChange={onChange} onSubmit={onSubmit} label="Name:" />
47
+ <Input value="" onChange={onChange} onSubmit={onSubmit} label="Name:" />,
41
48
  );
42
49
 
43
- expect(getByText('Name:')).toBeDefined();
50
+ expect(getByText("Name:")).toBeDefined();
44
51
  });
45
52
 
46
- it('should render label and placeholder together', () => {
53
+ it("should render label and placeholder together", () => {
47
54
  const onChange = vi.fn();
48
55
  const onSubmit = vi.fn();
49
56
  const { getByText } = render(
@@ -53,24 +60,24 @@ describe('Input', () => {
53
60
  onSubmit={onSubmit}
54
61
  label="Branch name:"
55
62
  placeholder="feature/..."
56
- />
63
+ />,
57
64
  );
58
65
 
59
- expect(getByText('Branch name:')).toBeDefined();
60
- expect(getByText('feature/...')).toBeDefined();
66
+ expect(getByText("Branch name:")).toBeDefined();
67
+ expect(getByText("feature/...")).toBeDefined();
61
68
  });
62
69
 
63
- it('should accept mask prop for password input', () => {
70
+ it("should accept mask prop for password input", () => {
64
71
  const onChange = vi.fn();
65
72
  const onSubmit = vi.fn();
66
73
  const { container } = render(
67
- <Input value="secret" onChange={onChange} onSubmit={onSubmit} mask="*" />
74
+ <Input value="secret" onChange={onChange} onSubmit={onSubmit} mask="*" />,
68
75
  );
69
76
 
70
77
  expect(container).toBeDefined();
71
78
  });
72
79
 
73
- it('should call onChange when value changes', () => {
80
+ it("should call onChange when value changes", () => {
74
81
  const onChange = vi.fn();
75
82
  const onSubmit = vi.fn();
76
83
  render(<Input value="" onChange={onChange} onSubmit={onSubmit} />);
@@ -80,7 +87,7 @@ describe('Input', () => {
80
87
  expect(onChange).not.toHaveBeenCalled();
81
88
  });
82
89
 
83
- it('should call onSubmit when submitted', () => {
90
+ it("should call onSubmit when submitted", () => {
84
91
  const onChange = vi.fn();
85
92
  const onSubmit = vi.fn();
86
93
  render(<Input value="test" onChange={onChange} onSubmit={onSubmit} />);
@@ -1,11 +1,11 @@
1
1
  /**
2
2
  * @vitest-environment happy-dom
3
3
  */
4
- import React from 'react';
5
- import { describe, it, expect, beforeEach, afterEach, vi } from 'vitest';
6
- import { act, render } from '@testing-library/react';
7
- import { LoadingIndicator } from '../../../components/common/LoadingIndicator.js';
8
- import { Window } from 'happy-dom';
4
+ import React from "react";
5
+ import { describe, it, expect, beforeEach, afterEach, vi } from "vitest";
6
+ import { act, render } from "@testing-library/react";
7
+ import { LoadingIndicator } from "../../../components/common/LoadingIndicator.js";
8
+ import { Window } from "happy-dom";
9
9
 
10
10
  const advanceTimersBy = async (ms: number) => {
11
11
  await act(async () => {
@@ -25,57 +25,63 @@ afterEach(() => {
25
25
  vi.useRealTimers();
26
26
  });
27
27
 
28
- describe('LoadingIndicator', () => {
28
+ describe("LoadingIndicator", () => {
29
29
  const getSpinnerText = (container: HTMLElement) => {
30
- return container.querySelector('ink-text')?.textContent ?? '';
30
+ return container.querySelector("ink-text")?.textContent ?? "";
31
31
  };
32
32
 
33
33
  const getMessageText = (container: HTMLElement) => {
34
- const texts = container.querySelectorAll('ink-text');
35
- return texts.length > 1 ? texts[1]?.textContent ?? '' : '';
34
+ const texts = container.querySelectorAll("ink-text");
35
+ return texts.length > 1 ? (texts[1]?.textContent ?? "") : "";
36
36
  };
37
37
 
38
- it('does not render before the delay elapses', async () => {
38
+ it("does not render before the delay elapses", async () => {
39
39
  const { container } = render(
40
- <LoadingIndicator isLoading={true} message="Loading data" delay={50} />
40
+ <LoadingIndicator isLoading={true} message="Loading data" delay={50} />,
41
41
  );
42
42
 
43
- expect(container.textContent).toBe('');
43
+ expect(container.textContent).toBe("");
44
44
 
45
45
  await advanceTimersBy(20);
46
46
 
47
- expect(container.textContent).toBe('');
47
+ expect(container.textContent).toBe("");
48
48
  });
49
49
 
50
- it('renders after the delay elapses', async () => {
50
+ it("renders after the delay elapses", async () => {
51
51
  const { container } = render(
52
- <LoadingIndicator isLoading={true} message="Loading data" delay={30} />
52
+ <LoadingIndicator isLoading={true} message="Loading data" delay={30} />,
53
53
  );
54
54
 
55
55
  await advanceTimersBy(30);
56
56
 
57
- expect(getMessageText(container)).toContain('Loading data');
57
+ expect(getMessageText(container)).toContain("Loading data");
58
58
  });
59
59
 
60
- it('stops rendering when loading becomes false', async () => {
60
+ it("stops rendering when loading becomes false", async () => {
61
61
  const { container, rerender } = render(
62
- <LoadingIndicator isLoading={true} message="Loading data" delay={10} />
62
+ <LoadingIndicator isLoading={true} message="Loading data" delay={10} />,
63
63
  );
64
64
 
65
65
  await advanceTimersBy(10);
66
66
 
67
- expect(getMessageText(container)).toContain('Loading data');
67
+ expect(getMessageText(container)).toContain("Loading data");
68
68
 
69
69
  await act(async () => {
70
- rerender(<LoadingIndicator isLoading={false} message="Loading data" delay={10} />);
70
+ rerender(
71
+ <LoadingIndicator
72
+ isLoading={false}
73
+ message="Loading data"
74
+ delay={10}
75
+ />,
76
+ );
71
77
  await vi.advanceTimersByTimeAsync(0);
72
78
  });
73
79
 
74
- expect(container.textContent).toBe('');
80
+ expect(container.textContent).toBe("");
75
81
  });
76
82
 
77
- it('cycles through spinner frames over time', async () => {
78
- const customFrames = ['.', '..', '...'];
83
+ it("cycles through spinner frames over time", async () => {
84
+ const customFrames = [".", "..", "..."];
79
85
  const { container } = render(
80
86
  <LoadingIndicator
81
87
  isLoading={true}
@@ -83,7 +89,7 @@ describe('LoadingIndicator', () => {
83
89
  delay={0}
84
90
  interval={5}
85
91
  frames={customFrames}
86
- />
92
+ />,
87
93
  );
88
94
 
89
95
  await advanceTimersBy(0);
@@ -100,28 +106,28 @@ describe('LoadingIndicator', () => {
100
106
 
101
107
  expect(secondFrame).not.toEqual(firstFrame);
102
108
  expect(thirdFrame).not.toEqual(secondFrame);
103
- expect(customFrames).toContain(firstFrame ?? '');
104
- expect(customFrames).toContain(secondFrame ?? '');
105
- expect(customFrames).toContain(thirdFrame ?? '');
106
- expect(getMessageText(container)).toContain('Loading data');
109
+ expect(customFrames).toContain(firstFrame ?? "");
110
+ expect(customFrames).toContain(secondFrame ?? "");
111
+ expect(customFrames).toContain(thirdFrame ?? "");
112
+ expect(getMessageText(container)).toContain("Loading data");
107
113
  });
108
114
 
109
- it('keeps rendering even when only a single frame is provided', async () => {
115
+ it("keeps rendering even when only a single frame is provided", async () => {
110
116
  const { container } = render(
111
117
  <LoadingIndicator
112
118
  isLoading={true}
113
119
  message="Loading data"
114
120
  delay={0}
115
121
  interval={10}
116
- frames={['*']}
117
- />
122
+ frames={["*"]}
123
+ />,
118
124
  );
119
125
 
120
126
  await advanceTimersBy(0);
121
- expect(getSpinnerText(container)).toBe('*');
127
+ expect(getSpinnerText(container)).toBe("*");
122
128
 
123
129
  await advanceTimersBy(30);
124
- expect(getSpinnerText(container)).toBe('*');
125
- expect(getMessageText(container)).toContain('Loading data');
130
+ expect(getSpinnerText(container)).toBe("*");
131
+ expect(getMessageText(container)).toContain("Loading data");
126
132
  });
127
133
  });