Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions .eslintrc.js
Original file line number Diff line number Diff line change
Expand Up @@ -52,5 +52,6 @@ module.exports = {
'react/prop-types': 'off',
'linebreak-style': 'off',
'no-proto': 'off',
'no-param-reassign': ['error', { props: true, ignorePropertyModificationsFor: ['draft'] }],
},
};
13 changes: 10 additions & 3 deletions package-lock.json

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

7 changes: 4 additions & 3 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -31,18 +31,19 @@
"draft-js": "^0.11.7",
"draftjs-to-html": "^0.9.1",
"firebase": "^8.1.1",
"immer": "^8.0.0",
"moment": "^2.29.1",
"moment-timezone": "^0.5.32",
"qs": "^6.9.4",
"react": "^17.0.1",
"redux-devtools-extension": "^2.13.8",
"react-dom": "^17.0.1",
"react-draft-wysiwyg": "^1.14.5",
"redux-logger": "^3.0.6",
"react-moment": "^1.0.0",
"react-redux": "^7.2.2",
"react-router-dom": "^5.2.0",
"redux": "^4.0.5"
"redux": "^4.0.5",
"redux-devtools-extension": "^2.13.8",
"redux-logger": "^3.0.6"
},
"devDependencies": {
"@babel/core": "^7.12.3",
Expand Down
13 changes: 11 additions & 2 deletions src/App.test.jsx
Original file line number Diff line number Diff line change
Expand Up @@ -27,6 +27,15 @@ describe('App', () => {
writeField: {
tags: [],
},
register: {
userEmail: '',
password: '',
passwordConfirm: '',
},
login: {
userEmail: '',
password: '',
},
}));
});

Expand Down Expand Up @@ -67,15 +76,15 @@ describe('App', () => {
it('renders the study login page', () => {
const { container } = renderApp({ path: '/login' });

expect(container).toHaveTextContent('Login');
expect(container).toHaveTextContent('로그인');
});
});

context('with path /register', () => {
it('renders the study register page', () => {
const { container } = renderApp({ path: '/register' });

expect(container).toHaveTextContent('Register');
expect(container).toHaveTextContent('회원가입');
});
});
});
60 changes: 49 additions & 11 deletions src/components/auth/AuthForm.jsx
Original file line number Diff line number Diff line change
@@ -1,20 +1,58 @@
import React from 'react';

import styled from '@emotion/styled';

import Responsive from '../../styles/Responsive';

const AuthFormWrapper = styled(Responsive)``;

const AuthForm = ({ type }) => (
<AuthFormWrapper>
<h2>{type}</h2>
<input type="text" placeholder="이메일" />
<input type="password" placeholder="비밀번호" />
{type === 'Register' && (
<input type="password" placeholder="비밀번호 확인" />
)}

</AuthFormWrapper>
);
const FORM_TYPE = {
login: '로그인',
register: '회원가입',
};

const AuthForm = ({ type, onChange, fields }) => {
const formType = FORM_TYPE[type];

const { userEmail, password } = fields;

const handleChange = (e) => {
const { name, value } = e.target;

onChange({ name, value });
};

return (
<AuthFormWrapper>
<h2>{formType}</h2>
<input
type="text"
value={userEmail}
name="userEmail"
placeholder="이메일"
autoComplete="email"
onChange={handleChange}
/>
Comment on lines +28 to +35
Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

  • input을 컴포넌트를 따로 빼도 좋을거 같다.

<input
type="password"
value={password}
name="password"
placeholder="비밀번호"
autoComplete="password"
onChange={handleChange}
/>
{type === 'register' && (
<input
type="password"
value={fields.passwordConfirm}
name="passwordConfirm"
placeholder="비밀번호 확인"
autoComplete="new-password"
onChange={handleChange}
/>
)}
</AuthFormWrapper>
);
};

export default AuthForm;
72 changes: 65 additions & 7 deletions src/components/auth/AuthForm.test.jsx
Original file line number Diff line number Diff line change
@@ -1,40 +1,98 @@
import React from 'react';

import { render } from '@testing-library/react';
import { render, fireEvent } from '@testing-library/react';

import AuthForm from './AuthForm';

describe('AuthForm', () => {
const renderAuthForm = ({ type }) => render((
<AuthForm type={type} />
const handleChange = jest.fn();

beforeEach(() => {
handleChange.mockClear();
});

const renderAuthForm = ({ type, fields }) => render((
<AuthForm
type={type}
fields={fields}
onChange={handleChange}
/>
));

context('when type is login', () => {
const login = {
type: 'Login',
type: 'login',
fields: {
userEmail: 'tktmdals@naver.com',
password: '1234',
},
};

it('renders login form text', () => {
const { container, getByPlaceholderText } = renderAuthForm(login);

expect(container).toHaveTextContent('Login');
expect(container).toHaveTextContent('로그인');
expect(getByPlaceholderText('이메일')).not.toBeNull();
expect(getByPlaceholderText('비밀번호')).not.toBeNull();
});

it('listens event call change', () => {
const { getByPlaceholderText } = renderAuthForm(login);

const inputs = [
{ value: 'seungmin@naver.com', name: 'userEmail', placeholder: '이메일' },
{ value: '345', name: 'password', placeholder: '비밀번호' },
];

inputs.forEach(({ name, value, placeholder }) => {
const field = getByPlaceholderText(placeholder);

expect(field).not.toBeNull();

fireEvent.change(field, { target: { value, name } });

expect(handleChange).toBeCalled();
});
});
});

context('when type is register', () => {
const register = {
type: 'Register',
type: 'register',
fields: {
userEmail: 'tktmdals@naver.com',
password: '1234',
passwordConfirm: '1234',
},
};

it('renders register form text', () => {
const { container, getByPlaceholderText } = renderAuthForm(register);

expect(container).toHaveTextContent('Register');
expect(container).toHaveTextContent('회원가입');
expect(getByPlaceholderText('이메일')).not.toBeNull();
expect(getByPlaceholderText('비밀번호')).not.toBeNull();
expect(getByPlaceholderText('비밀번호 확인')).not.toBeNull();
});

it('listens event call change', () => {
const { getByPlaceholderText } = renderAuthForm(register);

const inputs = [
{ value: 'seungmin@naver.com', name: 'userEmail', placeholder: '이메일' },
{ value: '345', name: 'password', placeholder: '비밀번호' },
{ value: '345', name: 'passwordConfirm', placeholder: '비밀번호 확인' },
];

inputs.forEach(({ name, value, placeholder }) => {
const field = getByPlaceholderText(placeholder);

expect(field).not.toBeNull();

fireEvent.change(field, { target: { value, name } });

expect(handleChange).toBeCalled();
});
});
});
});
34 changes: 34 additions & 0 deletions src/containers/auth/LoginFormContainer.jsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,34 @@
import React, { useCallback } from 'react';

import { useSelector, useDispatch } from 'react-redux';

import { get } from '../../util/utils';
import { changeAuthField } from '../../reducers/slice';

import AuthForm from '../../components/auth/AuthForm';

const LoginFormContainer = () => {
const dispatch = useDispatch();

const login = useSelector(get('login'));

const onChangeLoginField = useCallback(({ name, value }) => {
dispatch(
changeAuthField({
form: 'login',
name,
value,
}),
);
});

return (
<AuthForm
type="login"
fields={login}
onChange={onChangeLoginField}
/>
);
};

export default LoginFormContainer;
63 changes: 63 additions & 0 deletions src/containers/auth/LoginFormContainer.test.jsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,63 @@
import React from 'react';

import { useDispatch, useSelector } from 'react-redux';

import { render, fireEvent } from '@testing-library/react';

import LoginFormContainer from './LoginFormContainer';

describe('LoginFormContainer', () => {
const dispatch = jest.fn();

beforeEach(() => {
dispatch.mockClear();
useDispatch.mockImplementation(() => dispatch);

useSelector.mockImplementation((selector) => selector({
login: {
userEmail: '',
password: '',
},
}));
});

const renderLoginFormContainer = () => render((
<LoginFormContainer />
));

it('renders login form text', () => {
const { container, getByPlaceholderText } = renderLoginFormContainer();

expect(container).toHaveTextContent('로그인');
expect(getByPlaceholderText('이메일')).not.toBeNull();
expect(getByPlaceholderText('비밀번호')).not.toBeNull();
});

describe('action dispatch in login page', () => {
it('change event calls dispatch', () => {
const { getByPlaceholderText } = renderLoginFormContainer();

const inputs = [
{ value: 'seungmin@naver.com', name: 'userEmail', placeholder: '이메일' },
{ value: '345', name: 'password', placeholder: '비밀번호' },
];

inputs.forEach(({ name, value, placeholder }) => {
const field = getByPlaceholderText(placeholder);

expect(field).not.toBeNull();

fireEvent.change(field, { target: { value, name } });

expect(dispatch).toBeCalledWith({
type: 'application/changeAuthField',
payload: {
form: 'login',
name,
value,
},
});
});
});
});
});
Loading