diff --git a/fake-server/db.json b/fake-server/db.json
index 52c6d41..e88ad8c 100644
--- a/fake-server/db.json
+++ b/fake-server/db.json
@@ -18,7 +18,6 @@
"contents": "우리는 이것저것 합니다.1",
"tags": [
"JavaScript",
- "React",
"Algorithm"
]
},
@@ -34,8 +33,7 @@
"contents": "우리는 이것저것 합니다.2",
"tags": [
"JavaScript",
- "React",
- "Algorithm"
+ "React"
]
},
{
@@ -52,7 +50,6 @@
"contents": "우리는 이것저것 합니다.3",
"tags": [
"JavaScript",
- "React",
"Algorithm"
]
},
@@ -97,7 +94,6 @@
"personnel": 9,
"contents": "우리는 이것저것 합니다.5",
"tags": [
- "JavaScript",
"React",
"Algorithm"
]
@@ -137,8 +133,7 @@
"contents": "우리는 이것저것 합니다.7",
"tags": [
"JavaScript",
- "React",
- "Algorithm"
+ "React"
]
},
{
@@ -343,7 +338,7 @@
"tags": [
"JavaScript",
"React",
- "Algorithm"
+ "C"
]
},
{
@@ -364,7 +359,7 @@
"tags": [
"JavaScript",
"React",
- "Algorithm"
+ "C"
]
},
{
@@ -379,7 +374,6 @@
"contents": "우리는 이것저것 합니다.19",
"tags": [
"JavaScript",
- "React",
"Algorithm"
]
},
@@ -416,9 +410,8 @@
"personnel": 8,
"contents": "우리는 이것저것 합니다.21",
"tags": [
- "JavaScript",
"React",
- "Algorithm"
+ "Java"
]
}
],
diff --git a/fixtures/study-groups.js b/fixtures/study-groups.js
index 1ba2d65..edcd3b0 100644
--- a/fixtures/study-groups.js
+++ b/fixtures/study-groups.js
@@ -32,7 +32,6 @@ const studyGroups = [
personnel: 2,
contents: '우리는 이것저것 합니다.2',
tags: [
- 'JavaScript',
'React',
'Algorithm',
],
diff --git a/package-lock.json b/package-lock.json
index 0c888ac..9836a72 100644
--- a/package-lock.json
+++ b/package-lock.json
@@ -11019,10 +11019,9 @@
}
},
"qs": {
- "version": "6.5.2",
- "resolved": "https://registry.npmjs.org/qs/-/qs-6.5.2.tgz",
- "integrity": "sha512-N5ZAX4/LxJmF+7wN74pUD6qAh9/wnvdQcjq9TZjevvXzSUo7bfmw91saqMjzGS2xq91/odN2dW/WOl7qQHNDGA==",
- "dev": true
+ "version": "6.9.4",
+ "resolved": "https://registry.npmjs.org/qs/-/qs-6.9.4.tgz",
+ "integrity": "sha512-A1kFqHekCTM7cz0udomYUoYNWjBebHm/5wzU/XqrBRBNWectVH0QIiN+NEcZ0Dte5hvzHwbr8+XQmguPhJ6WdQ=="
},
"querystring": {
"version": "0.2.0",
@@ -11645,6 +11644,12 @@
"uuid": "^3.3.2"
},
"dependencies": {
+ "qs": {
+ "version": "6.5.2",
+ "resolved": "https://registry.npmjs.org/qs/-/qs-6.5.2.tgz",
+ "integrity": "sha512-N5ZAX4/LxJmF+7wN74pUD6qAh9/wnvdQcjq9TZjevvXzSUo7bfmw91saqMjzGS2xq91/odN2dW/WOl7qQHNDGA==",
+ "dev": true
+ },
"tough-cookie": {
"version": "2.5.0",
"resolved": "https://registry.npmjs.org/tough-cookie/-/tough-cookie-2.5.0.tgz",
diff --git a/package.json b/package.json
index 0c81c53..e3f3f95 100644
--- a/package.json
+++ b/package.json
@@ -30,6 +30,7 @@
"axios": "^0.21.0",
"moment": "^2.29.1",
"moment-timezone": "^0.5.32",
+ "qs": "^6.9.4",
"react": "^17.0.1",
"react-dom": "^17.0.1",
"react-moment": "^1.0.0",
diff --git a/src/components/common/Tags.jsx b/src/components/common/Tags.jsx
index 501ad44..ded60d3 100644
--- a/src/components/common/Tags.jsx
+++ b/src/components/common/Tags.jsx
@@ -8,7 +8,7 @@ import palette from '../../styles/palette';
const TagsWrapper = styled.div`
margin-top: 1rem;
- .lang {
+ .tag {
display: inline-flex;
align-items: center;
padding-left: .6em;
@@ -36,8 +36,8 @@ const Tags = ({ tags }) => {
{tags.map((tag) => (
{`#${tag}`}
diff --git a/src/components/common/Tags.test.jsx b/src/components/common/Tags.test.jsx
index cd31af0..de58794 100644
--- a/src/components/common/Tags.test.jsx
+++ b/src/components/common/Tags.test.jsx
@@ -16,13 +16,14 @@ describe('Tags', () => {
));
context('with tags', () => {
+ const tags = ['JavaScript', 'C', 'Python'];
it('renders tags name', () => {
- const tags = ['JavaScript', 'C', 'Python'];
-
const { container } = renderTags(tags);
tags.forEach((tag) => {
expect(container).toHaveTextContent(tag);
+
+ expect(container.innerHTML).toContain(' {
+ const { search } = useLocation();
+
+ const dispatch = useDispatch();
const groups = useSelector(get('groups'));
+ useEffect(() => {
+ const { tag } = qs.parse(search, {
+ ignoreQueryPrefix: true,
+ });
+
+ dispatch(loadStudyGroups(tag));
+ }, [dispatch, search]);
+
if (!groups || !groups.length) {
return 스터디가 존재하지 않습니다.
;
}
diff --git a/src/containers/groups/StudyGroupsContainer.test.jsx b/src/containers/groups/StudyGroupsContainer.test.jsx
index fa46e8a..3eed582 100644
--- a/src/containers/groups/StudyGroupsContainer.test.jsx
+++ b/src/containers/groups/StudyGroupsContainer.test.jsx
@@ -3,10 +3,19 @@ import React from 'react';
import { useDispatch, useSelector } from 'react-redux';
import { MemoryRouter } from 'react-router-dom';
-import { render } from '@testing-library/react';
+import { render, fireEvent } from '@testing-library/react';
import StudyGroupsContainer from './StudyGroupsContainer';
+const mockSearch = jest.fn();
+
+jest.mock('react-router-dom', () => ({
+ ...jest.requireActual('react-router-dom'),
+ useLocation() {
+ return { search: mockSearch };
+ },
+}));
+
describe('StudyGroupsContainer', () => {
const dispatch = jest.fn();
@@ -31,6 +40,7 @@ describe('StudyGroupsContainer', () => {
moderatorId: 'user1',
title: '소개합니다.',
participants: [],
+ tags: ['JavaScript'],
}]));
it('renders groups title', () => {
@@ -38,6 +48,14 @@ describe('StudyGroupsContainer', () => {
expect(container).toHaveTextContent('소개합니다.');
});
+
+ it('click event calls dispatch', () => {
+ const { getByText } = renderStudyGroupsContainer();
+
+ fireEvent.click(getByText('#JavaScript'));
+
+ expect(dispatch).toBeCalled();
+ });
});
context('without groups', () => {
diff --git a/src/pages/MainPage.jsx b/src/pages/MainPage.jsx
index 457f483..b8c25b2 100644
--- a/src/pages/MainPage.jsx
+++ b/src/pages/MainPage.jsx
@@ -1,10 +1,7 @@
-import React, { useEffect } from 'react';
-
-import { useDispatch } from 'react-redux';
+import React from 'react';
import styled from '@emotion/styled';
-import { loadStudyGroups } from '../reducers/slice';
import StudyGroupsContainer from '../containers/groups/StudyGroupsContainer';
import Responsive from '../styles/Responsive';
@@ -12,19 +9,11 @@ const MainPageWrapper = styled(Responsive)`
`;
-const MainPage = () => {
- const dispatch = useDispatch();
-
- useEffect(() => {
- dispatch(loadStudyGroups());
- }, []);
-
- return (
-
- 지금 바로 시작하세요!
-
-
- );
-};
+const MainPage = () => (
+
+ 지금 바로 시작하세요!
+
+
+);
export default MainPage;
diff --git a/src/pages/MainPage.test.jsx b/src/pages/MainPage.test.jsx
index a7bd0ed..f1366e3 100644
--- a/src/pages/MainPage.test.jsx
+++ b/src/pages/MainPage.test.jsx
@@ -2,11 +2,12 @@ import React from 'react';
import { useDispatch, useSelector } from 'react-redux';
-import { render } from '@testing-library/react';
+import { render, fireEvent } from '@testing-library/react';
-import MainPage from './MainPage';
+import { MemoryRouter } from 'react-router-dom';
-jest.mock('react-redux');
+import MainPage from './MainPage';
+import STUDY_GROUPS from '../../fixtures/study-groups';
describe('MainPage', () => {
const dispatch = jest.fn();
@@ -16,13 +17,15 @@ describe('MainPage', () => {
useDispatch.mockImplementation(() => dispatch);
useSelector.mockImplementation((selector) => selector({
- groups: [],
+ groups: STUDY_GROUPS,
}));
});
- const renderMainPage = () => render(
- ,
- );
+ const renderMainPage = () => render((
+
+
+
+ ));
it('renders Main Page Title', () => {
const { container } = renderMainPage();
@@ -31,7 +34,18 @@ describe('MainPage', () => {
});
it('calls dispatch with loadStudyGroups action', () => {
- renderMainPage();
+ const { container } = renderMainPage();
+
+ expect(dispatch).toBeCalled();
+
+ expect(container).toHaveTextContent('스터디를 소개합니다.1');
+ expect(container).toHaveTextContent('스터디를 소개합니다.2');
+ });
+
+ it('Click event to calls dispatch', () => {
+ const { getByText } = renderMainPage();
+
+ fireEvent.click(getByText('#JavaScript'));
expect(dispatch).toBeCalled();
});
diff --git a/src/reducers/slice.js b/src/reducers/slice.js
index b671dd4..651224e 100644
--- a/src/reducers/slice.js
+++ b/src/reducers/slice.js
@@ -12,10 +12,16 @@ const { actions, reducer } = createSlice({
group: null,
},
reducers: {
- setStudyGroups(state, { payload: groups }) {
+ setStudyGroups(state, { payload: { groups, tag } }) {
return {
...state,
- groups,
+ groups: tag ? groups.reduce((studies, group) => {
+ if (group.tags.includes(tag)) {
+ return [...studies, group];
+ }
+
+ return studies;
+ }, []) : groups,
};
},
setStudyGroup(state, { payload: group }) {
@@ -32,10 +38,10 @@ export const {
setStudyGroup,
} = actions;
-export const loadStudyGroups = () => async (dispatch) => {
+export const loadStudyGroups = (tag) => async (dispatch) => {
const groups = await getStudyGroups();
- dispatch(setStudyGroups(groups));
+ dispatch(setStudyGroups({ groups, tag }));
};
export const loadStudyGroup = (id) => async (dispatch) => {
diff --git a/src/reducers/slice.test.js b/src/reducers/slice.test.js
index cf8fb2f..4935970 100644
--- a/src/reducers/slice.test.js
+++ b/src/reducers/slice.test.js
@@ -33,14 +33,34 @@ describe('reducer', () => {
});
describe('setStudyGroups', () => {
- it('changes groups', () => {
- const initialState = {
- groups: [],
- };
+ context('with tag', () => {
+ it('get study groups list with tags filtered', () => {
+ const initialState = {
+ groups: [],
+ };
+
+ const state = reducer(
+ initialState,
+ setStudyGroups({ groups: STUDY_GROUPS, tag: 'JavaScript' }),
+ );
+
+ expect(state.groups).toHaveLength(1);
+ });
+ });
- const state = reducer(initialState, setStudyGroups(STUDY_GROUPS));
+ context('without tag', () => {
+ it("get study groups list doesn't tags filtered", () => {
+ const initialState = {
+ groups: [],
+ };
- expect(state.groups).toHaveLength(2);
+ const state = reducer(
+ initialState,
+ setStudyGroups({ groups: STUDY_GROUPS, tag: '' }),
+ );
+
+ expect(state.groups).toHaveLength(2);
+ });
});
});
@@ -65,16 +85,19 @@ describe('async actions', () => {
store = mockStore({});
});
- it('loads groups', async () => {
+ it('loads study group list', async () => {
await store.dispatch(loadStudyGroups());
const actions = store.getActions();
- expect(actions[0]).toEqual(setStudyGroups([]));
+ expect(actions[0]).toEqual(setStudyGroups({
+ groups: [],
+ tag: undefined,
+ }));
});
});
- describe('loadStudyGroups', () => {
+ describe('loadStudyGroup', () => {
beforeEach(() => {
store = mockStore({});
});