@powerhousedao/vetra 4.1.0-dev.81 → 4.1.0-dev.83
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/dist/document-models/app-module/src/reducers/base-operations.d.ts.map +1 -1
- package/dist/document-models/app-module/src/reducers/base-operations.js +5 -1
- package/dist/document-models/app-module/src/tests/base-operations.test.js +157 -30
- package/dist/document-models/app-module/src/tests/dnd-operations.test.js +38 -7
- package/dist/document-models/app-module/src/tests/document-model.test.js +80 -8
- package/dist/document-models/document-editor/src/reducers/base-operations.d.ts.map +1 -1
- package/dist/document-models/document-editor/src/reducers/base-operations.js +10 -1
- package/dist/document-models/document-editor/src/tests/base-operations.test.js +137 -23
- package/dist/document-models/document-editor/src/tests/document-model.test.js +91 -8
- package/dist/document-models/processor-module/src/reducers/base-operations.d.ts.map +1 -1
- package/dist/document-models/processor-module/src/reducers/base-operations.js +15 -2
- package/dist/document-models/processor-module/src/tests/base-operations.test.js +153 -33
- package/dist/document-models/processor-module/src/tests/document-model.test.js +96 -8
- package/dist/document-models/subgraph-module/src/reducers/base-operations.d.ts.map +1 -1
- package/dist/document-models/subgraph-module/src/reducers/base-operations.js +5 -1
- package/dist/document-models/subgraph-module/src/tests/base-operations.test.js +33 -12
- package/dist/document-models/subgraph-module/src/tests/document-model.test.js +25 -8
- package/dist/document-models/vetra-package/src/reducers/base-operations.d.ts.map +1 -1
- package/dist/document-models/vetra-package/src/reducers/base-operations.js +5 -0
- package/dist/document-models/vetra-package/src/tests/base-operations.test.js +171 -75
- package/dist/document-models/vetra-package/src/tests/document-model.test.js +101 -8
- package/dist/editors/app-editor/components/AppEditorForm.d.ts.map +1 -1
- package/dist/editors/app-editor/components/AppEditorForm.js +2 -2
- package/dist/editors/app-editor/editor.test.d.ts +2 -0
- package/dist/editors/app-editor/editor.test.d.ts.map +1 -0
- package/dist/editors/app-editor/editor.test.js +422 -0
- package/dist/editors/document-editor/components/DocumentEditorForm.d.ts.map +1 -1
- package/dist/editors/document-editor/components/DocumentEditorForm.js +1 -1
- package/dist/editors/document-editor/editor.test.d.ts +2 -0
- package/dist/editors/document-editor/editor.test.d.ts.map +1 -0
- package/dist/editors/document-editor/editor.test.js +374 -0
- package/dist/editors/processor-editor/components/ProcessorEditorForm.d.ts.map +1 -1
- package/dist/editors/processor-editor/components/ProcessorEditorForm.js +1 -1
- package/dist/editors/processor-editor/editor.test.d.ts +2 -0
- package/dist/editors/processor-editor/editor.test.d.ts.map +1 -0
- package/dist/editors/processor-editor/editor.test.js +459 -0
- package/dist/editors/subgraph-editor/components/SubgraphEditorForm.d.ts.map +1 -1
- package/dist/editors/subgraph-editor/components/SubgraphEditorForm.js +3 -3
- package/dist/editors/subgraph-editor/editor.test.d.ts +2 -0
- package/dist/editors/subgraph-editor/editor.test.d.ts.map +1 -0
- package/dist/editors/subgraph-editor/editor.test.js +201 -0
- package/dist/editors/vetra-package/components/MetaForm.d.ts.map +1 -1
- package/dist/editors/vetra-package/components/MetaForm.js +3 -3
- package/dist/editors/vetra-package/editor.test.d.ts +2 -0
- package/dist/editors/vetra-package/editor.test.d.ts.map +1 -0
- package/dist/editors/vetra-package/editor.test.js +330 -0
- package/dist/processors/codegen/__tests__/codegen-processor-e2e.test.d.ts +2 -0
- package/dist/processors/codegen/__tests__/codegen-processor-e2e.test.d.ts.map +1 -0
- package/dist/processors/codegen/__tests__/codegen-processor-e2e.test.js +615 -0
- package/dist/processors/codegen/__tests__/factory.test.d.ts +2 -0
- package/dist/processors/codegen/__tests__/factory.test.d.ts.map +1 -0
- package/dist/processors/codegen/__tests__/factory.test.js +190 -0
- package/dist/setupTests.d.ts +2 -0
- package/dist/setupTests.d.ts.map +1 -0
- package/dist/setupTests.js +1 -0
- package/dist/style.css +9 -0
- package/dist/tsconfig.tsbuildinfo +1 -1
- package/dist/vitest.config.d.ts.map +1 -1
- package/dist/vitest.config.js +9 -0
- package/package.json +19 -14
|
@@ -0,0 +1,201 @@
|
|
|
1
|
+
import { jsx as _jsx } from "react/jsx-runtime";
|
|
2
|
+
import { render, screen, waitFor } from "@testing-library/react";
|
|
3
|
+
import { userEvent } from "@testing-library/user-event";
|
|
4
|
+
import { beforeEach, describe, expect, it, vi } from "vitest";
|
|
5
|
+
import { useSelectedSubgraphModuleDocument } from "../hooks/useVetraDocument.js";
|
|
6
|
+
import { Editor } from "./editor.js";
|
|
7
|
+
vi.mock("../hooks/useVetraDocument.js", () => ({
|
|
8
|
+
useSelectedSubgraphModuleDocument: vi.fn(),
|
|
9
|
+
}));
|
|
10
|
+
describe("SubgraphModule Editor", () => {
|
|
11
|
+
let mockDispatch;
|
|
12
|
+
beforeEach(() => {
|
|
13
|
+
mockDispatch = vi.fn();
|
|
14
|
+
vi.mocked(useSelectedSubgraphModuleDocument).mockReturnValue([
|
|
15
|
+
{
|
|
16
|
+
state: {
|
|
17
|
+
global: {
|
|
18
|
+
name: "",
|
|
19
|
+
status: "DRAFT",
|
|
20
|
+
},
|
|
21
|
+
},
|
|
22
|
+
},
|
|
23
|
+
mockDispatch,
|
|
24
|
+
]);
|
|
25
|
+
});
|
|
26
|
+
describe("Core Rendering", () => {
|
|
27
|
+
it("should render all main form sections and labels", () => {
|
|
28
|
+
render(_jsx(Editor, {}));
|
|
29
|
+
expect(screen.getByText("Subgraph Configuration")).toBeInTheDocument();
|
|
30
|
+
expect(screen.getByText("Subgraph Name")).toBeInTheDocument();
|
|
31
|
+
expect(screen.getByText("Confirm")).toBeInTheDocument();
|
|
32
|
+
});
|
|
33
|
+
it("should display existing subgraph data when document has values", () => {
|
|
34
|
+
vi.mocked(useSelectedSubgraphModuleDocument).mockReturnValue([
|
|
35
|
+
{
|
|
36
|
+
state: {
|
|
37
|
+
global: {
|
|
38
|
+
name: "test-subgraph",
|
|
39
|
+
status: "DRAFT",
|
|
40
|
+
},
|
|
41
|
+
},
|
|
42
|
+
},
|
|
43
|
+
mockDispatch,
|
|
44
|
+
]);
|
|
45
|
+
render(_jsx(Editor, {}));
|
|
46
|
+
expect(screen.getByDisplayValue("test-subgraph")).toBeInTheDocument();
|
|
47
|
+
});
|
|
48
|
+
});
|
|
49
|
+
describe("Subgraph Name Input", () => {
|
|
50
|
+
it("should dispatch setSubgraphName when name changes (debounced)", async () => {
|
|
51
|
+
const user = userEvent.setup();
|
|
52
|
+
render(_jsx(Editor, {}));
|
|
53
|
+
const nameInput = screen.getByLabelText("Subgraph Name");
|
|
54
|
+
await user.type(nameInput, "new-subgraph");
|
|
55
|
+
await waitFor(() => {
|
|
56
|
+
expect(mockDispatch).toHaveBeenCalledWith(expect.objectContaining({
|
|
57
|
+
type: "SET_SUBGRAPH_NAME",
|
|
58
|
+
input: { name: "new-subgraph" },
|
|
59
|
+
}));
|
|
60
|
+
}, { timeout: 500 });
|
|
61
|
+
});
|
|
62
|
+
it("should dispatch when clearing a non-empty field", async () => {
|
|
63
|
+
vi.mocked(useSelectedSubgraphModuleDocument).mockReturnValue([
|
|
64
|
+
{
|
|
65
|
+
state: {
|
|
66
|
+
global: {
|
|
67
|
+
name: "existing-subgraph",
|
|
68
|
+
status: "DRAFT",
|
|
69
|
+
},
|
|
70
|
+
},
|
|
71
|
+
},
|
|
72
|
+
mockDispatch,
|
|
73
|
+
]);
|
|
74
|
+
const user = userEvent.setup();
|
|
75
|
+
render(_jsx(Editor, {}));
|
|
76
|
+
const nameInput = screen.getByLabelText("Subgraph Name");
|
|
77
|
+
await user.clear(nameInput);
|
|
78
|
+
await waitFor(() => {
|
|
79
|
+
expect(mockDispatch).toHaveBeenCalledWith(expect.objectContaining({
|
|
80
|
+
type: "SET_SUBGRAPH_NAME",
|
|
81
|
+
input: { name: "" },
|
|
82
|
+
}));
|
|
83
|
+
}, { timeout: 500 });
|
|
84
|
+
});
|
|
85
|
+
it("should NOT dispatch when typing identical value without clearing", async () => {
|
|
86
|
+
vi.mocked(useSelectedSubgraphModuleDocument).mockReturnValue([
|
|
87
|
+
{
|
|
88
|
+
state: {
|
|
89
|
+
global: {
|
|
90
|
+
name: "test",
|
|
91
|
+
status: "DRAFT",
|
|
92
|
+
},
|
|
93
|
+
},
|
|
94
|
+
},
|
|
95
|
+
mockDispatch,
|
|
96
|
+
]);
|
|
97
|
+
const user = userEvent.setup();
|
|
98
|
+
render(_jsx(Editor, {}));
|
|
99
|
+
const nameInput = screen.getByLabelText("Subgraph Name");
|
|
100
|
+
await user.tripleClick(nameInput);
|
|
101
|
+
await user.type(nameInput, "test");
|
|
102
|
+
await waitFor(() => {
|
|
103
|
+
expect(mockDispatch).not.toHaveBeenCalled();
|
|
104
|
+
});
|
|
105
|
+
});
|
|
106
|
+
it("should NOT dispatch when both old and new values are empty", async () => {
|
|
107
|
+
const user = userEvent.setup();
|
|
108
|
+
render(_jsx(Editor, {}));
|
|
109
|
+
const nameInput = screen.getByLabelText("Subgraph Name");
|
|
110
|
+
await user.click(nameInput);
|
|
111
|
+
await user.tab();
|
|
112
|
+
await waitFor(() => {
|
|
113
|
+
expect(mockDispatch).not.toHaveBeenCalled();
|
|
114
|
+
});
|
|
115
|
+
});
|
|
116
|
+
});
|
|
117
|
+
describe("Confirm Button", () => {
|
|
118
|
+
it("should dispatch setSubgraphStatus when confirm clicked", async () => {
|
|
119
|
+
vi.mocked(useSelectedSubgraphModuleDocument).mockReturnValue([
|
|
120
|
+
{
|
|
121
|
+
state: {
|
|
122
|
+
global: {
|
|
123
|
+
name: "test-subgraph",
|
|
124
|
+
status: "DRAFT",
|
|
125
|
+
},
|
|
126
|
+
},
|
|
127
|
+
},
|
|
128
|
+
mockDispatch,
|
|
129
|
+
]);
|
|
130
|
+
const user = userEvent.setup();
|
|
131
|
+
render(_jsx(Editor, {}));
|
|
132
|
+
const confirmButton = screen.getByText("Confirm");
|
|
133
|
+
await user.click(confirmButton);
|
|
134
|
+
expect(mockDispatch).toHaveBeenCalledWith(expect.objectContaining({
|
|
135
|
+
type: "SET_SUBGRAPH_STATUS",
|
|
136
|
+
input: { status: "CONFIRMED" },
|
|
137
|
+
}));
|
|
138
|
+
});
|
|
139
|
+
it("should be disabled when subgraph name is empty", () => {
|
|
140
|
+
render(_jsx(Editor, {}));
|
|
141
|
+
const confirmButton = screen.getByText("Confirm");
|
|
142
|
+
expect(confirmButton).toBeDisabled();
|
|
143
|
+
});
|
|
144
|
+
it("should be hidden when status is CONFIRMED", () => {
|
|
145
|
+
vi.mocked(useSelectedSubgraphModuleDocument).mockReturnValue([
|
|
146
|
+
{
|
|
147
|
+
state: {
|
|
148
|
+
global: {
|
|
149
|
+
name: "test-subgraph",
|
|
150
|
+
status: "CONFIRMED",
|
|
151
|
+
},
|
|
152
|
+
},
|
|
153
|
+
},
|
|
154
|
+
mockDispatch,
|
|
155
|
+
]);
|
|
156
|
+
render(_jsx(Editor, {}));
|
|
157
|
+
const confirmButton = screen.queryByText("Confirm");
|
|
158
|
+
expect(confirmButton).not.toBeInTheDocument();
|
|
159
|
+
});
|
|
160
|
+
});
|
|
161
|
+
describe("Read-only Mode", () => {
|
|
162
|
+
it("should disable form field when status is CONFIRMED", () => {
|
|
163
|
+
vi.mocked(useSelectedSubgraphModuleDocument).mockReturnValue([
|
|
164
|
+
{
|
|
165
|
+
state: {
|
|
166
|
+
global: {
|
|
167
|
+
name: "test-subgraph",
|
|
168
|
+
status: "CONFIRMED",
|
|
169
|
+
},
|
|
170
|
+
},
|
|
171
|
+
},
|
|
172
|
+
mockDispatch,
|
|
173
|
+
]);
|
|
174
|
+
render(_jsx(Editor, {}));
|
|
175
|
+
const nameInput = screen.getByLabelText("Subgraph Name");
|
|
176
|
+
expect(nameInput).toBeDisabled();
|
|
177
|
+
// Confirm button should not be visible
|
|
178
|
+
const confirmButton = screen.queryByText("Confirm");
|
|
179
|
+
expect(confirmButton).not.toBeInTheDocument();
|
|
180
|
+
});
|
|
181
|
+
it("should enable form field when status is DRAFT", () => {
|
|
182
|
+
vi.mocked(useSelectedSubgraphModuleDocument).mockReturnValue([
|
|
183
|
+
{
|
|
184
|
+
state: {
|
|
185
|
+
global: {
|
|
186
|
+
name: "test-subgraph",
|
|
187
|
+
status: "DRAFT",
|
|
188
|
+
},
|
|
189
|
+
},
|
|
190
|
+
},
|
|
191
|
+
mockDispatch,
|
|
192
|
+
]);
|
|
193
|
+
render(_jsx(Editor, {}));
|
|
194
|
+
const nameInput = screen.getByLabelText("Subgraph Name");
|
|
195
|
+
expect(nameInput).not.toBeDisabled();
|
|
196
|
+
// Confirm button should be visible
|
|
197
|
+
const confirmButton = screen.getByText("Confirm");
|
|
198
|
+
expect(confirmButton).toBeInTheDocument();
|
|
199
|
+
});
|
|
200
|
+
});
|
|
201
|
+
});
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"MetaForm.d.ts","sourceRoot":"","sources":["../../../../editors/vetra-package/components/MetaForm.tsx"],"names":[],"mappings":"AAEA,OAAO,KAAK,EAAE,OAAO,EAAE,MAAM,iDAAiD,CAAC;AAE/E,MAAM,WAAW,aAAa;IAC5B,IAAI,EAAE,MAAM,CAAC;IACb,WAAW,EAAE,MAAM,CAAC;IACpB,QAAQ,EAAE,MAAM,CAAC;IACjB,SAAS,EAAE,MAAM,CAAC;IAClB,YAAY,EAAE,MAAM,CAAC;IACrB,gBAAgB,EAAE,MAAM,CAAC;IACzB,UAAU,EAAE,MAAM,CAAC;IACnB,QAAQ,EAAE,OAAO,EAAE,CAAC;IACpB,YAAY,CAAC,EAAE,CAAC,IAAI,EAAE,MAAM,KAAK,IAAI,CAAC;IACtC,mBAAmB,CAAC,EAAE,CAAC,WAAW,EAAE,MAAM,KAAK,IAAI,CAAC;IACpD,gBAAgB,CAAC,EAAE,CAAC,QAAQ,EAAE,MAAM,KAAK,IAAI,CAAC;IAC9C,iBAAiB,CAAC,EAAE,CAAC,SAAS,EAAE,MAAM,KAAK,IAAI,CAAC;IAChD,oBAAoB,CAAC,EAAE,CAAC,YAAY,EAAE,MAAM,KAAK,IAAI,CAAC;IACtD,wBAAwB,CAAC,EAAE,CAAC,gBAAgB,EAAE,MAAM,KAAK,IAAI,CAAC;IAC9D,kBAAkB,CAAC,EAAE,CAAC,UAAU,EAAE,MAAM,KAAK,IAAI,CAAC;IAClD,YAAY,CAAC,EAAE,CAAC,OAAO,EAAE;QAAE,EAAE,EAAE,MAAM,CAAC;QAAC,KAAK,EAAE,MAAM,CAAA;KAAE,KAAK,IAAI,CAAC;IAChE,eAAe,CAAC,EAAE,CAAC,EAAE,EAAE,MAAM,KAAK,IAAI,CAAC;CACxC;AAED,eAAO,MAAM,QAAQ,EAAE,KAAK,CAAC,EAAE,CAAC,aAAa,
|
|
1
|
+
{"version":3,"file":"MetaForm.d.ts","sourceRoot":"","sources":["../../../../editors/vetra-package/components/MetaForm.tsx"],"names":[],"mappings":"AAEA,OAAO,KAAK,EAAE,OAAO,EAAE,MAAM,iDAAiD,CAAC;AAE/E,MAAM,WAAW,aAAa;IAC5B,IAAI,EAAE,MAAM,CAAC;IACb,WAAW,EAAE,MAAM,CAAC;IACpB,QAAQ,EAAE,MAAM,CAAC;IACjB,SAAS,EAAE,MAAM,CAAC;IAClB,YAAY,EAAE,MAAM,CAAC;IACrB,gBAAgB,EAAE,MAAM,CAAC;IACzB,UAAU,EAAE,MAAM,CAAC;IACnB,QAAQ,EAAE,OAAO,EAAE,CAAC;IACpB,YAAY,CAAC,EAAE,CAAC,IAAI,EAAE,MAAM,KAAK,IAAI,CAAC;IACtC,mBAAmB,CAAC,EAAE,CAAC,WAAW,EAAE,MAAM,KAAK,IAAI,CAAC;IACpD,gBAAgB,CAAC,EAAE,CAAC,QAAQ,EAAE,MAAM,KAAK,IAAI,CAAC;IAC9C,iBAAiB,CAAC,EAAE,CAAC,SAAS,EAAE,MAAM,KAAK,IAAI,CAAC;IAChD,oBAAoB,CAAC,EAAE,CAAC,YAAY,EAAE,MAAM,KAAK,IAAI,CAAC;IACtD,wBAAwB,CAAC,EAAE,CAAC,gBAAgB,EAAE,MAAM,KAAK,IAAI,CAAC;IAC9D,kBAAkB,CAAC,EAAE,CAAC,UAAU,EAAE,MAAM,KAAK,IAAI,CAAC;IAClD,YAAY,CAAC,EAAE,CAAC,OAAO,EAAE;QAAE,EAAE,EAAE,MAAM,CAAC;QAAC,KAAK,EAAE,MAAM,CAAA;KAAE,KAAK,IAAI,CAAC;IAChE,eAAe,CAAC,EAAE,CAAC,EAAE,EAAE,MAAM,KAAK,IAAI,CAAC;CACxC;AAED,eAAO,MAAM,QAAQ,EAAE,KAAK,CAAC,EAAE,CAAC,aAAa,CAgS5C,CAAC"}
|
|
@@ -20,11 +20,11 @@ export const MetaForm = (props) => {
|
|
|
20
20
|
useDebounce(publisherUrl, onPublisherUrlChange, 300);
|
|
21
21
|
useDebounce(githubRepository, onGithubRepositoryChange, 300);
|
|
22
22
|
useDebounce(npmPackage, onNpmPackageChange, 300);
|
|
23
|
-
return (_jsxs("div", { className: "grid grid-cols-1 gap-6 bg-white p-6 lg:grid-cols-3", children: [_jsxs("div", { className: "space-y-6", children: [_jsxs("div", { children: [_jsx("label", { className: "mb-2 block text-sm font-medium text-gray-700", children: "Name" }), _jsx("input", { type: "text", value: name, onChange: (e) => setName(e.target.value), className: "w-full rounded-md border border-gray-300 px-3 py-2 focus:border-transparent focus:outline-none focus:ring-2 focus:ring-blue-500" })] }), _jsxs("div", { children: [_jsx("label", { className: "mb-2 block text-sm font-medium text-gray-700", children: "Description" }), _jsx("textarea", { rows: 6, value: description, onChange: (e) => setDescription(e.target.value), className: "w-full resize-none rounded-md border border-gray-300 px-3 py-2 focus:border-transparent focus:outline-none focus:ring-2 focus:ring-blue-500" })] })] }), _jsxs("div", { className: "space-y-6", children: [_jsxs("div", { children: [_jsx("label", { className: "mb-2 block text-sm font-medium text-gray-700", children: "Category" }), _jsxs("select", { value: category, onChange: (e) => {
|
|
23
|
+
return (_jsxs("div", { className: "grid grid-cols-1 gap-6 bg-white p-6 lg:grid-cols-3", children: [_jsxs("div", { className: "space-y-6", children: [_jsxs("div", { children: [_jsx("label", { htmlFor: "package-name", className: "mb-2 block text-sm font-medium text-gray-700", children: "Name" }), _jsx("input", { id: "package-name", type: "text", value: name, onChange: (e) => setName(e.target.value), className: "w-full rounded-md border border-gray-300 px-3 py-2 focus:border-transparent focus:outline-none focus:ring-2 focus:ring-blue-500" })] }), _jsxs("div", { children: [_jsx("label", { htmlFor: "package-description", className: "mb-2 block text-sm font-medium text-gray-700", children: "Description" }), _jsx("textarea", { id: "package-description", rows: 6, value: description, onChange: (e) => setDescription(e.target.value), className: "w-full resize-none rounded-md border border-gray-300 px-3 py-2 focus:border-transparent focus:outline-none focus:ring-2 focus:ring-blue-500" })] })] }), _jsxs("div", { className: "space-y-6", children: [_jsxs("div", { children: [_jsx("label", { htmlFor: "package-category", className: "mb-2 block text-sm font-medium text-gray-700", children: "Category" }), _jsxs("select", { id: "package-category", value: category, onChange: (e) => {
|
|
24
24
|
const newValue = e.target.value;
|
|
25
25
|
setCategory(newValue);
|
|
26
26
|
onCategoryChange?.(newValue);
|
|
27
|
-
}, className: "w-full rounded-md border border-gray-300 px-3 py-2 focus:border-transparent focus:outline-none focus:ring-2 focus:ring-blue-500", children: [_jsx("option", { value: "", children: "Not selected" }), _jsx("option", { value: "Productivity", children: "Productivity" }), _jsx("option", { value: "Governance", children: "Governance" }), _jsx("option", { value: "Project Management", children: "Project Management" }), _jsx("option", { value: "Finance", children: "Finance" }), _jsx("option", { value: "Legal", children: "Legal" }), _jsx("option", { value: "People & Culture", children: "People & Culture" }), _jsx("option", { value: "Engineering", children: "Engineering" })] })] }), _jsxs("div", { children: [_jsx("label", { className: "mb-2 block text-sm font-medium text-gray-700", children: "Publisher" }), _jsx("input", { type: "text", value: publisher, onChange: (e) => setPublisher(e.target.value), className: "w-full rounded-md border border-gray-300 px-3 py-2 focus:border-transparent focus:outline-none focus:ring-2 focus:ring-blue-500" })] }), _jsxs("div", { children: [_jsx("label", { className: "mb-2 block text-sm font-medium text-gray-700", children: "Publisher URL" }), _jsx("input", { type: "text", value: publisherUrl, onChange: (e) => setPublisherUrl(e.target.value), className: "w-full rounded-md border border-gray-300 px-3 py-2 focus:border-transparent focus:outline-none focus:ring-2 focus:ring-blue-500" })] }), _jsxs("div", { children: [_jsx("label", { className: "mb-2 block text-sm font-medium text-gray-700", children: "Keywords" }), _jsxs("div", { className: "space-y-2", children: [_jsx("input", { type: "text", value: keywordInput, onChange: (e) => setKeywordInput(e.target.value), onKeyDown: (e) => {
|
|
27
|
+
}, className: "w-full rounded-md border border-gray-300 px-3 py-2 focus:border-transparent focus:outline-none focus:ring-2 focus:ring-blue-500", children: [_jsx("option", { value: "", children: "Not selected" }), _jsx("option", { value: "Productivity", children: "Productivity" }), _jsx("option", { value: "Governance", children: "Governance" }), _jsx("option", { value: "Project Management", children: "Project Management" }), _jsx("option", { value: "Finance", children: "Finance" }), _jsx("option", { value: "Legal", children: "Legal" }), _jsx("option", { value: "People & Culture", children: "People & Culture" }), _jsx("option", { value: "Engineering", children: "Engineering" })] })] }), _jsxs("div", { children: [_jsx("label", { htmlFor: "package-publisher", className: "mb-2 block text-sm font-medium text-gray-700", children: "Publisher" }), _jsx("input", { id: "package-publisher", type: "text", value: publisher, onChange: (e) => setPublisher(e.target.value), className: "w-full rounded-md border border-gray-300 px-3 py-2 focus:border-transparent focus:outline-none focus:ring-2 focus:ring-blue-500" })] }), _jsxs("div", { children: [_jsx("label", { htmlFor: "package-publisher-url", className: "mb-2 block text-sm font-medium text-gray-700", children: "Publisher URL" }), _jsx("input", { id: "package-publisher-url", type: "text", value: publisherUrl, onChange: (e) => setPublisherUrl(e.target.value), className: "w-full rounded-md border border-gray-300 px-3 py-2 focus:border-transparent focus:outline-none focus:ring-2 focus:ring-blue-500" })] }), _jsxs("div", { children: [_jsx("label", { htmlFor: "package-keywords", className: "mb-2 block text-sm font-medium text-gray-700", children: "Keywords" }), _jsxs("div", { className: "space-y-2", children: [_jsx("input", { id: "package-keywords", type: "text", value: keywordInput, onChange: (e) => setKeywordInput(e.target.value), onKeyDown: (e) => {
|
|
28
28
|
if (e.key === "Enter" && keywordInput.trim()) {
|
|
29
29
|
e.preventDefault();
|
|
30
30
|
const newKeyword = {
|
|
@@ -38,5 +38,5 @@ export const MetaForm = (props) => {
|
|
|
38
38
|
}, placeholder: "Type a keyword and press Enter", className: "w-full rounded-md border border-gray-300 px-3 py-2 focus:border-transparent focus:outline-none focus:ring-2 focus:ring-blue-500" }), _jsx("div", { className: "flex min-h-[80px] flex-wrap gap-2 rounded-md border border-gray-300 p-3", children: keywords.map((keyword) => (_jsxs("span", { className: "inline-flex items-center rounded border border-blue-300 bg-blue-100 px-2 py-0.5 text-xs text-blue-800", children: [keyword.label, _jsx("button", { onClick: () => {
|
|
39
39
|
setKeywords(keywords.filter((k) => k.id !== keyword.id));
|
|
40
40
|
onRemoveKeyword?.(keyword.id);
|
|
41
|
-
}, className: "ml-1 text-blue-600 hover:text-blue-800 focus:outline-none", children: "\u00D7" })] }, keyword.id))) })] })] })] }), _jsxs("div", { className: "space-y-6", children: [_jsxs("div", { children: [_jsx("label", { className: "mb-2 block text-sm font-medium text-gray-700", children: "Github Repository" }), _jsx("input", { type: "text", value: githubRepository, onChange: (e) => setGithubRepository(e.target.value), className: "w-full rounded-md border border-gray-300 px-3 py-2 focus:border-transparent focus:outline-none focus:ring-2 focus:ring-blue-500" })] }), _jsxs("div", { children: [_jsx("label", { className: "mb-2 block text-sm font-medium text-gray-700", children: "NPM-package" }), _jsx("input", { type: "text", value: npmPackage, onChange: (e) => setNpmPackage(e.target.value), className: "w-full rounded-md border border-gray-300 px-3 py-2 focus:border-transparent focus:outline-none focus:ring-2 focus:ring-blue-500" })] }), _jsxs("div", { children: [_jsx("label", { className: "mb-2 block text-sm font-medium text-gray-700", children: "Version" }), _jsx("input", { type: "text", placeholder: "1.0.0-dev", readOnly: true, className: "w-full cursor-not-allowed rounded-md border border-gray-300 bg-gray-50 px-3 py-2 text-gray-500" })] }), _jsxs("div", { children: [_jsx("label", { className: "mb-2 block text-sm font-medium text-gray-700", children: "License" }), _jsx("input", { type: "text", placeholder: "AGPL-3.0-only", readOnly: true, className: "w-full cursor-not-allowed rounded-md border border-gray-300 bg-gray-50 px-3 py-2 text-gray-500" })] }), _jsxs("div", { children: [_jsx("label", { className: "mb-2 block text-sm font-medium text-gray-700", children: "Install with:" }), _jsx("input", { type: "text", placeholder: "@powerhousedao/todo-demo-package", readOnly: true, className: "w-full cursor-not-allowed rounded-md border border-gray-300 bg-gray-50 px-3 py-2 text-gray-500" })] })] })] }));
|
|
41
|
+
}, className: "ml-1 text-blue-600 hover:text-blue-800 focus:outline-none", children: "\u00D7" })] }, keyword.id))) })] })] })] }), _jsxs("div", { className: "space-y-6", children: [_jsxs("div", { children: [_jsx("label", { htmlFor: "package-github", className: "mb-2 block text-sm font-medium text-gray-700", children: "Github Repository" }), _jsx("input", { id: "package-github", type: "text", value: githubRepository, onChange: (e) => setGithubRepository(e.target.value), className: "w-full rounded-md border border-gray-300 px-3 py-2 focus:border-transparent focus:outline-none focus:ring-2 focus:ring-blue-500" })] }), _jsxs("div", { children: [_jsx("label", { htmlFor: "package-npm", className: "mb-2 block text-sm font-medium text-gray-700", children: "NPM-package" }), _jsx("input", { id: "package-npm", type: "text", value: npmPackage, onChange: (e) => setNpmPackage(e.target.value), className: "w-full rounded-md border border-gray-300 px-3 py-2 focus:border-transparent focus:outline-none focus:ring-2 focus:ring-blue-500" })] }), _jsxs("div", { children: [_jsx("label", { htmlFor: "package-version", className: "mb-2 block text-sm font-medium text-gray-700", children: "Version" }), _jsx("input", { id: "package-version", type: "text", placeholder: "1.0.0-dev", readOnly: true, className: "w-full cursor-not-allowed rounded-md border border-gray-300 bg-gray-50 px-3 py-2 text-gray-500" })] }), _jsxs("div", { children: [_jsx("label", { htmlFor: "package-license", className: "mb-2 block text-sm font-medium text-gray-700", children: "License" }), _jsx("input", { id: "package-license", type: "text", placeholder: "AGPL-3.0-only", readOnly: true, className: "w-full cursor-not-allowed rounded-md border border-gray-300 bg-gray-50 px-3 py-2 text-gray-500" })] }), _jsxs("div", { children: [_jsx("label", { htmlFor: "package-install", className: "mb-2 block text-sm font-medium text-gray-700", children: "Install with:" }), _jsx("input", { id: "package-install", type: "text", placeholder: "@powerhousedao/todo-demo-package", readOnly: true, className: "w-full cursor-not-allowed rounded-md border border-gray-300 bg-gray-50 px-3 py-2 text-gray-500" })] })] })] }));
|
|
42
42
|
};
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"editor.test.d.ts","sourceRoot":"","sources":["../../../editors/vetra-package/editor.test.tsx"],"names":[],"mappings":""}
|
|
@@ -0,0 +1,330 @@
|
|
|
1
|
+
import { jsx as _jsx } from "react/jsx-runtime";
|
|
2
|
+
import { render, screen, waitFor } from "@testing-library/react";
|
|
3
|
+
import { userEvent } from "@testing-library/user-event";
|
|
4
|
+
import { beforeEach, describe, expect, it, vi } from "vitest";
|
|
5
|
+
import { useSelectedDriveVetraPackage } from "../hooks/useVetraDocument.js";
|
|
6
|
+
import { Editor } from "./editor.js";
|
|
7
|
+
vi.mock("../hooks/useVetraDocument.js", () => ({
|
|
8
|
+
useSelectedDriveVetraPackage: vi.fn(),
|
|
9
|
+
}));
|
|
10
|
+
describe("VetraPackage Editor", () => {
|
|
11
|
+
let mockDispatch;
|
|
12
|
+
beforeEach(() => {
|
|
13
|
+
mockDispatch = vi.fn();
|
|
14
|
+
vi.mocked(useSelectedDriveVetraPackage).mockReturnValue([
|
|
15
|
+
{
|
|
16
|
+
state: {
|
|
17
|
+
global: {
|
|
18
|
+
name: null,
|
|
19
|
+
description: null,
|
|
20
|
+
category: null,
|
|
21
|
+
author: {
|
|
22
|
+
name: null,
|
|
23
|
+
website: null,
|
|
24
|
+
},
|
|
25
|
+
keywords: [],
|
|
26
|
+
githubUrl: null,
|
|
27
|
+
npmUrl: null,
|
|
28
|
+
},
|
|
29
|
+
},
|
|
30
|
+
},
|
|
31
|
+
mockDispatch,
|
|
32
|
+
]);
|
|
33
|
+
});
|
|
34
|
+
describe("Core Rendering", () => {
|
|
35
|
+
it("should render all main form sections and labels", () => {
|
|
36
|
+
render(_jsx(Editor, {}));
|
|
37
|
+
expect(screen.getByText("Name")).toBeInTheDocument();
|
|
38
|
+
expect(screen.getByText("Description")).toBeInTheDocument();
|
|
39
|
+
expect(screen.getByText("Category")).toBeInTheDocument();
|
|
40
|
+
expect(screen.getByText("Publisher")).toBeInTheDocument();
|
|
41
|
+
expect(screen.getByText("Publisher URL")).toBeInTheDocument();
|
|
42
|
+
expect(screen.getByText("Keywords")).toBeInTheDocument();
|
|
43
|
+
expect(screen.getByText("Github Repository")).toBeInTheDocument();
|
|
44
|
+
expect(screen.getByText("NPM-package")).toBeInTheDocument();
|
|
45
|
+
});
|
|
46
|
+
});
|
|
47
|
+
describe("Initial Data Display", () => {
|
|
48
|
+
it("should display existing package data when document has values", () => {
|
|
49
|
+
vi.mocked(useSelectedDriveVetraPackage).mockReturnValue([
|
|
50
|
+
{
|
|
51
|
+
state: {
|
|
52
|
+
global: {
|
|
53
|
+
name: "test-package",
|
|
54
|
+
description: "A test package",
|
|
55
|
+
category: "Productivity",
|
|
56
|
+
author: {
|
|
57
|
+
name: "John Doe",
|
|
58
|
+
website: "https://johndoe.com",
|
|
59
|
+
},
|
|
60
|
+
keywords: [
|
|
61
|
+
{ id: "kw-1", label: "react" },
|
|
62
|
+
{ id: "kw-2", label: "typescript" },
|
|
63
|
+
],
|
|
64
|
+
githubUrl: "https://github.com/test/package",
|
|
65
|
+
npmUrl: "https://npmjs.com/package/test",
|
|
66
|
+
},
|
|
67
|
+
},
|
|
68
|
+
},
|
|
69
|
+
mockDispatch,
|
|
70
|
+
]);
|
|
71
|
+
render(_jsx(Editor, {}));
|
|
72
|
+
expect(screen.getByDisplayValue("test-package")).toBeInTheDocument();
|
|
73
|
+
expect(screen.getByDisplayValue("A test package")).toBeInTheDocument();
|
|
74
|
+
expect(screen.getByDisplayValue("Productivity")).toBeInTheDocument();
|
|
75
|
+
expect(screen.getByDisplayValue("John Doe")).toBeInTheDocument();
|
|
76
|
+
expect(screen.getByDisplayValue("https://johndoe.com")).toBeInTheDocument();
|
|
77
|
+
expect(screen.getByText("react")).toBeInTheDocument();
|
|
78
|
+
expect(screen.getByText("typescript")).toBeInTheDocument();
|
|
79
|
+
expect(screen.getByDisplayValue("https://github.com/test/package")).toBeInTheDocument();
|
|
80
|
+
expect(screen.getByDisplayValue("https://npmjs.com/package/test")).toBeInTheDocument();
|
|
81
|
+
});
|
|
82
|
+
});
|
|
83
|
+
describe("Text Input Fields - Dispatch Verification", () => {
|
|
84
|
+
it("should dispatch setPackageName when name changes", async () => {
|
|
85
|
+
const user = userEvent.setup();
|
|
86
|
+
render(_jsx(Editor, {}));
|
|
87
|
+
const nameInput = screen.getByLabelText("Name");
|
|
88
|
+
await user.type(nameInput, "new-package");
|
|
89
|
+
await waitFor(() => {
|
|
90
|
+
expect(mockDispatch).toHaveBeenCalledWith(expect.objectContaining({
|
|
91
|
+
type: "SET_PACKAGE_NAME",
|
|
92
|
+
input: { name: "new-package" },
|
|
93
|
+
}));
|
|
94
|
+
}, { timeout: 500 });
|
|
95
|
+
});
|
|
96
|
+
it("should dispatch setPackageDescription when description changes", async () => {
|
|
97
|
+
const user = userEvent.setup();
|
|
98
|
+
render(_jsx(Editor, {}));
|
|
99
|
+
const descriptionInput = screen.getByLabelText("Description");
|
|
100
|
+
await user.type(descriptionInput, "New description");
|
|
101
|
+
await waitFor(() => {
|
|
102
|
+
expect(mockDispatch).toHaveBeenCalledWith(expect.objectContaining({
|
|
103
|
+
type: "SET_PACKAGE_DESCRIPTION",
|
|
104
|
+
input: { description: "New description" },
|
|
105
|
+
}));
|
|
106
|
+
}, { timeout: 500 });
|
|
107
|
+
});
|
|
108
|
+
it("should dispatch setPackageAuthorName when publisher changes", async () => {
|
|
109
|
+
const user = userEvent.setup();
|
|
110
|
+
render(_jsx(Editor, {}));
|
|
111
|
+
const publisherInput = screen.getByLabelText("Publisher");
|
|
112
|
+
await user.type(publisherInput, "Acme Corp");
|
|
113
|
+
await waitFor(() => {
|
|
114
|
+
expect(mockDispatch).toHaveBeenCalledWith(expect.objectContaining({
|
|
115
|
+
type: "SET_PACKAGE_AUTHOR_NAME",
|
|
116
|
+
input: { name: "Acme Corp" },
|
|
117
|
+
}));
|
|
118
|
+
}, { timeout: 500 });
|
|
119
|
+
});
|
|
120
|
+
it("should dispatch setPackageAuthorWebsite when publisher URL changes", async () => {
|
|
121
|
+
const user = userEvent.setup();
|
|
122
|
+
render(_jsx(Editor, {}));
|
|
123
|
+
const publisherUrlInput = screen.getByLabelText("Publisher URL");
|
|
124
|
+
await user.type(publisherUrlInput, "https://acme.com");
|
|
125
|
+
await waitFor(() => {
|
|
126
|
+
expect(mockDispatch).toHaveBeenCalledWith(expect.objectContaining({
|
|
127
|
+
type: "SET_PACKAGE_AUTHOR_WEBSITE",
|
|
128
|
+
input: { website: "https://acme.com" },
|
|
129
|
+
}));
|
|
130
|
+
}, { timeout: 500 });
|
|
131
|
+
});
|
|
132
|
+
it("should dispatch setPackageGithubUrl when Github repository changes", async () => {
|
|
133
|
+
const user = userEvent.setup();
|
|
134
|
+
render(_jsx(Editor, {}));
|
|
135
|
+
const githubInput = screen.getByLabelText("Github Repository");
|
|
136
|
+
await user.type(githubInput, "https://github.com/acme/test");
|
|
137
|
+
await waitFor(() => {
|
|
138
|
+
expect(mockDispatch).toHaveBeenCalledWith(expect.objectContaining({
|
|
139
|
+
type: "SET_PACKAGE_GITHUB_URL",
|
|
140
|
+
input: { url: "https://github.com/acme/test" },
|
|
141
|
+
}));
|
|
142
|
+
}, { timeout: 500 });
|
|
143
|
+
});
|
|
144
|
+
it("should dispatch setPackageNpmUrl when NPM package changes", async () => {
|
|
145
|
+
const user = userEvent.setup();
|
|
146
|
+
render(_jsx(Editor, {}));
|
|
147
|
+
const npmInput = screen.getByLabelText("NPM-package");
|
|
148
|
+
await user.type(npmInput, "https://npmjs.com/package/acme");
|
|
149
|
+
await waitFor(() => {
|
|
150
|
+
expect(mockDispatch).toHaveBeenCalledWith(expect.objectContaining({
|
|
151
|
+
type: "SET_PACKAGE_NPM_URL",
|
|
152
|
+
input: { url: "https://npmjs.com/package/acme" },
|
|
153
|
+
}));
|
|
154
|
+
}, { timeout: 500 });
|
|
155
|
+
});
|
|
156
|
+
});
|
|
157
|
+
describe("Conditional Dispatch Logic", () => {
|
|
158
|
+
it("should dispatch when clearing a non-empty field", async () => {
|
|
159
|
+
vi.mocked(useSelectedDriveVetraPackage).mockReturnValue([
|
|
160
|
+
{
|
|
161
|
+
state: {
|
|
162
|
+
global: {
|
|
163
|
+
name: "existing-package",
|
|
164
|
+
description: null,
|
|
165
|
+
category: null,
|
|
166
|
+
author: { name: null, website: null },
|
|
167
|
+
keywords: [],
|
|
168
|
+
githubUrl: null,
|
|
169
|
+
npmUrl: null,
|
|
170
|
+
},
|
|
171
|
+
},
|
|
172
|
+
},
|
|
173
|
+
mockDispatch,
|
|
174
|
+
]);
|
|
175
|
+
const user = userEvent.setup();
|
|
176
|
+
render(_jsx(Editor, {}));
|
|
177
|
+
const nameInput = screen.getByLabelText("Name");
|
|
178
|
+
await user.clear(nameInput);
|
|
179
|
+
await waitFor(() => {
|
|
180
|
+
expect(mockDispatch).toHaveBeenCalledWith(expect.objectContaining({
|
|
181
|
+
type: "SET_PACKAGE_NAME",
|
|
182
|
+
input: { name: "" },
|
|
183
|
+
}));
|
|
184
|
+
}, { timeout: 500 });
|
|
185
|
+
});
|
|
186
|
+
it("should NOT dispatch when typing identical value without clearing", async () => {
|
|
187
|
+
vi.mocked(useSelectedDriveVetraPackage).mockReturnValue([
|
|
188
|
+
{
|
|
189
|
+
state: {
|
|
190
|
+
global: {
|
|
191
|
+
name: "test",
|
|
192
|
+
description: null,
|
|
193
|
+
category: null,
|
|
194
|
+
author: { name: null, website: null },
|
|
195
|
+
keywords: [],
|
|
196
|
+
githubUrl: null,
|
|
197
|
+
npmUrl: null,
|
|
198
|
+
},
|
|
199
|
+
},
|
|
200
|
+
},
|
|
201
|
+
mockDispatch,
|
|
202
|
+
]);
|
|
203
|
+
const user = userEvent.setup();
|
|
204
|
+
render(_jsx(Editor, {}));
|
|
205
|
+
const nameInput = screen.getByLabelText("Name");
|
|
206
|
+
// Simulate user selecting all text and typing the same value
|
|
207
|
+
await user.tripleClick(nameInput); // Select all
|
|
208
|
+
await user.type(nameInput, "test");
|
|
209
|
+
await waitFor(() => {
|
|
210
|
+
expect(mockDispatch).not.toHaveBeenCalled();
|
|
211
|
+
});
|
|
212
|
+
});
|
|
213
|
+
it("should NOT dispatch when both old and new values are empty", async () => {
|
|
214
|
+
const user = userEvent.setup();
|
|
215
|
+
render(_jsx(Editor, {}));
|
|
216
|
+
const nameInput = screen.getByLabelText("Name");
|
|
217
|
+
await user.click(nameInput);
|
|
218
|
+
await user.tab(); // Focus and blur without typing
|
|
219
|
+
await waitFor(() => {
|
|
220
|
+
expect(mockDispatch).not.toHaveBeenCalled();
|
|
221
|
+
});
|
|
222
|
+
});
|
|
223
|
+
});
|
|
224
|
+
describe("Category Selection", () => {
|
|
225
|
+
it("should dispatch category change immediately (no debounce)", async () => {
|
|
226
|
+
const user = userEvent.setup();
|
|
227
|
+
render(_jsx(Editor, {}));
|
|
228
|
+
const categorySelect = screen.getByLabelText("Category");
|
|
229
|
+
await user.selectOptions(categorySelect, "Productivity");
|
|
230
|
+
// Should dispatch immediately without waiting for debounce
|
|
231
|
+
expect(mockDispatch).toHaveBeenCalledWith(expect.objectContaining({
|
|
232
|
+
type: "SET_PACKAGE_CATEGORY",
|
|
233
|
+
input: { category: "Productivity" },
|
|
234
|
+
}));
|
|
235
|
+
});
|
|
236
|
+
});
|
|
237
|
+
describe("Debounce Behavior", () => {
|
|
238
|
+
it("should debounce text input changes (300ms delay)", async () => {
|
|
239
|
+
const user = userEvent.setup();
|
|
240
|
+
render(_jsx(Editor, {}));
|
|
241
|
+
const nameInput = screen.getByLabelText("Name");
|
|
242
|
+
// Type multiple characters quickly
|
|
243
|
+
await user.type(nameInput, "test");
|
|
244
|
+
// Should not dispatch immediately
|
|
245
|
+
expect(mockDispatch).not.toHaveBeenCalled();
|
|
246
|
+
// Should dispatch after debounce delay
|
|
247
|
+
await waitFor(() => {
|
|
248
|
+
expect(mockDispatch).toHaveBeenCalledWith(expect.objectContaining({
|
|
249
|
+
type: "SET_PACKAGE_NAME",
|
|
250
|
+
input: { name: "test" },
|
|
251
|
+
}));
|
|
252
|
+
}, { timeout: 500 });
|
|
253
|
+
});
|
|
254
|
+
});
|
|
255
|
+
describe("Keywords Management", () => {
|
|
256
|
+
it("should add keyword on Enter with valid input", async () => {
|
|
257
|
+
const user = userEvent.setup();
|
|
258
|
+
render(_jsx(Editor, {}));
|
|
259
|
+
const keywordInput = screen.getByPlaceholderText("Type a keyword and press Enter");
|
|
260
|
+
await user.type(keywordInput, "react{Enter}");
|
|
261
|
+
expect(screen.getByText("react")).toBeInTheDocument();
|
|
262
|
+
expect(mockDispatch).toHaveBeenCalledWith(expect.objectContaining({
|
|
263
|
+
type: "ADD_PACKAGE_KEYWORD",
|
|
264
|
+
input: expect.objectContaining({
|
|
265
|
+
label: "react",
|
|
266
|
+
}),
|
|
267
|
+
}));
|
|
268
|
+
});
|
|
269
|
+
it("should NOT add empty or whitespace-only keyword", async () => {
|
|
270
|
+
const user = userEvent.setup();
|
|
271
|
+
render(_jsx(Editor, {}));
|
|
272
|
+
const keywordInput = screen.getByPlaceholderText("Type a keyword and press Enter");
|
|
273
|
+
// Try to add empty keyword
|
|
274
|
+
await user.type(keywordInput, "{Enter}");
|
|
275
|
+
expect(mockDispatch).not.toHaveBeenCalled();
|
|
276
|
+
// Try to add whitespace-only keyword
|
|
277
|
+
await user.type(keywordInput, " {Enter}");
|
|
278
|
+
expect(mockDispatch).not.toHaveBeenCalled();
|
|
279
|
+
});
|
|
280
|
+
it("should display keywords and allow removal", async () => {
|
|
281
|
+
vi.mocked(useSelectedDriveVetraPackage).mockReturnValue([
|
|
282
|
+
{
|
|
283
|
+
state: {
|
|
284
|
+
global: {
|
|
285
|
+
name: null,
|
|
286
|
+
description: null,
|
|
287
|
+
category: null,
|
|
288
|
+
author: { name: null, website: null },
|
|
289
|
+
keywords: [
|
|
290
|
+
{ id: "kw-1", label: "react" },
|
|
291
|
+
{ id: "kw-2", label: "typescript" },
|
|
292
|
+
],
|
|
293
|
+
githubUrl: null,
|
|
294
|
+
npmUrl: null,
|
|
295
|
+
},
|
|
296
|
+
},
|
|
297
|
+
},
|
|
298
|
+
mockDispatch,
|
|
299
|
+
]);
|
|
300
|
+
const user = userEvent.setup();
|
|
301
|
+
render(_jsx(Editor, {}));
|
|
302
|
+
expect(screen.getByText("react")).toBeInTheDocument();
|
|
303
|
+
expect(screen.getByText("typescript")).toBeInTheDocument();
|
|
304
|
+
// Find and click the remove button for "react"
|
|
305
|
+
const reactKeyword = screen.getByText("react").closest("span");
|
|
306
|
+
const removeButton = reactKeyword?.querySelector("button");
|
|
307
|
+
if (removeButton) {
|
|
308
|
+
await user.click(removeButton);
|
|
309
|
+
}
|
|
310
|
+
expect(mockDispatch).toHaveBeenCalledWith(expect.objectContaining({
|
|
311
|
+
type: "REMOVE_PACKAGE_KEYWORD",
|
|
312
|
+
input: { id: "kw-1" },
|
|
313
|
+
}));
|
|
314
|
+
});
|
|
315
|
+
it("should dispatch addKeyword action with correct payload", async () => {
|
|
316
|
+
const user = userEvent.setup();
|
|
317
|
+
render(_jsx(Editor, {}));
|
|
318
|
+
// Add keyword
|
|
319
|
+
const keywordInput = screen.getByPlaceholderText("Type a keyword and press Enter");
|
|
320
|
+
await user.type(keywordInput, "testing{Enter}");
|
|
321
|
+
expect(mockDispatch).toHaveBeenCalledWith(expect.objectContaining({
|
|
322
|
+
type: "ADD_PACKAGE_KEYWORD",
|
|
323
|
+
input: expect.objectContaining({
|
|
324
|
+
label: "testing",
|
|
325
|
+
id: expect.any(String),
|
|
326
|
+
}),
|
|
327
|
+
}));
|
|
328
|
+
});
|
|
329
|
+
});
|
|
330
|
+
});
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"codegen-processor-e2e.test.d.ts","sourceRoot":"","sources":["../../../../processors/codegen/__tests__/codegen-processor-e2e.test.ts"],"names":[],"mappings":""}
|