@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.
- package/README.ja.md +6 -4
- package/README.md +6 -4
- package/dist/claude.d.ts +1 -0
- package/dist/claude.d.ts.map +1 -1
- package/dist/claude.js +6 -3
- package/dist/claude.js.map +1 -1
- package/dist/cli/ui/components/App.d.ts +6 -4
- package/dist/cli/ui/components/App.d.ts.map +1 -1
- package/dist/cli/ui/components/App.js +184 -107
- 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 +3 -3
- 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/ModelSelectorScreen.d.ts +18 -0
- package/dist/cli/ui/components/screens/ModelSelectorScreen.d.ts.map +1 -0
- package/dist/cli/ui/components/screens/ModelSelectorScreen.js +201 -0
- package/dist/cli/ui/components/screens/ModelSelectorScreen.js.map +1 -0
- 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 +11 -1
- package/dist/cli/ui/types.d.ts.map +1 -1
- package/dist/cli/ui/utils/modelOptions.d.ts +6 -0
- package/dist/cli/ui/utils/modelOptions.d.ts.map +1 -0
- package/dist/cli/ui/utils/modelOptions.js +111 -0
- package/dist/cli/ui/utils/modelOptions.js.map +1 -0
- package/dist/client/assets/{index-V6hDu9KS.js → index-Difv1Hwu.js} +2 -2
- package/dist/client/index.html +1 -1
- package/dist/codex.d.ts +6 -0
- package/dist/codex.d.ts.map +1 -1
- package/dist/codex.js +11 -4
- package/dist/codex.js.map +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 +13 -0
- package/dist/gemini.d.ts.map +1 -0
- package/dist/gemini.js +157 -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 +59 -7
- package/dist/index.js.map +1 -1
- package/dist/qwen.d.ts +13 -0
- package/dist/qwen.d.ts.map +1 -0
- package/dist/qwen.js +157 -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/claude.ts +8 -3
- 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/ModelSelectorScreen.initial.test.tsx +81 -0
- 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 +63 -43
- 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 +317 -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 +20 -15
- 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/ModelSelectorScreen.tsx +320 -0
- 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 +21 -1
- package/src/cli/ui/utils/modelOptions.test.ts +36 -0
- package/src/cli/ui/utils/modelOptions.ts +122 -0
- package/src/codex.ts +23 -4
- 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 +207 -0
- package/src/git.ts +2 -1
- package/src/index.ts +86 -6
- package/src/qwen.ts +213 -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 { Confirm } 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 { Confirm } from "../../../components/common/Confirm.js";
|
|
8
|
+
import { Window } from "happy-dom";
|
|
9
9
|
|
|
10
|
-
describe(
|
|
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(
|
|
18
|
+
it("should render the message", () => {
|
|
19
19
|
const onConfirm = vi.fn();
|
|
20
|
-
const { getByText } = render(
|
|
20
|
+
const { getByText } = render(
|
|
21
|
+
<Confirm message="Are you sure?" onConfirm={onConfirm} />,
|
|
22
|
+
);
|
|
21
23
|
|
|
22
|
-
expect(getByText(
|
|
24
|
+
expect(getByText("Are you sure?")).toBeDefined();
|
|
23
25
|
});
|
|
24
26
|
|
|
25
|
-
it(
|
|
27
|
+
it("should render Yes and No options", () => {
|
|
26
28
|
const onConfirm = vi.fn();
|
|
27
|
-
const { getByText } = render(
|
|
29
|
+
const { getByText } = render(
|
|
30
|
+
<Confirm message="Continue?" onConfirm={onConfirm} />,
|
|
31
|
+
);
|
|
28
32
|
|
|
29
|
-
expect(getByText(
|
|
30
|
-
expect(getByText(
|
|
33
|
+
expect(getByText("Yes")).toBeDefined();
|
|
34
|
+
expect(getByText("No")).toBeDefined();
|
|
31
35
|
});
|
|
32
36
|
|
|
33
|
-
it(
|
|
37
|
+
it("should render custom Yes and No labels", () => {
|
|
34
38
|
const onConfirm = vi.fn();
|
|
35
39
|
const { getByText } = render(
|
|
36
|
-
<Confirm
|
|
40
|
+
<Confirm
|
|
41
|
+
message="Delete?"
|
|
42
|
+
onConfirm={onConfirm}
|
|
43
|
+
yesLabel="Confirm"
|
|
44
|
+
noLabel="Cancel"
|
|
45
|
+
/>,
|
|
37
46
|
);
|
|
38
47
|
|
|
39
|
-
expect(getByText(
|
|
40
|
-
expect(getByText(
|
|
48
|
+
expect(getByText("Confirm")).toBeDefined();
|
|
49
|
+
expect(getByText("Cancel")).toBeDefined();
|
|
41
50
|
});
|
|
42
51
|
|
|
43
|
-
it(
|
|
52
|
+
it("should default to Yes option", () => {
|
|
44
53
|
const onConfirm = vi.fn();
|
|
45
|
-
const { container } = render(
|
|
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(
|
|
62
|
+
it("should accept defaultNo prop to default to No", () => {
|
|
52
63
|
const onConfirm = vi.fn();
|
|
53
|
-
const { container } = render(
|
|
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(
|
|
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
|
|
5
|
-
import { render } from
|
|
6
|
-
import React from
|
|
7
|
-
import { ErrorBoundary } from
|
|
8
|
-
import { Text, Box } from
|
|
9
|
-
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 { 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(
|
|
14
|
+
throw new Error("Test error message");
|
|
15
15
|
}
|
|
16
16
|
return <Text>No error</Text>;
|
|
17
17
|
};
|
|
18
18
|
|
|
19
|
-
describe(
|
|
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,
|
|
27
|
+
vi.spyOn(console, "error").mockImplementation(() => {});
|
|
28
28
|
});
|
|
29
29
|
|
|
30
|
-
it(
|
|
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(
|
|
37
|
+
expect(getByText("No error")).toBeDefined();
|
|
38
38
|
});
|
|
39
39
|
|
|
40
|
-
it(
|
|
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(
|
|
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(
|
|
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(
|
|
86
|
+
expect(getByText("No error")).toBeDefined();
|
|
87
87
|
});
|
|
88
88
|
|
|
89
|
-
it(
|
|
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
|
|
5
|
-
import { render } from
|
|
6
|
-
import React from
|
|
7
|
-
import { Input } 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 { Input } from "../../../components/common/Input.js";
|
|
8
|
+
import { Window } from "happy-dom";
|
|
9
9
|
|
|
10
|
-
describe(
|
|
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(
|
|
18
|
+
it("should render with value", () => {
|
|
19
19
|
const onChange = vi.fn();
|
|
20
20
|
const onSubmit = vi.fn();
|
|
21
|
-
const { container } = render(
|
|
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(
|
|
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
|
|
32
|
+
<Input
|
|
33
|
+
value=""
|
|
34
|
+
onChange={onChange}
|
|
35
|
+
onSubmit={onSubmit}
|
|
36
|
+
placeholder="Enter text..."
|
|
37
|
+
/>,
|
|
31
38
|
);
|
|
32
39
|
|
|
33
|
-
expect(getByText(
|
|
40
|
+
expect(getByText("Enter text...")).toBeDefined();
|
|
34
41
|
});
|
|
35
42
|
|
|
36
|
-
it(
|
|
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(
|
|
50
|
+
expect(getByText("Name:")).toBeDefined();
|
|
44
51
|
});
|
|
45
52
|
|
|
46
|
-
it(
|
|
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(
|
|
60
|
-
expect(getByText(
|
|
66
|
+
expect(getByText("Branch name:")).toBeDefined();
|
|
67
|
+
expect(getByText("feature/...")).toBeDefined();
|
|
61
68
|
});
|
|
62
69
|
|
|
63
|
-
it(
|
|
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(
|
|
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(
|
|
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
|
|
5
|
-
import { describe, it, expect, beforeEach, afterEach, vi } from
|
|
6
|
-
import { act, render } from
|
|
7
|
-
import { LoadingIndicator } from
|
|
8
|
-
import { Window } from
|
|
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
|
-
|
|
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
|
-
|
|
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(
|
|
40
|
+
describe("LoadingIndicator", () => {
|
|
29
41
|
const getSpinnerText = (container: HTMLElement) => {
|
|
30
|
-
return container.querySelector(
|
|
42
|
+
return container.querySelector("ink-text")?.textContent ?? "";
|
|
31
43
|
};
|
|
32
44
|
|
|
33
45
|
const getMessageText = (container: HTMLElement) => {
|
|
34
|
-
const texts = container.querySelectorAll(
|
|
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(
|
|
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(
|
|
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(
|
|
69
|
+
expect(getMessageText(container)).toContain("Loading data");
|
|
58
70
|
});
|
|
59
71
|
|
|
60
|
-
it(
|
|
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(
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
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(
|
|
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(
|
|
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(
|
|
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(
|
|
144
|
+
expect(getSpinnerText(container)).toBe("*");
|
|
145
|
+
expect(getMessageText(container)).toContain("Loading data");
|
|
126
146
|
});
|
|
127
147
|
});
|