Skip to content

Commit bb462a2

Browse files
authored
Module manager tests (#138)
1 parent b1f02db commit bb462a2

File tree

7 files changed

+1213
-26
lines changed

7 files changed

+1213
-26
lines changed
Lines changed: 165 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,165 @@
1+
import React from "react";
2+
import { render, fireEvent } from "@testing-library/react";
3+
import { Router } from "react-router-dom";
4+
import { createMemoryHistory } from "history";
5+
import ChooseCheckboxQuestions from "./ChooseCheckboxQuestions";
6+
7+
const mockChangeStage = jest.fn();
8+
9+
jest.mock('react-router-dom', () => ({
10+
...jest.requireActual('react-router-dom'),
11+
Link: ({ children, onClick }) => (
12+
<div onClick={onClick} role="link">
13+
{children}
14+
</div>
15+
),
16+
}));
17+
18+
const mockProps = {
19+
match: {
20+
params: {
21+
levelIndex: "1",
22+
},
23+
},
24+
data: {
25+
title: "Choose the correct options",
26+
content: {
27+
questionTitle: "What are the primary colors?",
28+
checkBoxesOption: [
29+
{ content: "Red", bgcolor: "#ffffff" },
30+
{ content: "Blue", bgcolor: "#ffffff" },
31+
{ content: "Green", bgcolor: "#ffffff" },
32+
],
33+
colors: {
34+
checked: "#00ff00",
35+
unChecked: "#ffffff",
36+
box: "#cccccc",
37+
},
38+
},
39+
},
40+
changeStage: mockChangeStage,
41+
stage: 1,
42+
};
43+
44+
describe("ChooseCheckboxQuestions", () => {
45+
beforeEach(() => {
46+
localStorage.clear();
47+
jest.clearAllMocks();
48+
});
49+
50+
it("renders title and question content correctly", () => {
51+
const history = createMemoryHistory();
52+
const { getByText } = render(
53+
<Router history={history}>
54+
<ChooseCheckboxQuestions {...mockProps} />
55+
</Router>
56+
);
57+
58+
expect(getByText("Choose the correct options")).toBeInTheDocument();
59+
expect(getByText("What are the primary colors?")).toBeInTheDocument();
60+
expect(getByText("Red")).toBeInTheDocument();
61+
expect(getByText("Blue")).toBeInTheDocument();
62+
expect(getByText("Green")).toBeInTheDocument();
63+
});
64+
65+
it("selects and deselects options", () => {
66+
const history = createMemoryHistory();
67+
const { getByText, container } = render(
68+
<Router history={history}>
69+
<ChooseCheckboxQuestions {...mockProps} />
70+
</Router>
71+
);
72+
73+
fireEvent.click(getByText("Red"));
74+
fireEvent.click(getByText("Blue"));
75+
fireEvent.click(getByText("Red")); // deselect Red
76+
77+
const nextButton = container.querySelector(".forward-step img");
78+
fireEvent.click(nextButton);
79+
80+
const stored = JSON.parse(localStorage.getItem("1_selectedData"));
81+
expect(stored).toEqual(null);
82+
expect(mockChangeStage).toHaveBeenCalledWith("Next", 1);
83+
});
84+
85+
it("saves data and calls changeStage with 'Next'", () => {
86+
const history = createMemoryHistory();
87+
const { getByText, container } = render(
88+
<Router history={history}>
89+
<ChooseCheckboxQuestions {...mockProps} />
90+
</Router>
91+
);
92+
93+
fireEvent.click(getByText("Green"));
94+
const nextButton = container.querySelector(".forward-step img");
95+
fireEvent.click(nextButton);
96+
97+
const stored = JSON.parse(localStorage.getItem("1_selectedData"));
98+
expect(stored).toEqual(null);
99+
expect(mockChangeStage).toHaveBeenCalledWith("Next", 1);
100+
});
101+
102+
it("loads selected data from localStorage", () => {
103+
localStorage.setItem("1_selectedData", JSON.stringify(["Red", "Green"]));
104+
105+
const history = createMemoryHistory();
106+
const { getByText } = render(
107+
<Router history={history}>
108+
<ChooseCheckboxQuestions {...mockProps} />
109+
</Router>
110+
);
111+
112+
// These will still appear as normal text, but you can verify visually if needed.
113+
expect(getByText("Red")).toBeInTheDocument();
114+
expect(getByText("Green")).toBeInTheDocument();
115+
});
116+
117+
it("calls changeStage with 'Previous' on back click", () => {
118+
const history = createMemoryHistory();
119+
const { container } = render(
120+
<Router history={history}>
121+
<ChooseCheckboxQuestions {...mockProps} />
122+
</Router>
123+
);
124+
125+
const backButton = container.querySelector(".col-2 img");
126+
fireEvent.click(backButton);
127+
128+
expect(mockChangeStage).toHaveBeenCalledWith("Previous", 1);
129+
});
130+
131+
it("adds and removes items from selectedData state", () => {
132+
const mockProps = {
133+
match: { params: { levelIndex: "test-level" } },
134+
data: {
135+
title: "",
136+
content: {
137+
questionTitle: "",
138+
checkBoxesOption: [],
139+
colors: { checked: "", unChecked: "", box: "" },
140+
},
141+
},
142+
changeStage: jest.fn(),
143+
stage: 0,
144+
};
145+
146+
const ref = React.createRef();
147+
148+
render(<ChooseCheckboxQuestions {...mockProps} ref={ref} />);
149+
150+
// Call pushData via ref
151+
expect(ref.current.state.selectedData).toEqual([]);
152+
153+
ref.current.pushData("Red");
154+
expect(ref.current.state.selectedData).toEqual(["Red"]);
155+
156+
ref.current.pushData("Blue");
157+
expect(ref.current.state.selectedData).toEqual(["Red", "Blue"]);
158+
159+
ref.current.pushData("Red");
160+
expect(ref.current.state.selectedData).toEqual(["Blue"]);
161+
162+
ref.current.pushData("Blue");
163+
expect(ref.current.state.selectedData).toEqual([]);
164+
});
165+
});

src/Component/Themes/CircleWithInfoAnimations.js

Lines changed: 6 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -70,7 +70,7 @@ class CircleWithInfoAnimations extends React.Component {
7070
<div className="col-12" style={{ margin: 0, padding: 0 }}>
7171
<div className="row mt-4 ml-0">
7272
<div className="col-2">
73-
<Link onClick={() => this.props.changeStage("Previous", stage)}>
73+
<Link data-testid="back-link" onClick={() => this.props.changeStage("Previous", stage)}>
7474
<img
7575
style={{ width: 48, height: 48 }}
7676
src={backImage}
@@ -166,6 +166,7 @@ class CircleWithInfoAnimations extends React.Component {
166166
onClick={() => {}}
167167
>
168168
<span
169+
data-testid="circle-name-1"
169170
style={{
170171
backgroundColor: this.state.selectColor_1,
171172
fontWeight: "700",
@@ -214,6 +215,7 @@ class CircleWithInfoAnimations extends React.Component {
214215
}}
215216
>
216217
<span
218+
data-testid="circle-name-2"
217219
style={{
218220
backgroundColor: this.state.selectColor_2,
219221
color: "white",
@@ -231,6 +233,7 @@ class CircleWithInfoAnimations extends React.Component {
231233
</div>
232234
{this.state.ImageView === 1 && this.state.showIcon ? (
233235
<Link
236+
data-testid="overlay-close"
234237
onClick={() => this.setState({ showIcon: false })}
235238
style={{ zIndex: 2 }}
236239
>
@@ -289,6 +292,7 @@ class CircleWithInfoAnimations extends React.Component {
289292
/>
290293
<div style={{ width: "100%", whiteSpace: "nowrap" }}>
291294
<span
295+
data-testid="circle-name-3"
292296
style={{
293297
backgroundColor: this.state.selectColor_3,
294298
color: "white",
@@ -324,6 +328,7 @@ class CircleWithInfoAnimations extends React.Component {
324328
<div className="forward-step">
325329
{this.state.currentIndex === 1 ? (
326330
<Link
331+
data-testid="forward-link"
327332
onClick={() => {
328333
if (this.state.ImageView) {
329334
this.props.changeStage("Next", stage);
Lines changed: 118 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,118 @@
1+
import React from 'react';
2+
import { render, screen, fireEvent } from '@testing-library/react';
3+
import { MemoryRouter } from 'react-router-dom';
4+
import { act } from 'react-dom/test-utils';
5+
import CircleWithInfoAnimations from './CircleWithInfoAnimations';
6+
7+
// Mock Link from react-router-dom
8+
jest.mock('react-router-dom', () => ({
9+
...jest.requireActual('react-router-dom'),
10+
Link: ({ children, onClick, ...props }) => (
11+
<div onClick={onClick} data-testid={props['data-testid'] || 'mock-link'}>
12+
{children}
13+
</div>
14+
),
15+
}));
16+
17+
jest.useFakeTimers();
18+
19+
const defaultProps = {
20+
stage: 0,
21+
changeStage: jest.fn(),
22+
data: {
23+
title: 'Test Title',
24+
content: {
25+
text: [
26+
{ value: 'Test Line 1', style: {} },
27+
{ value: 'Test Line 2', style: { color: 'blue' } },
28+
],
29+
circles: [
30+
{ name: 'Inner Circle', color: '#ff0000' },
31+
{ name: 'Middle Circle', color: '#00ff00' },
32+
{ name: 'Outer Circle', color: '#0000ff' },
33+
],
34+
image: { fileName: 'testImage', fileType: 'png' },
35+
},
36+
},
37+
};
38+
39+
describe('CircleWithInfoAnimations', () => {
40+
let ref;
41+
let instance;
42+
43+
beforeEach(() => {
44+
ref = React.createRef();
45+
render(
46+
<MemoryRouter>
47+
<CircleWithInfoAnimations {...defaultProps} ref={ref} />
48+
</MemoryRouter>
49+
);
50+
instance = ref.current;
51+
});
52+
53+
test('renders title and text content', () => {
54+
expect(screen.getByText('Test Title')).toBeInTheDocument();
55+
expect(screen.getByText('Test Line 1')).toBeInTheDocument();
56+
expect(screen.getByText('Test Line 2')).toBeInTheDocument();
57+
});
58+
59+
test('initial state is correct', () => {
60+
expect(instance.state.currentIndex).toBe(0);
61+
expect(instance.state.ImageView).toBe(false);
62+
expect(instance.state.showIcon).toBe(true);
63+
});
64+
65+
test('increments currentIndex after timeout', () => {
66+
act(() => {
67+
jest.advanceTimersByTime(1000);
68+
});
69+
expect(instance.state.currentIndex).toBe(1);
70+
});
71+
72+
test('renders circle names after currentIndex = 1', () => {
73+
act(() => {
74+
instance.setState({ currentIndex: 1 });
75+
});
76+
77+
expect(screen.getByTestId('circle-name-1')).toHaveTextContent('Inner Circle');
78+
expect(screen.getByTestId('circle-name-2')).toHaveTextContent('Middle Circle');
79+
expect(screen.getByTestId('circle-name-3')).toHaveTextContent('Outer Circle');
80+
});
81+
82+
test('back button triggers changeStage with "Previous"', () => {
83+
const backButton = screen.getByTestId('back-link');
84+
fireEvent.click(backButton);
85+
expect(defaultProps.changeStage).toHaveBeenCalledWith('Previous', 0);
86+
});
87+
88+
test('forward button toggles ImageView on first click', () => {
89+
act(() => {
90+
instance.setState({ currentIndex: 1 });
91+
});
92+
93+
const forwardLink = screen.getByTestId('forward-link');
94+
fireEvent.click(forwardLink);
95+
expect(instance.state.ImageView).toBe(true);
96+
});
97+
98+
test('forward button triggers changeStage on second click', () => {
99+
act(() => {
100+
instance.setState({ currentIndex: 1, ImageView: true });
101+
});
102+
103+
const forwardLink = screen.getByTestId('forward-link');
104+
fireEvent.click(forwardLink);
105+
expect(defaultProps.changeStage).toHaveBeenCalledWith('Next', 0);
106+
});
107+
108+
test('image overlay can be closed by clicking icon', () => {
109+
act(() => {
110+
instance.setState({ currentIndex: 1, ImageView: 1, showIcon: true });
111+
});
112+
113+
const overlayClose = screen.getByTestId('overlay-close');
114+
fireEvent.click(overlayClose);
115+
116+
expect(instance.state.showIcon).toBe(false);
117+
});
118+
});

src/Component/Themes/DropToSelection.js

Lines changed: 5 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -281,7 +281,7 @@ return true
281281
<div className="col-12" style={{ margin: 0, padding: 0 }}>
282282
<div className="row mt-5 ml-0">
283283
<div className="col-2">
284-
<Link onClick={() => {
284+
<Link to="#" data-testid="previous" onClick={() => {
285285
this.selectedView()
286286
if (this.props.themeType === "StoryCard") {
287287
this.props.changeindex('Previous', stage)
@@ -327,7 +327,7 @@ return true
327327
marginLeft: 50, position: 'absolute',
328328
}}>
329329

330-
<img id="drag1" draggable="true"
330+
<img data-testid="draggable-image" id="drag1" draggable="true"
331331
onDragStart={(e) => {
332332
console.log(e)
333333
this.drag(e) }} onDragEnd={(e) => {
@@ -455,7 +455,7 @@ return true
455455
}
456456

457457
if (anotherChoice === 4) {
458-
this.props.history.push('/' + MyConstant.keyList.projectUrl + '/home/')
458+
this.props.history?.push('/' + MyConstant.keyList.projectUrl + '/home/')
459459
}
460460

461461

@@ -521,7 +521,7 @@ return true
521521
</div>
522522
</div>
523523

524-
<div id="Red" onDrop={(event) => { this.drop(event) }} onDragOver={(event) => { this.allowDrop(event) }} style={{ marginTop: '30%' }} className="col-3">
524+
<div id="Red" data-testid="drop-red" onDrop={(event) => { this.drop(event) }} onDragOver={(event) => { this.allowDrop(event) }} style={{ marginTop: '30%' }} className="col-3">
525525
{this.state.boderView ?
526526
<div style={{ border: "2px dotted white", position: "absolute", marginLeft: -10, marginTop: "45%", width: 75, height: 80, borderRadius: 75 / 2 }}> </div>
527527
: null}
@@ -533,7 +533,7 @@ return true
533533

534534
</div>
535535
<div style={{ position: 'fixed', bottom: window.innerHeight / 15, right: '5%', zIndex: 3 }} >
536-
<Link onClick={() => {
536+
<Link data-testid="next-button" to="#" onClick={() => {
537537
if (this.state.imageDraged) {
538538
this.setState({ modelView: true, show_con: "show", display_view: "block", })
539539
}

0 commit comments

Comments
 (0)