Skip to content
Open
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
23 changes: 23 additions & 0 deletions .gitignore
Original file line number Diff line number Diff line change
@@ -0,0 +1,23 @@
# See https://help.github.com/articles/ignoring-files/ for more about ignoring files.

# dependencies
/node_modules
/.pnp
.pnp.js

# testing
/coverage

# production
/build

# misc
.DS_Store
.env.local
.env.development.local
.env.test.local
.env.production.local

npm-debug.log*
yarn-debug.log*
yarn-error.log*
Binary file removed images/template.png
Binary file not shown.
43 changes: 43 additions & 0 deletions package.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,43 @@
{
"name": "teste-front",
"version": "0.1.0",
"private": true,
"dependencies": {
"@testing-library/jest-dom": "^5.11.4",
"@testing-library/react": "^11.1.0",
"@testing-library/user-event": "^12.1.10",
"axios": "^0.21.1",
"react": "^17.0.2",
"react-dom": "^17.0.2",
"react-router-dom": "^5.2.0",
"react-scripts": "4.0.3",
"web-vitals": "^1.0.1"
},
"scripts": {
"start": "react-scripts start",
"build": "react-scripts build",
"test": "react-scripts test",
"eject": "react-scripts eject"
},
"eslintConfig": {
"extends": [
"react-app",
"react-app/jest"
]
},
"browserslist": {
"production": [
">0.2%",
"not dead",
"not op_mini all"
],
"development": [
"last 1 chrome version",
"last 1 firefox version",
"last 1 safari version"
]
},
"devDependencies": {
"react-test-library": "^0.0.1"
}
}
11 changes: 11 additions & 0 deletions public/index.html
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="utf-8" />
<meta name="viewport" content="width=device-width, initial-scale=1" />
<title>Teste Front-end Mastertech</title>
</head>
<body>
<div id="root"></div>
</body>
</html>
12 changes: 12 additions & 0 deletions src/App.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
import './global.css';
import Routes from './routes';

function App() {
return (
<div className="container">
<Routes />
</div>
);
}

export default App;
14 changes: 14 additions & 0 deletions src/global.css
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
* {
margin: 0;
padding: 0;
box-sizing: border-box;
}
.container {
width: 100vw;
height: 100vh;
background: #6C7A89;
display: flex;
flex-direction: row;
justify-content: center;
align-items: center
}
11 changes: 11 additions & 0 deletions src/index.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
import React from 'react';
import ReactDOM from 'react-dom';
import { BrowserRouter } from 'react-router-dom';
import App from './App';

ReactDOM.render(
<BrowserRouter>
<App />
</BrowserRouter>,
document.getElementById('root'),
);
68 changes: 68 additions & 0 deletions src/pages/login/index.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,68 @@
import React, { useState } from 'react';
import { Redirect } from 'react-router';
import getProfile from '../../services/api';

import './style.css';

const Login = () => {
const [email, setEmail] = useState('');
const [password, setPassword] = useState('');
const [user, setUser] = useState(false);
const [error, setError] = useState(false);

const loginAction = async (e) => {
e.preventDefault();
const result = await getProfile(email, password);
if (typeof result === 'object') {
setUser(result);
} else {
setError(result);
}
};
const showMessage = () => {
return <span className="error">{error}</span>;
};
return (
<form className="login-form" type="POST">
{user && (
<Redirect
to={{
pathname: '/profile',
state: { data: user },
}}
/>
)}
<h3>Login</h3>
<label>
E-mail
<input
type="email"
placeholder="email@email.com"
value={email}
data-testid="email"
onChange={({ target }) => setEmail(target.value)}
></input>
</label>
<label>
Senha
<input
type="password"
placeholder="password"
value={password}
data-testid="password"
onChange={({ target }) => setPassword(target.value)}
></input>
</label>
<button
data-testid="btn-login"
type="submit"
onClick={(e) => loginAction(e)}
>
Entrar
</button>
{error && showMessage()}
</form>
);
};

export default Login;
41 changes: 41 additions & 0 deletions src/pages/login/style.css
Original file line number Diff line number Diff line change
@@ -0,0 +1,41 @@
.login-form {
align-items: center;
background-color: white;
display: flex;
flex-direction: column;
height: 350px;
justify-content: center;
width: 350px;
}

.login-form h3 {
margin-bottom: 16px;
}

.login-form input {
border: none;
border-bottom: 1px solid #ccc;
font-size: 18px;
height: 30px;
margin: 8px 0;
outline: 0;
padding: 4px;
width: 100%;
}

.login-form button {
background-color: lightblue;
border: none;
box-shadow: 1px 1px 5px rgba(0, 0, 0, 0.5);
font-size: 18px;
margin-top: 8px;
padding: 5px 15px;
cursor: pointer;
}
.login-form button:hover {
opacity: 0.7;
}
.error {
color: red;
margin-top: 16px;
}
24 changes: 24 additions & 0 deletions src/pages/profile/index.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,24 @@
import React from 'react';
import { Link } from 'react-router-dom';
import './style.css';

const Profile = ({ location }) => {
const { name, email, state, avatar } = location.state.data;
return (
<section className="user-card">
<div className="user-info">
<h2>{name}</h2>
<span>{email}</span>
<span>{state}</span>
</div>
<div className="user-avatar">
<img src={avatar} alt="Profile Avatar" />
</div>
<Link to="/">
<button type="button">Sair</button>
</Link>
</section>
);
};

export default Profile;
40 changes: 40 additions & 0 deletions src/pages/profile/style.css
Original file line number Diff line number Diff line change
@@ -0,0 +1,40 @@
.user-card {
align-items: center;
background-color: white;
display: flex;
flex-wrap: wrap;
justify-content: center;
padding: 8px;
width: 350px;
box-shadow: 2px 2px 5px rgba(0, 0, 0, 0.8);
}

.user-info {
display: flex;
flex-direction: column;
width: 70%;
}

.user-avatar {
width: 30%;
}
.user-info span {
margin: 8px 0;
}

.user-card .user-avatar img {
width: 100px;
}

.user-card button {
background-color: lightblue;
border: none;
box-shadow: 1px 1px 5px rgba(0, 0, 0, 0.5);
font-size: 18px;
margin-top: 16px;
padding: 5px 30px;
cursor: pointer;
}
.user-card button:hover {
opacity: 0.7;
}
13 changes: 13 additions & 0 deletions src/routes.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
import { Route, Switch } from 'react-router';
import Login from './pages/login';
import Profile from './pages/profile';

const Routes = () => {
return (
<Switch>
<Route exact path="/" component={Login} />
<Route exact path="/profile" component={Profile} />
</Switch>
);
};
export default Routes;
24 changes: 24 additions & 0 deletions src/services/api.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,24 @@
import axios from 'axios';
const baseURL = 'http://jrwee.mocklab.io';
const api = axios.create({
baseURL,
});
const getProfile = async (email, password) => {
const validUser = {
email: 'teste@front.com',
password: 'teste123',
};
if (email === '' || password === '') {
return 'Os campos email e senha não podem ser vazios!';
}
if (email !== validUser.email && password !== validUser.password) {
return 'Email e/ou senha incorretos!';
}
try {
const result = await api.post('/user/login', { email, password });
return result.data;
} catch (e) {
return false;
}
};
export default getProfile;
47 changes: 47 additions & 0 deletions src/test/login.test.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,47 @@
import React from 'react';
import renderWithRouter from './renderWithRouter';
import App from '../App';
import userEvent from '@testing-library/user-event';
import { screen } from '@testing-library/react';

describe('1 - Check the items on the screen', () => {
it('should render the App component', () => {
const { getByText } = renderWithRouter(<App />);
const loginText = getByText(/Login/i);
expect(loginText).toBeDefined();
});
it('input fields must be present', () => {
const { getByTestId } = renderWithRouter(<App />);
const inputLogin = getByTestId('email');
const inputPass = getByTestId('password');
const btnLogin = getByTestId('btn-login');
expect(inputLogin).toBeDefined();
expect(inputPass).toBeDefined();
expect(btnLogin).toBeDefined();
});
});

describe('2 - Check error messages', () => {
it('unfilled fields', async () => {
renderWithRouter(<App />);
const inputLogin = screen.getByTestId('email');
const inputPass = screen.getByTestId('password');
const btnLogin = screen.getByTestId('btn-login');
userEvent.type(inputLogin, '');
userEvent.type(inputPass, '');
userEvent.click(btnLogin);

await screen.findByText('Os campos email e senha não podem ser vazios!');
});
it('Email or password not match', async () => {
renderWithRouter(<App />);
const inputLogin = screen.getByTestId('email');
const inputPass = screen.getByTestId('password');
const btnLogin = screen.getByTestId('btn-login');
userEvent.type(inputLogin, 'as');
userEvent.type(inputPass, 'ss');
userEvent.click(btnLogin);

await screen.findByText('Email e/ou senha incorretos!');
});
});
14 changes: 14 additions & 0 deletions src/test/renderWithRouter.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
import React from 'react';
import { Router } from 'react-router-dom';
import { createMemoryHistory } from 'history';
import { render } from '@testing-library/react';

const renderWithRouter = (component) => {
const history = createMemoryHistory();
return {
...render(<Router history={history}>{component}</Router>),
history,
};
};

export default renderWithRouter;
Loading