Skip to content

Commit

Permalink
(feat): userLogin
Browse files Browse the repository at this point in the history
- user should be able to login
- user should receive appropriate error message

[Finishes #171380695]
  • Loading branch information
Ugizwenayo-Divine committed Jun 12, 2020
1 parent 8c78fbd commit 14e3e20
Show file tree
Hide file tree
Showing 35 changed files with 13,578 additions and 40 deletions.
6 changes: 6 additions & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -20,3 +20,9 @@ yarn-error.log

#test coverage
coverage
# Logs
logs
*.log
npm-debug.log*
yarn-debug.log*
yarn-error.log*
2 changes: 1 addition & 1 deletion .travis.yml
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,7 @@ install:
- yarn

script:
- yarn test
- yarn test --updateSnapshot

notification:
- email: false
Expand Down
2 changes: 2 additions & 0 deletions debug.log
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
[0609/102203.692:ERROR:process_info.cc(98)] ReadProcessMemory UNICODE_STRING: Only part of a ReadProcessMemory or WriteProcessMemory request was completed. (0x12B)
[0609/102204.114:ERROR:process_info.cc(551)] ReadProcessData failed
16 changes: 14 additions & 2 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -13,8 +13,7 @@
"coverage": "codeclimate-test-reporter < ./coverage/lcov.info"
},
"engines": {
"yarn": "1.x",
"node": "14.x"
"yarn": "1.x"
},
"repository": {
"type": "git",
Expand All @@ -34,21 +33,32 @@
"homepage": "https://github.com/Stackup-Rwanda/stackup2-barefoot-frontend#readme",
"dependencies": {
"@babel/core": "^7.9.6",
"@babel/plugin-transform-runtime": "^7.10.1",
"@babel/polyfill": "^7.10.1",
"@babel/preset-env": "^7.9.6",
"@babel/preset-react": "^7.9.4",
"@babel/runtime": "^7.10.2",
"@fortawesome/fontawesome-svg-core": "^1.2.28",
"@fortawesome/free-brands-svg-icons": "^5.13.0",
"@fortawesome/free-solid-svg-icons": "^5.13.0",
"@fortawesome/react-fontawesome": "^0.1.9",
"@material-ui/core": "^4.10.0",
"@material-ui/icons": "^4.9.1",
"@material-ui/styles": "^4.10.0",
"@storybook/addon-actions": "^5.3.18",
"@storybook/addon-links": "^5.3.18",
"@storybook/addons": "^5.3.18",
"@storybook/react": "^5.3.18",
"@testing-library/react": "^10.0.4",
"axios": "^0.19.2",
"babel-eslint": "^10.1.0",
"babel-jest": "^26.0.1",
"babel-loader": "^8.1.0",
"babel-plugin-transform-class-properties": "^6.24.1",
"codeclimate-test-reporter": "^0.5.1",
"css-loader": "^3.5.3",
"dotenv": "^8.2.0",
"dotenv-webpack": "^1.8.0",
"enzyme": "^3.11.0",
"enzyme-adapter-react-16": "^1.15.2",
"enzyme-to-json": "^3.4.4",
Expand All @@ -64,12 +74,14 @@
"react": "^16.13.1",
"react-dom": "^16.13.1",
"react-redux": "^7.2.0",
"react-router": "^5.2.0",
"react-router-dom": "^5.2.0",
"react-test-renderer": "^16.13.1",
"redux": "^4.0.5",
"redux-devtools-extension": "^2.13.8",
"redux-mock-store": "^1.5.4",
"redux-thunk": "^2.3.0",
"regenerator-runtime": "^0.13.5",
"style-loader": "^1.2.1",
"webpack": "^4.43.0",
"webpack-cli": "^3.3.11",
Expand Down
13 changes: 10 additions & 3 deletions src/__tests__/App.test.js
Original file line number Diff line number Diff line change
Expand Up @@ -2,13 +2,14 @@
/* eslint-disable no-undef */
import { mount, shallow } from 'enzyme';
import React from 'react';
import 'regenerator-runtime/runtime';
import { Provider } from 'react-redux';
import renderer from 'react-test-renderer';
import configureStore from 'redux-mock-store';
import App from '../entry/App';
import LandingPage from '../views/LandingPage/LandingPage';
import reducer from '../reducers/reducer';
import firstMessage from '../actions/actions';
import reducer from '../redux/login/reducer';
import firstMessage from '../redux/actions/actions';

const mockStore = configureStore([]);
const store = mockStore({
Expand All @@ -20,14 +21,20 @@ const component = renderer.create(
<LandingPage />
</Provider>,
);
const initialObj = {
errors: '',
message: 'Welcome',
success: false,
token: '',
};
describe('App tests', () => {
it('Will prove that the app is rendered from App component', () => {
const appRender = shallow(<App />);
expect(appRender.contains(<LandingPage />));
});

it('should return welcome when no action provided', () => {
expect(reducer(undefined, {})).toEqual({ message: 'Welcome' });
expect(reducer(undefined, {})).toEqual(initialObj);
});
it('should return Redux when action is provided with value', () => {
expect(reducer(undefined, { ...firstMessage, value: 'Redux' })).toEqual({ message: 'Redux' });
Expand Down
3 changes: 2 additions & 1 deletion src/__tests__/NavBar.test.js
Original file line number Diff line number Diff line change
@@ -1,13 +1,14 @@
/* eslint-disable no-undef */
import React from 'react';
import renderer from 'react-test-renderer';
import { BrowserRouter as Router } from 'react-router-dom';
import { cleanup } from '@testing-library/react';
import NavBar from '../views/NavBar/NavBar';

describe('<NavBar/>', () => {
afterEach(cleanup);
it('Should match the NavBar component snapshot', () => {
const tree = renderer.create(<NavBar />).toJSON();
const tree = renderer.create(<Router><NavBar /></Router>).toJSON();
expect(tree).toMatchSnapshot();
});
});
3 changes: 2 additions & 1 deletion src/__tests__/__snapshots__/NavBar.test.js.snap
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@

exports[`<NavBar/> Should match the NavBar component snapshot 1`] = `
<div
className="makeStyles-root-1"
className="jss1"
>
<header
className="MuiPaper-root MuiAppBar-root MuiAppBar-positionStatic MuiAppBar-colorPrimary navbar MuiPaper-elevation4"
Expand Down Expand Up @@ -31,6 +31,7 @@ exports[`<NavBar/> Should match the NavBar component snapshot 1`] = `
className="MuiTypography-root MuiLink-root MuiLink-underlineHover navlink MuiTypography-colorPrimary"
href="/login"
onBlur={[Function]}
onClick={[Function]}
onFocus={[Function]}
>
Login
Expand Down
14 changes: 14 additions & 0 deletions src/__tests__/action/__snapshots__/loginAction.test.js.snap
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
// Jest Snapshot v1, https://goo.gl/fbAQLP

exports[`login actions Dispatches the correct action and payload 1`] = `Array []`;

exports[`login actions Dispatches the correct action and payload of wrong email 1`] = `
Array [
Object {
"payload": Object {
"error": "Invalid email",
},
"type": "LOGIN_HANDLE",
},
]
`;
31 changes: 31 additions & 0 deletions src/__tests__/action/loginAction.test.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,31 @@
/* eslint-disable no-undef */
import 'regenerator-runtime/runtime';
import configureStore from 'redux-mock-store';
import thunk from 'redux-thunk';
import handleLogin from '../../redux/login/loginActions';

const mockStore = configureStore([thunk]);
const store = mockStore();

global.fetch = jest.fn(() => Promise.resolve({
json: () => Promise.resolve({}),
}));
describe('login actions', () => {
beforeEach(() => {
store.clearActions();
});
test('Dispatches the correct action and payload', () => {
store.dispatch(handleLogin({
email: '[email protected]',
password: 'Diny@2020',
}));
expect(store.getActions()).toMatchSnapshot();
});
test('Dispatches the correct action and payload of wrong email', () => {
store.dispatch(handleLogin({
email: 'din',
password: 'Diny@2020',
}));
expect(store.getActions()).toMatchSnapshot();
});
});
69 changes: 69 additions & 0 deletions src/__tests__/component/login.test.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,69 @@
/* eslint-disable no-undef */
import { mount } from 'enzyme';
import React from 'react';
import 'regenerator-runtime/runtime';
import { Provider } from 'react-redux';
import configureStore from 'redux-mock-store';
import TextField from '@material-ui/core/TextField';
import Login, {
mapDispatchToProps,
mapStateToProps,
} from '../../components/forms/UserLogin';
import InputField from '../../components/forms/InputField';
import Lines from '../../components/forms/Lines';
import Links from '../../components/forms/Link';
import SubmitButton from '../../components/forms/SubmitButton';
import SocialLogin from '../../components/forms/SocialLogin';

const defaultProps = {
errors: '',
success: false,
token: '',
};
const mockStore = configureStore([]);
const store = mockStore({
message: 'Welcome',
errors: '',
success: false,
token: '',
});
store.dispatch = jest.fn();

describe('App tests', () => {
it('rendering the user login component', () => {
const submit = jest.fn();
const change = jest.fn();
const chi = 'forget Password?';
const login = mount(<Provider store={store}><Login /></Provider>);
expect(login.contains(
<InputField name="email" handleLoginChange={change} />,
<SubmitButton submitForm={submit}>Login</SubmitButton>,
<Links>{chi}</Links>,
<Lines />,
<SocialLogin />,
));
});
it('login', () => {
const event = {
preventDefault() {},
target: { value: '[email protected]' },
};
const dispatch = jest.fn();
mapDispatchToProps(dispatch).login();
mapStateToProps({ defaultProps });
const wrapper = mount(<Provider store={store}><Login /></Provider>);

wrapper
.find(TextField)
.at(0)
.simulate('change', event);
wrapper
.find(TextField)
.at(1)
.simulate('change', { target: { value: 'Example@2020' } });
wrapper
.find(SubmitButton)
.simulate('click');
expect(dispatch).toBeCalledTimes(1);
});
});
26 changes: 26 additions & 0 deletions src/__tests__/helpers/loginHelper.test.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,26 @@
/* eslint-disable no-undef */
import 'regenerator-runtime/runtime';
import userLogin from '../../helpers/userLogin';

describe('login helpers', () => {
it('login functionality success', async () => {
const credentials = {
email: '[email protected]',
password: 'TravelAdmin2@',
};
global.fetch = jest.fn(() => Promise.resolve({
json: () => Promise.resolve({}),
}));
await userLogin(credentials);
expect(fetch).toHaveBeenCalledTimes(1);
});
it('login functionality fail', async () => {
const credentials = {
email: 'travel',
password: 'Travel',
};
global.fetch = jest.fn(() => Promise.reject());
await userLogin(credentials);
expect(fetch).toHaveBeenCalledTimes(1);
});
});
18 changes: 18 additions & 0 deletions src/__tests__/reducer/loginReducer.test.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
/* eslint-disable no-undef */
import 'regenerator-runtime/runtime';
import reducer, { initialState } from '../../redux/login/reducer';
import LOGIN_HANDLE from '../../redux/login/loginTypes';


describe('', () => {
it('should return Redux when action is provided with value', () => {
const payload = {
error: 'invalid email',
};
const expected = {
...initialState,
errors: payload.error,
};
expect(reducer(undefined, { type: LOGIN_HANDLE, payload })).toEqual(expected);
});
});
Binary file added src/assets/HomePic.jpg
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
21 changes: 20 additions & 1 deletion src/assets/styles/css/index.css
Original file line number Diff line number Diff line change
@@ -1,5 +1,24 @@
h1 {
font-family: Arial, Helvetica, sans-serif;
text-align: center;
padding: 20px;
font-size: larger;
}
body{
height: 100%;
}
.span {
color: red;
}
.main{
width: 100% ;
padding-top: 1.5%;
box-sizing: border-box;
background-image: url("../../HomePic.jpg");
height: 100%;
background-position: center;
background-repeat: no-repeat;
background-size: cover;
}
.main h1{
color: white;
}
44 changes: 44 additions & 0 deletions src/components/forms/InputField.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,44 @@
import React from 'react';
import TextField from '@material-ui/core/TextField';
import { makeStyles } from '@material-ui/core/styles';
import PropTypes from 'prop-types';

const useStyles = makeStyles({
textField: {
marginBottom: '7%',
marginTop: '1%',
'& div': {
borderRadius: 18,
},
},
input: {
color: 'black',
backgroundColor: 'white',
},
});

const InputField = ({ handleLoginChange, name }) => {
const classes = useStyles();
return (
<TextField
variant="outlined"
required
fullWidth
id={name}
label={name}
name={name}
type={name}
className={classes.textField}
InputProps={{
className: classes.input,
}}
size="small"
onChange={handleLoginChange}
/>
);
};
InputField.propTypes = {
name: PropTypes.string.isRequired,
handleLoginChange: PropTypes.func.isRequired,
};
export default InputField;
Loading

0 comments on commit 14e3e20

Please sign in to comment.