lhcb-ntuple-wizard-test 2.1.0 → 2.2.1
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/components/AddTupleToolButton.d.ts +1 -0
- package/dist/components/AddTupleToolButton.js +16 -0
- package/dist/components/BookkeepingPathDropdown.d.ts +1 -1
- package/dist/components/BookkeepingPathDropdown.js +1 -4
- package/dist/components/DatasetEventTypeBadge.js +1 -1
- package/dist/components/DatasetInfo.js +3 -3
- package/dist/components/DecayCard.d.ts +1 -1
- package/dist/components/DecayCard.js +12 -40
- package/dist/components/DecayLatex.d.ts +1 -1
- package/dist/components/DecayLatex.js +4 -87
- package/dist/components/DecayListItem.js +2 -2
- package/dist/components/DecayTagBadge.d.ts +1 -1
- package/dist/components/DecayTagBadge.js +0 -3
- package/dist/components/DecayTreeCard.d.ts +1 -7
- package/dist/components/DecayTreeCard.js +13 -18
- package/dist/components/DecayTreeCardHeader.d.ts +2 -3
- package/dist/components/DecayTreeCardHeader.js +2 -2
- package/dist/components/DecayTreeGraph.d.ts +1 -4
- package/dist/components/DecayTreeGraph.js +66 -41
- package/dist/components/DeleteButton.d.ts +2 -1
- package/dist/components/DeleteButton.js +2 -2
- package/dist/components/DttNameInput.d.ts +9 -0
- package/dist/components/DttNameInput.js +43 -0
- package/dist/components/GuideLinkButton.d.ts +15 -0
- package/dist/components/GuideLinkButton.js +16 -0
- package/dist/components/NtupleWizard.js +1 -7
- package/dist/components/ParticleDropdown.d.ts +11 -1
- package/dist/components/ParticleDropdown.js +3 -6
- package/dist/components/ParticleLatex.d.ts +6 -0
- package/dist/components/ParticleLatex.js +13 -0
- package/dist/components/ParticleTagBadge.d.ts +2 -1
- package/dist/components/ParticleTagBadge.js +5 -7
- package/dist/components/ParticleTagFilters.d.ts +1 -6
- package/dist/components/ParticleTagFilters.js +16 -17
- package/dist/components/RequestButtonGroup.d.ts +1 -1
- package/dist/components/RequestButtonGroup.js +0 -3
- package/dist/components/RequestRow.d.ts +1 -1
- package/dist/components/RequestRow.js +4 -9
- package/dist/components/StrippingLineDropdown.js +14 -16
- package/dist/components/StrippingLineInfo.d.ts +5 -5
- package/dist/components/StrippingLineInfo.js +14 -4
- package/dist/components/StrippingLineInfoButton.d.ts +6 -0
- package/dist/components/StrippingLineInfoButton.js +7 -0
- package/dist/components/StrippingLineVersionBadge.d.ts +7 -0
- package/dist/components/{StrippingLineBadge.js → StrippingLineVersionBadge.js} +5 -5
- package/dist/components/StrippingLinesCountBadge.d.ts +8 -0
- package/dist/components/StrippingLinesCountBadge.js +11 -0
- package/dist/components/TagDropdown.d.ts +3 -3
- package/dist/components/TagDropdown.js +2 -2
- package/dist/components/TupleToolClassDropdown.js +11 -14
- package/dist/components/TupleToolDocsAccordion.d.ts +1 -1
- package/dist/components/TupleToolDocsAccordion.js +4 -8
- package/dist/components/TupleToolGroupsAccordion.d.ts +5 -0
- package/dist/components/TupleToolGroupsAccordion.js +31 -0
- package/dist/components/TupleToolLabel.d.ts +1 -1
- package/dist/components/TupleToolLabel.js +2 -5
- package/dist/components/TupleToolsAccordion.d.ts +1 -0
- package/dist/components/TupleToolsAccordion.js +22 -0
- package/dist/components/modals/AddTupleToolModal.js +3 -2
- package/dist/components/modals/ConfigureTupleToolModal.js +1 -1
- package/dist/components/modals/UploadDttConfigModal.d.ts +1 -1
- package/dist/components/modals/UploadDttConfigModal.js +1 -4
- package/dist/config.d.ts +1 -0
- package/dist/config.js +3 -2
- package/dist/models/bkPath.js +1 -1
- package/dist/models/dtt.d.ts +5 -2
- package/dist/models/dtt.js +37 -18
- package/dist/models/rowData.d.ts +1 -1
- package/dist/models/yamlFile.js +1 -1
- package/dist/pages/DecaySearchPage.js +4 -9
- package/dist/pages/DecayTreeConfigPage.js +4 -38
- package/dist/pages/RequestPage.js +2 -4
- package/dist/providers/DttProvider.d.ts +3 -3
- package/dist/providers/DttProvider.js +30 -55
- package/dist/providers/MetadataProvider.d.ts +1 -1
- package/dist/providers/MetadataProvider.js +11 -5
- package/dist/providers/RequestProvider.js +2 -2
- package/dist/providers/RowProvider.d.ts +2 -2
- package/dist/providers/RowProvider.js +10 -9
- package/dist/providers/RowsProvider.js +0 -3
- package/dist/tests/components/BookkeepingPathDropdown.test.d.ts +1 -0
- package/dist/tests/components/BookkeepingPathDropdown.test.js +118 -0
- package/dist/tests/components/DatasetInfo.test.d.ts +1 -0
- package/dist/tests/components/DatasetInfo.test.js +38 -0
- package/dist/tests/components/DecayCard.test.d.ts +1 -0
- package/dist/tests/components/DecayCard.test.js +115 -0
- package/dist/tests/components/DecayLatex.test.d.ts +1 -0
- package/dist/tests/components/DecayLatex.test.js +31 -0
- package/dist/tests/components/DecayList.test.d.ts +1 -0
- package/dist/tests/components/DecayList.test.js +76 -0
- package/dist/tests/components/DecayListItem.test.d.ts +1 -0
- package/dist/tests/components/DecayListItem.test.js +51 -0
- package/dist/tests/components/DecayTreeCard.test.d.ts +1 -0
- package/dist/tests/components/DecayTreeCard.test.js +119 -0
- package/dist/tests/components/DecayTreeGraph.test.d.ts +1 -0
- package/dist/tests/components/DecayTreeGraph.test.js +125 -0
- package/dist/tests/components/DeleteButton.test.d.ts +1 -0
- package/dist/tests/components/DeleteButton.test.js +45 -0
- package/dist/tests/components/DttNameInput.test.d.ts +1 -0
- package/dist/tests/components/DttNameInput.test.js +75 -0
- package/dist/tests/components/NtupleWizard.test.d.ts +1 -0
- package/dist/tests/components/NtupleWizard.test.js +57 -0
- package/dist/tests/components/ParticleDropdown.test.d.ts +1 -0
- package/dist/tests/components/ParticleDropdown.test.js +23 -0
- package/dist/tests/components/ParticleTagFilters.test.d.ts +1 -0
- package/dist/tests/components/ParticleTagFilters.test.js +87 -0
- package/dist/tests/components/RequestButtonGroup.test.d.ts +1 -0
- package/dist/tests/components/RequestButtonGroup.test.js +132 -0
- package/dist/tests/components/RequestRow.test.d.ts +1 -0
- package/dist/tests/components/RequestRow.test.js +58 -0
- package/dist/tests/components/StrippingLineDropdown.test.d.ts +1 -0
- package/dist/tests/components/StrippingLineDropdown.test.js +88 -0
- package/dist/tests/components/badges.test.d.ts +1 -0
- package/dist/tests/components/badges.test.js +120 -0
- package/dist/tests/components/dropdowns.test.d.ts +1 -0
- package/dist/tests/components/dropdowns.test.js +110 -0
- package/dist/tests/components/dttComponents.test.d.ts +1 -0
- package/dist/tests/components/dttComponents.test.js +287 -0
- package/dist/tests/components/formInputs.test.d.ts +1 -0
- package/dist/tests/components/formInputs.test.js +96 -0
- package/dist/tests/components/metadataComponents.test.d.ts +1 -0
- package/dist/tests/components/metadataComponents.test.js +137 -0
- package/dist/tests/components/miscComponents.test.d.ts +1 -0
- package/dist/tests/components/miscComponents.test.js +134 -0
- package/dist/tests/components/modals.test.d.ts +1 -0
- package/dist/tests/components/modals.test.js +554 -0
- package/dist/tests/components/tupleToolParams.test.d.ts +1 -0
- package/dist/tests/components/tupleToolParams.test.js +213 -0
- package/dist/tests/config.test.d.ts +1 -0
- package/dist/tests/config.test.js +31 -0
- package/dist/tests/mockSetup.d.ts +1 -0
- package/dist/tests/mockSetup.js +30 -0
- package/dist/tests/models/BkPath.test.d.ts +1 -0
- package/dist/tests/models/BkPath.test.js +87 -0
- package/dist/tests/models/Dtt.test.d.ts +1 -0
- package/dist/tests/models/Dtt.test.js +376 -0
- package/dist/tests/models/TupleTool.test.d.ts +1 -0
- package/dist/tests/models/TupleTool.test.js +80 -0
- package/dist/tests/models/YamlFile.test.d.ts +1 -0
- package/dist/tests/models/YamlFile.test.js +123 -0
- package/dist/tests/pages/DecaySearchPage.test.d.ts +1 -0
- package/dist/tests/pages/DecaySearchPage.test.js +228 -0
- package/dist/tests/pages/DecayTreeConfigPage.test.d.ts +1 -0
- package/dist/tests/pages/DecayTreeConfigPage.test.js +105 -0
- package/dist/tests/pages/RequestPage.test.d.ts +1 -0
- package/dist/tests/pages/RequestPage.test.js +439 -0
- package/dist/tests/providers/DttProvider.test.d.ts +1 -0
- package/dist/tests/providers/DttProvider.test.js +105 -0
- package/dist/tests/providers/MetadataProvider.test.d.ts +1 -0
- package/dist/tests/providers/MetadataProvider.test.js +129 -0
- package/dist/tests/providers/RequestProvider.test.d.ts +1 -0
- package/dist/tests/providers/RequestProvider.test.js +306 -0
- package/dist/tests/providers/RowProvider.test.d.ts +1 -0
- package/dist/tests/providers/RowProvider.test.js +110 -0
- package/dist/tests/providers/RowsProvider.test.d.ts +1 -0
- package/dist/tests/providers/RowsProvider.test.js +84 -0
- package/dist/tests/providers/WizardConfigProvider.test.d.ts +1 -0
- package/dist/tests/providers/WizardConfigProvider.test.js +36 -0
- package/dist/tests/setupTests.d.ts +1 -0
- package/dist/tests/setupTests.js +15 -0
- package/dist/tests/testUtils.d.ts +33 -0
- package/dist/tests/testUtils.js +196 -0
- package/dist/tests/utils/latexUtils.test.d.ts +1 -0
- package/dist/tests/utils/latexUtils.test.js +62 -0
- package/dist/tests/utils/utils.test.d.ts +1 -0
- package/dist/tests/utils/utils.test.js +394 -0
- package/dist/utils/latexUtils.d.ts +13 -0
- package/dist/utils/latexUtils.js +86 -0
- package/dist/utils/utils.d.ts +1 -0
- package/dist/utils/utils.js +4 -1
- package/package.json +19 -9
- package/dist/components/NumStrippingLinesBadge.d.ts +0 -8
- package/dist/components/NumStrippingLinesBadge.js +0 -10
- package/dist/components/StrippingLineBadge.d.ts +0 -7
- package/dist/components/TupleToolGroup.d.ts +0 -5
- package/dist/components/TupleToolGroup.js +0 -22
- package/dist/components/TupleToolList.d.ts +0 -6
- package/dist/components/TupleToolList.js +0 -42
|
@@ -0,0 +1,554 @@
|
|
|
1
|
+
import { jsx as _jsx } from "react/jsx-runtime";
|
|
2
|
+
import { afterEach, beforeEach, describe, expect, it, vi } from "vitest";
|
|
3
|
+
import { fireEvent, render, screen } from "@testing-library/react";
|
|
4
|
+
import { toast } from "react-toastify";
|
|
5
|
+
import { AddTupleToolModal } from "../../components/modals/AddTupleToolModal";
|
|
6
|
+
import { ConfigureTupleToolModal } from "../../components/modals/ConfigureTupleToolModal";
|
|
7
|
+
import { UploadDttConfigModal } from "../../components/modals/UploadDttConfigModal";
|
|
8
|
+
import { ReasonForRequestModal } from "../../components/modals/ReasonForRequestModal";
|
|
9
|
+
import { createMockDtt, createMockRow, mockBranchItems, mockDecay, mockToolMetadata } from "../testUtils";
|
|
10
|
+
import { TupleTool } from "../../models/tupleTool";
|
|
11
|
+
import Dtt from "../../models/dtt";
|
|
12
|
+
import * as utils from "../../utils/utils";
|
|
13
|
+
// ---------------------------------------------------------------------------
|
|
14
|
+
// Shared mocks
|
|
15
|
+
// ---------------------------------------------------------------------------
|
|
16
|
+
const mockValidateFn = vi.fn(() => null);
|
|
17
|
+
vi.mock("../../config", () => ({
|
|
18
|
+
config: {
|
|
19
|
+
disabledTupleTools: [],
|
|
20
|
+
tupleToolValidation: {
|
|
21
|
+
TupleToolKinematic: {
|
|
22
|
+
validate: () => mockValidateFn(),
|
|
23
|
+
},
|
|
24
|
+
},
|
|
25
|
+
},
|
|
26
|
+
}));
|
|
27
|
+
vi.mock("react-toastify", () => ({
|
|
28
|
+
toast: vi.fn(),
|
|
29
|
+
}));
|
|
30
|
+
const mockAddTool = vi.fn();
|
|
31
|
+
const mockRemoveTool = vi.fn();
|
|
32
|
+
const mockUpdateToolParam = vi.fn();
|
|
33
|
+
let mockDtt = createMockDtt("MyTree");
|
|
34
|
+
let mockSelectedBranch = [];
|
|
35
|
+
vi.mock("../../providers/DttProvider", () => ({
|
|
36
|
+
useDtt: () => ({
|
|
37
|
+
dtt: mockDtt,
|
|
38
|
+
addTool: mockAddTool,
|
|
39
|
+
removeTool: mockRemoveTool,
|
|
40
|
+
updateToolParam: mockUpdateToolParam,
|
|
41
|
+
selectedBranch: mockSelectedBranch,
|
|
42
|
+
setSelectedBranch: vi.fn(),
|
|
43
|
+
setHoveredBranch: vi.fn(),
|
|
44
|
+
hoveredBranch: [],
|
|
45
|
+
highlightedBranch: [],
|
|
46
|
+
}),
|
|
47
|
+
}));
|
|
48
|
+
vi.mock("../../components/TupleToolClassDropdown", () => ({
|
|
49
|
+
TupleToolClassDropdown: ({ onChange }) => (_jsx("button", { "data-testid": "tool-class-dropdown", onClick: () => onChange({ value: "TupleToolKinematic" }), children: "Select tool" })),
|
|
50
|
+
}));
|
|
51
|
+
vi.mock("../../components/TupleToolDocsAccordion", () => ({
|
|
52
|
+
TupleToolDocsAccordion: () => _jsx("div", { "data-testid": "docs-accordion" }),
|
|
53
|
+
}));
|
|
54
|
+
vi.mock("../../components/ParticleLatex", () => ({
|
|
55
|
+
ParticleLatex: ({ particleId }) => _jsx("span", { "data-testid": `particle-${particleId}` }),
|
|
56
|
+
}));
|
|
57
|
+
const mockSetRows = vi.fn();
|
|
58
|
+
const mockUpdateRow = vi.fn();
|
|
59
|
+
const mockSetContactEmails = vi.fn();
|
|
60
|
+
const mockGenerateAllFiles = vi.fn(() => []);
|
|
61
|
+
// Tool metadata with diverse param types for testing ConfigureTupleToolModal switch cases
|
|
62
|
+
const diverseToolMetadata = {
|
|
63
|
+
...mockToolMetadata,
|
|
64
|
+
DiverseTool: {
|
|
65
|
+
description: "Tool with diverse param types",
|
|
66
|
+
documentation: "",
|
|
67
|
+
tags: [],
|
|
68
|
+
interface: [
|
|
69
|
+
{ name: "StrParam", type: "str", cpp_type: "string", default: "hello", description: "A string param" },
|
|
70
|
+
{ name: "BoolParam", type: "bool", cpp_type: "bool", default: false, description: "A bool param" },
|
|
71
|
+
{ name: "IntParam", type: "int", cpp_type: "int", default: 0, description: "An int param" },
|
|
72
|
+
{ name: "FloatParam", type: "float", cpp_type: "float", default: 0.0, description: "A float param" },
|
|
73
|
+
{ name: "TextParam", type: "text", cpp_type: "vector<string>", default: [], description: "A text param" },
|
|
74
|
+
{
|
|
75
|
+
name: "IntListParam",
|
|
76
|
+
type: "[int]",
|
|
77
|
+
cpp_type: "vector<int>",
|
|
78
|
+
default: [],
|
|
79
|
+
description: "An int list param",
|
|
80
|
+
},
|
|
81
|
+
{
|
|
82
|
+
name: "DictParam",
|
|
83
|
+
type: "{str:str}",
|
|
84
|
+
cpp_type: "map<string,string>",
|
|
85
|
+
default: {},
|
|
86
|
+
description: "A dict param",
|
|
87
|
+
},
|
|
88
|
+
{
|
|
89
|
+
name: "DictListParam",
|
|
90
|
+
type: "{str:[str]}",
|
|
91
|
+
cpp_type: "map<string,vector<string>>",
|
|
92
|
+
default: {},
|
|
93
|
+
description: "A dict list param",
|
|
94
|
+
},
|
|
95
|
+
],
|
|
96
|
+
},
|
|
97
|
+
};
|
|
98
|
+
function createDiverseDtt() {
|
|
99
|
+
return Dtt.create("[B+ -> ${head} ${k} ${mup} ${mum}]cc", mockBranchItems, [], "MyTree", diverseToolMetadata).withAddedTool(new TupleTool("DiverseTool", ""));
|
|
100
|
+
}
|
|
101
|
+
vi.mock("../../providers/RowsProvider", () => ({
|
|
102
|
+
useRows: () => ({
|
|
103
|
+
setRows: mockSetRows,
|
|
104
|
+
updateRow: mockUpdateRow,
|
|
105
|
+
rows: [],
|
|
106
|
+
configuredRows: [],
|
|
107
|
+
removeRow: vi.fn(),
|
|
108
|
+
generateAllFiles: mockGenerateAllFiles,
|
|
109
|
+
}),
|
|
110
|
+
}));
|
|
111
|
+
let mockReasonForRequest = "";
|
|
112
|
+
const mockSetReasonForRequest = vi.fn();
|
|
113
|
+
vi.mock("../../providers/RequestProvider", () => ({
|
|
114
|
+
useRequest: () => ({
|
|
115
|
+
setContactEmails: mockSetContactEmails,
|
|
116
|
+
productionName: "TestProduction",
|
|
117
|
+
setProductionName: vi.fn(),
|
|
118
|
+
contactEmails: [],
|
|
119
|
+
showErrors: false,
|
|
120
|
+
validation: { isEmailValid: false },
|
|
121
|
+
trySubmit: vi.fn(),
|
|
122
|
+
clearAll: vi.fn(),
|
|
123
|
+
reasonForRequest: mockReasonForRequest,
|
|
124
|
+
setReasonForRequest: mockSetReasonForRequest,
|
|
125
|
+
}),
|
|
126
|
+
}));
|
|
127
|
+
vi.mock("../../providers/WizardConfigProvider", () => ({
|
|
128
|
+
useWizardConfig: () => ({
|
|
129
|
+
requestReasonMessage: "Please state your reason for requesting ntuples.",
|
|
130
|
+
submitLocation: "https://example.com/api/submit",
|
|
131
|
+
variant: "embedded",
|
|
132
|
+
basePath: "/",
|
|
133
|
+
}),
|
|
134
|
+
}));
|
|
135
|
+
vi.mock("../../utils/utils", () => ({
|
|
136
|
+
parseProductionFiles: vi.fn(),
|
|
137
|
+
sanitizeFilename: vi.fn((s) => s),
|
|
138
|
+
downloadText: vi.fn(),
|
|
139
|
+
downloadZip: vi.fn(),
|
|
140
|
+
getControlKey: vi.fn(() => "ctrl"),
|
|
141
|
+
}));
|
|
142
|
+
// ---------------------------------------------------------------------------
|
|
143
|
+
// AddTupleToolModal
|
|
144
|
+
// ---------------------------------------------------------------------------
|
|
145
|
+
describe("AddTupleToolModal", () => {
|
|
146
|
+
beforeEach(() => {
|
|
147
|
+
mockDtt = createMockDtt("MyTree");
|
|
148
|
+
mockSelectedBranch = [];
|
|
149
|
+
mockAddTool.mockClear();
|
|
150
|
+
});
|
|
151
|
+
it("renders the modal title", () => {
|
|
152
|
+
render(_jsx(AddTupleToolModal, { onClose: vi.fn() }));
|
|
153
|
+
expect(screen.getByText("Add TupleTool")).toBeInTheDocument();
|
|
154
|
+
});
|
|
155
|
+
it("renders the TupleToolClassDropdown", () => {
|
|
156
|
+
render(_jsx(AddTupleToolModal, { onClose: vi.fn() }));
|
|
157
|
+
expect(screen.getByTestId("tool-class-dropdown")).toBeInTheDocument();
|
|
158
|
+
});
|
|
159
|
+
it("calls onClose with null when Cancel is clicked", () => {
|
|
160
|
+
const onClose = vi.fn();
|
|
161
|
+
render(_jsx(AddTupleToolModal, { onClose: onClose }));
|
|
162
|
+
fireEvent.click(screen.getByText("Cancel"));
|
|
163
|
+
expect(onClose).toHaveBeenCalledWith(null);
|
|
164
|
+
});
|
|
165
|
+
it("shows the docs accordion after a tool class is selected", () => {
|
|
166
|
+
render(_jsx(AddTupleToolModal, { onClose: vi.fn() }));
|
|
167
|
+
fireEvent.click(screen.getByTestId("tool-class-dropdown"));
|
|
168
|
+
expect(screen.getByTestId("docs-accordion")).toBeInTheDocument();
|
|
169
|
+
});
|
|
170
|
+
it("Add tool button is disabled when selected tool already exists", () => {
|
|
171
|
+
// TupleToolKinematic is already in mockDtt, so button should be disabled
|
|
172
|
+
render(_jsx(AddTupleToolModal, { onClose: vi.fn() }));
|
|
173
|
+
fireEvent.click(screen.getByTestId("tool-class-dropdown"));
|
|
174
|
+
// The "Add tool" submit button should be disabled
|
|
175
|
+
const addBtn = screen
|
|
176
|
+
.getAllByText("Add tool")
|
|
177
|
+
.find((el) => el.tagName === "BUTTON" && el !== screen.getByTestId("tool-class-dropdown"));
|
|
178
|
+
expect(addBtn).toBeDisabled();
|
|
179
|
+
});
|
|
180
|
+
it("shows target particles when selectedBranch is non-empty", () => {
|
|
181
|
+
mockSelectedBranch = ["head"];
|
|
182
|
+
render(_jsx(AddTupleToolModal, { onClose: vi.fn() }));
|
|
183
|
+
expect(screen.getByTestId("particle-head")).toBeInTheDocument();
|
|
184
|
+
});
|
|
185
|
+
it("sanitizes the tool name on input and reflects the value", () => {
|
|
186
|
+
render(_jsx(AddTupleToolModal, { onClose: vi.fn() }));
|
|
187
|
+
fireEvent.click(screen.getByTestId("tool-class-dropdown"));
|
|
188
|
+
const nameInput = screen.getByPlaceholderText("TupleTool name");
|
|
189
|
+
fireEvent.change(nameInput, { target: { value: "my tool!" } });
|
|
190
|
+
expect(nameInput).toHaveValue("mytool");
|
|
191
|
+
});
|
|
192
|
+
it("pressing Enter on name input calls addTool and onClose when tool doesn't exist", () => {
|
|
193
|
+
mockDtt = createMockDtt("MyTree").withRemovedTool(new TupleTool("TupleToolKinematic", ""));
|
|
194
|
+
const onClose = vi.fn();
|
|
195
|
+
render(_jsx(AddTupleToolModal, { onClose: onClose }));
|
|
196
|
+
fireEvent.click(screen.getByTestId("tool-class-dropdown"));
|
|
197
|
+
const nameInput = screen.getByPlaceholderText("TupleTool name");
|
|
198
|
+
fireEvent.keyDown(nameInput, { key: "Enter" });
|
|
199
|
+
expect(mockAddTool).toHaveBeenCalled();
|
|
200
|
+
expect(onClose).toHaveBeenCalledWith(expect.any(TupleTool));
|
|
201
|
+
});
|
|
202
|
+
it("clicking Add tool calls addTool and onClose when tool doesn't exist", () => {
|
|
203
|
+
mockDtt = createMockDtt("MyTree").withRemovedTool(new TupleTool("TupleToolKinematic", ""));
|
|
204
|
+
const onClose = vi.fn();
|
|
205
|
+
render(_jsx(AddTupleToolModal, { onClose: onClose }));
|
|
206
|
+
fireEvent.click(screen.getByTestId("tool-class-dropdown"));
|
|
207
|
+
const addBtn = screen
|
|
208
|
+
.getAllByText("Add tool")
|
|
209
|
+
.find((el) => el.tagName === "BUTTON" && el !== screen.getByTestId("tool-class-dropdown"));
|
|
210
|
+
expect(addBtn).not.toBeDisabled();
|
|
211
|
+
fireEvent.click(addBtn);
|
|
212
|
+
expect(mockAddTool).toHaveBeenCalled();
|
|
213
|
+
expect(onClose).toHaveBeenCalledWith(expect.any(TupleTool));
|
|
214
|
+
});
|
|
215
|
+
});
|
|
216
|
+
// ---------------------------------------------------------------------------
|
|
217
|
+
// ConfigureTupleToolModal
|
|
218
|
+
// ---------------------------------------------------------------------------
|
|
219
|
+
describe("ConfigureTupleToolModal", () => {
|
|
220
|
+
// Use no-name tool — matches the key "TupleToolKinematic" in mockDtt
|
|
221
|
+
const kineticTool = new TupleTool("TupleToolKinematic", "");
|
|
222
|
+
beforeEach(() => {
|
|
223
|
+
// Add TupleToolKinematic to the dtt so getToolConfig returns real config
|
|
224
|
+
mockDtt = createMockDtt("MyTree");
|
|
225
|
+
mockSelectedBranch = [];
|
|
226
|
+
mockRemoveTool.mockClear();
|
|
227
|
+
mockValidateFn.mockReturnValue(null);
|
|
228
|
+
vi.mocked(toast).mockClear();
|
|
229
|
+
});
|
|
230
|
+
it("renders the modal title with tool name", () => {
|
|
231
|
+
render(_jsx(ConfigureTupleToolModal, { tool: kineticTool, deleteIfCancelled: false, onClose: vi.fn() }));
|
|
232
|
+
expect(screen.getByText(/configure TupleToolKinematic/i)).toBeInTheDocument();
|
|
233
|
+
});
|
|
234
|
+
it("renders the docs accordion", () => {
|
|
235
|
+
render(_jsx(ConfigureTupleToolModal, { tool: kineticTool, deleteIfCancelled: false, onClose: vi.fn() }));
|
|
236
|
+
expect(screen.getByTestId("docs-accordion")).toBeInTheDocument();
|
|
237
|
+
});
|
|
238
|
+
it("calls onClose when Save & close is clicked", () => {
|
|
239
|
+
const onClose = vi.fn();
|
|
240
|
+
render(_jsx(ConfigureTupleToolModal, { tool: kineticTool, deleteIfCancelled: false, onClose: onClose }));
|
|
241
|
+
fireEvent.click(screen.getByText("Save & close"));
|
|
242
|
+
expect(onClose).toHaveBeenCalled();
|
|
243
|
+
});
|
|
244
|
+
it("calls onClose (not removeTool) on cancel when deleteIfCancelled=false", () => {
|
|
245
|
+
const onClose = vi.fn();
|
|
246
|
+
render(_jsx(ConfigureTupleToolModal, { tool: kineticTool, deleteIfCancelled: false, onClose: onClose }));
|
|
247
|
+
fireEvent.click(screen.getByText("Cancel"));
|
|
248
|
+
expect(mockRemoveTool).not.toHaveBeenCalled();
|
|
249
|
+
expect(onClose).toHaveBeenCalled();
|
|
250
|
+
});
|
|
251
|
+
it("calls removeTool on cancel when deleteIfCancelled=true", () => {
|
|
252
|
+
const onClose = vi.fn();
|
|
253
|
+
render(_jsx(ConfigureTupleToolModal, { tool: kineticTool, deleteIfCancelled: true, onClose: onClose }));
|
|
254
|
+
fireEvent.click(screen.getByText("Cancel"));
|
|
255
|
+
expect(mockRemoveTool).toHaveBeenCalled();
|
|
256
|
+
expect(onClose).toHaveBeenCalled();
|
|
257
|
+
});
|
|
258
|
+
it("calls onClose when validation passes (validate returns null)", () => {
|
|
259
|
+
mockValidateFn.mockReturnValue(null);
|
|
260
|
+
const onClose = vi.fn();
|
|
261
|
+
render(_jsx(ConfigureTupleToolModal, { tool: kineticTool, deleteIfCancelled: false, onClose: onClose }));
|
|
262
|
+
fireEvent.click(screen.getByText("Save & close"));
|
|
263
|
+
expect(onClose).toHaveBeenCalled();
|
|
264
|
+
});
|
|
265
|
+
it("shows toast error and does not close when validation fails", () => {
|
|
266
|
+
mockValidateFn.mockReturnValue("Please add at least one variable");
|
|
267
|
+
const onClose = vi.fn();
|
|
268
|
+
render(_jsx(ConfigureTupleToolModal, { tool: kineticTool, deleteIfCancelled: false, onClose: onClose }));
|
|
269
|
+
fireEvent.click(screen.getByText("Save & close"));
|
|
270
|
+
expect(toast).toHaveBeenCalledWith("Please add at least one variable", { type: "error" });
|
|
271
|
+
expect(onClose).not.toHaveBeenCalled();
|
|
272
|
+
});
|
|
273
|
+
});
|
|
274
|
+
describe("ConfigureTupleToolModal — diverse param types", () => {
|
|
275
|
+
beforeEach(() => {
|
|
276
|
+
mockDtt = createDiverseDtt();
|
|
277
|
+
mockSelectedBranch = [];
|
|
278
|
+
mockRemoveTool.mockClear();
|
|
279
|
+
mockValidateFn.mockReturnValue(null);
|
|
280
|
+
});
|
|
281
|
+
it("renders str param input", () => {
|
|
282
|
+
render(_jsx(ConfigureTupleToolModal, { tool: new TupleTool("DiverseTool", ""), deleteIfCancelled: false, onClose: vi.fn() }));
|
|
283
|
+
// StrParamInput renders as a text input
|
|
284
|
+
const inputs = screen.getAllByRole("textbox");
|
|
285
|
+
expect(inputs.length).toBeGreaterThan(0);
|
|
286
|
+
});
|
|
287
|
+
it("renders int param as spinbutton", () => {
|
|
288
|
+
render(_jsx(ConfigureTupleToolModal, { tool: new TupleTool("DiverseTool", ""), deleteIfCancelled: false, onClose: vi.fn() }));
|
|
289
|
+
const spinbuttons = screen.getAllByRole("spinbutton");
|
|
290
|
+
expect(spinbuttons.length).toBeGreaterThan(0);
|
|
291
|
+
});
|
|
292
|
+
it("renders [int] list param with an add button", () => {
|
|
293
|
+
render(_jsx(ConfigureTupleToolModal, { tool: new TupleTool("DiverseTool", ""), deleteIfCancelled: false, onClose: vi.fn() }));
|
|
294
|
+
// ListParamInput renders an add button
|
|
295
|
+
const buttons = screen.getAllByRole("button");
|
|
296
|
+
expect(buttons.length).toBeGreaterThan(0);
|
|
297
|
+
});
|
|
298
|
+
it("renders {str:str} dict param with an Edit button", () => {
|
|
299
|
+
render(_jsx(ConfigureTupleToolModal, { tool: new TupleTool("DiverseTool", ""), deleteIfCancelled: false, onClose: vi.fn() }));
|
|
300
|
+
expect(screen.getAllByText("Edit").length).toBeGreaterThan(0);
|
|
301
|
+
});
|
|
302
|
+
it("calls updateToolParam when str param value is changed", () => {
|
|
303
|
+
render(_jsx(ConfigureTupleToolModal, { tool: new TupleTool("DiverseTool", ""), deleteIfCancelled: false, onClose: vi.fn() }));
|
|
304
|
+
const inputs = screen.getAllByRole("textbox");
|
|
305
|
+
fireEvent.change(inputs[0], { target: { value: "new_value" } });
|
|
306
|
+
expect(mockUpdateToolParam).toHaveBeenCalled();
|
|
307
|
+
});
|
|
308
|
+
it("calls updateToolParam when bool param is toggled", () => {
|
|
309
|
+
render(_jsx(ConfigureTupleToolModal, { tool: new TupleTool("DiverseTool", ""), deleteIfCancelled: false, onClose: vi.fn() }));
|
|
310
|
+
const checkbox = screen.getByRole("checkbox");
|
|
311
|
+
fireEvent.click(checkbox);
|
|
312
|
+
expect(mockUpdateToolParam).toHaveBeenCalled();
|
|
313
|
+
});
|
|
314
|
+
it("calls updateToolParam when int param value is changed", () => {
|
|
315
|
+
render(_jsx(ConfigureTupleToolModal, { tool: new TupleTool("DiverseTool", ""), deleteIfCancelled: false, onClose: vi.fn() }));
|
|
316
|
+
const spinbuttons = screen.getAllByRole("spinbutton");
|
|
317
|
+
fireEvent.change(spinbuttons[0], { target: { value: "42" } });
|
|
318
|
+
expect(mockUpdateToolParam).toHaveBeenCalled();
|
|
319
|
+
});
|
|
320
|
+
it("calls updateToolParam when text list item is added", () => {
|
|
321
|
+
render(_jsx(ConfigureTupleToolModal, { tool: new TupleTool("DiverseTool", ""), deleteIfCancelled: false, onClose: vi.fn() }));
|
|
322
|
+
// TextParam list add button is first .btn-success
|
|
323
|
+
const addBtns = document.querySelectorAll(".btn-success");
|
|
324
|
+
expect(addBtns.length).toBeGreaterThanOrEqual(1);
|
|
325
|
+
fireEvent.click(addBtns[0]);
|
|
326
|
+
expect(mockUpdateToolParam).toHaveBeenCalled();
|
|
327
|
+
});
|
|
328
|
+
it("renders NumParamInput inside [int] list param after clicking add button", () => {
|
|
329
|
+
render(_jsx(ConfigureTupleToolModal, { tool: new TupleTool("DiverseTool", ""), deleteIfCancelled: false, onClose: vi.fn() }));
|
|
330
|
+
// Two ListParamInputs: TextParam (str list) and IntListParam (int list)
|
|
331
|
+
// Both have a .btn-success add button. The int list is the second one.
|
|
332
|
+
// Modal renders in a portal so use document-level query.
|
|
333
|
+
const addBtns = document.querySelectorAll(".btn-success");
|
|
334
|
+
expect(addBtns.length).toBeGreaterThanOrEqual(2);
|
|
335
|
+
// Click the [int] list add button (second success button)
|
|
336
|
+
fireEvent.click(addBtns[1]);
|
|
337
|
+
// After adding an item, buildInnerInput renders a NumParamInput (spinbutton)
|
|
338
|
+
expect(screen.getAllByRole("spinbutton").length).toBeGreaterThan(1);
|
|
339
|
+
});
|
|
340
|
+
it("calls updateToolParam when dict param onChange fires via Save", () => {
|
|
341
|
+
render(_jsx(ConfigureTupleToolModal, { tool: new TupleTool("DiverseTool", ""), deleteIfCancelled: false, onClose: vi.fn() }));
|
|
342
|
+
// Click the first Edit button (for DictParam)
|
|
343
|
+
fireEvent.click(screen.getAllByText("Edit")[0]);
|
|
344
|
+
// Modal renders in a portal; use document-level query for enabled textarea
|
|
345
|
+
const enabledTextarea = document.querySelector("textarea:not(:disabled)");
|
|
346
|
+
expect(enabledTextarea).not.toBeNull();
|
|
347
|
+
fireEvent.change(enabledTextarea, { target: { value: '{"k":"v"}' } });
|
|
348
|
+
fireEvent.click(screen.getByText("Save"));
|
|
349
|
+
expect(mockUpdateToolParam).toHaveBeenCalled();
|
|
350
|
+
});
|
|
351
|
+
});
|
|
352
|
+
// ---------------------------------------------------------------------------
|
|
353
|
+
// UploadDttConfigModal
|
|
354
|
+
// ---------------------------------------------------------------------------
|
|
355
|
+
describe("UploadDttConfigModal", () => {
|
|
356
|
+
beforeEach(() => {
|
|
357
|
+
mockSetRows.mockClear();
|
|
358
|
+
mockSetContactEmails.mockClear();
|
|
359
|
+
vi.mocked(utils.parseProductionFiles).mockClear();
|
|
360
|
+
});
|
|
361
|
+
it("renders the modal title", () => {
|
|
362
|
+
render(_jsx(UploadDttConfigModal, { onClose: vi.fn() }));
|
|
363
|
+
expect(screen.getByText(/upload configuration file/i)).toBeInTheDocument();
|
|
364
|
+
});
|
|
365
|
+
it("renders Cancel and Import buttons", () => {
|
|
366
|
+
render(_jsx(UploadDttConfigModal, { onClose: vi.fn() }));
|
|
367
|
+
expect(screen.getByText("Cancel")).toBeInTheDocument();
|
|
368
|
+
expect(screen.getByText("Import")).toBeInTheDocument();
|
|
369
|
+
});
|
|
370
|
+
it("calls onClose when Cancel is clicked", () => {
|
|
371
|
+
const onClose = vi.fn();
|
|
372
|
+
render(_jsx(UploadDttConfigModal, { onClose: onClose }));
|
|
373
|
+
fireEvent.click(screen.getByText("Cancel"));
|
|
374
|
+
expect(onClose).toHaveBeenCalled();
|
|
375
|
+
});
|
|
376
|
+
it("calls parseProductionFiles and setRows on Import click with files", async () => {
|
|
377
|
+
vi.mocked(utils.parseProductionFiles).mockResolvedValue({ rows: [], emails: ["user@cern.ch"] });
|
|
378
|
+
const onClose = vi.fn();
|
|
379
|
+
render(_jsx(UploadDttConfigModal, { onClose: onClose }));
|
|
380
|
+
// Simulate file selection
|
|
381
|
+
const input = document.querySelector("input[type='file']");
|
|
382
|
+
const file = new File(["content"], "test.yaml", { type: "text/plain" });
|
|
383
|
+
fireEvent.change(input, { target: { files: [file] } });
|
|
384
|
+
fireEvent.click(screen.getByText("Import"));
|
|
385
|
+
// Wait for async parseProductionFiles
|
|
386
|
+
await vi.waitFor(() => expect(mockSetRows).toHaveBeenCalled());
|
|
387
|
+
expect(mockSetContactEmails).toHaveBeenCalledWith(["user@cern.ch"]);
|
|
388
|
+
});
|
|
389
|
+
it("does not call parseProductionFiles when no files are selected and Import is clicked", async () => {
|
|
390
|
+
render(_jsx(UploadDttConfigModal, { onClose: vi.fn() }));
|
|
391
|
+
fireEvent.click(screen.getByText("Import"));
|
|
392
|
+
await new Promise((r) => setTimeout(r, 20));
|
|
393
|
+
expect(vi.mocked(utils.parseProductionFiles)).not.toHaveBeenCalled();
|
|
394
|
+
});
|
|
395
|
+
it("shows alert when parseProductionFiles returns an error string", async () => {
|
|
396
|
+
vi.mocked(utils.parseProductionFiles).mockResolvedValue("Error: invalid format");
|
|
397
|
+
const alertMock = vi.spyOn(window, "alert").mockImplementation(() => { });
|
|
398
|
+
const onClose = vi.fn();
|
|
399
|
+
render(_jsx(UploadDttConfigModal, { onClose: onClose }));
|
|
400
|
+
const input = document.querySelector("input[type='file']");
|
|
401
|
+
fireEvent.change(input, { target: { files: [new File(["x"], "test.yaml")] } });
|
|
402
|
+
fireEvent.click(screen.getByText("Import"));
|
|
403
|
+
await vi.waitFor(() => expect(alertMock).toHaveBeenCalled());
|
|
404
|
+
expect(onClose).not.toHaveBeenCalled();
|
|
405
|
+
alertMock.mockRestore();
|
|
406
|
+
});
|
|
407
|
+
it("calls updateRow and onClose when currentRow template matches imported DTT", async () => {
|
|
408
|
+
const dttForImport = createMockDtt("ImportedTree");
|
|
409
|
+
const currentRow = createMockRow({
|
|
410
|
+
id: 5,
|
|
411
|
+
decay: {
|
|
412
|
+
...mockDecay,
|
|
413
|
+
descriptors: {
|
|
414
|
+
...mockDecay.descriptors,
|
|
415
|
+
template: "[B+ -> ${head} ${k} ${mup} ${mum}]cc",
|
|
416
|
+
},
|
|
417
|
+
},
|
|
418
|
+
});
|
|
419
|
+
vi.mocked(utils.parseProductionFiles).mockResolvedValue({
|
|
420
|
+
rows: [createMockRow({ dtt: dttForImport })],
|
|
421
|
+
emails: [],
|
|
422
|
+
});
|
|
423
|
+
const onClose = vi.fn();
|
|
424
|
+
render(_jsx(UploadDttConfigModal, { onClose: onClose, currentRow: currentRow }));
|
|
425
|
+
const input = document.querySelector("input[type='file']");
|
|
426
|
+
fireEvent.change(input, { target: { files: [new File(["x"], "test.yaml")] } });
|
|
427
|
+
fireEvent.click(screen.getByText("Import"));
|
|
428
|
+
await vi.waitFor(() => expect(onClose).toHaveBeenCalled());
|
|
429
|
+
expect(mockUpdateRow).toHaveBeenCalled();
|
|
430
|
+
});
|
|
431
|
+
it("updateRow callback applies imported dtt to the row", async () => {
|
|
432
|
+
const dttForImport = createMockDtt("ImportedTree");
|
|
433
|
+
const currentRow = createMockRow({
|
|
434
|
+
id: 5,
|
|
435
|
+
line: null,
|
|
436
|
+
decay: {
|
|
437
|
+
...mockDecay,
|
|
438
|
+
descriptors: { ...mockDecay.descriptors, template: "[B+ -> ${head} ${k} ${mup} ${mum}]cc" },
|
|
439
|
+
},
|
|
440
|
+
});
|
|
441
|
+
vi.mocked(utils.parseProductionFiles).mockResolvedValue({
|
|
442
|
+
rows: [createMockRow({ dtt: dttForImport })],
|
|
443
|
+
emails: [],
|
|
444
|
+
});
|
|
445
|
+
mockUpdateRow.mockImplementationOnce((_id, fn) => {
|
|
446
|
+
fn(currentRow);
|
|
447
|
+
});
|
|
448
|
+
const onClose = vi.fn();
|
|
449
|
+
render(_jsx(UploadDttConfigModal, { onClose: onClose, currentRow: currentRow }));
|
|
450
|
+
const input = document.querySelector("input[type='file']");
|
|
451
|
+
fireEvent.change(input, { target: { files: [new File(["x"], "test.yaml")] } });
|
|
452
|
+
fireEvent.click(screen.getByText("Import"));
|
|
453
|
+
await vi.waitFor(() => expect(onClose).toHaveBeenCalled());
|
|
454
|
+
});
|
|
455
|
+
it("shows alert when currentRow template does not match imported DTT", async () => {
|
|
456
|
+
const dttForImport = createMockDtt("ImportedTree");
|
|
457
|
+
const currentRow = createMockRow({
|
|
458
|
+
id: 5,
|
|
459
|
+
decay: {
|
|
460
|
+
...mockDecay,
|
|
461
|
+
descriptors: {
|
|
462
|
+
...mockDecay.descriptors,
|
|
463
|
+
template: "COMPLETELY_DIFFERENT_TEMPLATE",
|
|
464
|
+
},
|
|
465
|
+
},
|
|
466
|
+
});
|
|
467
|
+
vi.mocked(utils.parseProductionFiles).mockResolvedValue({
|
|
468
|
+
rows: [createMockRow({ dtt: dttForImport })],
|
|
469
|
+
emails: [],
|
|
470
|
+
});
|
|
471
|
+
const alertMock = vi.spyOn(window, "alert").mockImplementation(() => { });
|
|
472
|
+
const onClose = vi.fn();
|
|
473
|
+
render(_jsx(UploadDttConfigModal, { onClose: onClose, currentRow: currentRow }));
|
|
474
|
+
const input = document.querySelector("input[type='file']");
|
|
475
|
+
fireEvent.change(input, { target: { files: [new File(["x"], "test.yaml")] } });
|
|
476
|
+
fireEvent.click(screen.getByText("Import"));
|
|
477
|
+
await vi.waitFor(() => expect(alertMock).toHaveBeenCalled());
|
|
478
|
+
expect(onClose).not.toHaveBeenCalled();
|
|
479
|
+
alertMock.mockRestore();
|
|
480
|
+
});
|
|
481
|
+
});
|
|
482
|
+
// ---------------------------------------------------------------------------
|
|
483
|
+
// ReasonForRequestModal
|
|
484
|
+
// ---------------------------------------------------------------------------
|
|
485
|
+
describe("ReasonForRequestModal", () => {
|
|
486
|
+
beforeEach(() => {
|
|
487
|
+
mockReasonForRequest = "";
|
|
488
|
+
mockSetReasonForRequest.mockClear();
|
|
489
|
+
mockGenerateAllFiles.mockClear();
|
|
490
|
+
vi.stubGlobal("fetch", vi.fn(() => Promise.resolve({ ok: true })));
|
|
491
|
+
});
|
|
492
|
+
afterEach(() => {
|
|
493
|
+
vi.unstubAllGlobals();
|
|
494
|
+
});
|
|
495
|
+
it("renders the modal title", () => {
|
|
496
|
+
render(_jsx(ReasonForRequestModal, { onClose: vi.fn() }));
|
|
497
|
+
expect(screen.getAllByText("Reason for request").length).toBeGreaterThan(0);
|
|
498
|
+
});
|
|
499
|
+
it("renders the requestReasonMessage", () => {
|
|
500
|
+
render(_jsx(ReasonForRequestModal, { onClose: vi.fn() }));
|
|
501
|
+
expect(screen.getByText("Please state your reason for requesting ntuples.")).toBeInTheDocument();
|
|
502
|
+
});
|
|
503
|
+
it("Submit button is disabled when reasonForRequest is empty", () => {
|
|
504
|
+
mockReasonForRequest = "";
|
|
505
|
+
render(_jsx(ReasonForRequestModal, { onClose: vi.fn() }));
|
|
506
|
+
expect(screen.getByText("Submit request")).toBeDisabled();
|
|
507
|
+
});
|
|
508
|
+
it("Submit button is enabled when reasonForRequest is non-empty", () => {
|
|
509
|
+
mockReasonForRequest = "I need these for my thesis.";
|
|
510
|
+
render(_jsx(ReasonForRequestModal, { onClose: vi.fn() }));
|
|
511
|
+
expect(screen.getByText("Submit request")).not.toBeDisabled();
|
|
512
|
+
});
|
|
513
|
+
it("calls onClose(false) when the modal close button is clicked", () => {
|
|
514
|
+
const onClose = vi.fn();
|
|
515
|
+
render(_jsx(ReasonForRequestModal, { onClose: onClose }));
|
|
516
|
+
fireEvent.click(screen.getByLabelText("Close"));
|
|
517
|
+
expect(onClose).toHaveBeenCalledWith(false);
|
|
518
|
+
});
|
|
519
|
+
it("calls fetch and onClose(true) on successful submit", async () => {
|
|
520
|
+
mockReasonForRequest = "Research purposes";
|
|
521
|
+
const onClose = vi.fn();
|
|
522
|
+
render(_jsx(ReasonForRequestModal, { onClose: onClose }));
|
|
523
|
+
fireEvent.click(screen.getByText("Submit request"));
|
|
524
|
+
await vi.waitFor(() => expect(onClose).toHaveBeenCalledWith(true));
|
|
525
|
+
});
|
|
526
|
+
it("shows error alert on failed fetch (non-ok response)", async () => {
|
|
527
|
+
vi.stubGlobal("fetch", vi.fn(() => Promise.resolve({ ok: false, status: 500 })));
|
|
528
|
+
mockReasonForRequest = "Research purposes";
|
|
529
|
+
render(_jsx(ReasonForRequestModal, { onClose: vi.fn() }));
|
|
530
|
+
fireEvent.click(screen.getByText("Submit request"));
|
|
531
|
+
await vi.waitFor(() => expect(screen.getByText(/something went wrong while submitting/i)).toBeInTheDocument());
|
|
532
|
+
});
|
|
533
|
+
it("shows error alert when fetch rejects", async () => {
|
|
534
|
+
vi.stubGlobal("fetch", vi.fn(() => Promise.reject(new Error("Network error"))));
|
|
535
|
+
mockReasonForRequest = "Research purposes";
|
|
536
|
+
render(_jsx(ReasonForRequestModal, { onClose: vi.fn() }));
|
|
537
|
+
fireEvent.click(screen.getByText("Submit request"));
|
|
538
|
+
await vi.waitFor(() => expect(screen.getByText(/something went wrong while submitting/i)).toBeInTheDocument());
|
|
539
|
+
});
|
|
540
|
+
it("calls generateAllFiles on submit", async () => {
|
|
541
|
+
mockReasonForRequest = "Research purposes";
|
|
542
|
+
render(_jsx(ReasonForRequestModal, { onClose: vi.fn() }));
|
|
543
|
+
fireEvent.click(screen.getByText("Submit request"));
|
|
544
|
+
await vi.waitFor(() => expect(mockGenerateAllFiles).toHaveBeenCalled());
|
|
545
|
+
});
|
|
546
|
+
it("appends file contents from generateAllFiles to the FormData", async () => {
|
|
547
|
+
mockReasonForRequest = "Research purposes";
|
|
548
|
+
mockGenerateAllFiles.mockReturnValueOnce([{ name: "tree.yaml", content: "yaml: content" }]);
|
|
549
|
+
const onClose = vi.fn();
|
|
550
|
+
render(_jsx(ReasonForRequestModal, { onClose: onClose }));
|
|
551
|
+
fireEvent.click(screen.getByText("Submit request"));
|
|
552
|
+
await vi.waitFor(() => expect(onClose).toHaveBeenCalledWith(true));
|
|
553
|
+
});
|
|
554
|
+
});
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export {};
|