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.
- 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 +16 -7
- 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,119 @@
|
|
|
1
|
+
import { jsx as _jsx } from "react/jsx-runtime";
|
|
2
|
+
import { describe, expect, it, vi, beforeEach } from "vitest";
|
|
3
|
+
import { fireEvent, render, screen } from "@testing-library/react";
|
|
4
|
+
import { DecayTreeCard } from "../../components/DecayTreeCard";
|
|
5
|
+
import { mockDecay } from "../testUtils";
|
|
6
|
+
// Mutable state — read at render time by the useDtt factory closure
|
|
7
|
+
let mockSelectedBranch = [];
|
|
8
|
+
let mockHoveredBranch = [];
|
|
9
|
+
let mockDttDecay = mockDecay;
|
|
10
|
+
const mockSetSelectedBranch = vi.fn();
|
|
11
|
+
vi.mock("../../providers/DttProvider", () => ({
|
|
12
|
+
useDtt: () => ({
|
|
13
|
+
dtt: { getName: () => "MyTree", config: { input: "/Leptonic/StrippingBuToKJpsiee2Line" } },
|
|
14
|
+
decay: mockDttDecay,
|
|
15
|
+
selectedBranch: mockSelectedBranch,
|
|
16
|
+
setSelectedBranch: mockSetSelectedBranch,
|
|
17
|
+
hoveredBranch: mockHoveredBranch,
|
|
18
|
+
highlightedBranch: mockHoveredBranch.length > 0 ? mockHoveredBranch : mockSelectedBranch,
|
|
19
|
+
setHoveredBranch: vi.fn(),
|
|
20
|
+
updateToolParam: vi.fn(),
|
|
21
|
+
addTool: vi.fn(),
|
|
22
|
+
removeTool: vi.fn(),
|
|
23
|
+
}),
|
|
24
|
+
}));
|
|
25
|
+
vi.mock("../../components/DecayTagBadge", () => ({
|
|
26
|
+
DecayTagBadge: ({ tag }) => _jsx("span", { "data-testid": `tag-badge-${tag}`, children: tag }),
|
|
27
|
+
}));
|
|
28
|
+
vi.mock("../../components/DecayLatex", () => ({
|
|
29
|
+
DecayLatex: ({ selection }) => (_jsx("span", { "data-testid": "decay-latex", "data-selection": selection.join(",") })),
|
|
30
|
+
}));
|
|
31
|
+
vi.mock("../../components/DecayTreeGraph", () => ({
|
|
32
|
+
DecayTreeGraph: () => _jsx("div", { "data-testid": "decay-tree-graph" }),
|
|
33
|
+
}));
|
|
34
|
+
vi.mock("../../components/DecayTreeCardHeader", () => ({
|
|
35
|
+
DecayTreeCardHeader: ({ dttName }) => _jsx("div", { "data-testid": "decay-tree-card-header", children: dttName }),
|
|
36
|
+
}));
|
|
37
|
+
vi.mock("../../components/ParticleTagFilters", () => ({
|
|
38
|
+
ParticleTagFilters: () => _jsx("div", { "data-testid": "particle-tag-filters" }),
|
|
39
|
+
}));
|
|
40
|
+
vi.mock("../../components/TupleToolsAccordion", () => ({
|
|
41
|
+
TupleToolsAccordion: () => _jsx("div", { "data-testid": "tuple-tools-accordion" }),
|
|
42
|
+
}));
|
|
43
|
+
vi.mock("../../components/TupleToolGroupsAccordion", () => ({
|
|
44
|
+
TupleToolGroupsAccordion: () => _jsx("div", { "data-testid": "tuple-tool-groups-accordion" }),
|
|
45
|
+
}));
|
|
46
|
+
beforeEach(() => {
|
|
47
|
+
mockSelectedBranch = [];
|
|
48
|
+
mockHoveredBranch = [];
|
|
49
|
+
mockDttDecay = mockDecay;
|
|
50
|
+
mockSetSelectedBranch.mockClear();
|
|
51
|
+
});
|
|
52
|
+
describe("DecayTreeCard — particle selection count", () => {
|
|
53
|
+
it("shows '0 particles selected' (plural) when nothing is selected", () => {
|
|
54
|
+
render(_jsx(DecayTreeCard, {}));
|
|
55
|
+
expect(screen.getByText(/0 particles selected/i)).toBeInTheDocument();
|
|
56
|
+
});
|
|
57
|
+
it("shows '1 particle selected' (singular) when one branch is selected", () => {
|
|
58
|
+
mockSelectedBranch = ["head"];
|
|
59
|
+
render(_jsx(DecayTreeCard, {}));
|
|
60
|
+
expect(screen.getByText(/1 particle selected/i)).toBeInTheDocument();
|
|
61
|
+
});
|
|
62
|
+
it("shows '2 particles selected' (plural) when two branches are selected", () => {
|
|
63
|
+
mockSelectedBranch = ["head", "k"];
|
|
64
|
+
render(_jsx(DecayTreeCard, {}));
|
|
65
|
+
expect(screen.getByText(/2 particles selected/i)).toBeInTheDocument();
|
|
66
|
+
});
|
|
67
|
+
});
|
|
68
|
+
describe("DecayTreeCard — Deselect button", () => {
|
|
69
|
+
it("is disabled when nothing is selected", () => {
|
|
70
|
+
render(_jsx(DecayTreeCard, {}));
|
|
71
|
+
const btn = screen.getByRole("button", { name: /deselect/i });
|
|
72
|
+
expect(btn).toBeDisabled();
|
|
73
|
+
});
|
|
74
|
+
it("is enabled when a branch is selected", () => {
|
|
75
|
+
mockSelectedBranch = ["head"];
|
|
76
|
+
render(_jsx(DecayTreeCard, {}));
|
|
77
|
+
const btn = screen.getByRole("button", { name: /deselect/i });
|
|
78
|
+
expect(btn).not.toBeDisabled();
|
|
79
|
+
});
|
|
80
|
+
it("calls setSelectedBranch([]) when the Deselect button is clicked", () => {
|
|
81
|
+
mockSelectedBranch = ["head"];
|
|
82
|
+
render(_jsx(DecayTreeCard, {}));
|
|
83
|
+
fireEvent.click(screen.getByRole("button", { name: /deselect/i }));
|
|
84
|
+
expect(mockSetSelectedBranch).toHaveBeenCalledWith([]);
|
|
85
|
+
});
|
|
86
|
+
});
|
|
87
|
+
describe("DecayTreeCard — DecayLatex selection prop", () => {
|
|
88
|
+
it("passes hoveredBranch as selection when nothing is selected", () => {
|
|
89
|
+
mockHoveredBranch = ["k"];
|
|
90
|
+
render(_jsx(DecayTreeCard, {}));
|
|
91
|
+
const el = screen.getByTestId("decay-latex");
|
|
92
|
+
expect(el.dataset.selection).toBe("k");
|
|
93
|
+
});
|
|
94
|
+
it("passes selectedBranch as selection when a branch is selected", () => {
|
|
95
|
+
mockSelectedBranch = ["head"];
|
|
96
|
+
mockHoveredBranch = ["k"];
|
|
97
|
+
render(_jsx(DecayTreeCard, {}));
|
|
98
|
+
const el = screen.getByTestId("decay-latex");
|
|
99
|
+
expect(el.dataset.selection).toBe("head");
|
|
100
|
+
});
|
|
101
|
+
});
|
|
102
|
+
describe("DecayTreeCard — decay tag badges", () => {
|
|
103
|
+
it("renders a DecayTagBadge for tags with warn=true", () => {
|
|
104
|
+
// mockMetadata.userHints.decayTags has SLOW with warn=true
|
|
105
|
+
mockDttDecay = { ...mockDecay, tags: ["SLOW"] };
|
|
106
|
+
render(_jsx(DecayTreeCard, {}));
|
|
107
|
+
expect(screen.getByTestId("tag-badge-SLOW")).toBeInTheDocument();
|
|
108
|
+
});
|
|
109
|
+
it("does not render a DecayTagBadge for tags with warn=false", () => {
|
|
110
|
+
// B2OC has warn=false in mockMetadata
|
|
111
|
+
mockDttDecay = { ...mockDecay, tags: ["B2OC"] };
|
|
112
|
+
render(_jsx(DecayTreeCard, {}));
|
|
113
|
+
expect(screen.queryByTestId("tag-badge-B2OC")).not.toBeInTheDocument();
|
|
114
|
+
});
|
|
115
|
+
it("does not render any badges when decay has no tags", () => {
|
|
116
|
+
render(_jsx(DecayTreeCard, {}));
|
|
117
|
+
expect(screen.queryByTestId(/tag-badge/)).not.toBeInTheDocument();
|
|
118
|
+
});
|
|
119
|
+
});
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export {};
|
|
@@ -0,0 +1,125 @@
|
|
|
1
|
+
import { jsx as _jsx } from "react/jsx-runtime";
|
|
2
|
+
import { describe, expect, it, vi, beforeEach } from "vitest";
|
|
3
|
+
import { render } from "@testing-library/react";
|
|
4
|
+
import { DecayTreeGraph } from "../../components/DecayTreeGraph";
|
|
5
|
+
import { mockDecay } from "../testUtils";
|
|
6
|
+
import { LATEX_SELECTED_COLOR } from "../../utils/latexUtils";
|
|
7
|
+
// Mutable state — read at render time by the useDtt factory closure
|
|
8
|
+
let mockSelectedBranch = [];
|
|
9
|
+
let mockHighlightedBranch = [];
|
|
10
|
+
let capturedElements = [];
|
|
11
|
+
// Stub dtt — vi.fn() methods let individual tests override return values
|
|
12
|
+
const mockDttGraph = {
|
|
13
|
+
getBranchTools: vi.fn(() => []),
|
|
14
|
+
getGroupsThatIncludeBranch: vi.fn(() => []),
|
|
15
|
+
};
|
|
16
|
+
vi.mock("../../providers/DttProvider", () => ({
|
|
17
|
+
useDtt: () => ({
|
|
18
|
+
dtt: mockDttGraph,
|
|
19
|
+
decay: mockDecay,
|
|
20
|
+
selectedBranch: mockSelectedBranch,
|
|
21
|
+
highlightedBranch: mockHighlightedBranch,
|
|
22
|
+
setSelectedBranch: vi.fn(),
|
|
23
|
+
hoveredBranch: [],
|
|
24
|
+
setHoveredBranch: vi.fn(),
|
|
25
|
+
updateToolParam: vi.fn(),
|
|
26
|
+
addTool: vi.fn(),
|
|
27
|
+
removeTool: vi.fn(),
|
|
28
|
+
}),
|
|
29
|
+
}));
|
|
30
|
+
vi.mock("react-cytoscapejs", () => ({
|
|
31
|
+
default: ({ elements }) => {
|
|
32
|
+
capturedElements = elements;
|
|
33
|
+
return _jsx("div", { "data-testid": "cytoscape" });
|
|
34
|
+
},
|
|
35
|
+
}));
|
|
36
|
+
// Prevent cytoscape.use(dagre) at module-top from throwing
|
|
37
|
+
vi.mock("cytoscape", () => ({
|
|
38
|
+
default: Object.assign(vi.fn(), { use: vi.fn() }),
|
|
39
|
+
}));
|
|
40
|
+
vi.mock("cytoscape-dagre", () => ({ default: {} }));
|
|
41
|
+
// tex2svg is used to generate SVG labels for graph nodes; include "currentColor" so color
|
|
42
|
+
// substitution in makeSVG is visible in the imageSrc output
|
|
43
|
+
vi.mock("../../utils/mathjaxUtils", () => ({
|
|
44
|
+
tex2svg: () => ({ innerHTML: "<text fill='currentColor'>x</text>" }),
|
|
45
|
+
}));
|
|
46
|
+
beforeEach(() => {
|
|
47
|
+
mockSelectedBranch = [];
|
|
48
|
+
mockHighlightedBranch = [];
|
|
49
|
+
capturedElements = [];
|
|
50
|
+
mockDttGraph.getBranchTools.mockReturnValue([]);
|
|
51
|
+
mockDttGraph.getGroupsThatIncludeBranch.mockReturnValue([]);
|
|
52
|
+
});
|
|
53
|
+
describe("DecayTreeGraph — rendering", () => {
|
|
54
|
+
it("renders the cytoscape component", () => {
|
|
55
|
+
const { getByTestId } = render(_jsx(DecayTreeGraph, { onNodeSelectionChanged: vi.fn() }));
|
|
56
|
+
expect(getByTestId("cytoscape")).toBeInTheDocument();
|
|
57
|
+
});
|
|
58
|
+
});
|
|
59
|
+
describe("DecayTreeGraph — buildElements", () => {
|
|
60
|
+
it("creates one node per particle in the decay", () => {
|
|
61
|
+
// mockDecay has B+, K+, mu+, mu- → 4 nodes
|
|
62
|
+
render(_jsx(DecayTreeGraph, { onNodeSelectionChanged: vi.fn() }));
|
|
63
|
+
const nodes = capturedElements.filter((e) => !e.data.source);
|
|
64
|
+
expect(nodes).toHaveLength(4);
|
|
65
|
+
});
|
|
66
|
+
it("creates one edge per parent-child relationship", () => {
|
|
67
|
+
// B+ → K+, mu+, mu- gives 3 edges
|
|
68
|
+
render(_jsx(DecayTreeGraph, { onNodeSelectionChanged: vi.fn() }));
|
|
69
|
+
const edges = capturedElements.filter((e) => e.data.source);
|
|
70
|
+
expect(edges).toHaveLength(3);
|
|
71
|
+
});
|
|
72
|
+
it("assigns the correct node ids from branch names", () => {
|
|
73
|
+
render(_jsx(DecayTreeGraph, { onNodeSelectionChanged: vi.fn() }));
|
|
74
|
+
const nodeIds = capturedElements.filter((e) => !e.data.source).map((e) => e.data.id);
|
|
75
|
+
expect(nodeIds).toEqual(expect.arrayContaining(["head", "k", "mup", "mum"]));
|
|
76
|
+
});
|
|
77
|
+
it("creates edges from head to each daughter", () => {
|
|
78
|
+
render(_jsx(DecayTreeGraph, { onNodeSelectionChanged: vi.fn() }));
|
|
79
|
+
const edges = capturedElements.filter((e) => e.data.source);
|
|
80
|
+
const edgePairs = edges.map((e) => `${e.data.source}->${e.data.target}`);
|
|
81
|
+
expect(edgePairs).toEqual(expect.arrayContaining(["head->k", "head->mup", "head->mum"]));
|
|
82
|
+
});
|
|
83
|
+
it("marks selected nodes with selected=true", () => {
|
|
84
|
+
mockSelectedBranch = ["head"];
|
|
85
|
+
render(_jsx(DecayTreeGraph, { onNodeSelectionChanged: vi.fn() }));
|
|
86
|
+
const headNode = capturedElements.find((e) => e.data.id === "head");
|
|
87
|
+
expect(headNode?.selected).toBe(true);
|
|
88
|
+
});
|
|
89
|
+
it("marks non-selected nodes with selected=false", () => {
|
|
90
|
+
mockSelectedBranch = ["head"];
|
|
91
|
+
render(_jsx(DecayTreeGraph, { onNodeSelectionChanged: vi.fn() }));
|
|
92
|
+
const kNode = capturedElements.find((e) => e.data.id === "k");
|
|
93
|
+
expect(kNode?.selected).toBe(false);
|
|
94
|
+
});
|
|
95
|
+
it("uses LATEX_SELECTED_COLOR in imageSrc for highlighted branches", () => {
|
|
96
|
+
mockHighlightedBranch = ["head"];
|
|
97
|
+
render(_jsx(DecayTreeGraph, { onNodeSelectionChanged: vi.fn() }));
|
|
98
|
+
const headNode = capturedElements.find((e) => e.data.id === "head");
|
|
99
|
+
expect(headNode?.data.imageSrc).toContain(encodeURIComponent(LATEX_SELECTED_COLOR));
|
|
100
|
+
});
|
|
101
|
+
it("uses black color in imageSrc for non-highlighted branches", () => {
|
|
102
|
+
mockHighlightedBranch = ["head"];
|
|
103
|
+
render(_jsx(DecayTreeGraph, { onNodeSelectionChanged: vi.fn() }));
|
|
104
|
+
const kNode = capturedElements.find((e) => e.data.id === "k");
|
|
105
|
+
expect(kNode?.data.imageSrc).toContain(encodeURIComponent("black"));
|
|
106
|
+
});
|
|
107
|
+
it("shows grey tupleToolStatusColor when the branch has no tools", () => {
|
|
108
|
+
render(_jsx(DecayTreeGraph, { onNodeSelectionChanged: vi.fn() }));
|
|
109
|
+
const headNode = capturedElements.find((e) => e.data.id === "head");
|
|
110
|
+
expect(headNode?.data.tupleToolStatusColor).toBe("#6c757d");
|
|
111
|
+
});
|
|
112
|
+
it("shows green tupleToolStatusColor when the branch has tools", () => {
|
|
113
|
+
// Override getBranchTools to return a non-empty array for this test
|
|
114
|
+
mockDttGraph.getBranchTools.mockReturnValue([{}]);
|
|
115
|
+
render(_jsx(DecayTreeGraph, { onNodeSelectionChanged: vi.fn() }));
|
|
116
|
+
const headNode = capturedElements.find((e) => e.data.id === "head");
|
|
117
|
+
expect(headNode?.data.tupleToolStatusColor).toBe("#198754");
|
|
118
|
+
});
|
|
119
|
+
it("shows green tupleToolStatusColor when the branch belongs to a group with tools", () => {
|
|
120
|
+
mockDttGraph.getGroupsThatIncludeBranch.mockReturnValue([{}]);
|
|
121
|
+
render(_jsx(DecayTreeGraph, { onNodeSelectionChanged: vi.fn() }));
|
|
122
|
+
const headNode = capturedElements.find((e) => e.data.id === "head");
|
|
123
|
+
expect(headNode?.data.tupleToolStatusColor).toBe("#198754");
|
|
124
|
+
});
|
|
125
|
+
});
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export {};
|
|
@@ -0,0 +1,45 @@
|
|
|
1
|
+
import { jsx as _jsx } from "react/jsx-runtime";
|
|
2
|
+
import { describe, expect, it, vi } from "vitest";
|
|
3
|
+
import { fireEvent, render, screen } from "@testing-library/react";
|
|
4
|
+
import { DeleteButton } from "../../components/DeleteButton";
|
|
5
|
+
describe("DeleteButton", () => {
|
|
6
|
+
it("renders the trash icon button", () => {
|
|
7
|
+
render(_jsx(DeleteButton, { action: vi.fn() }));
|
|
8
|
+
expect(screen.getByRole("button")).toBeInTheDocument();
|
|
9
|
+
});
|
|
10
|
+
it("renders null when disabled", () => {
|
|
11
|
+
const { container } = render(_jsx(DeleteButton, { action: vi.fn(), disabled: true }));
|
|
12
|
+
expect(container).toBeEmptyDOMElement();
|
|
13
|
+
});
|
|
14
|
+
it("shows the popover with the default confirm message when clicked", async () => {
|
|
15
|
+
render(_jsx(DeleteButton, { action: vi.fn() }));
|
|
16
|
+
fireEvent.click(screen.getByRole("button"));
|
|
17
|
+
// The popover body containing the confirm button should appear
|
|
18
|
+
expect(await screen.findByText("Confirm")).toBeInTheDocument();
|
|
19
|
+
});
|
|
20
|
+
it("shows a custom popup message in the popover", async () => {
|
|
21
|
+
render(_jsx(DeleteButton, { action: vi.fn(), popupMessage: "Delete DecayTreeTuple" }));
|
|
22
|
+
fireEvent.click(screen.getByRole("button"));
|
|
23
|
+
expect(await screen.findByText("Delete DecayTreeTuple")).toBeInTheDocument();
|
|
24
|
+
});
|
|
25
|
+
it("calls the action callback when the confirm button is clicked", async () => {
|
|
26
|
+
const action = vi.fn();
|
|
27
|
+
render(_jsx(DeleteButton, { action: action, popupMessage: "Confirm Delete" }));
|
|
28
|
+
fireEvent.click(screen.getByRole("button"));
|
|
29
|
+
const confirmButton = await screen.findByText("Confirm Delete");
|
|
30
|
+
fireEvent.click(confirmButton);
|
|
31
|
+
expect(action).toHaveBeenCalledOnce();
|
|
32
|
+
});
|
|
33
|
+
it("renders children inside the trigger button", () => {
|
|
34
|
+
render(_jsx(DeleteButton, { action: vi.fn(), children: "Remove item" }));
|
|
35
|
+
expect(screen.getByText("Remove item")).toBeInTheDocument();
|
|
36
|
+
});
|
|
37
|
+
it("applies outline-danger variant when outline prop is set", () => {
|
|
38
|
+
render(_jsx(DeleteButton, { action: vi.fn(), outline: true }));
|
|
39
|
+
expect(screen.getByRole("button")).toHaveClass("btn-outline-danger");
|
|
40
|
+
});
|
|
41
|
+
it("applies danger variant by default (no outline prop)", () => {
|
|
42
|
+
render(_jsx(DeleteButton, { action: vi.fn() }));
|
|
43
|
+
expect(screen.getByRole("button")).toHaveClass("btn-danger");
|
|
44
|
+
});
|
|
45
|
+
});
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export {};
|
|
@@ -0,0 +1,75 @@
|
|
|
1
|
+
import { jsx as _jsx } from "react/jsx-runtime";
|
|
2
|
+
import { describe, expect, it, vi } from "vitest";
|
|
3
|
+
import { fireEvent, render, screen } from "@testing-library/react";
|
|
4
|
+
import { DttNameInput } from "../../components/DttNameInput";
|
|
5
|
+
import { createMockDtt, createMockRow } from "../testUtils";
|
|
6
|
+
const mockUpdateRow = vi.fn();
|
|
7
|
+
vi.mock("../../providers/RowsProvider", () => ({
|
|
8
|
+
useRows: () => ({
|
|
9
|
+
rows: [createMockRow({ id: 0, dtt: createMockDtt("MyTree") })],
|
|
10
|
+
updateRow: mockUpdateRow,
|
|
11
|
+
configuredRows: [],
|
|
12
|
+
setRows: vi.fn(),
|
|
13
|
+
removeRow: vi.fn(),
|
|
14
|
+
generateAllFiles: vi.fn(),
|
|
15
|
+
}),
|
|
16
|
+
}));
|
|
17
|
+
function renderInput(name = "MyTree", onNameValidated = vi.fn()) {
|
|
18
|
+
const dtt = createMockDtt(name);
|
|
19
|
+
return render(_jsx(DttNameInput, { dtt: dtt, rowId: 0, onNameValidated: onNameValidated }));
|
|
20
|
+
}
|
|
21
|
+
describe("DttNameInput", () => {
|
|
22
|
+
it("renders an input with the current DTT name", () => {
|
|
23
|
+
renderInput("MyTree");
|
|
24
|
+
expect(screen.getByDisplayValue("MyTree")).toBeInTheDocument();
|
|
25
|
+
});
|
|
26
|
+
it("accepts typing a new name", () => {
|
|
27
|
+
renderInput("MyTree");
|
|
28
|
+
const input = screen.getByDisplayValue("MyTree");
|
|
29
|
+
fireEvent.change(input, { target: { value: "NewTree" } });
|
|
30
|
+
expect(screen.getByDisplayValue("NewTree")).toBeInTheDocument();
|
|
31
|
+
});
|
|
32
|
+
it("calls onNameValidated(true) when a valid name is blurred", () => {
|
|
33
|
+
const onNameValidated = vi.fn();
|
|
34
|
+
renderInput("MyTree", onNameValidated);
|
|
35
|
+
const input = screen.getByDisplayValue("MyTree");
|
|
36
|
+
fireEvent.blur(input);
|
|
37
|
+
expect(onNameValidated).toHaveBeenCalledWith(true);
|
|
38
|
+
});
|
|
39
|
+
it("calls onNameValidated(false) when the name is emptied and blurred", () => {
|
|
40
|
+
const onNameValidated = vi.fn();
|
|
41
|
+
renderInput("MyTree", onNameValidated);
|
|
42
|
+
const input = screen.getByDisplayValue("MyTree");
|
|
43
|
+
fireEvent.change(input, { target: { value: "" } });
|
|
44
|
+
fireEvent.blur(input);
|
|
45
|
+
expect(onNameValidated).toHaveBeenCalledWith(false);
|
|
46
|
+
});
|
|
47
|
+
it("shows 'Name cannot be empty' feedback when name is cleared", () => {
|
|
48
|
+
renderInput("MyTree");
|
|
49
|
+
const input = screen.getByDisplayValue("MyTree");
|
|
50
|
+
fireEvent.change(input, { target: { value: "" } });
|
|
51
|
+
fireEvent.blur(input);
|
|
52
|
+
expect(screen.getByText(/name cannot be empty/i)).toBeInTheDocument();
|
|
53
|
+
});
|
|
54
|
+
it("shows 'Name contains invalid characters' feedback for bad chars", () => {
|
|
55
|
+
renderInput("MyTree");
|
|
56
|
+
const input = screen.getByDisplayValue("MyTree");
|
|
57
|
+
fireEvent.change(input, { target: { value: "My Tree!" } });
|
|
58
|
+
fireEvent.blur(input);
|
|
59
|
+
expect(screen.getByText(/name contains invalid characters/i)).toBeInTheDocument();
|
|
60
|
+
});
|
|
61
|
+
it("calls updateRow with the new name on a valid blur", () => {
|
|
62
|
+
renderInput("MyTree");
|
|
63
|
+
const input = screen.getByDisplayValue("MyTree");
|
|
64
|
+
fireEvent.change(input, { target: { value: "ValidName" } });
|
|
65
|
+
fireEvent.blur(input);
|
|
66
|
+
expect(mockUpdateRow).toHaveBeenCalledOnce();
|
|
67
|
+
});
|
|
68
|
+
it("does NOT call updateRow when the name is invalid on blur", () => {
|
|
69
|
+
renderInput("MyTree");
|
|
70
|
+
const input = screen.getByDisplayValue("MyTree");
|
|
71
|
+
fireEvent.change(input, { target: { value: "" } });
|
|
72
|
+
fireEvent.blur(input);
|
|
73
|
+
expect(mockUpdateRow).not.toHaveBeenCalled();
|
|
74
|
+
});
|
|
75
|
+
});
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export {};
|
|
@@ -0,0 +1,57 @@
|
|
|
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 { MemoryRouter } from "react-router-dom";
|
|
5
|
+
import { NtupleWizard } from "../../components/NtupleWizard";
|
|
6
|
+
// Stub all providers to pass children through
|
|
7
|
+
vi.mock("../../providers/WizardConfigProvider", () => ({
|
|
8
|
+
WizardConfigProvider: ({ children }) => children,
|
|
9
|
+
}));
|
|
10
|
+
vi.mock("../../providers/RowsProvider", () => ({
|
|
11
|
+
RowsProvider: ({ children }) => children,
|
|
12
|
+
}));
|
|
13
|
+
vi.mock("../../providers/RequestProvider", () => ({
|
|
14
|
+
RequestProvider: ({ children }) => children,
|
|
15
|
+
}));
|
|
16
|
+
// Stub pages
|
|
17
|
+
vi.mock("../../pages/DecaySearchPage", () => ({
|
|
18
|
+
DecaySearchPage: () => _jsx("div", { "data-testid": "decay-search-page" }),
|
|
19
|
+
}));
|
|
20
|
+
vi.mock("../../pages/DecayTreeConfigPage", () => ({
|
|
21
|
+
DecayTreeConfigPage: () => _jsx("div", { "data-testid": "decay-tree-config-page" }),
|
|
22
|
+
}));
|
|
23
|
+
vi.mock("../../pages/RequestPage", () => ({
|
|
24
|
+
RequestPage: () => _jsx("div", { "data-testid": "request-page" }),
|
|
25
|
+
}));
|
|
26
|
+
function renderWizard(path, props = {}) {
|
|
27
|
+
return render(_jsx(MemoryRouter, { initialEntries: [path], children: _jsx(NtupleWizard, { ...props }) }));
|
|
28
|
+
}
|
|
29
|
+
describe("NtupleWizard — routing", () => {
|
|
30
|
+
it("renders DecaySearchPage when pathname ends with /select-decays", () => {
|
|
31
|
+
renderWizard("/select-decays");
|
|
32
|
+
expect(screen.getByTestId("decay-search-page")).toBeInTheDocument();
|
|
33
|
+
});
|
|
34
|
+
it("renders DecayTreeConfigPage when pathname ends with /variables", () => {
|
|
35
|
+
renderWizard("/variables");
|
|
36
|
+
expect(screen.getByTestId("decay-tree-config-page")).toBeInTheDocument();
|
|
37
|
+
});
|
|
38
|
+
it("renders RequestPage for the root path", () => {
|
|
39
|
+
renderWizard("/");
|
|
40
|
+
expect(screen.getByTestId("request-page")).toBeInTheDocument();
|
|
41
|
+
});
|
|
42
|
+
it("renders RequestPage for any other path", () => {
|
|
43
|
+
renderWizard("/some-other-path");
|
|
44
|
+
expect(screen.getByTestId("request-page")).toBeInTheDocument();
|
|
45
|
+
});
|
|
46
|
+
});
|
|
47
|
+
describe("NtupleWizard — contactEmail", () => {
|
|
48
|
+
it("sets localStorage email when contactEmail is provided", () => {
|
|
49
|
+
renderWizard("/", { contactEmail: "test@example.com" });
|
|
50
|
+
expect(localStorage.getItem("email")).toBe("test@example.com");
|
|
51
|
+
});
|
|
52
|
+
it("does not set localStorage email when contactEmail is not provided", () => {
|
|
53
|
+
localStorage.removeItem("email");
|
|
54
|
+
renderWizard("/");
|
|
55
|
+
expect(localStorage.getItem("email")).toBeNull();
|
|
56
|
+
});
|
|
57
|
+
});
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export {};
|
|
@@ -0,0 +1,23 @@
|
|
|
1
|
+
import { jsx as _jsx } from "react/jsx-runtime";
|
|
2
|
+
import { describe, expect, it } from "vitest";
|
|
3
|
+
import { render, screen } from "@testing-library/react";
|
|
4
|
+
import { ParticleDropdown } from "../../components/ParticleDropdown";
|
|
5
|
+
describe("ParticleDropdown", () => {
|
|
6
|
+
it("renders a combobox", () => {
|
|
7
|
+
render(_jsx(ParticleDropdown, {}));
|
|
8
|
+
expect(screen.getByRole("combobox")).toBeInTheDocument();
|
|
9
|
+
});
|
|
10
|
+
it("renders with a placeholder", () => {
|
|
11
|
+
render(_jsx(ParticleDropdown, { placeholder: "Choose particle" }));
|
|
12
|
+
expect(screen.getByText("Choose particle")).toBeInTheDocument();
|
|
13
|
+
});
|
|
14
|
+
it("renders without error in onlyHeads mode", () => {
|
|
15
|
+
expect(() => render(_jsx(ParticleDropdown, { onlyHeads: true }))).not.toThrow();
|
|
16
|
+
});
|
|
17
|
+
it("renders without error in onlyKnown mode", () => {
|
|
18
|
+
expect(() => render(_jsx(ParticleDropdown, { onlyKnown: true }))).not.toThrow();
|
|
19
|
+
});
|
|
20
|
+
it("renders without error in default mode (all particles)", () => {
|
|
21
|
+
expect(() => render(_jsx(ParticleDropdown, {}))).not.toThrow();
|
|
22
|
+
});
|
|
23
|
+
});
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export {};
|
|
@@ -0,0 +1,87 @@
|
|
|
1
|
+
import { jsx as _jsx } from "react/jsx-runtime";
|
|
2
|
+
import { beforeEach, describe, expect, it, vi } from "vitest";
|
|
3
|
+
import { fireEvent, render, screen } from "@testing-library/react";
|
|
4
|
+
import { ParticleTagFilters } from "../../components/ParticleTagFilters";
|
|
5
|
+
import { createMockDtt, mockMetadata } from "../testUtils";
|
|
6
|
+
// Custom metadata where particles have tags so filters have something to show
|
|
7
|
+
const mockMetadataWithTags = {
|
|
8
|
+
...mockMetadata,
|
|
9
|
+
particleProperties: {
|
|
10
|
+
...mockMetadata.particleProperties,
|
|
11
|
+
"B+": { ...mockMetadata.particleProperties["B+"], tags: [] },
|
|
12
|
+
"K+": { ...mockMetadata.particleProperties["K+"], tags: ["kaon"] },
|
|
13
|
+
"mu+": { ...mockMetadata.particleProperties["mu+"], tags: ["muon"] },
|
|
14
|
+
"mu-": { ...mockMetadata.particleProperties["mu-"], tags: ["muon"] },
|
|
15
|
+
},
|
|
16
|
+
};
|
|
17
|
+
let mockMetadataValue = mockMetadataWithTags;
|
|
18
|
+
vi.mock("../../providers/MetadataProvider", () => ({
|
|
19
|
+
useMetadata: () => mockMetadataValue,
|
|
20
|
+
}));
|
|
21
|
+
vi.mock("../../config", () => ({
|
|
22
|
+
config: {
|
|
23
|
+
disabledTupleTools: [],
|
|
24
|
+
tupleToolValidation: {},
|
|
25
|
+
particleTagGroupStyles: {
|
|
26
|
+
category: "dark",
|
|
27
|
+
charge: "primary",
|
|
28
|
+
flavour: "success",
|
|
29
|
+
spin: "danger",
|
|
30
|
+
lifetime: "secondary",
|
|
31
|
+
},
|
|
32
|
+
},
|
|
33
|
+
}));
|
|
34
|
+
let mockDtt = createMockDtt("MyTree");
|
|
35
|
+
let mockSelectedBranch = [];
|
|
36
|
+
const mockSetSelectedBranch = vi.fn();
|
|
37
|
+
vi.mock("../../providers/DttProvider", () => ({
|
|
38
|
+
useDtt: () => ({
|
|
39
|
+
dtt: mockDtt,
|
|
40
|
+
selectedBranch: mockSelectedBranch,
|
|
41
|
+
setSelectedBranch: mockSetSelectedBranch,
|
|
42
|
+
}),
|
|
43
|
+
}));
|
|
44
|
+
describe("ParticleTagFilters", () => {
|
|
45
|
+
beforeEach(() => {
|
|
46
|
+
mockDtt = createMockDtt("MyTree");
|
|
47
|
+
mockSelectedBranch = [];
|
|
48
|
+
mockSetSelectedBranch.mockClear();
|
|
49
|
+
mockMetadataValue = mockMetadataWithTags;
|
|
50
|
+
});
|
|
51
|
+
it("renders tag badges when particles have tags (no branch selected)", () => {
|
|
52
|
+
render(_jsx(ParticleTagFilters, {}));
|
|
53
|
+
expect(screen.getByText("muon")).toBeInTheDocument();
|
|
54
|
+
expect(screen.getByText("kaon")).toBeInTheDocument();
|
|
55
|
+
});
|
|
56
|
+
it("calls setSelectedBranch with matching branches when a tag is clicked", () => {
|
|
57
|
+
render(_jsx(ParticleTagFilters, {}));
|
|
58
|
+
fireEvent.click(screen.getByText("muon"));
|
|
59
|
+
expect(mockSetSelectedBranch).toHaveBeenCalled();
|
|
60
|
+
const branches = mockSetSelectedBranch.mock.calls[0][0];
|
|
61
|
+
expect(branches).toContain("mup");
|
|
62
|
+
expect(branches).toContain("mum");
|
|
63
|
+
});
|
|
64
|
+
it("clicking kaon tag selects only kaon branches", () => {
|
|
65
|
+
render(_jsx(ParticleTagFilters, {}));
|
|
66
|
+
fireEvent.click(screen.getByText("kaon"));
|
|
67
|
+
expect(mockSetSelectedBranch).toHaveBeenCalled();
|
|
68
|
+
const branches = mockSetSelectedBranch.mock.calls[0][0];
|
|
69
|
+
expect(branches).toContain("k");
|
|
70
|
+
expect(branches).not.toContain("mup");
|
|
71
|
+
});
|
|
72
|
+
it("renders no tag badges when all particles have empty tags", () => {
|
|
73
|
+
mockMetadataValue = mockMetadata; // all particles have tags=[]
|
|
74
|
+
const { container } = render(_jsx(ParticleTagFilters, {}));
|
|
75
|
+
expect(container.querySelectorAll(".badge").length).toBe(0);
|
|
76
|
+
});
|
|
77
|
+
it("shows only tags for the selected branch when one branch is selected", () => {
|
|
78
|
+
mockSelectedBranch = ["mup"]; // mu+ only → should see muon tag
|
|
79
|
+
render(_jsx(ParticleTagFilters, {}));
|
|
80
|
+
expect(screen.getByText("muon")).toBeInTheDocument();
|
|
81
|
+
});
|
|
82
|
+
it("shows tags common to a group when multiple branches are selected", () => {
|
|
83
|
+
mockSelectedBranch = ["mup", "mum"]; // both mu particles → muon tag common
|
|
84
|
+
render(_jsx(ParticleTagFilters, {}));
|
|
85
|
+
expect(screen.getByText("muon")).toBeInTheDocument();
|
|
86
|
+
});
|
|
87
|
+
});
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export {};
|