Skip to content

Commit e58c807

Browse files
committed
Co-authored-by: Jimmy Phy <[email protected]>
2 parents 728bc10 + d96bd1e commit e58c807

File tree

12 files changed

+389
-126
lines changed

12 files changed

+389
-126
lines changed

package.json

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -237,6 +237,7 @@
237237
"react-spinners": "^0.11.0",
238238
"recoil": "0.0.10",
239239
"redux": "^4.2.1",
240+
"redux-mock-store": "^1.5.4",
240241
"styled-components": "^6.0.4",
241242
"util": "^0.12.4",
242243
"web-vitals": "^1.1.0",

src/app/FrontendTypes.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -143,7 +143,7 @@ export interface InitialStateProps {
143143
tabs: unknown;
144144
currentTabInApp: null | string;
145145
connectionStatus: boolean;
146-
reconnectRequested: boolean;
146+
connectRequested: boolean;
147147
}
148148

149149
export interface DiffProps {

src/app/RTKslices.tsx

Lines changed: 10 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -9,7 +9,7 @@ const initialState: InitialStateProps = { // we initialize what our initialState
99
tabs: {},
1010
currentTabInApp: null,
1111
connectionStatus: true,
12-
reconnectRequested: false,
12+
connectRequested: true,
1313
};
1414

1515
const findName = (index, obj) => {
@@ -40,6 +40,7 @@ export const mainSlice = createSlice({
4040

4141
emptySnapshots: (state) => {
4242
const { tabs, currentTab, port } = state;
43+
console.log("this is state 2", current(state));
4344

4445
port.postMessage({ action: 'emptySnap', tabId: currentTab });
4546

@@ -116,7 +117,9 @@ export const mainSlice = createSlice({
116117
},
117118

118119
setPort: (state, action) => {
120+
console.log('port start: ', current(state))
119121
state.port = action.payload;
122+
console.log('port end: ', current(state))
120123
},
121124

122125
setTab: (state, action) => {
@@ -206,8 +209,8 @@ export const mainSlice = createSlice({
206209

207210
const nameFromIndex = findName(action.payload, hierarchy);
208211

209-
console.log('this is action payload', action.payload);
210-
console.log('this is nameFromIndex', nameFromIndex);
212+
// console.log('this is action payload', action.payload);
213+
// console.log('this is nameFromIndex', nameFromIndex);
211214

212215
port.postMessage({
213216
action: 'jumpToSnap',
@@ -489,12 +492,12 @@ export const mainSlice = createSlice({
489492
},
490493

491494
startReconnect: (state) => {
492-
state.reconnectRequested = true;
495+
state.connectRequested = true;
493496
state.port = initialState.port;
494497
},
495498

496-
endReconnect: (state) => {
497-
state.reconnectRequested = false;
499+
endConnect: (state) => {
500+
state.connectRequested = false;
498501
state.connectionStatus = true;
499502
}
500503

@@ -530,5 +533,5 @@ export const {
530533
deleteSeries,
531534
disconnected,
532535
startReconnect,
533-
endReconnect,
536+
endConnect,
534537
} = mainSlice.actions

src/app/__tests__/ActionContainer.test.tsx

Lines changed: 17 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -17,11 +17,12 @@ import { store } from '../RTKstore';
1717
// useSelector: jest.fn() //override the useDispatch from the react redux module with a jest mock function
1818
// }));
1919

20-
const render = component => rtlRender(
21-
<Provider store={store}>
22-
{component}
23-
</Provider>
24-
)
20+
// const render = component => rtlRender(
21+
// <Provider store={store}>
22+
// {component}
23+
// </Provider>
24+
// )
25+
2526

2627
const state = {
2728
tabs: {
@@ -175,17 +176,17 @@ describe('unit testing for ActionContainer', () => {
175176
});
176177
});
177178

178-
describe('integration testing for ActionContainer', () => {
179-
beforeEach(() => {
180-
mockeduseStoreContext.mockClear();
181-
dispatch.mockClear();
182-
render(
183-
<ActionContainer actionView={true} />
184-
)
185-
render(
186-
<TravelContainer snapshotsLength={0} />
187-
)
188-
});
179+
// describe('integration testing for ActionContainer', () => {
180+
// beforeEach(() => {
181+
// mockeduseStoreContext.mockClear();
182+
// dispatch.mockClear();
183+
// render(
184+
// <ActionContainer actionView={true} />
185+
// )
186+
// render(
187+
// <TravelContainer snapshotsLength={0} />
188+
// )
189+
// });
189190

190191
test('Slider resets on clear button', () => {
191192
fireEvent.click(screen.getAllByRole('button')[0]);
Lines changed: 158 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,158 @@
1+
import React from 'react';
2+
import { render as rtlRender, screen, fireEvent } from '@testing-library/react';
3+
import '@testing-library/jest-dom/extend-expect';
4+
import ActionContainer from '../containers/ActionContainer';
5+
import TravelContainer from '../containers/TravelContainer';
6+
import { Provider } from 'react-redux';
7+
import { configureStore } from '@reduxjs/toolkit';
8+
import { store } from '../RTKstore';
9+
import { mainSlice } from '../RTKslices'
10+
11+
//Note for testing:
12+
//typically, jest.mock is commonly used in unit testing to isolate the code under test.
13+
//In contrast, when performing integration testing of components with a real Redux store,
14+
//you typically don't need to use jest.mock because you're interested in testing how the real components interact with the actual store.
15+
//The decision to use jest.mock depends on the type of testing (unit or integration) and your specific testing goals.
16+
17+
const customTabs = {
18+
87: {
19+
snapshots: [1, 2, 3, 4],
20+
hierarchy: {
21+
index: 0,
22+
name: 1,
23+
branch: 0,
24+
stateSnapshot: {
25+
state: {},
26+
children: [
27+
{
28+
state: { test: 'test' },
29+
name: 'App',
30+
componentData: { actualDuration: 3.5 },
31+
},
32+
],
33+
route: {
34+
id: 1,
35+
url: 'http://localhost:8080/',
36+
},
37+
},
38+
children: [
39+
{
40+
index: 1,
41+
name: 2,
42+
branch: 0,
43+
stateSnapshot: {
44+
state: {},
45+
children: [
46+
{
47+
state: { test: 'test' },
48+
name: 'App',
49+
componentData: { actualDuration: 3.5 },
50+
},
51+
],
52+
route: {
53+
id: 2,
54+
url: 'http://localhost:8080/',
55+
},
56+
},
57+
children: [
58+
{
59+
index: 2,
60+
name: 3,
61+
branch: 0,
62+
stateSnapshot: {
63+
state: {},
64+
children: [
65+
{
66+
state: { test: 'test' },
67+
name: 'App',
68+
componentData: { actualDuration: 3.5 },
69+
},
70+
],
71+
route: {
72+
id: 3,
73+
url: 'http://localhost:8080/',
74+
},
75+
},
76+
children: [
77+
{
78+
index: 3,
79+
name: 4,
80+
branch: 0,
81+
stateSnapshot: {
82+
state: {},
83+
children: [
84+
{
85+
state: { test: 'test' },
86+
name: 'App',
87+
componentData: { actualDuration: 3.5 },
88+
},
89+
],
90+
route: {
91+
id: 4,
92+
url: 'http://localhost:8080/test/',
93+
},
94+
},
95+
children: [],
96+
},
97+
],
98+
},
99+
],
100+
},
101+
],
102+
},
103+
currLocation: {
104+
index: 0,
105+
name: 1,
106+
branch: 0,
107+
},
108+
sliderIndex: 0,
109+
viewIndex: -1,
110+
},
111+
}
112+
113+
const customInitialState = {
114+
main: {
115+
port: null,
116+
currentTab: 87, // Update with your desired value
117+
currentTitle: null,
118+
tabs: customTabs, // Replace with the actual (testing) tab data
119+
currentTabInApp: null,
120+
connectionStatus: false,
121+
reconnectRequested: false,
122+
},
123+
};
124+
125+
const customStore = configureStore({
126+
reducer: {
127+
main: mainSlice.reducer,
128+
},
129+
preloadedState: customInitialState, // Provide custom initial state
130+
middleware: (getDefaultMiddleware) =>
131+
getDefaultMiddleware({ serializableCheck: false }),
132+
});
133+
134+
const render = component => rtlRender(
135+
<Provider store={customStore}>
136+
{component}
137+
</Provider>
138+
);
139+
140+
//need to add this mockFunction for setActionView
141+
//because in actual actioncontainer componenent, it is prop drilled down from maincontainer
142+
//here we set it as a jest.fn()
143+
//then we pass it into our actionContainer on render
144+
const setActionViewMock = jest.fn();
145+
146+
describe('Integration testing for ActionContainer.tsx', () => {
147+
test('renders the ActionContainer component', () => {
148+
//tests that the clearButton is rendered by testing if we can get "Clear"
149+
//need to set actionView to true to correctly render clearbutton
150+
render(<ActionContainer setActionView={setActionViewMock} actionView={true}/>);
151+
const clearButton = screen.getByText('Clear'); // Use an existing element
152+
expect(setActionViewMock).toHaveBeenCalledWith(true);
153+
expect(clearButton).toBeInTheDocument();
154+
});
155+
});
156+
157+
158+

src/app/__tests__/action.test.tsx

Lines changed: 27 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -6,14 +6,16 @@ import Action from '../components/Action';
66
import { changeView, changeSlider } from '../RTKslices';
77
import { Provider } from 'react-redux';
88
import { store } from '../RTKstore'; //importing store for testing to give us access to Redux Store we configured
9-
import { useDispatch } from 'react-redux' //import all exports from react-redux as an object, reactRedux
9+
// import * as reactRedux from 'react-redux'
10+
import { useDispatch } from 'react-redux'; //more explicit about what we are importing from library for a more focused testing approach
1011

1112
// @ts-ignore
1213
Action.cleanTime = jest.fn().mockReturnValue();
13-
//create a mock of the react-redux module
14+
15+
//creating a mock function to mock the react-redux module and overwrite the useDispatch method with a jest.fn()
1416
jest.mock('react-redux', () => ({
15-
...jest.requireActual('react-redux'), // include all the exports from the actual react-redux module
16-
useDispatch: jest.fn(), //override the useDispatch from the react redux module with a jest mock function
17+
...jest.requireActual('react-redux'), // Use the actual react-redux module except for the functions you want to mock
18+
useDispatch: jest.fn(), // set up a mock function for useDispatch
1719
}));
1820

1921
//wraps the component with our provider each time we use render
@@ -24,12 +26,9 @@ const render = component => rtlRender(
2426
)
2527

2628
describe('Unit testing for Action.tsx', () => {
27-
//declare a var useDispatchMock, and assign it to the useDispatch from the reactRedux object, and set it's type as jest.Mock
28-
//we expect useDispatchMock to have a type assertion of jest.Mock
29-
const useDispatchMock = useDispatch as jest.Mock;
30-
const dummyDispatch = jest.fn(); //define a mock function and store it in the var dummyDispatch
31-
useDispatchMock.mockReturnValue(dummyDispatch);
32-
//when the test runs, its going to see that the component invokes useDispatch, but since we have it overridden as a jest mock func, it'll run that instead, and we set it up so that when the jest mock func runs, it returns dummy dispatch to run in its place. This allows us to check the number of times dummy dispatch was called, which would represent the number of times useDispatch was called.
29+
const useDispatchMock = useDispatch as jest.Mock; //getting a reference to the mock function you setup during jest.mock configuration on line 18
30+
const dummyDispatch = jest.fn(); //separate mock function created because we need to explicitly define on line 30 what
31+
useDispatchMock.mockReturnValue(dummyDispatch);//exactly useDispatchMock returns (which is a jest.fn())
3332
const props = {
3433
key: 'actions2',
3534
selected: true,
@@ -140,4 +139,21 @@ describe('Unit testing for Action.tsx', () => {
140139
expect(dummyDispatch).toHaveBeenCalledWith(changeView(props.index));
141140
});
142141
});
143-
});
142+
});
143+
144+
145+
146+
//these were the tests for 9 and 10 before our changes... in progress
147+
148+
// test('Clicking the snapshot should trigger onClick', () => {
149+
// render(<Action {...props} />);
150+
// fireEvent.click(screen.getByRole('presentation'));
151+
// expect(props.dispatch).toHaveBeenCalledWith(changeView(props.index));;
152+
// });
153+
154+
// test('Clicking Jump button should trigger changeSlider and changeView', () => {
155+
// render(<Action {...props} />);
156+
// fireEvent.click(screen.getAllByRole('button')[1]);
157+
// expect(props.dispatch).toHaveBeenCalledWith(changeSlider(props.index));
158+
// expect(props.dispatch).toHaveBeenCalledWith(changeView(props.index));
159+
// });

src/app/containers/ActionContainer.tsx

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -203,7 +203,7 @@ function ActionContainer(props): JSX.Element {
203203
dispatch(emptySnapshots()); // set slider back to zero, visually
204204
resetSlider();
205205
}}
206-
type='button'
206+
type='button'
207207
>
208208
Clear
209209
</Button>

src/app/containers/ButtonsContainer.tsx

Lines changed: 6 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -14,6 +14,7 @@ import { useDispatch, useSelector } from 'react-redux';
1414
import StatusDot from '../components/StatusDot';
1515
import LoopIcon from '@mui/icons-material/Loop';
1616
import CloseIcon from '@mui/icons-material/Close';
17+
import WarningIcon from '@mui/icons-material/Warning';
1718

1819
function exportHandler(snapshots: []): void { // function that takes in our tabs[currentTab] object to be exported as a JSON file. NOTE: TypeScript needs to be updated
1920
const fileDownload: HTMLAnchorElement = document.createElement('a'); // invisible HTML element that will hold our tabs[currentTab] object
@@ -57,17 +58,15 @@ function ButtonsContainer(): JSX.Element {
5758

5859
//adding a local state using useState for the reconnect button functionality
5960
const [reconnectDialogOpen, setReconnectDialogOpen] = useState(false);
60-
const [disconnectedDialogOpen, setDisconnectedDialogOpen] = useState(false);
6161

6262
//logic for handling dialog box opening and closing
6363
const handleReconnectClick = () => {
6464
setReconnectDialogOpen(true);
6565
}
6666

6767
const handleReconnectConfirm = () => {
68-
//reconnection logic here
69-
dispatch(startReconnect());
7068
handleReconnectCancel();
69+
dispatch(startReconnect());
7170
}
7271

7372
const handleReconnectCancel = () => {
@@ -127,7 +126,10 @@ function ButtonsContainer(): JSX.Element {
127126
<div className='close-icon-pop-up-div' >
128127
<CloseIcon type="button" onClick={() => handleReconnectCancel()} className='close-icon-pop-up'/>
129128
</div>
130-
<DialogTitle className='dialog-pop-up-header'>WARNING</DialogTitle>
129+
<div className="warning-header-container">
130+
<WarningIcon className='warning-icon-pop-up'/>
131+
<DialogTitle className='dialog-pop-up-header'>WARNING</DialogTitle>
132+
</div>
131133
<DialogContent className='dialog-pop-up-contents'>
132134
<h3>Status: {connectionStatus ? 'Connected' : 'Disconnected'}</h3>
133135
{connectionStatus

0 commit comments

Comments
 (0)