lhcb-ntuple-wizard-test 2.1.0 → 2.2.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (178) hide show
  1. package/dist/components/AddTupleToolButton.d.ts +1 -0
  2. package/dist/components/AddTupleToolButton.js +16 -0
  3. package/dist/components/BookkeepingPathDropdown.d.ts +1 -1
  4. package/dist/components/BookkeepingPathDropdown.js +1 -4
  5. package/dist/components/DatasetEventTypeBadge.js +1 -1
  6. package/dist/components/DatasetInfo.js +3 -3
  7. package/dist/components/DecayCard.d.ts +1 -1
  8. package/dist/components/DecayCard.js +12 -40
  9. package/dist/components/DecayLatex.d.ts +1 -1
  10. package/dist/components/DecayLatex.js +4 -87
  11. package/dist/components/DecayListItem.js +2 -2
  12. package/dist/components/DecayTagBadge.d.ts +1 -1
  13. package/dist/components/DecayTagBadge.js +0 -3
  14. package/dist/components/DecayTreeCard.d.ts +1 -7
  15. package/dist/components/DecayTreeCard.js +13 -18
  16. package/dist/components/DecayTreeCardHeader.d.ts +2 -3
  17. package/dist/components/DecayTreeCardHeader.js +2 -2
  18. package/dist/components/DecayTreeGraph.d.ts +1 -4
  19. package/dist/components/DecayTreeGraph.js +66 -41
  20. package/dist/components/DeleteButton.d.ts +2 -1
  21. package/dist/components/DeleteButton.js +2 -2
  22. package/dist/components/DttNameInput.d.ts +9 -0
  23. package/dist/components/DttNameInput.js +43 -0
  24. package/dist/components/GuideLinkButton.d.ts +15 -0
  25. package/dist/components/GuideLinkButton.js +16 -0
  26. package/dist/components/NtupleWizard.js +1 -7
  27. package/dist/components/ParticleDropdown.d.ts +11 -1
  28. package/dist/components/ParticleDropdown.js +3 -6
  29. package/dist/components/ParticleLatex.d.ts +6 -0
  30. package/dist/components/ParticleLatex.js +13 -0
  31. package/dist/components/ParticleTagBadge.d.ts +2 -1
  32. package/dist/components/ParticleTagBadge.js +5 -7
  33. package/dist/components/ParticleTagFilters.d.ts +1 -6
  34. package/dist/components/ParticleTagFilters.js +16 -17
  35. package/dist/components/RequestButtonGroup.d.ts +1 -1
  36. package/dist/components/RequestButtonGroup.js +0 -3
  37. package/dist/components/RequestRow.d.ts +1 -1
  38. package/dist/components/RequestRow.js +4 -9
  39. package/dist/components/StrippingLineDropdown.js +14 -16
  40. package/dist/components/StrippingLineInfo.d.ts +5 -5
  41. package/dist/components/StrippingLineInfo.js +14 -4
  42. package/dist/components/StrippingLineInfoButton.d.ts +6 -0
  43. package/dist/components/StrippingLineInfoButton.js +7 -0
  44. package/dist/components/StrippingLineVersionBadge.d.ts +7 -0
  45. package/dist/components/{StrippingLineBadge.js → StrippingLineVersionBadge.js} +5 -5
  46. package/dist/components/StrippingLinesCountBadge.d.ts +8 -0
  47. package/dist/components/StrippingLinesCountBadge.js +11 -0
  48. package/dist/components/TagDropdown.d.ts +3 -3
  49. package/dist/components/TagDropdown.js +2 -2
  50. package/dist/components/TupleToolClassDropdown.js +11 -14
  51. package/dist/components/TupleToolDocsAccordion.d.ts +1 -1
  52. package/dist/components/TupleToolDocsAccordion.js +4 -8
  53. package/dist/components/TupleToolGroupsAccordion.d.ts +5 -0
  54. package/dist/components/TupleToolGroupsAccordion.js +31 -0
  55. package/dist/components/TupleToolLabel.d.ts +1 -1
  56. package/dist/components/TupleToolLabel.js +2 -5
  57. package/dist/components/TupleToolsAccordion.d.ts +1 -0
  58. package/dist/components/TupleToolsAccordion.js +22 -0
  59. package/dist/components/modals/AddTupleToolModal.js +3 -2
  60. package/dist/components/modals/ConfigureTupleToolModal.js +1 -1
  61. package/dist/components/modals/UploadDttConfigModal.d.ts +1 -1
  62. package/dist/components/modals/UploadDttConfigModal.js +1 -4
  63. package/dist/config.d.ts +1 -0
  64. package/dist/config.js +3 -2
  65. package/dist/models/bkPath.js +1 -1
  66. package/dist/models/dtt.d.ts +5 -2
  67. package/dist/models/dtt.js +37 -18
  68. package/dist/models/rowData.d.ts +1 -1
  69. package/dist/models/yamlFile.js +1 -1
  70. package/dist/pages/DecaySearchPage.js +4 -9
  71. package/dist/pages/DecayTreeConfigPage.js +4 -38
  72. package/dist/pages/RequestPage.js +2 -4
  73. package/dist/providers/DttProvider.d.ts +3 -3
  74. package/dist/providers/DttProvider.js +30 -55
  75. package/dist/providers/MetadataProvider.d.ts +1 -1
  76. package/dist/providers/MetadataProvider.js +11 -5
  77. package/dist/providers/RequestProvider.js +2 -2
  78. package/dist/providers/RowProvider.d.ts +2 -2
  79. package/dist/providers/RowProvider.js +10 -9
  80. package/dist/providers/RowsProvider.js +0 -3
  81. package/dist/tests/components/BookkeepingPathDropdown.test.d.ts +1 -0
  82. package/dist/tests/components/BookkeepingPathDropdown.test.js +118 -0
  83. package/dist/tests/components/DatasetInfo.test.d.ts +1 -0
  84. package/dist/tests/components/DatasetInfo.test.js +38 -0
  85. package/dist/tests/components/DecayCard.test.d.ts +1 -0
  86. package/dist/tests/components/DecayCard.test.js +115 -0
  87. package/dist/tests/components/DecayLatex.test.d.ts +1 -0
  88. package/dist/tests/components/DecayLatex.test.js +31 -0
  89. package/dist/tests/components/DecayList.test.d.ts +1 -0
  90. package/dist/tests/components/DecayList.test.js +76 -0
  91. package/dist/tests/components/DecayListItem.test.d.ts +1 -0
  92. package/dist/tests/components/DecayListItem.test.js +51 -0
  93. package/dist/tests/components/DecayTreeCard.test.d.ts +1 -0
  94. package/dist/tests/components/DecayTreeCard.test.js +119 -0
  95. package/dist/tests/components/DecayTreeGraph.test.d.ts +1 -0
  96. package/dist/tests/components/DecayTreeGraph.test.js +125 -0
  97. package/dist/tests/components/DeleteButton.test.d.ts +1 -0
  98. package/dist/tests/components/DeleteButton.test.js +45 -0
  99. package/dist/tests/components/DttNameInput.test.d.ts +1 -0
  100. package/dist/tests/components/DttNameInput.test.js +75 -0
  101. package/dist/tests/components/NtupleWizard.test.d.ts +1 -0
  102. package/dist/tests/components/NtupleWizard.test.js +57 -0
  103. package/dist/tests/components/ParticleDropdown.test.d.ts +1 -0
  104. package/dist/tests/components/ParticleDropdown.test.js +23 -0
  105. package/dist/tests/components/ParticleTagFilters.test.d.ts +1 -0
  106. package/dist/tests/components/ParticleTagFilters.test.js +87 -0
  107. package/dist/tests/components/RequestButtonGroup.test.d.ts +1 -0
  108. package/dist/tests/components/RequestButtonGroup.test.js +132 -0
  109. package/dist/tests/components/RequestRow.test.d.ts +1 -0
  110. package/dist/tests/components/RequestRow.test.js +58 -0
  111. package/dist/tests/components/StrippingLineDropdown.test.d.ts +1 -0
  112. package/dist/tests/components/StrippingLineDropdown.test.js +88 -0
  113. package/dist/tests/components/badges.test.d.ts +1 -0
  114. package/dist/tests/components/badges.test.js +120 -0
  115. package/dist/tests/components/dropdowns.test.d.ts +1 -0
  116. package/dist/tests/components/dropdowns.test.js +110 -0
  117. package/dist/tests/components/dttComponents.test.d.ts +1 -0
  118. package/dist/tests/components/dttComponents.test.js +287 -0
  119. package/dist/tests/components/formInputs.test.d.ts +1 -0
  120. package/dist/tests/components/formInputs.test.js +96 -0
  121. package/dist/tests/components/metadataComponents.test.d.ts +1 -0
  122. package/dist/tests/components/metadataComponents.test.js +137 -0
  123. package/dist/tests/components/miscComponents.test.d.ts +1 -0
  124. package/dist/tests/components/miscComponents.test.js +134 -0
  125. package/dist/tests/components/modals.test.d.ts +1 -0
  126. package/dist/tests/components/modals.test.js +554 -0
  127. package/dist/tests/components/tupleToolParams.test.d.ts +1 -0
  128. package/dist/tests/components/tupleToolParams.test.js +213 -0
  129. package/dist/tests/config.test.d.ts +1 -0
  130. package/dist/tests/config.test.js +31 -0
  131. package/dist/tests/mockSetup.d.ts +1 -0
  132. package/dist/tests/mockSetup.js +30 -0
  133. package/dist/tests/models/BkPath.test.d.ts +1 -0
  134. package/dist/tests/models/BkPath.test.js +87 -0
  135. package/dist/tests/models/Dtt.test.d.ts +1 -0
  136. package/dist/tests/models/Dtt.test.js +376 -0
  137. package/dist/tests/models/TupleTool.test.d.ts +1 -0
  138. package/dist/tests/models/TupleTool.test.js +80 -0
  139. package/dist/tests/models/YamlFile.test.d.ts +1 -0
  140. package/dist/tests/models/YamlFile.test.js +123 -0
  141. package/dist/tests/pages/DecaySearchPage.test.d.ts +1 -0
  142. package/dist/tests/pages/DecaySearchPage.test.js +228 -0
  143. package/dist/tests/pages/DecayTreeConfigPage.test.d.ts +1 -0
  144. package/dist/tests/pages/DecayTreeConfigPage.test.js +105 -0
  145. package/dist/tests/pages/RequestPage.test.d.ts +1 -0
  146. package/dist/tests/pages/RequestPage.test.js +439 -0
  147. package/dist/tests/providers/DttProvider.test.d.ts +1 -0
  148. package/dist/tests/providers/DttProvider.test.js +105 -0
  149. package/dist/tests/providers/MetadataProvider.test.d.ts +1 -0
  150. package/dist/tests/providers/MetadataProvider.test.js +129 -0
  151. package/dist/tests/providers/RequestProvider.test.d.ts +1 -0
  152. package/dist/tests/providers/RequestProvider.test.js +306 -0
  153. package/dist/tests/providers/RowProvider.test.d.ts +1 -0
  154. package/dist/tests/providers/RowProvider.test.js +110 -0
  155. package/dist/tests/providers/RowsProvider.test.d.ts +1 -0
  156. package/dist/tests/providers/RowsProvider.test.js +84 -0
  157. package/dist/tests/providers/WizardConfigProvider.test.d.ts +1 -0
  158. package/dist/tests/providers/WizardConfigProvider.test.js +36 -0
  159. package/dist/tests/setupTests.d.ts +1 -0
  160. package/dist/tests/setupTests.js +15 -0
  161. package/dist/tests/testUtils.d.ts +33 -0
  162. package/dist/tests/testUtils.js +196 -0
  163. package/dist/tests/utils/latexUtils.test.d.ts +1 -0
  164. package/dist/tests/utils/latexUtils.test.js +62 -0
  165. package/dist/tests/utils/utils.test.d.ts +1 -0
  166. package/dist/tests/utils/utils.test.js +394 -0
  167. package/dist/utils/latexUtils.d.ts +13 -0
  168. package/dist/utils/latexUtils.js +86 -0
  169. package/dist/utils/utils.d.ts +1 -0
  170. package/dist/utils/utils.js +4 -1
  171. package/package.json +16 -7
  172. package/dist/components/NumStrippingLinesBadge.d.ts +0 -8
  173. package/dist/components/NumStrippingLinesBadge.js +0 -10
  174. package/dist/components/StrippingLineBadge.d.ts +0 -7
  175. package/dist/components/TupleToolGroup.d.ts +0 -5
  176. package/dist/components/TupleToolGroup.js +0 -22
  177. package/dist/components/TupleToolList.d.ts +0 -6
  178. package/dist/components/TupleToolList.js +0 -42
@@ -0,0 +1,132 @@
1
+ import { jsx as _jsx } from "react/jsx-runtime";
2
+ import { beforeEach, describe, expect, it, vi } from "vitest";
3
+ import { render, screen } from "@testing-library/react";
4
+ import { fireEvent } from "@testing-library/react";
5
+ import { RequestButtonGroup } from "../../components/RequestButtonGroup";
6
+ import { createMockDtt, createMockRow } from "../testUtils";
7
+ // ---------------------------------------------------------------------------
8
+ // Mocks
9
+ // ---------------------------------------------------------------------------
10
+ const mockNavigate = vi.fn();
11
+ vi.mock("react-router-dom", () => ({
12
+ useNavigate: () => mockNavigate,
13
+ }));
14
+ vi.mock("../../utils/utils", () => ({
15
+ downloadText: vi.fn(),
16
+ sanitizeFilename: vi.fn((s) => s),
17
+ }));
18
+ vi.mock("../../models/yamlFile", () => ({
19
+ YamlFile: {
20
+ createInfoYaml: vi.fn(() => ({ name: "info.yaml", content: "" })),
21
+ },
22
+ }));
23
+ vi.mock("../../components/modals/UploadDttConfigModal", () => ({
24
+ UploadDttConfigModal: ({ onClose }) => (_jsx("div", { "data-testid": "upload-modal", children: _jsx("button", { onClick: onClose, children: "Close" }) })),
25
+ }));
26
+ let mockVariant = "standalone";
27
+ let mockBasePath = "";
28
+ vi.mock("../../providers/WizardConfigProvider", () => ({
29
+ useWizardConfig: () => ({ variant: mockVariant, basePath: mockBasePath }),
30
+ }));
31
+ let mockValidation = { allRowsHaveDtt: true, allRowsHavePaths: true, isEmailValid: true };
32
+ vi.mock("../../providers/RequestProvider", () => ({
33
+ useRequest: () => ({ validation: mockValidation }),
34
+ }));
35
+ const mockSetRows = vi.fn();
36
+ let mockRows = [createMockRow({ dtt: createMockDtt() })];
37
+ let mockConfiguredRows = mockRows;
38
+ vi.mock("../../providers/RowsProvider", () => ({
39
+ useRows: () => ({
40
+ rows: mockRows,
41
+ configuredRows: mockConfiguredRows,
42
+ setRows: mockSetRows,
43
+ }),
44
+ }));
45
+ // ---------------------------------------------------------------------------
46
+ // Tests
47
+ // ---------------------------------------------------------------------------
48
+ describe("RequestButtonGroup — standalone variant", () => {
49
+ beforeEach(() => {
50
+ mockVariant = "standalone";
51
+ mockNavigate.mockClear();
52
+ mockSetRows.mockClear();
53
+ });
54
+ it("renders the Select decays button", () => {
55
+ render(_jsx(RequestButtonGroup, {}));
56
+ expect(screen.getByText(/select decays/i)).toBeInTheDocument();
57
+ });
58
+ it("renders the upload button in standalone mode", () => {
59
+ const { container } = render(_jsx(RequestButtonGroup, {}));
60
+ // Upload button is icon-only; find by aria or just count buttons
61
+ const buttons = container.querySelectorAll("button");
62
+ expect(buttons.length).toBeGreaterThanOrEqual(3); // Select + Upload + Configure + Download
63
+ });
64
+ it("renders the download button in standalone mode", () => {
65
+ const { container } = render(_jsx(RequestButtonGroup, {}));
66
+ const buttons = container.querySelectorAll("button");
67
+ // 4 buttons: Select decays, Upload, Configure, Download
68
+ expect(buttons.length).toBe(4);
69
+ });
70
+ it("navigates to select decays page on Select button click", () => {
71
+ render(_jsx(RequestButtonGroup, {}));
72
+ fireEvent.click(screen.getByText(/select decays/i));
73
+ expect(mockNavigate).toHaveBeenCalledWith("/select-decays");
74
+ });
75
+ it("opens UploadDttConfigModal when upload button is clicked", () => {
76
+ const { container } = render(_jsx(RequestButtonGroup, {}));
77
+ // The upload button is the second button
78
+ const buttons = container.querySelectorAll("button");
79
+ fireEvent.click(buttons[1]);
80
+ expect(screen.getByTestId("upload-modal")).toBeInTheDocument();
81
+ });
82
+ it("closes UploadDttConfigModal when onClose is called", () => {
83
+ const { container } = render(_jsx(RequestButtonGroup, {}));
84
+ const buttons = container.querySelectorAll("button");
85
+ fireEvent.click(buttons[1]);
86
+ expect(screen.getByTestId("upload-modal")).toBeInTheDocument();
87
+ fireEvent.click(screen.getByText("Close"));
88
+ expect(screen.queryByTestId("upload-modal")).not.toBeInTheDocument();
89
+ });
90
+ it("download button is disabled when validation fails", () => {
91
+ mockValidation = { allRowsHaveDtt: false, allRowsHavePaths: false, isEmailValid: false };
92
+ const { container } = render(_jsx(RequestButtonGroup, {}));
93
+ const buttons = container.querySelectorAll("button");
94
+ // Download button is the last one (index 3)
95
+ expect(buttons[3]).toBeDisabled();
96
+ mockValidation = { allRowsHaveDtt: true, allRowsHavePaths: true, isEmailValid: true };
97
+ });
98
+ it("configure button is disabled when not all rows have DTT", () => {
99
+ mockValidation = { allRowsHaveDtt: false, allRowsHavePaths: true, isEmailValid: true };
100
+ const { container } = render(_jsx(RequestButtonGroup, {}));
101
+ const buttons = container.querySelectorAll("button");
102
+ // Configure button is index 2 (after Select and Upload)
103
+ expect(buttons[2]).toBeDisabled();
104
+ mockValidation = { allRowsHaveDtt: true, allRowsHavePaths: true, isEmailValid: true };
105
+ });
106
+ it("clicking Configure all DTTs calls setRows and navigates", async () => {
107
+ // mockValidation has allRowsHaveDtt: true by default
108
+ const { container } = render(_jsx(RequestButtonGroup, {}));
109
+ const buttons = container.querySelectorAll("button");
110
+ // Configure button is index 2 (Select, Upload, Configure, Download)
111
+ fireEvent.click(buttons[2]);
112
+ expect(mockSetRows).toHaveBeenCalled();
113
+ await vi.waitFor(() => expect(mockNavigate).toHaveBeenCalledWith("/variables"));
114
+ });
115
+ });
116
+ describe("RequestButtonGroup — embedded variant", () => {
117
+ beforeEach(() => {
118
+ mockVariant = "embedded";
119
+ mockNavigate.mockClear();
120
+ });
121
+ it("does not render upload button in embedded mode", () => {
122
+ const { container } = render(_jsx(RequestButtonGroup, {}));
123
+ // Only Select decays + Configure (no Upload, no Download)
124
+ const buttons = container.querySelectorAll("button");
125
+ expect(buttons.length).toBe(2);
126
+ });
127
+ it("does not render download button in embedded mode", () => {
128
+ const { container } = render(_jsx(RequestButtonGroup, {}));
129
+ const buttons = container.querySelectorAll("button");
130
+ expect(buttons.length).toBe(2);
131
+ });
132
+ });
@@ -0,0 +1 @@
1
+ export {};
@@ -0,0 +1,58 @@
1
+ import { jsx as _jsx } from "react/jsx-runtime";
2
+ import { describe, expect, it, vi } from "vitest";
3
+ import { render, screen } from "@testing-library/react";
4
+ import { RequestRow } from "../../components/RequestRow";
5
+ import { createMockRow, mockStrippingLine } from "../testUtils";
6
+ const mockRemoveRow = vi.fn();
7
+ vi.mock("../../providers/RowProvider", () => ({
8
+ useRow: () => ({
9
+ row: createMockRow({ line: mockStrippingLine }),
10
+ validateBkPath: vi.fn(() => true),
11
+ updateBkPaths: vi.fn(),
12
+ }),
13
+ }));
14
+ vi.mock("../../providers/RowsProvider", () => ({
15
+ useRows: () => ({
16
+ rows: [],
17
+ configuredRows: [],
18
+ setRows: vi.fn(),
19
+ updateRow: vi.fn(),
20
+ removeRow: mockRemoveRow,
21
+ generateAllFiles: vi.fn(),
22
+ }),
23
+ }));
24
+ // Stub all heavy sub-components
25
+ vi.mock("../../components/DecayCard", () => ({
26
+ DecayCard: () => _jsx("div", { "data-testid": "decay-card" }),
27
+ }));
28
+ vi.mock("../../components/BookkeepingPathDropdown", () => ({
29
+ BookkeepingPathDropdown: () => _jsx("div", { "data-testid": "bk-dropdown" }),
30
+ }));
31
+ vi.mock("../../components/StrippingLineDropdown", () => ({
32
+ StrippingLineDropdown: () => _jsx("div", { "data-testid": "stripping-dropdown" }),
33
+ }));
34
+ vi.mock("../../components/StrippingLineInfoButton", () => ({
35
+ StrippingLineInfoButton: () => _jsx("button", { "data-testid": "info-button" }),
36
+ }));
37
+ vi.mock("../../components/VerticalLine", () => ({ VerticalLine: () => _jsx("div", { "data-testid": "vertical-line" }) }));
38
+ vi.mock("../../components/DeleteButton", () => ({
39
+ DeleteButton: ({ action }) => (_jsx("button", { "data-testid": "delete-button", onClick: action, children: "Delete" })),
40
+ }));
41
+ describe("RequestRow", () => {
42
+ it("renders the DecayCard", () => {
43
+ render(_jsx(RequestRow, {}));
44
+ expect(screen.getByTestId("decay-card")).toBeInTheDocument();
45
+ });
46
+ it("renders the StrippingLineDropdown", () => {
47
+ render(_jsx(RequestRow, {}));
48
+ expect(screen.getByTestId("stripping-dropdown")).toBeInTheDocument();
49
+ });
50
+ it("renders the BookkeepingPathDropdown", () => {
51
+ render(_jsx(RequestRow, {}));
52
+ expect(screen.getByTestId("bk-dropdown")).toBeInTheDocument();
53
+ });
54
+ it("renders the DeleteButton", () => {
55
+ render(_jsx(RequestRow, {}));
56
+ expect(screen.getByTestId("delete-button")).toBeInTheDocument();
57
+ });
58
+ });
@@ -0,0 +1,88 @@
1
+ import { jsx as _jsx } from "react/jsx-runtime";
2
+ import { describe, expect, it, vi } from "vitest";
3
+ import { render } from "@testing-library/react";
4
+ import { StrippingLineDropdown } from "../../components/StrippingLineDropdown";
5
+ import { createMockDtt, createMockRow, mockDecay, mockStrippingLine } from "../testUtils";
6
+ const mockUpdateBkPaths = vi.fn();
7
+ const mockUpdateRow = vi.fn();
8
+ vi.mock("../../providers/RowProvider", () => ({
9
+ useRow: () => ({
10
+ row: { id: 0, decay: mockDecay, dtt: null, line: mockStrippingLine, paths: [], pathOptions: [] },
11
+ validateBkPath: vi.fn(() => true),
12
+ updateBkPaths: mockUpdateBkPaths,
13
+ }),
14
+ }));
15
+ vi.mock("../../providers/RowsProvider", () => ({
16
+ useRows: () => ({
17
+ rows: [],
18
+ configuredRows: [],
19
+ setRows: vi.fn(),
20
+ updateRow: mockUpdateRow,
21
+ removeRow: vi.fn(),
22
+ generateAllFiles: vi.fn(),
23
+ }),
24
+ }));
25
+ vi.mock("../../components/StrippingLineInfo", () => ({
26
+ StrippingLineInfo: () => _jsx("span", { "data-testid": "stripping-line-info" }),
27
+ }));
28
+ let capturedOnChange = null;
29
+ vi.mock("react-select", () => ({
30
+ default: ({ onChange, placeholder }) => {
31
+ capturedOnChange = onChange;
32
+ return (_jsx("div", { className: "react-select", children: _jsx("div", { className: "control", children: _jsx("input", { role: "combobox", placeholder: placeholder }) }) }));
33
+ },
34
+ }));
35
+ describe("StrippingLineDropdown — handleStrippingLineChanged", () => {
36
+ it("calls updateBkPaths when a stripping line is selected", () => {
37
+ mockUpdateBkPaths.mockClear();
38
+ render(_jsx(StrippingLineDropdown, {}));
39
+ capturedOnChange({
40
+ group: "Leptonic",
41
+ value: "StrippingBuToKJpsiee2Line",
42
+ label: null,
43
+ });
44
+ expect(mockUpdateBkPaths).toHaveBeenCalled();
45
+ });
46
+ it("calls updateRow when a stripping line is selected", () => {
47
+ mockUpdateRow.mockClear();
48
+ render(_jsx(StrippingLineDropdown, {}));
49
+ capturedOnChange({
50
+ group: "Leptonic",
51
+ value: "StrippingBuToKJpsiee2Line",
52
+ label: null,
53
+ });
54
+ expect(mockUpdateRow).toHaveBeenCalled();
55
+ });
56
+ it("passes the correct line object to updateRow", () => {
57
+ mockUpdateRow.mockClear();
58
+ render(_jsx(StrippingLineDropdown, {}));
59
+ capturedOnChange({
60
+ group: "Leptonic",
61
+ value: "StrippingBuToKJpsiee2Line",
62
+ label: null,
63
+ });
64
+ // Verify the updater function builds the correct line
65
+ const updater = mockUpdateRow.mock.calls[0][1];
66
+ const result = updater(createMockRow({ line: null }));
67
+ expect(result.line).toEqual({
68
+ stream: "Leptonic",
69
+ line: "StrippingBuToKJpsiee2Line",
70
+ versions: ["28r2"],
71
+ });
72
+ });
73
+ it("updates dtt input when row already has a dtt", () => {
74
+ mockUpdateRow.mockClear();
75
+ render(_jsx(StrippingLineDropdown, {}));
76
+ capturedOnChange({
77
+ group: "Leptonic",
78
+ value: "StrippingBuToKJpsiee2Line",
79
+ label: null,
80
+ });
81
+ const updater = mockUpdateRow.mock.calls[0][1];
82
+ const mockDtt = createMockDtt("MyTree");
83
+ const result = updater(createMockRow({ line: null, dtt: mockDtt }));
84
+ // dtt.withInputFromLine should have been called, updating the input
85
+ expect(result.dtt).not.toBeNull();
86
+ expect(result.dtt?.config.input).toContain("Leptonic");
87
+ });
88
+ });
@@ -0,0 +1 @@
1
+ export {};
@@ -0,0 +1,120 @@
1
+ import { jsx as _jsx } from "react/jsx-runtime";
2
+ import { describe, expect, it, vi } from "vitest";
3
+ // Restore the real module — the global mock in mockSetup.tsx is overridden here
4
+ vi.mock("../../components/LoadingIndicator", async (importOriginal) => await importOriginal());
5
+ import { render, screen } from "@testing-library/react";
6
+ import { YearBadge } from "../../components/YearBadge";
7
+ import { PolarityBadge } from "../../components/PolarityBadge";
8
+ import { DatasetEventTypeBadge } from "../../components/DatasetEventTypeBadge";
9
+ import { VerticalLine } from "../../components/VerticalLine";
10
+ import { LoadingIndicator } from "../../components/LoadingIndicator";
11
+ // ---------------------------------------------------------------------------
12
+ // YearBadge
13
+ // ---------------------------------------------------------------------------
14
+ describe("YearBadge", () => {
15
+ it("renders the year text", () => {
16
+ render(_jsx(YearBadge, { year: "2016" }));
17
+ expect(screen.getByText("2016")).toBeInTheDocument();
18
+ });
19
+ it("applies the success background variant", () => {
20
+ render(_jsx(YearBadge, { year: "2018" }));
21
+ expect(screen.getByText("2018")).toHaveClass("bg-success");
22
+ });
23
+ });
24
+ // ---------------------------------------------------------------------------
25
+ // PolarityBadge
26
+ // ---------------------------------------------------------------------------
27
+ describe("PolarityBadge", () => {
28
+ it("renders MagDown polarity", () => {
29
+ render(_jsx(PolarityBadge, { polarity: "MagDown" }));
30
+ expect(screen.getByText("MagDown")).toBeInTheDocument();
31
+ });
32
+ it("renders MagUp polarity", () => {
33
+ render(_jsx(PolarityBadge, { polarity: "MagUp" }));
34
+ expect(screen.getByText("MagUp")).toBeInTheDocument();
35
+ });
36
+ it("applies the danger background variant", () => {
37
+ render(_jsx(PolarityBadge, { polarity: "MagDown" }));
38
+ expect(screen.getByText("MagDown")).toHaveClass("bg-danger");
39
+ });
40
+ });
41
+ // ---------------------------------------------------------------------------
42
+ // DatasetEventTypeBadge
43
+ // ---------------------------------------------------------------------------
44
+ describe("DatasetEventTypeBadge", () => {
45
+ it("renders 'Data' for the special event type 90000000", () => {
46
+ render(_jsx(DatasetEventTypeBadge, { eventType: "90000000" }));
47
+ expect(screen.getByText("Data")).toBeInTheDocument();
48
+ });
49
+ it("renders the raw event type code for MC event types", () => {
50
+ render(_jsx(DatasetEventTypeBadge, { eventType: "23103101" }));
51
+ expect(screen.getByText("23103101")).toBeInTheDocument();
52
+ });
53
+ it("Data badge has no link", () => {
54
+ const { container } = render(_jsx(DatasetEventTypeBadge, { eventType: "90000000" }));
55
+ // The badge renders as a span, not an anchor
56
+ expect(container.querySelector("a")).toBeNull();
57
+ });
58
+ it("MC event type badge links to decfiles documentation", () => {
59
+ const { container } = render(_jsx(DatasetEventTypeBadge, { eventType: "23103101" }));
60
+ const link = container.querySelector("a");
61
+ expect(link).not.toBeNull();
62
+ expect(link?.href).toContain("lhcbdoc");
63
+ });
64
+ it("applies the primary background variant", () => {
65
+ render(_jsx(DatasetEventTypeBadge, { eventType: "90000000" }));
66
+ expect(screen.getByText("Data")).toHaveClass("bg-primary");
67
+ });
68
+ });
69
+ // ---------------------------------------------------------------------------
70
+ // VerticalLine
71
+ // ---------------------------------------------------------------------------
72
+ describe("VerticalLine", () => {
73
+ it("renders a div element", () => {
74
+ const { container } = render(_jsx(VerticalLine, {}));
75
+ expect(container.querySelector("div")).toBeInTheDocument();
76
+ });
77
+ it("applies default border-left style", () => {
78
+ const { container } = render(_jsx(VerticalLine, {}));
79
+ const div = container.querySelector("div");
80
+ expect(div.style.borderLeft).toContain("solid");
81
+ });
82
+ it("uses custom width when provided", () => {
83
+ const { container } = render(_jsx(VerticalLine, { width: "3px" }));
84
+ expect(container.querySelector("div").style.borderLeft).toContain("3px");
85
+ });
86
+ it("uses custom color when provided", () => {
87
+ const { container } = render(_jsx(VerticalLine, { color: "red" }));
88
+ expect(container.querySelector("div").style.borderLeft).toContain("red");
89
+ });
90
+ it("applies height style", () => {
91
+ const { container } = render(_jsx(VerticalLine, { height: "50px" }));
92
+ expect(container.querySelector("div").style.height).toBe("50px");
93
+ });
94
+ });
95
+ // ---------------------------------------------------------------------------
96
+ // LoadingIndicator
97
+ // ---------------------------------------------------------------------------
98
+ describe("LoadingIndicator", () => {
99
+ it("renders the spinner", () => {
100
+ render(_jsx(LoadingIndicator, {}));
101
+ expect(screen.getByTestId("loading-spinner")).toBeInTheDocument();
102
+ });
103
+ it("displays the message when provided", () => {
104
+ render(_jsx(LoadingIndicator, { message: "Loading metadata..." }));
105
+ expect(screen.getByText("Loading metadata...")).toBeInTheDocument();
106
+ });
107
+ it("does not render message paragraph when no message is provided", () => {
108
+ render(_jsx(LoadingIndicator, {}));
109
+ expect(screen.queryByRole("paragraph")).not.toBeInTheDocument();
110
+ });
111
+ it("applies height style when provided", () => {
112
+ const { container } = render(_jsx(LoadingIndicator, { height: "200px" }));
113
+ const wrapper = container.firstElementChild;
114
+ expect(wrapper.style.height).toBe("200px");
115
+ });
116
+ it("renders spinner with status role", () => {
117
+ render(_jsx(LoadingIndicator, {}));
118
+ expect(screen.getByRole("status")).toBeInTheDocument();
119
+ });
120
+ });
@@ -0,0 +1 @@
1
+ export {};
@@ -0,0 +1,110 @@
1
+ import { Fragment as _Fragment, jsx as _jsx } from "react/jsx-runtime";
2
+ import { describe, expect, it, vi } from "vitest";
3
+ import { render, screen } from "@testing-library/react";
4
+ import { TagDropdown, getSelectTagOptions } from "../../components/TagDropdown";
5
+ import { TupleToolClassDropdown } from "../../components/TupleToolClassDropdown";
6
+ import { StrippingLineDropdown } from "../../components/StrippingLineDropdown";
7
+ import { mockDecay, mockStrippingLine } from "../testUtils";
8
+ // ---------------------------------------------------------------------------
9
+ // Mocks
10
+ // ---------------------------------------------------------------------------
11
+ let mockSelectedBranch = [];
12
+ vi.mock("../../providers/DttProvider", () => ({
13
+ useDtt: () => ({
14
+ selectedBranch: mockSelectedBranch,
15
+ }),
16
+ }));
17
+ vi.mock("../../config", () => ({
18
+ config: { disabledTupleTools: [] },
19
+ }));
20
+ const mockUpdateBkPaths = vi.fn();
21
+ const mockUpdateRow = vi.fn();
22
+ vi.mock("../../providers/RowProvider", () => ({
23
+ useRow: () => ({
24
+ row: { ...{ id: 0, decay: mockDecay, dtt: null, line: mockStrippingLine, paths: [], pathOptions: [] } },
25
+ validateBkPath: vi.fn(() => true),
26
+ updateBkPaths: mockUpdateBkPaths,
27
+ }),
28
+ }));
29
+ vi.mock("../../providers/RowsProvider", () => ({
30
+ useRows: () => ({
31
+ rows: [],
32
+ configuredRows: [],
33
+ setRows: vi.fn(),
34
+ updateRow: mockUpdateRow,
35
+ removeRow: vi.fn(),
36
+ generateAllFiles: vi.fn(),
37
+ }),
38
+ }));
39
+ // ---------------------------------------------------------------------------
40
+ // getSelectTagOptions (pure function)
41
+ // ---------------------------------------------------------------------------
42
+ describe("getSelectTagOptions()", () => {
43
+ it("returns one option per tag", () => {
44
+ const tags = {
45
+ B2OC: { description: "B to OC", hide: false, warn: false },
46
+ SLOW: { description: "Slow", hide: false, warn: true },
47
+ };
48
+ const options = getSelectTagOptions(tags);
49
+ expect(options).toHaveLength(2);
50
+ });
51
+ it("filters tags based on the filter function", () => {
52
+ const tags = {
53
+ B2OC: { description: "B to OC", hide: false, warn: false },
54
+ SLOW: { description: "Slow", hide: false, warn: true },
55
+ };
56
+ const options = getSelectTagOptions(tags, (tag) => tag.warn);
57
+ expect(options).toHaveLength(1);
58
+ expect(options[0].value).toBe("SLOW");
59
+ });
60
+ it("maps keys to option values", () => {
61
+ const tags = {
62
+ B2OC: { description: "B to OC", hide: false, warn: false },
63
+ };
64
+ const options = getSelectTagOptions(tags);
65
+ expect(options[0].value).toBe("B2OC");
66
+ });
67
+ it("renders the option label JSX with the tag key as visible text", () => {
68
+ const tags = { B2OC: { description: "B to open charm", hide: false, warn: false } };
69
+ const options = getSelectTagOptions(tags);
70
+ render(_jsx(_Fragment, { children: options[0].label }));
71
+ expect(screen.getByText("B2OC")).toBeInTheDocument();
72
+ });
73
+ });
74
+ // ---------------------------------------------------------------------------
75
+ // TagDropdown
76
+ // ---------------------------------------------------------------------------
77
+ describe("TagDropdown", () => {
78
+ it("renders a select element for decayTags", () => {
79
+ const { container } = render(_jsx(TagDropdown, { type: "decayTags" }));
80
+ // react-select renders its input element
81
+ expect(container.querySelector(".react-select")).toBeInTheDocument();
82
+ });
83
+ it("renders a select element for particleTags", () => {
84
+ const { container } = render(_jsx(TagDropdown, { type: "particleTags" }));
85
+ expect(container.querySelector(".react-select")).toBeInTheDocument();
86
+ });
87
+ });
88
+ // ---------------------------------------------------------------------------
89
+ // TupleToolClassDropdown
90
+ // ---------------------------------------------------------------------------
91
+ describe("TupleToolClassDropdown", () => {
92
+ it("renders a select with placeholder", () => {
93
+ const { container } = render(_jsx(TupleToolClassDropdown, {}));
94
+ expect(container.querySelector(".react-select")).toBeInTheDocument();
95
+ });
96
+ });
97
+ // ---------------------------------------------------------------------------
98
+ // StrippingLineDropdown
99
+ // ---------------------------------------------------------------------------
100
+ describe("StrippingLineDropdown", () => {
101
+ it("renders a select element", () => {
102
+ const { container } = render(_jsx(StrippingLineDropdown, {}));
103
+ // react-select renders a div with class 'react-select__container' or similar
104
+ expect(container.querySelector("[class*='control']")).toBeInTheDocument();
105
+ });
106
+ it("renders a combobox input for keyboard access", () => {
107
+ render(_jsx(StrippingLineDropdown, {}));
108
+ expect(screen.getByRole("combobox")).toBeInTheDocument();
109
+ });
110
+ });
@@ -0,0 +1 @@
1
+ export {};