Skip to content

Commit b19dbf2

Browse files
committed
add marketplace testing
1 parent ea686a8 commit b19dbf2

File tree

7 files changed

+143
-59
lines changed

7 files changed

+143
-59
lines changed

__tests__/marketplace.test.tsx

Lines changed: 78 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -3,20 +3,30 @@ import '@testing-library/jest-dom/extend-expect';
33
import { fireEvent, render, screen } from '@testing-library/react';
44

55
import MarketplaceCard from '../app/src/components/marketplace/MarketplaceCard';
6+
import MarketplaceCardContainer from '../app/src/components/marketplace/MarketplaceCardContainer';
67
import { Provider } from 'react-redux';
78
import React from 'react';
9+
import SearchBar from '../app/src/components/marketplace/Searchbar';
810
import axios from 'axios';
911
import store from '../app/src/redux/store';
1012

1113
// Mocking the axios module to avoid actual network calls
1214
jest.mock('axios');
1315

14-
describe('MarketplaceCard', () => {
16+
describe('MarketplaceCard Render Test', () => {
1517
const mockProject = {
1618
_id: 123,
1719
name: 'Sample Project',
18-
username: 'user123'
19-
// ... other properties as needed
20+
username: 'user123',
21+
forked: 'false',
22+
comments: [],
23+
createdAt: new Date(),
24+
likes: 0,
25+
project: {
26+
id: 'sample-project-id'
27+
},
28+
published: true,
29+
userId: 123456
2030
};
2131

2232
it('displays project name and username', () => {
@@ -29,9 +39,6 @@ describe('MarketplaceCard', () => {
2939
expect(screen.getByText('Sample Project')).toBeInTheDocument();
3040
expect(screen.getByText('user123')).toBeInTheDocument();
3141
});
32-
33-
// You can also test handleClone and handleCloneOpen functionalities
34-
// e.g. using mock implementations for axios.get, dispatch, history.push, etc.
3542
});
3643

3744
describe('MarketplaceContainer', () => {
@@ -40,32 +47,86 @@ describe('MarketplaceContainer', () => {
4047
_id: 1,
4148
name: 'Project 1',
4249
username: 'user1'
43-
// ... other properties
4450
},
4551
{
4652
_id: 2,
4753
name: 'Project 2',
4854
username: 'user2'
49-
// ... other properties
5055
}
5156
];
5257

5358
beforeEach(() => {
5459
// Set up mock axios call for every test
55-
axios.get.mockResolvedValue({ data: mockProjects });
60+
axios.get = jest.fn().mockResolvedValue({ data: mockProjects });
5661
});
5762

58-
it('fetches and displays projects', async () => {
59-
render(<MarketplaceCard proj={undefined} />);
60-
61-
// Wait for the async axios call to complete and state to update
62-
const project1 = await screen.findByText('Project 1');
63-
const project2 = await screen.findByText('Project 2');
63+
it('renders multiple MarketplaceCards', () => {
64+
render(
65+
<Provider store={store}>
66+
<MarketplaceCardContainer displayProjects={mockProjects} />
67+
</Provider>
68+
);
6469

65-
expect(project1).toBeInTheDocument();
66-
expect(project2).toBeInTheDocument();
70+
expect(screen.getByText('Project 1')).toBeInTheDocument();
71+
expect(screen.getByText('user1')).toBeInTheDocument();
72+
expect(screen.getByText('Project 2')).toBeInTheDocument();
73+
expect(screen.getByText('user2')).toBeInTheDocument();
6774
});
6875

6976
// Additional tests can include: testing search bar functionality,
7077
// loading states, and no results found message.
7178
});
79+
80+
const mockProjects = [
81+
{
82+
name: 'Sample Project',
83+
username: 'user123'
84+
},
85+
{
86+
name: 'Test Project',
87+
username: 'user_test'
88+
},
89+
{
90+
name: 'Hello Project',
91+
username: 'hello_user'
92+
}
93+
];
94+
95+
describe('SearchBar Component', () => {
96+
it('updates the text field value on change', () => {
97+
const updateDisplayProjects = jest.fn();
98+
99+
render(
100+
<SearchBar
101+
marketplaceProjects={mockProjects}
102+
updateDisplayProjects={updateDisplayProjects}
103+
/>
104+
);
105+
106+
const textField = screen.getByLabelText('Search') as HTMLInputElement;
107+
fireEvent.change(textField, { target: { value: 'Sample' } });
108+
109+
expect(textField.value).toBe('Sample');
110+
});
111+
112+
it('filters projects by username', () => {
113+
const updateDisplayProjects = jest.fn();
114+
115+
render(
116+
<SearchBar
117+
marketplaceProjects={mockProjects}
118+
updateDisplayProjects={updateDisplayProjects}
119+
/>
120+
);
121+
122+
const textField = screen.getByLabelText('Search');
123+
fireEvent.change(textField, { target: { value: 'test' } });
124+
125+
// Using setImmediate to wait for useEffect to execute.
126+
setTimeout(() => {
127+
expect(updateDisplayProjects).toHaveBeenCalledWith([
128+
{ name: 'Test Project', username: 'user_test' }
129+
]);
130+
});
131+
});
132+
});

app/src/components/marketplace/MarketplaceCard.tsx

Lines changed: 34 additions & 26 deletions
Original file line numberDiff line numberDiff line change
@@ -12,52 +12,63 @@ import {
1212
Typography,
1313
styled
1414
} from '@mui/material';
15+
import React, { useEffect } from 'react';
16+
import {
17+
openProject,
18+
resetAllState
19+
} from '../../redux/reducers/slice/appStateSlice';
20+
import { useDispatch, useSelector } from 'react-redux';
1521

1622
import { MoreVert } from '@mui/icons-material';
17-
import React, { useEffect } from 'react';
23+
import { RootState } from '../../redux/store';
24+
import axios from 'axios';
1825
import imageSrc from '../../../../resources/marketplace_images/marketplace_image.png';
1926
import { red } from '@mui/material/colors';
20-
import axios from 'axios';
21-
import { useDispatch, useSelector } from 'react-redux'
22-
import { RootState } from '../../redux/store';
2327
import { saveProject } from '../../helperFunctions/projectGetSaveDel';
2428
import { useHistory } from 'react-router-dom';
25-
import { openProject, resetAllState } from '../../redux/reducers/slice/appStateSlice';
2629

2730
interface Project {
28-
forked: String,
29-
comments: string[]
30-
createdAt: Date
31-
likes: number
32-
name: string
33-
project: object
34-
published: boolean
35-
userId: number
36-
username: string
37-
_id: number
31+
forked: String;
32+
comments: string[];
33+
createdAt: Date;
34+
likes: number;
35+
name: string;
36+
project: object;
37+
published: boolean;
38+
userId: number;
39+
username: string;
40+
_id: number;
3841
}
3942

4043
const ITEM_HEIGHT = 48;
41-
const MarketplaceCard = ({proj} :{proj: Project}) => {
44+
const MarketplaceCard = ({ proj }: { proj: Project }) => {
4245
const dispatch = useDispatch();
4346
const history = useHistory();
4447
const [anchorEl, setAnchorEl] = React.useState<null | HTMLElement>(null);
4548
const open = Boolean(anchorEl);
46-
const state = useSelector((store:RootState) => store.appState);
49+
const state = useSelector((store: RootState) => store.appState);
4750
const handleClick = (event: React.MouseEvent<HTMLElement>) => {
4851
setAnchorEl(event.currentTarget);
4952
};
50-
const handleClone = async () => { // creates a copy of the project
53+
const handleClone = async () => {
54+
// creates a copy of the project
5155
const docId = proj._id;
52-
const response = await axios.get(`/cloneProject/${docId}`, { params: { username: window.localStorage.getItem('username') } });//passing in username as a query param is query params
56+
const response = await axios.get(`/cloneProject/${docId}`, {
57+
params: { username: window.localStorage.getItem('username') }
58+
}); //passing in username as a query param is query params
5359
const project = response.data;
54-
console.log('handleClone project', response.data)
60+
console.log('handleClone project', response.data);
5561
alert('Project cloned!');
5662
setAnchorEl(null);
57-
return {_id: project._id, name: project.name, published: project.published, ...project.project};
63+
return {
64+
_id: project._id,
65+
name: project.name,
66+
published: project.published,
67+
...project.project
68+
};
5869
};
59-
60-
const handleCloneOpen = async() => {
70+
71+
const handleCloneOpen = async () => {
6172
const project = await handleClone();
6273
history.push('/');
6374
dispatch(openProject(project));
@@ -66,9 +77,6 @@ const MarketplaceCard = ({proj} :{proj: Project}) => {
6677
setAnchorEl(null);
6778
};
6879

69-
70-
71-
7280
return (
7381
<>
7482
<Card

app/src/components/marketplace/MarketplaceCardContainer.tsx

Lines changed: 3 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -3,10 +3,7 @@ import { Container, Grid } from '@mui/material';
33
import MarketplaceCard from './MarketplaceCard';
44
import React from 'react';
55

6-
7-
const MarketplaceCardContainer = ({displayProjects}) => {
8-
9-
6+
const MarketplaceCardContainer = ({ displayProjects }) => {
107
return (
118
<>
129
<Container>
@@ -17,9 +14,8 @@ const MarketplaceCardContainer = ({displayProjects}) => {
1714
columns={{ xs: 4, sm: 8, md: 12 }}
1815
>
1916
{displayProjects.map((proj, i) => (
20-
21-
<Grid item xs={4} sm={4} md={4} key={i}>
22-
<MarketplaceCard proj={proj}/>
17+
<Grid item xs={4} sm={4} md={4} key={proj._id}>
18+
<MarketplaceCard proj={proj} />
2319
</Grid>
2420
))}
2521
</Grid>

app/src/interfaces/Interfaces.ts

Lines changed: 17 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -113,9 +113,9 @@ export interface AddRoutes {
113113
}
114114

115115
export interface ManageSeparators {
116-
mergeSeparator: (arg1:ChildElement[], arg2?:number) => any; // update specificity
116+
mergeSeparator: (arg1: ChildElement[], arg2?: number) => any; // update specificity
117117
handleSeparators: (arg1: ChildElement[], arg2?: string) => number;
118-
nextTopSeparatorId: number
118+
nextTopSeparatorId: number;
119119
}
120120

121121
export interface StateUsed {
@@ -133,15 +133,24 @@ export interface Attributes {
133133
}
134134

135135
// interface PublishResponse {
136-
// success: boolean;
136+
// success: boolean;
137137
// error?: string;
138138
// }
139139

140-
141140
export interface Arrow {
142141
renderArrow: (id: number) => any;
143142
deleteLines: () => void;
144-
lineDraw: (x1:number, y1:number,x2:number,y2:number) => void;
145-
createHeadElement:(x:number, y:number,length:number,angle:number) => HTMLDivElement;
146-
createLineElement: (x:number, y:number,length:number,angle:number) => HTMLDivElement;
147-
}
143+
lineDraw: (x1: number, y1: number, x2: number, y2: number) => void;
144+
createHeadElement: (
145+
x: number,
146+
y: number,
147+
length: number,
148+
angle: number
149+
) => HTMLDivElement;
150+
createLineElement: (
151+
x: number,
152+
y: number,
153+
length: number,
154+
angle: number
155+
) => HTMLDivElement;
156+
}

app/src/interfaces/declarations.d.ts

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
declare module '*.png';
2+
declare module '*.jpg';
3+
declare module '*.jpeg';
4+
declare module '*.svg';
5+
declare module '*.gif';

app/src/interfaces/global.ts

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4,4 +4,5 @@ declare global {
44
api: any;
55
}
66
}
7+
78
let api = window.api;

tsconfig.json

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -17,5 +17,9 @@
1717
"noEmitOnError": false
1818
},
1919
// only compile ts files in this directory
20-
"include": ["app/src/**/*","server/**/*"],
20+
"include": [
21+
"app/src/**/*",
22+
"app/src/interfaces/declarations.d.ts",
23+
"server/**/*"
24+
]
2125
}

0 commit comments

Comments
 (0)