diff --git a/.gitignore b/.gitignore index 26ddb21..faeedef 100644 --- a/.gitignore +++ b/.gitignore @@ -2,3 +2,5 @@ node_modules/** public/dist/** public/css/** +jest/** +coverage/** diff --git a/.travis.yml b/.travis.yml new file mode 100644 index 0000000..a0d2fc8 --- /dev/null +++ b/.travis.yml @@ -0,0 +1,13 @@ +language: node_js +node_js: + - "6.7" + +before_script: + - npm install + +script: + - npm run coverage + - codecov + +after_success: + - bash <(curl -s https://codecov.io/bash) diff --git a/README.md b/README.md new file mode 100644 index 0000000..32b3cbe --- /dev/null +++ b/README.md @@ -0,0 +1,22 @@ +# IClient - React + +[![Build Status](https://travis-ci.org/marcoaraujojunior/iClient-react.svg?branch=master)](https://travis-ci.org/marcoaraujojunior/iClient-react) [![codecov](https://codecov.io/gh/marcoaraujojunior/iClient-react/branch/master/graph/badge.svg)](https://codecov.io/gh/marcoaraujojunior/iClient-react) + +Simple client to IClient Server made in React JS + + +# To Try + +docker-compose up -d + +docker-compose exec iClientReact bash + +cd client/ + +npm run dev + +License +---- + +MIT + diff --git a/app/App.js b/app/App.js index 3be4078..2d2e6a1 100644 --- a/app/App.js +++ b/app/App.js @@ -1,10 +1,12 @@ import React from 'react'; import ReactDOM from 'react-dom'; import { Router, Route, IndexRoute, hashHistory } from 'react-router' +import 'bulma/css/bulma.css' +import 'font-awesome-webpack' -import iClientComponent from 'components/iClient/iClientComponent'; -import HomeComponent from 'components/Home/HomeComponent'; -import ClientComponent from 'components/Client/ClientComponent'; +import iClientComponent from 'components/IClient/IClient'; +import HomeComponent from 'components/Home/Home'; +import ClientComponent from 'components/Client/Client'; import AreaComponent from 'components/Area/Area'; ReactDOM.render( diff --git a/app/components/Area/Area.js b/app/components/Area/Area.js index d2f8902..f97ac3b 100644 --- a/app/components/Area/Area.js +++ b/app/components/Area/Area.js @@ -1,68 +1,63 @@ import React from 'react'; -import { Router, Link } from 'react-router' +import { Link } from 'react-router' -import Visit from 'services/Visit'; +import VisitService from 'services/Visit' + +import Visit from 'components/Visit/Visit' +import ErrorComponent from 'components/Error/Error' class Area extends React.Component { constructor(props) { super(props); this.state = { - areas : [] + areas : [], + error : '' }; - this.renderVisit = this.renderVisit.bind(this); - this.renderArea = this.renderArea.bind(this); + this.generate = this.generate.bind(this); + this.generateError = this.generateError.bind(this); + this.getVisitGroupByArea = this.getVisitGroupByArea.bind(this); this.getVisitGroupByArea(); } getVisitGroupByArea() { - Visit.getGroupByArea().then((response) => { - this.setState({areas: response.data.visits}); + VisitService.getGroupByArea().then((response) => { + this.setState({error: ''}); + this.setState({ + areas: this.generate(response.data.visits) + }); + }).catch((error) => { + if (error.response) { + this.setState({error: error.response.data.error}); + } }); } - renderVisit(visits) { - return visits.map((areaVisit, key) => { - return ( - - { areaVisit.visit.client.name } - { areaVisit.visit.visit_date } - - - - - - - ); - }); + generateError(error) { + return ( + + ); } - renderArea(areas) { + generate(areas) { return areas.map((area, key) => { return (

{area._id}

- - - - - - - - - {this.renderVisit(area.visits)} - -
NameLast Visit -
+
); }); } render() { + if (this.state.error) { + let error = this.generateError(this.state.error); + return error; + } return (
- { this.renderArea(this.state.areas) } + { this.state.areas }
); } diff --git a/app/components/Client/ClientComponent.js b/app/components/Client/Client.js similarity index 70% rename from app/components/Client/ClientComponent.js rename to app/components/Client/Client.js index 2eac5e3..26c602e 100644 --- a/app/components/Client/ClientComponent.js +++ b/app/components/Client/Client.js @@ -1,24 +1,34 @@ import React from 'react'; -import Client from 'services/Client'; +import ClientService from 'services/Client'; +import Error from 'components/Error/Error' -class ClientComponent extends React.Component +class Client extends React.Component { constructor(props) { super(props); this.state = { - clients : [] + clients : [], + error : '' }; this.getClients(); } getClients() { - Client.getClients().then((response) => { + ClientService.getClients().then((response) => { this.setState({clients: response.data.clients}); + }).catch((error) => { + this.setState({error: 'Error Found: Trying get client'}); + if (error.response) { + this.setState({error: error.response.data.error}); + } }); } render() { + if (this.state.error) { + return (); + } const clientList = this.state.clients.map((client, key) => { return ( @@ -52,5 +62,5 @@ class ClientComponent extends React.Component } } -export default ClientComponent; +export default Client; diff --git a/app/components/Error/Error.js b/app/components/Error/Error.js index 8c08caa..86bf441 100644 --- a/app/components/Error/Error.js +++ b/app/components/Error/Error.js @@ -6,4 +6,6 @@ const Error = ({error}) => ( {error} : null ); + export default Error; + diff --git a/app/components/Home/HomeComponent.js b/app/components/Home/Home.js similarity index 58% rename from app/components/Home/HomeComponent.js rename to app/components/Home/Home.js index 11b0826..cc90b9f 100644 --- a/app/components/Home/HomeComponent.js +++ b/app/components/Home/Home.js @@ -1,12 +1,8 @@ import React from 'react'; -import { Router } from 'react-router' -class HomeComponent extends React.Component{ +class Home extends React.Component{ render() { - if (!localStorage.token) { - this.context.router.push("/"); - } return (
@@ -19,10 +15,5 @@ class HomeComponent extends React.Component{ } } -HomeComponent.contextTypes = { - router: React.PropTypes.object.isRequired -}; - -export default HomeComponent; - +export default Home; diff --git a/app/components/iClient/iClientComponent.js b/app/components/IClient/IClient.js similarity index 65% rename from app/components/iClient/iClientComponent.js rename to app/components/IClient/IClient.js index 16f1a07..d19fa49 100644 --- a/app/components/iClient/iClientComponent.js +++ b/app/components/IClient/IClient.js @@ -1,12 +1,12 @@ import React from 'react'; -import { Router, Route, IndexRoute, IndexLink, Link } from 'react-router' -import LoginComponent from 'components/Login/LoginComponent'; +import LoginComponent from 'components/Login/Login'; import MenuComponent from 'components/Menu/Menu'; -class iClientComponent extends React.Component{ - constructor(props) { - super(props); +class IClient extends React.Component +{ + constructor(props, context) { + super(props, context); this.handleView = this.handleView.bind(this); } @@ -20,10 +20,11 @@ class iClientComponent extends React.Component{
); } + render() { let view = this.handleView(); - if (!localStorage.token) { + if (!window.localStorage.getItem('token')) { view = ; } return ( @@ -32,5 +33,5 @@ class iClientComponent extends React.Component{ } } -export default iClientComponent; +export default IClient; diff --git a/app/components/LinksApp/LinksApp.js b/app/components/LinksApp/LinksApp.js new file mode 100644 index 0000000..2d0dc67 --- /dev/null +++ b/app/components/LinksApp/LinksApp.js @@ -0,0 +1,55 @@ +import React from 'react'; +import { Link } from 'react-router' + +class LinksApp extends React.Component +{ + constructor(props, context) { + super(props, context); + this.generate = this.generate.bind(this); + this.handleClick = this.handleClick.bind(this); + this.state = { + links: this.props.links + }; + } + + handleClick(e) { + if (this.context.onClick) { + this.context.onClick(); + } + } + + generate() { + return this.state.links.map((link, index) => { + return ( + + {link[1]} + + ); + }); + } + + render() { + return ( + + {this.generate()} + + ); + } +} + +LinksApp.propTypes = { + links: React.PropTypes.array.isRequired +}; + +LinksApp.contextTypes = { + onClick: React.PropTypes.func +}; + +export default LinksApp; + diff --git a/app/components/Login/LoginComponent.js b/app/components/Login/Login.js similarity index 91% rename from app/components/Login/LoginComponent.js rename to app/components/Login/Login.js index da73cc9..82783a3 100644 --- a/app/components/Login/LoginComponent.js +++ b/app/components/Login/Login.js @@ -4,12 +4,11 @@ import { Router } from 'react-router' import User from 'services/User'; import ErrorComponent from 'components/Error/Error'; -class LoginComponent extends React.Component +class Login extends React.Component { constructor(props, context) { super(props, context); this.handleSubmit = this.handleSubmit.bind(this); - this.handleDeleteMessage = this.handleDeleteMessage.bind(this); this.state = { error: '' }; @@ -23,7 +22,7 @@ class LoginComponent extends React.Component this.refs.password.value ).then((response) => { if (response.data.success == 200) { - localStorage.token = response.data.token; + window.localStorage.setItem('token', response.data.token); this.context.router.push("/"); } }).catch((error) => { @@ -34,10 +33,6 @@ class LoginComponent extends React.Component }); } - handleDeleteMessage() { - this.setState({error: ''}); - } - render() { return (
@@ -84,8 +79,9 @@ class LoginComponent extends React.Component } } -LoginComponent.contextTypes = { +Login.contextTypes = { router: React.PropTypes.object.isRequired }; -export default LoginComponent; +export default Login; + diff --git a/app/components/Menu/Menu.js b/app/components/Menu/Menu.js index 88b7d01..51edf30 100644 --- a/app/components/Menu/Menu.js +++ b/app/components/Menu/Menu.js @@ -1,47 +1,46 @@ import React from 'react'; -import { Router, Link } from 'react-router' +import { Router } from 'react-router' + +import Nav from 'components/Nav/Nav' +import LinksApp from 'components/LinksApp/LinksApp' + class Menu extends React.Component{ constructor(props, context) { super(props, context); this.handleLogout = this.handleLogout.bind(this); this.handleView = this.handleView.bind(this); + this.state = { + links: [ + [ '/', 'Home'], + ['/client', 'Client'], + ['/area', 'Area'] + ] + }; } handleLogout() { - delete localStorage.token; + window.localStorage.removeItem('token'); this.context.router.push("/"); } handleView() { return ( - + ); } render() { let view = this.handleView(); - if (!localStorage.token) { + if (!window.localStorage.getItem('token')) { view = ; } return ( diff --git a/app/components/Nav/Nav.js b/app/components/Nav/Nav.js new file mode 100644 index 0000000..616512a --- /dev/null +++ b/app/components/Nav/Nav.js @@ -0,0 +1,55 @@ +import React from 'react'; + +class Nav extends React.Component +{ + constructor(props, context) { + super(props, context); + this.toggleNavStatus = this.toggleNavStatus.bind(this); + this.hide = this.hide.bind(this); + this.state = { + toggleNavStatus: '' + }; + } + + getChildContext() { + return { + onClick: this.toggleNavStatus + } + } + + hide(e) { + this.setState({toggleNavStatus: ''}); + } + + toggleNavStatus() { + let isActive = this.state.toggleNavStatus ? '' : 'is-active'; + this.setState({toggleNavStatus: isActive}); + } + + render() { + return ( + + ); + } +} + +Nav.childContextTypes = { + onClick: React.PropTypes.func +}; + +export default Nav; + diff --git a/app/components/Visit/Visit.js b/app/components/Visit/Visit.js new file mode 100644 index 0000000..79a9266 --- /dev/null +++ b/app/components/Visit/Visit.js @@ -0,0 +1,51 @@ +import React from 'react'; +import { Link } from 'react-router' + +class Visit extends React.Component +{ + constructor(props, context) { + super(props, context); + this.generate = this.generate.bind(this); + this.state = { + visits: this.props.visits + }; + } + + generate() { + return this.state.visits.map((areaVisit, key) => ( + + { areaVisit.visit.client.name } + { areaVisit.visit.visit_date } + + + + + + + )); + } + + render() { + return ( + + + + + + + + + {this.generate()} + +
NameLast Visit +
+ ); + } +} + +Visit.propTypes = { + visits: React.PropTypes.array.isRequired +}; + +export default Visit; + diff --git a/package.json b/package.json index e5c9beb..68810a7 100644 --- a/package.json +++ b/package.json @@ -13,21 +13,39 @@ }, "devDependencies": { "babel-core": "^6.17.0", + "babel-jest": "^16.0.0", "babel-loader": "^6.2.5", - "babel-preset-es2015": "^6.16.0", + "babel-preset-es2015": "^6.18.0", "babel-preset-react": "^6.16.0", + "codecov": "^1.0.1", "css-loader": "^0.25.0", + "enzyme": "^2.6.0", + "file-loader": "^0.9.0", + "font-awesome-webpack": "0.0.4", "http-server": "^0.9.0", + "jest": "^16.0.2", + "less": "^2.7.1", + "less-loader": "^2.2.3", "npm-run-all": "^3.1.0", "path": "^0.12.7", + "react-addons-test-utils": "^15.3.2", + "react-test-renderer": "^15.3.2", "style-loader": "^0.13.1", + "url-loader": "^0.5.7", "webpack": "^1.13.2" }, "scripts": { - "test": "echo \"Error: no test specified\" && exit 1", + "test": "jest", "webpack": "webpack -w", "serve": "http-server -o -c 1 -p 80", - "dev": "npm-run-all --parallel webpack serve" + "dev": "npm-run-all --parallel webpack serve", + "coverage": "jest --coverage" + }, + "jest": { + "modulePaths": [ + "app" + ], + "collectCoverage": true }, "author": "", "license": "ISC" diff --git a/public/index.html b/public/index.html index aeec7b8..64cd577 100644 --- a/public/index.html +++ b/public/index.html @@ -2,12 +2,11 @@ + React Client - -
- + diff --git a/tests/Area.test.js b/tests/Area.test.js new file mode 100644 index 0000000..4c7cbb0 --- /dev/null +++ b/tests/Area.test.js @@ -0,0 +1,148 @@ +jest.enableAutomock(); +jest.dontMock('components/Area/Area'); +jest.dontMock('components/Error/Error'); +jest.dontMock('react'); +jest.dontMock('axios'); +jest.dontMock('../tests/__mocks__/AreasResponseMock'); +jest.dontMock('enzyme'); + + +describe('Test Area', () => { + const React = require('react'); + const Enzyme = require('enzyme'); + const shallow = Enzyme.shallow; + let Visit = require('services/Visit').default; + + it('Area should show error message', (done) => { + + let error = {response:{data:{error:"Not Found"}}}; + let promises = []; + let Area; + let component; + + promises.push( + (() => { + Visit.getGroupByArea = jest.genMockFunction().mockImplementation(() => { + return new Promise((resolve, reject) => { + throw error; + }); + }) + })() + ); + + promises.push( + (() => { + Area = require('components/Area/Area').default; + })() + ); + + promises.push( + (() => { + component = shallow( + + ); + })() + ); + + Promise.all(promises).then(() => { + expect(component.state('error')).toEqual('Not Found'); + + let errorComponent = shallow( + component.instance().generateError(error.response.data.error) + ); + + expect(errorComponent.find('div').text()).toEqual('Not Found'); + done(); + }).catch((error) => { + console.log(error); + }); + }); + + it('Area should show nothing if no data', (done) => { + + let error = {data:{error:"Not Found"}}; + let promises = []; + let Area; + let component; + + promises.push( + (() => { + Visit.getGroupByArea = jest.genMockFunction().mockImplementation(() => { + return new Promise((resolve, reject) => { + throw error; + }); + }) + })() + ); + + promises.push( + (() => { + Area = require('components/Area/Area').default; + })() + ); + + promises.push( + (() => { + component = shallow( + + ); + })() + ); + + Promise.all(promises).then(() => { + expect(component.state('error')).toEqual(''); + done(); + }).catch((error) => { + console.log(error); + }); + }); + + it('Area should show mocked data', (done) => { + + let response = {data:require('AreasResponseMock').default}; + let promises = []; + let Area; + let component; + + promises.push( + (() => { + Visit.getGroupByArea = jest.genMockFunction().mockImplementation(() => { + return new Promise((resolve, reject) => { + resolve(response); + }); + }) + })() + ); + + promises.push( + (() => { + Area = require('components/Area/Area').default; + })() + ); + + promises.push( + (() => { + component = shallow( + + ); + })() + ); + + Promise.all(promises).then(() => { + expect( + shallow( + component.state().areas[0] + ).find('.title').at(0).text() + ).toEqual('Center'); + expect( + shallow( + component.state().areas[1] + ).find('.title').at(0).text() + ).toEqual('South'); + done(); + }).catch((error) => { + console.log(error); + }); + }); + +}); diff --git a/tests/Client.test.js b/tests/Client.test.js new file mode 100644 index 0000000..c2731f3 --- /dev/null +++ b/tests/Client.test.js @@ -0,0 +1,144 @@ +jest.enableAutomock(); +jest.dontMock('components/Client/Client'); +jest.dontMock('components/Error/Error'); +jest.dontMock('react'); +jest.dontMock('axios'); +jest.dontMock('enzyme'); + + +describe('Test Client', () => { + const React = require('react'); + const Enzyme = require('enzyme'); + const shallow = Enzyme.shallow; + let ClientService = require('services/Client').default; + + it('Client should show error message', (done) => { + + let error = {response:{data:{error:"Client Not Found"}}}; + let promises = []; + let Client; + let component; + + promises.push( + (() => { + ClientService.getClients = jest.genMockFunction().mockImplementation(() => { + return new Promise((resolve, reject) => { + throw error; + }); + }) + })() + ); + + promises.push( + (() => { + Client = require('components/Client/Client').default; + })() + ); + + promises.push( + (() => { + component = shallow( + + ); + })() + ); + + Promise.all(promises).then(() => { + component.update(); + expect(component.render().text()).toEqual('Client Not Found'); + done(); + }).catch((error) => { + console.log(error); + }); + }); + + it('Client should show default error message', (done) => { + + let error = {error:"Client Not Found"}; + let promises = []; + let Client; + let component; + + promises.push( + (() => { + ClientService.getClients = jest.genMockFunction().mockImplementation(() => { + return new Promise((resolve, reject) => { + throw error; + }); + }) + })() + ); + + promises.push( + (() => { + Client = require('components/Client/Client').default; + })() + ); + + promises.push( + (() => { + component = shallow( + + ); + })() + ); + + Promise.all(promises).then(() => { + component.update(); + expect(component.render().text()).toEqual('Error Found: Trying get client'); + done(); + }).catch((error) => { + console.log(error); + }); + }); + + it('Client should show mocked data', (done) => { + + let response = { + data: { + clients: [ + {name: 'Jon Snow', address: '7 Street', city: 'Winterfell'} + ] + } + }; + let promises = []; + let Client; + let component; + + promises.push( + (() => { + ClientService.getClients = jest.genMockFunction().mockImplementation(() => { + return new Promise((resolve, reject) => { + resolve(response); + }); + }) + })() + ); + + promises.push( + (() => { + Client = require('components/Client/Client').default; + })() + ); + + promises.push( + (() => { + component = shallow( + + ); + })() + ); + + Promise.all(promises).then(() => { + component.update(); + expect(component.find('td').at(0).text()).toEqual('Jon Snow'); + expect(component.find('td').at(1).text()).toEqual('7 Street'); + expect(component.find('td').at(2).text()).toEqual('Winterfell'); + done(); + }).catch((error) => { + console.log(error); + }); + }); + +}); + diff --git a/tests/Error.test.js b/tests/Error.test.js new file mode 100644 index 0000000..336d924 --- /dev/null +++ b/tests/Error.test.js @@ -0,0 +1,21 @@ +import React from 'react' +import {shallow} from 'enzyme'; + +import Error from 'components/Error/Error' + +test('Error should show null if no error', () => { + const errorComponent = shallow( + + ); + + expect(errorComponent.text()).toEqual(''); +}); + +test('Error should show error if error pass', () => { + const errorMessage = 'Error found'; + const errorComponent = shallow( + + ); + + expect(errorComponent.text()).toEqual('Error found'); +}); diff --git a/tests/Home.test.js b/tests/Home.test.js new file mode 100644 index 0000000..cec81e6 --- /dev/null +++ b/tests/Home.test.js @@ -0,0 +1,17 @@ +describe('Test Home', () => { + const React = require('react'); + const Enzyme = require('enzyme'); + const shallow = Enzyme.shallow; + + test('Home should show welcome message', () => { + + let Home = require('components/Home/Home').default; + + const component = shallow( + + ); + + expect(component.find('h1').text()).toEqual('Welcome to IClient'); + }); +}); + diff --git a/tests/IClient.test.js b/tests/IClient.test.js new file mode 100644 index 0000000..9d4bd10 --- /dev/null +++ b/tests/IClient.test.js @@ -0,0 +1,37 @@ + +describe('Test iClient', () => { + require('../tests/__mocks__/LocalStorageMock'); + + const React = require('react'); + const enzyme = require('enzyme'); + const shallow = enzyme.shallow; + const mount = enzyme.mount; + const IClient = require('components/IClient/IClient').default; + + it('iClient should show login component if not logged', (done) => { + + let component = shallow( + + ); + + expect(component.text()).toEqual(''); + + done(); + }); + + it('iClient should show login component if not logged', (done) => { + + window.localStorage.setItem('token', 'test_menu'); + + let component = shallow( + + Test + + ); + + expect(component.text()).toEqual('Test'); + + done(); + }); +}); + diff --git a/tests/LinksApp.test.js b/tests/LinksApp.test.js new file mode 100644 index 0000000..6d10e90 --- /dev/null +++ b/tests/LinksApp.test.js @@ -0,0 +1,55 @@ +describe('Test LinksApp', () => { + const React = require('react'); + const Enzyme = require('enzyme'); + const shallow = Enzyme.shallow; + + beforeEach((done) => { + done(); + }); + + test('LinksApp should show links received from props', () => { + + let LinksApp = require('components/LinksApp/LinksApp').default; + let links = [ + ['/route', 'description'], + ['/anotherRoute', 'Another Description'] + ]; + const context = { onClick: () => 'foo' }; + + const component = shallow( + , + { context } + ); + + component.instance().handleClick(null); + + let firstLink = shallow( + component.instance().generate()[0] + ); + + let secondLink = shallow( + component.instance().generate()[1] + ); + + expect(firstLink.text()).toEqual('description'); + expect(firstLink.instance().props.to).toEqual('/route'); + + expect(secondLink.text()).toEqual('Another Description'); + expect(secondLink.instance().props.to).toEqual('/anotherRoute'); + }); + + test('LinksApp should show nothing', () => { + + let LinksApp = require('components/LinksApp/LinksApp').default; + let links = []; + + const component = shallow( + + ); + + component.instance().handleClick(null); + + expect(component.instance().generate()).toEqual([]); + }); +}); + diff --git a/tests/Login.test.js b/tests/Login.test.js new file mode 100644 index 0000000..5c8a705 --- /dev/null +++ b/tests/Login.test.js @@ -0,0 +1,238 @@ +jest.enableAutomock(); +jest.dontMock('components/Login/Login'); +jest.dontMock('components/Error/Error'); +jest.dontMock('react'); +jest.dontMock('axios'); +jest.dontMock('enzyme'); + +describe('Test Login', () => { + require('../tests/__mocks__/LocalStorageMock'); + + const React = require('react'); + const enzyme = require('enzyme'); + const shallow = enzyme.shallow; + const mount = enzyme.mount; + const Login = require('components/Login/Login').default; + const context = { + router: { + push: (arg) => arg + } + }; + let User = require('services/User').default; + + it('Login should show form', (done) => { + + let component = shallow( + , + { context } + ); + + expect(component.find('form').length).toEqual(1); + + done(); + }); + + it('Login should get login values', (done) => { + + let Login = require('components/Login/Login').default; + let loginInformed; + let passwordInformed; + + User.login = jest.genMockFunction().mockImplementation((login, password) => { + return new Promise((resolve, reject) => { + loginInformed = login; + passwordInformed = password; + }); + }) + + let component = mount( + , + { context } + ); + + expect(loginInformed).toEqual(undefined); + expect(passwordInformed).toEqual(undefined); + + let inputLogin = component.find('form div p input[type="text"]'); + let inputPassword = component.find('form div p input[type="password"]'); + + inputLogin.node.value = 'Astolfo'; + inputLogin.simulate('change', inputLogin); + + inputPassword.node.value = 'abcd'; + inputPassword.simulate('change', inputPassword); + + component.find('form').simulate('submit', { target: component.find('form').get(0) }); + + expect(loginInformed).toEqual('Astolfo'); + expect(passwordInformed).toEqual('abcd'); + + done(); + }); + + it('Login should not set localStorage if success is different from 200', (done) => { + + let Login = require('components/Login/Login').default; + let promises = []; + + User.login = jest.genMockFunction().mockImplementation((login, password) => { + return new Promise((resolve, reject) => { + resolve({data: {success: 201, token: 'token_test'}}); + }); + }) + + let component = mount( + , + { context } + ); + + let inputLogin = component.find('form div p input[type="text"]'); + let inputPassword = component.find('form div p input[type="password"]'); + + inputLogin.node.value = 'Astolfo'; + inputLogin.simulate('change', inputLogin); + + inputPassword.node.value = 'abcd'; + inputPassword.simulate('change', inputPassword); + + expect(window.localStorage.getItem('token')).toEqual(null); + + promises.push( + (() => { + component.find('form').simulate('submit', { target: component.find('form').get(0) }); + })() + ); + + Promise.all(promises).then(() => { + expect(window.localStorage.getItem('token')).toEqual(null); + done(); + }).catch((error) => { + console.log(error); + }); + }); + + + it('Login should set localStorage', (done) => { + + let Login = require('components/Login/Login').default; + let promises = []; + + User.login = jest.genMockFunction().mockImplementation((login, password) => { + return new Promise((resolve, reject) => { + resolve({data: {success: 200, token: 'token_test'}}); + }); + }) + + let component = mount( + , + { context } + ); + + let inputLogin = component.find('form div p input[type="text"]'); + let inputPassword = component.find('form div p input[type="password"]'); + + inputLogin.node.value = 'Astolfo'; + inputLogin.simulate('change', inputLogin); + + inputPassword.node.value = 'abcd'; + inputPassword.simulate('change', inputPassword); + + expect(window.localStorage.getItem('token')).toEqual(null); + + promises.push( + (() => { + component.find('form').simulate('submit', { target: component.find('form').get(0) }); + })() + ); + + Promise.all(promises).then(() => { + expect(window.localStorage.getItem('token')).toEqual('token_test'); + done(); + }).catch((error) => { + console.log(error); + }); + }); + + it('Login should show error default on state', (done) => { + + let Login = require('components/Login/Login').default; + let error = {response:{error:"Another error"}}; + let promises = []; + + User.login = jest.genMockFunction().mockImplementation((login, password) => { + return new Promise((resolve, reject) => { + throw error; + }); + }) + + let component = mount( + , + { context } + ); + + let inputLogin = component.find('form div p input[type="text"]'); + let inputPassword = component.find('form div p input[type="password"]'); + + inputLogin.node.value = 'Astolfo'; + inputLogin.simulate('change', inputLogin); + + inputPassword.node.value = 'abcd'; + inputPassword.simulate('change', inputPassword); + + promises.push( + (() => { + component.find('form').simulate('submit', { target: component.find('form').get(0) }); + })() + ); + + Promise.all(promises).then(() => { + expect(component.state().error).toEqual('Authentication failed'); + done(); + }).catch((error) => { + console.log(error); + }); + }); + + + it('Login should set error received on state', (done) => { + + let Login = require('components/Login/Login').default; + let error = {response:{data:{error:"User Not Found"}}}; + let promises = []; + + User.login = jest.genMockFunction().mockImplementation((login, password) => { + return new Promise((resolve, reject) => { + throw error; + }); + }) + + let component = mount( + , + { context } + ); + + let inputLogin = component.find('form div p input[type="text"]'); + let inputPassword = component.find('form div p input[type="password"]'); + + inputLogin.node.value = 'Astolfo'; + inputLogin.simulate('change', inputLogin); + + inputPassword.node.value = 'abcd'; + inputPassword.simulate('change', inputPassword); + + promises.push( + (() => { + component.find('form').simulate('submit', { target: component.find('form').get(0) }); + })() + ); + + Promise.all(promises).then(() => { + expect(component.state().error).toEqual('User Not Found'); + done(); + }).catch((error) => { + console.log(error); + }); + }); + +}); + diff --git a/tests/Menu.test.js b/tests/Menu.test.js new file mode 100644 index 0000000..68fe50b --- /dev/null +++ b/tests/Menu.test.js @@ -0,0 +1,63 @@ + +describe('Test Menu', () => { + require('../tests/__mocks__/LocalStorageMock'); + + const React = require('react'); + const shallow = require('enzyme').shallow; + const Menu = require('components/Menu/Menu').default; + const context = { + router: { + push: () => null + } + }; + + it('Menu should to know list of links', (done) => { + + let component = shallow( + , + { context } + ); + + let expectedLinks = [ + ['/', 'Home'], + ['/client', 'Client'], + ['/area', 'Area'], + ]; + + expect(component.state().links).toEqual(expectedLinks); + + done(); + }); + + it('HandleLogout should erase token in localStorage', (done) => { + + let component = shallow( + , + { context } + ); + + window.localStorage.setItem('token', 'test_menu'); + + expect(window.localStorage.getItem('token')).toEqual('test_menu'); + component.instance().handleLogout(); + expect(window.localStorage.getItem('token')).toEqual(null); + done(); + }); + + it('Menu should render links if logged in', (done) => { + window.localStorage.setItem('token', 'test_menu'); + + let component = shallow( + , + { context } + ); + + expect(window.localStorage.getItem('token')).toEqual('test_menu'); + + expect(component.childAt(0).text()).toEqual(''); + expect(component.childAt(0).render().find('.nav-item.is-tab').length).toEqual(3); + expect(component.childAt(1).text()).toEqual('Logout'); + done(); + }); +}); + diff --git a/tests/Nav.test.js b/tests/Nav.test.js new file mode 100644 index 0000000..f113044 --- /dev/null +++ b/tests/Nav.test.js @@ -0,0 +1,61 @@ + +describe('Test Nav', () => { + const React = require('react'); + const shallow = require('enzyme').shallow; + const Nav = require('components/Nav/Nav').default; + + it('Nav should render child', (done) => { + + let component = shallow( + + ); + + expect(component.find('directive').text()).toEqual('Child'); + + done(); + }); + + it('toggleNavStatus function should change toggleNavStatus state from is-active to empty', (done) => { + + let component = shallow( +