@akiojin/gwt 2.2.0 → 2.4.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 (172) hide show
  1. package/README.ja.md +6 -4
  2. package/README.md +6 -4
  3. package/dist/claude.d.ts +1 -0
  4. package/dist/claude.d.ts.map +1 -1
  5. package/dist/claude.js +6 -3
  6. package/dist/claude.js.map +1 -1
  7. package/dist/cli/ui/components/App.d.ts +6 -4
  8. package/dist/cli/ui/components/App.d.ts.map +1 -1
  9. package/dist/cli/ui/components/App.js +184 -107
  10. package/dist/cli/ui/components/App.js.map +1 -1
  11. package/dist/cli/ui/components/common/Confirm.d.ts +1 -1
  12. package/dist/cli/ui/components/common/Confirm.d.ts.map +1 -1
  13. package/dist/cli/ui/components/common/Confirm.js +7 -7
  14. package/dist/cli/ui/components/common/Confirm.js.map +1 -1
  15. package/dist/cli/ui/components/common/ErrorBoundary.d.ts +1 -1
  16. package/dist/cli/ui/components/common/ErrorBoundary.d.ts.map +1 -1
  17. package/dist/cli/ui/components/common/ErrorBoundary.js +4 -4
  18. package/dist/cli/ui/components/common/ErrorBoundary.js.map +1 -1
  19. package/dist/cli/ui/components/common/Input.d.ts +2 -2
  20. package/dist/cli/ui/components/common/Input.d.ts.map +1 -1
  21. package/dist/cli/ui/components/common/Input.js +4 -4
  22. package/dist/cli/ui/components/common/Input.js.map +1 -1
  23. package/dist/cli/ui/components/common/LoadingIndicator.d.ts +1 -1
  24. package/dist/cli/ui/components/common/LoadingIndicator.d.ts.map +1 -1
  25. package/dist/cli/ui/components/common/LoadingIndicator.js +4 -4
  26. package/dist/cli/ui/components/common/LoadingIndicator.js.map +1 -1
  27. package/dist/cli/ui/components/common/Select.d.ts +1 -1
  28. package/dist/cli/ui/components/common/Select.d.ts.map +1 -1
  29. package/dist/cli/ui/components/common/Select.js +11 -12
  30. package/dist/cli/ui/components/common/Select.js.map +1 -1
  31. package/dist/cli/ui/components/screens/AIToolSelectorScreen.d.ts +3 -3
  32. package/dist/cli/ui/components/screens/AIToolSelectorScreen.d.ts.map +1 -1
  33. package/dist/cli/ui/components/screens/AIToolSelectorScreen.js +11 -11
  34. package/dist/cli/ui/components/screens/AIToolSelectorScreen.js.map +1 -1
  35. package/dist/cli/ui/components/screens/BranchCreatorScreen.d.ts +1 -1
  36. package/dist/cli/ui/components/screens/BranchCreatorScreen.d.ts.map +1 -1
  37. package/dist/cli/ui/components/screens/BranchCreatorScreen.js +39 -36
  38. package/dist/cli/ui/components/screens/BranchCreatorScreen.js.map +1 -1
  39. package/dist/cli/ui/components/screens/BranchListScreen.d.ts +3 -3
  40. package/dist/cli/ui/components/screens/BranchListScreen.d.ts.map +1 -1
  41. package/dist/cli/ui/components/screens/BranchListScreen.js +55 -50
  42. package/dist/cli/ui/components/screens/BranchListScreen.js.map +1 -1
  43. package/dist/cli/ui/components/screens/ExecutionModeSelectorScreen.d.ts +2 -2
  44. package/dist/cli/ui/components/screens/ExecutionModeSelectorScreen.d.ts.map +1 -1
  45. package/dist/cli/ui/components/screens/ExecutionModeSelectorScreen.js +25 -25
  46. package/dist/cli/ui/components/screens/ExecutionModeSelectorScreen.js.map +1 -1
  47. package/dist/cli/ui/components/screens/ModelSelectorScreen.d.ts +18 -0
  48. package/dist/cli/ui/components/screens/ModelSelectorScreen.d.ts.map +1 -0
  49. package/dist/cli/ui/components/screens/ModelSelectorScreen.js +201 -0
  50. package/dist/cli/ui/components/screens/ModelSelectorScreen.js.map +1 -0
  51. package/dist/cli/ui/components/screens/PRCleanupScreen.d.ts +2 -2
  52. package/dist/cli/ui/components/screens/PRCleanupScreen.js +21 -21
  53. package/dist/cli/ui/components/screens/SessionSelectorScreen.d.ts +1 -1
  54. package/dist/cli/ui/components/screens/SessionSelectorScreen.js +8 -8
  55. package/dist/cli/ui/components/screens/WorktreeManagerScreen.d.ts +1 -1
  56. package/dist/cli/ui/components/screens/WorktreeManagerScreen.js +8 -8
  57. package/dist/cli/ui/screens/BranchActionSelectorScreen.d.ts.map +1 -1
  58. package/dist/cli/ui/screens/BranchActionSelectorScreen.js +7 -4
  59. package/dist/cli/ui/screens/BranchActionSelectorScreen.js.map +1 -1
  60. package/dist/cli/ui/types.d.ts +11 -1
  61. package/dist/cli/ui/types.d.ts.map +1 -1
  62. package/dist/cli/ui/utils/modelOptions.d.ts +6 -0
  63. package/dist/cli/ui/utils/modelOptions.d.ts.map +1 -0
  64. package/dist/cli/ui/utils/modelOptions.js +111 -0
  65. package/dist/cli/ui/utils/modelOptions.js.map +1 -0
  66. package/dist/client/assets/{index-V6hDu9KS.js → index-Difv1Hwu.js} +2 -2
  67. package/dist/client/index.html +1 -1
  68. package/dist/codex.d.ts +6 -0
  69. package/dist/codex.d.ts.map +1 -1
  70. package/dist/codex.js +11 -4
  71. package/dist/codex.js.map +1 -1
  72. package/dist/config/builtin-tools.d.ts +10 -2
  73. package/dist/config/builtin-tools.d.ts.map +1 -1
  74. package/dist/config/builtin-tools.js +40 -4
  75. package/dist/config/builtin-tools.js.map +1 -1
  76. package/dist/config/index.d.ts.map +1 -1
  77. package/dist/config/index.js.map +1 -1
  78. package/dist/config/tools.d.ts.map +1 -1
  79. package/dist/config/tools.js +4 -3
  80. package/dist/config/tools.js.map +1 -1
  81. package/dist/gemini.d.ts +13 -0
  82. package/dist/gemini.d.ts.map +1 -0
  83. package/dist/gemini.js +157 -0
  84. package/dist/gemini.js.map +1 -0
  85. package/dist/git.d.ts.map +1 -1
  86. package/dist/git.js.map +1 -1
  87. package/dist/index.d.ts.map +1 -1
  88. package/dist/index.js +59 -7
  89. package/dist/index.js.map +1 -1
  90. package/dist/qwen.d.ts +13 -0
  91. package/dist/qwen.d.ts.map +1 -0
  92. package/dist/qwen.js +157 -0
  93. package/dist/qwen.js.map +1 -0
  94. package/dist/services/git.service.d.ts.map +1 -1
  95. package/dist/services/git.service.js.map +1 -1
  96. package/dist/web/client/src/components/BranchGraph.d.ts.map +1 -1
  97. package/dist/web/client/src/components/BranchGraph.js +1 -1
  98. package/dist/web/client/src/components/BranchGraph.js.map +1 -1
  99. package/dist/web/client/src/components/EnvEditor.d.ts.map +1 -1
  100. package/dist/web/client/src/components/EnvEditor.js +7 -4
  101. package/dist/web/client/src/components/EnvEditor.js.map +1 -1
  102. package/dist/web/client/src/pages/BranchDetailPage.d.ts.map +1 -1
  103. package/dist/web/client/src/pages/BranchDetailPage.js +55 -18
  104. package/dist/web/client/src/pages/BranchDetailPage.js.map +1 -1
  105. package/dist/web/client/src/pages/BranchListPage.d.ts.map +1 -1
  106. package/dist/web/client/src/pages/BranchListPage.js +10 -4
  107. package/dist/web/client/src/pages/BranchListPage.js.map +1 -1
  108. package/dist/web/client/src/pages/ConfigManagementPage.d.ts.map +1 -1
  109. package/dist/web/client/src/pages/ConfigManagementPage.js +4 -2
  110. package/dist/web/client/src/pages/ConfigManagementPage.js.map +1 -1
  111. package/package.json +2 -1
  112. package/src/claude.ts +8 -3
  113. package/src/cli/ui/__tests__/acceptance/navigation.acceptance.test.tsx +69 -50
  114. package/src/cli/ui/__tests__/components/App.protected-branch.test.tsx +67 -45
  115. package/src/cli/ui/__tests__/components/App.shortcuts.test.tsx +117 -75
  116. package/src/cli/ui/__tests__/components/App.test.tsx +45 -37
  117. package/src/cli/ui/__tests__/components/ModelSelectorScreen.initial.test.tsx +81 -0
  118. package/src/cli/ui/__tests__/components/common/Confirm.test.tsx +35 -22
  119. package/src/cli/ui/__tests__/components/common/ErrorBoundary.test.tsx +22 -22
  120. package/src/cli/ui/__tests__/components/common/Input.test.tsx +29 -22
  121. package/src/cli/ui/__tests__/components/common/LoadingIndicator.test.tsx +63 -43
  122. package/src/cli/ui/__tests__/components/common/Select.memo.test.tsx +57 -66
  123. package/src/cli/ui/__tests__/components/common/Select.test.tsx +121 -91
  124. package/src/cli/ui/__tests__/components/parts/Footer.test.tsx +18 -16
  125. package/src/cli/ui/__tests__/components/parts/Header.test.tsx +13 -13
  126. package/src/cli/ui/__tests__/components/parts/ScrollableList.test.tsx +20 -20
  127. package/src/cli/ui/__tests__/components/parts/Stats.test.tsx +38 -26
  128. package/src/cli/ui/__tests__/components/screens/AIToolSelectorScreen.test.tsx +31 -31
  129. package/src/cli/ui/__tests__/components/screens/BranchCreatorScreen.test.tsx +73 -37
  130. package/src/cli/ui/__tests__/components/screens/BranchListScreen.test.tsx +261 -153
  131. package/src/cli/ui/__tests__/components/screens/ExecutionModeSelectorScreen.test.tsx +38 -32
  132. package/src/cli/ui/__tests__/components/screens/PRCleanupScreen.test.tsx +39 -39
  133. package/src/cli/ui/__tests__/components/screens/SessionSelectorScreen.test.tsx +49 -21
  134. package/src/cli/ui/__tests__/components/screens/WorktreeManagerScreen.test.tsx +52 -28
  135. package/src/cli/ui/__tests__/integration/edgeCases.test.tsx +84 -48
  136. package/src/cli/ui/__tests__/integration/navigation.test.tsx +111 -83
  137. package/src/cli/ui/__tests__/integration/realtimeUpdate.test.tsx +111 -108
  138. package/src/cli/ui/__tests__/performance/branchList.performance.test.tsx +50 -37
  139. package/src/cli/ui/__tests__/performance/useMemoOptimization.test.tsx +75 -76
  140. package/src/cli/ui/components/App.tsx +317 -150
  141. package/src/cli/ui/components/common/Confirm.tsx +13 -9
  142. package/src/cli/ui/components/common/ErrorBoundary.tsx +8 -5
  143. package/src/cli/ui/components/common/Input.tsx +12 -4
  144. package/src/cli/ui/components/common/LoadingIndicator.tsx +8 -5
  145. package/src/cli/ui/components/common/Select.tsx +28 -17
  146. package/src/cli/ui/components/parts/Header.test.tsx +5 -15
  147. package/src/cli/ui/components/screens/AIToolSelectorScreen.tsx +20 -15
  148. package/src/cli/ui/components/screens/BranchCreatorScreen.tsx +74 -54
  149. package/src/cli/ui/components/screens/BranchListScreen.tsx +92 -75
  150. package/src/cli/ui/components/screens/ExecutionModeSelectorScreen.tsx +35 -28
  151. package/src/cli/ui/components/screens/ModelSelectorScreen.tsx +320 -0
  152. package/src/cli/ui/components/screens/PRCleanupScreen.tsx +22 -22
  153. package/src/cli/ui/components/screens/SessionSelectorScreen.tsx +8 -8
  154. package/src/cli/ui/components/screens/WorktreeManagerScreen.tsx +8 -8
  155. package/src/cli/ui/screens/BranchActionSelectorScreen.tsx +9 -4
  156. package/src/cli/ui/types.ts +21 -1
  157. package/src/cli/ui/utils/modelOptions.test.ts +36 -0
  158. package/src/cli/ui/utils/modelOptions.ts +122 -0
  159. package/src/codex.ts +23 -4
  160. package/src/config/builtin-tools.ts +42 -4
  161. package/src/config/index.ts +2 -12
  162. package/src/config/tools.ts +16 -6
  163. package/src/gemini.ts +207 -0
  164. package/src/git.ts +2 -1
  165. package/src/index.ts +86 -6
  166. package/src/qwen.ts +213 -0
  167. package/src/services/git.service.ts +2 -1
  168. package/src/web/client/src/components/BranchGraph.tsx +3 -2
  169. package/src/web/client/src/components/EnvEditor.tsx +44 -11
  170. package/src/web/client/src/pages/BranchDetailPage.tsx +165 -54
  171. package/src/web/client/src/pages/BranchListPage.tsx +37 -13
  172. 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 '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,81 +1,101 @@
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 () => {
12
- await vi.advanceTimersByTimeAsync(ms);
12
+ if (typeof vi.advanceTimersByTimeAsync === "function") {
13
+ await vi.advanceTimersByTimeAsync(ms);
14
+ } else if (typeof vi.advanceTimersByTime === "function") {
15
+ vi.advanceTimersByTime(ms);
16
+ } else {
17
+ await new Promise((resolve) => setTimeout(resolve, ms));
18
+ }
13
19
  });
14
20
  };
15
21
 
16
22
  beforeEach(() => {
17
- vi.useFakeTimers();
23
+ if (typeof vi.useFakeTimers === "function") {
24
+ vi.useFakeTimers();
25
+ }
18
26
  const window = new Window();
19
27
  globalThis.window = window as any;
20
28
  globalThis.document = window.document as any;
21
29
  });
22
30
 
23
31
  afterEach(() => {
24
- vi.clearAllTimers();
25
- vi.useRealTimers();
32
+ if (typeof vi.clearAllTimers === "function") {
33
+ vi.clearAllTimers();
34
+ }
35
+ if (typeof vi.useRealTimers === "function") {
36
+ vi.useRealTimers();
37
+ }
26
38
  });
27
39
 
28
- describe('LoadingIndicator', () => {
40
+ describe("LoadingIndicator", () => {
29
41
  const getSpinnerText = (container: HTMLElement) => {
30
- return container.querySelector('ink-text')?.textContent ?? '';
42
+ return container.querySelector("ink-text")?.textContent ?? "";
31
43
  };
32
44
 
33
45
  const getMessageText = (container: HTMLElement) => {
34
- const texts = container.querySelectorAll('ink-text');
35
- return texts.length > 1 ? texts[1]?.textContent ?? '' : '';
46
+ const texts = container.querySelectorAll("ink-text");
47
+ return texts.length > 1 ? (texts[1]?.textContent ?? "") : "";
36
48
  };
37
49
 
38
- it('does not render before the delay elapses', async () => {
50
+ it("does not render before the delay elapses", async () => {
39
51
  const { container } = render(
40
- <LoadingIndicator isLoading={true} message="Loading data" delay={50} />
52
+ <LoadingIndicator isLoading={true} message="Loading data" delay={50} />,
41
53
  );
42
54
 
43
- expect(container.textContent).toBe('');
55
+ expect(container.textContent).toBe("");
44
56
 
45
57
  await advanceTimersBy(20);
46
58
 
47
- expect(container.textContent).toBe('');
59
+ expect(container.textContent).toBe("");
48
60
  });
49
61
 
50
- it('renders after the delay elapses', async () => {
62
+ it("renders after the delay elapses", async () => {
51
63
  const { container } = render(
52
- <LoadingIndicator isLoading={true} message="Loading data" delay={30} />
64
+ <LoadingIndicator isLoading={true} message="Loading data" delay={30} />,
53
65
  );
54
66
 
55
67
  await advanceTimersBy(30);
56
68
 
57
- expect(getMessageText(container)).toContain('Loading data');
69
+ expect(getMessageText(container)).toContain("Loading data");
58
70
  });
59
71
 
60
- it('stops rendering when loading becomes false', async () => {
72
+ it("stops rendering when loading becomes false", async () => {
61
73
  const { container, rerender } = render(
62
- <LoadingIndicator isLoading={true} message="Loading data" delay={10} />
74
+ <LoadingIndicator isLoading={true} message="Loading data" delay={10} />,
63
75
  );
64
76
 
65
77
  await advanceTimersBy(10);
66
78
 
67
- expect(getMessageText(container)).toContain('Loading data');
68
-
69
- await act(async () => {
70
- rerender(<LoadingIndicator isLoading={false} message="Loading data" delay={10} />);
71
- await vi.advanceTimersByTimeAsync(0);
72
- });
73
-
74
- expect(container.textContent).toBe('');
79
+ expect(getMessageText(container)).toContain("Loading data");
80
+
81
+ await act(async () => {
82
+ rerender(
83
+ <LoadingIndicator
84
+ isLoading={false}
85
+ message="Loading data"
86
+ delay={10}
87
+ />,
88
+ );
89
+ if (typeof vi.advanceTimersByTimeAsync === "function") {
90
+ await vi.advanceTimersByTimeAsync(0);
91
+ }
92
+ });
93
+
94
+ expect(container.textContent).toBe("");
75
95
  });
76
96
 
77
- it('cycles through spinner frames over time', async () => {
78
- const customFrames = ['.', '..', '...'];
97
+ it("cycles through spinner frames over time", async () => {
98
+ const customFrames = [".", "..", "..."];
79
99
  const { container } = render(
80
100
  <LoadingIndicator
81
101
  isLoading={true}
@@ -83,7 +103,7 @@ describe('LoadingIndicator', () => {
83
103
  delay={0}
84
104
  interval={5}
85
105
  frames={customFrames}
86
- />
106
+ />,
87
107
  );
88
108
 
89
109
  await advanceTimersBy(0);
@@ -100,28 +120,28 @@ describe('LoadingIndicator', () => {
100
120
 
101
121
  expect(secondFrame).not.toEqual(firstFrame);
102
122
  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');
123
+ expect(customFrames).toContain(firstFrame ?? "");
124
+ expect(customFrames).toContain(secondFrame ?? "");
125
+ expect(customFrames).toContain(thirdFrame ?? "");
126
+ expect(getMessageText(container)).toContain("Loading data");
107
127
  });
108
128
 
109
- it('keeps rendering even when only a single frame is provided', async () => {
129
+ it("keeps rendering even when only a single frame is provided", async () => {
110
130
  const { container } = render(
111
131
  <LoadingIndicator
112
132
  isLoading={true}
113
133
  message="Loading data"
114
134
  delay={0}
115
135
  interval={10}
116
- frames={['*']}
117
- />
136
+ frames={["*"]}
137
+ />,
118
138
  );
119
139
 
120
140
  await advanceTimersBy(0);
121
- expect(getSpinnerText(container)).toBe('*');
141
+ expect(getSpinnerText(container)).toBe("*");
122
142
 
123
143
  await advanceTimersBy(30);
124
- expect(getSpinnerText(container)).toBe('*');
125
- expect(getMessageText(container)).toContain('Loading data');
144
+ expect(getSpinnerText(container)).toBe("*");
145
+ expect(getMessageText(container)).toContain("Loading data");
126
146
  });
127
147
  });