Team tests (ongoing)

This commit is contained in:
Rodrigo Pedroso 2019-07-25 23:45:01 -04:00
commit 97509a85d7
7 changed files with 283 additions and 230 deletions

View file

@ -10,6 +10,10 @@
"plugins": ["prettier"], "plugins": ["prettier"],
"rules": { "rules": {
"prettier/prettier": "error", "prettier/prettier": "error",
"no-unused-vars": 1 "no-unused-vars": 1,
} "react/prop-types": 0
},
'extends': [
'plugin:react/recommended'
]
} }

View file

@ -6,51 +6,71 @@ import Team from '../views/Team'
import Member from '../views/Member' import Member from '../views/Member'
import config from '../config.json' import config from '../config.json'
history.listen(location => { history.listen(() => {
window.scrollTo(0,0) window.scrollTo(0, 0)
}) })
export default function Router(props) { export default function Router() {
let [team, setTeam] = useState([]) // let [team, setTeam] = useState([])
let [allTeams, setAllTeams] = useState([]) let [allTeams, setAllTeams] = useState([])
let [users, setUsers] = useState([]) // let [users, setUsers] = useState([])
let [memberProps, setMemberProps] = useState({}) let [memberProps, setMemberProps] = useState({})
let [teamProps, setTeamProps] = useState({})
let teamCallback = (el) => { let teamCallback = (teamId, users) => {
setTeam(el) // Remove this:
} // setTeam(teamId)
let usersCallback = (el) => { // Leave:
setUsers(el) setTeamProps({
} url: config.api + '/team/' + teamId,
team: teamId,
users: users,
cb: userIdCallback
})
}
let userIdCallback = (el) => { let usersCallback = el => {
setMemberProps({ setUsers(el)
url: config.api + '/user/' + el, }
teams: allTeams
})
}
let allTeamsCallback = (el) => { let userIdCallback = el => {
setAllTeams(el) setMemberProps({
} url: config.api + '/user/' + el,
teams: allTeams
})
}
return ( let allTeamsCallback = el => {
<ReactRouter history = { history }> setAllTeams(el)
<Switch> }
<Route
exact path='/' // <Route
render={(props) => <Home teamCallback={teamCallback} usersCallback={usersCallback} allTeamsCallback={allTeamsCallback} {...props} />} // exact
/> // path="/team"
<Route // render={props => <Team teamProps={team} usersProps={users} userIdCallback={userIdCallback} {...props} />}
exact path='/team' // />
render={(props) => <Team teamProps={team} usersProps={users} userIdCallback={userIdCallback} {...props} />}
/> return (
<Route <ReactRouter history={history}>
exact path='/member' <Switch>
render={(props) => <Member props={memberProps} />} <Route
/> exact
</Switch> path="/"
</ReactRouter> render={props => (
) <Home
teamCallback={teamCallback}
usersCallback={usersCallback}
allTeamsCallback={allTeamsCallback}
{...props}
/>
)}
/>
<Route exact path="/team" render={() => <Team props={teamProps} />} />
<Route exact path="/member" render={() => <Member props={memberProps} />} />
</Switch>
</ReactRouter>
)
} }

View file

@ -1,78 +1,78 @@
// MARK: Definitions // MARK: Definitions
import React, { useState, useEffect } from 'react' import React, { useState, useEffect } from 'react'
import axios from 'axios' import axios from 'axios'
import history from '../history.js' import history from '../history.js'
// import config from '../config.json' // import config from '../config.json'
import './Member.scss' import './Member.scss'
export default function Member({ props }) { export default function Member({ props }) {
// MARK: State // MARK: State
let [user, setUser] = useState(null) let [user, setUser] = useState(null)
let [teamNames, setTeamNames] = useState([]) let [teamNames, setTeamNames] = useState([])
// MARK: Effects // MARK: Effects
// MARK: - Load user info from Tempo backend on initialization // MARK: - Load user info from Tempo backend on initialization
useEffect(() => { useEffect(() => {
let fetchData = async() => { let fetchData = async () => {
try { try {
let result = await axios.get(props.url) let result = await axios.get(props.url)
if (result.data) { if (result.data) {
setUser(result.data) setUser(result.data)
result.data.member_teams.map(teamId => { result.data.member_teams.map(teamId => {
let arr = props.teams.filter(el => el.id === teamId) let arr = props.teams.filter(el => el.id === teamId)
setTeamNames(t => [...t, arr[0].name]) setTeamNames(t => [...t, arr[0].name])
return null return null
}) })
} }
} } catch (err) {
catch(err) { history.push('/')
history.push('/') }
} }
}
fetchData() fetchData()
}, [props]) }, [props])
// MARK: Helpers // MARK: Helpers
let navBack = () => { let navBack = () => {
history.push('/team') history.push('/team')
} }
// MARK: Return // MARK: Return
return ( return (
<div className='member'> <div className="member">
{user === null ? (
<div data-testid="loading">Loading...</div>
) : (
user !== undefined && (
<div>
<div className="header">
<span data-testid="resolved">
<h1>Member {user.name}</h1>
</span>
</div>
{user === null ? (<div data-testid='loading'>Loading...</div>) : ( <div className="back">
user !== undefined && <button className="back-btn" onClick={navBack}>{`< Back to team`}</button>
<div> </div>
<div className='header'>
<span data-testid='resolved'><h1>Member {user.name}</h1></span>
</div>
<div className='back'> <h2>Username:</h2>
<button className='back-btn' onClick={navBack}>{`< Back to team`}</button> <div className="username">
</div> <p>{user.username}</p>
</div>
<h2>Username:</h2> <h2>Member of:</h2>
<div className='username'> <ul className="list">
<p>{user.username}</p> {teamNames.map((name, index) => (
</div> <li className="list-item" key={index}>
<div className="username">{name}</div>
<h2>Member of:</h2> </li>
<ul className='list'> ))}
{teamNames.map((name, index) => ( </ul>
<li className='list-item' key={index}> </div>
<div className='username'> )
{name} )}
</div> </div>
</li> )
))}
</ul>
</div>
)}
</div>
)
} }

View file

@ -5,27 +5,29 @@ import '@testing-library/react/cleanup-after-each'
import axiosMock from 'axios' import axiosMock from 'axios'
import Member from './Member' import Member from './Member'
it('Renders without crashing', () => { describe('A members page', () => {
const { getByTestId } = render(<Member />) it('should render without crashing', () => {
expect(getByTestId('loading')).toHaveTextContent('Loading...') const { getByTestId } = render(<Member />)
}) expect(getByTestId('loading')).toHaveTextContent('Loading...')
})
it('Fetches and displays data', async () => {
const callData = { it('should fetch and display data', async () => {
username: 'goodpanda', const callData = {
member_teams: [3], username: 'goodpanda',
lead_teams: [], member_teams: [3],
id: 15, lead_teams: [],
name: 'Charlotte Amsterdan' id: 15,
} name: 'Charlotte Amsterdan'
}
axiosMock.get.mockResolvedValueOnce({ data: callData })
axiosMock.get.mockResolvedValueOnce({ data: callData })
const address = { url: '/user15' }
const { getByTestId } = render(<Member props={address} />) const address = { url: '/user15' }
const resolvedSpan = await waitForElement(() => getByTestId('resolved')) const { getByTestId } = render(<Member props={address} />)
const resolvedSpan = await waitForElement(() => getByTestId('resolved'))
expect(resolvedSpan).toHaveTextContent('Member ' + callData.name)
expect(axiosMock.get).toHaveBeenCalledTimes(1) expect(resolvedSpan).toHaveTextContent('Member ' + callData.name)
expect(axiosMock.get).toHaveBeenCalledWith(address.url) expect(axiosMock.get).toHaveBeenCalledTimes(1)
expect(axiosMock.get).toHaveBeenCalledWith(address.url)
})
}) })

View file

@ -1,127 +1,123 @@
// MARK: Definitions // MARK: Definitions
import React, { useState, useEffect } from 'react' import React, { useState, useEffect } from 'react'
import axios from 'axios' import axios from 'axios'
import history from '../history.js' import history from '../history.js'
import config from '../config.json'
import FilterForm from '../components/FilterForm.jsx' import FilterForm from '../components/FilterForm.jsx'
import './Team.scss' import './Team.scss'
// teamProps, usersProps, userIdCallback
export default function Team(props) { export default function Team(props) {
// MARK: State // MARK: State
let [loading, setLoading] = useState(true) let [team, setTeam] = useState([])
let [team, setTeam] = useState([]) let [members, setMembers] = useState([])
let [members, setMembers] = useState([]) let [filteredMembers, setFilteredMembers] = useState([])
let [filteredMembers, setFilteredMembers] = useState([])
// MARK: Effect // MARK: Effect
// MARK: - Load user info from Tempo backend on initialization // MARK: - Load user info from Tempo backend on initialization
useEffect(() => { useEffect(() => {
let fetchData = async() => { let fetchData = async () => {
setLoading(true) try {
try { let result = await axios(props.url)
let result = await axios(config.api + '/team/' + props.teamProps.id) if (result.data) {
if (result.data) { setTeam(result.data)
setTeam(result.data)
result.data.members.map(memberId => { result.data.members.map(memberId => {
let arr = props.usersProps.filter(el => el.id === memberId) let arr = props.users.filter(el => el.id === memberId)
if (arr[0] !== undefined) { if (arr[0] !== undefined) {
let tupple = { let tupple = {
name: arr[0].name, name: arr[0].name,
id: memberId id: memberId
} }
setMembers(t => [...t, tupple]) setMembers(t => [...t, tupple])
setFilteredMembers(t => [...t, tupple]) setFilteredMembers(t => [...t, tupple])
} } else {
else { history.push('/')
history.push('/') }
}
return null return null
}) })
} } else {
else { history.push('/')
history.push('/') }
} } catch (err) {
setLoading(false) console.log('Fetch data error: ' + err)
} }
catch(err) { }
setLoading(false)
console.log('Fetch data error: ' + err)
}
}
fetchData() fetchData()
}, [props]) }, [props])
// MARK: Helpers // MARK: Helpers
let userData = (userId) => { let userData = userId => {
let arr = props.usersProps.filter(el => el.id === userId) if (props.users === undefined) {
if (arr[0] !== undefined) { history.push('/')
return arr[0].name } else {
} let arr = props.users.filter(el => el.id === userId)
else {
history.push('/')
}
}
let selectUser = (id) => { if (arr[0] !== undefined) {
props.userIdCallback(id) return arr[0].name
history.push('/member') } else {
} history.push('/')
}
}
}
let filterCallback = (e) => { let selectUser = id => {
let filtered = members.filter(member => { props.cb(id)
return member.name.toUpperCase().includes(e.target.value.toUpperCase()) history.push('/member')
}) }
setFilteredMembers(filtered) let filterCallback = e => {
} let filtered = members.filter(member => {
return member.name.toUpperCase().includes(e.target.value.toUpperCase())
})
let navBack = () => { setFilteredMembers(filtered)
history.push('/') }
}
// MARK: Return let navBack = () => {
return ( history.push('/')
<div className='team'> }
{props.teamProps !== undefined && // MARK: Return
<div className='header'> return (
<h1>Team {props.teamProps.name}</h1> <div className="team">
</div> {props.team !== undefined && (
} <div className="header">
<h1>Team {props.team.name}</h1>
</div>
)}
<div className='back'> <div className="back">
<button className='back-btn' onClick={navBack}>{`< Back to teams`}</button> <button className="back-btn" onClick={navBack}>{`< Back to teams`}</button>
</div> </div>
<FilterForm filterCallback = { filterCallback } /> <FilterForm filterCallback={filterCallback} />
{loading ? (<div>Loading...</div>) : ( {team.length == 0 ? (
team !== undefined && <div data-testId="loading">Loading...</div>
<div> ) : (
<h2>Team lead</h2> team !== undefined && (
<div>
<h2>Team lead</h2>
<button className='selector-btn' onClick={() => selectUser(team.lead)}> <button data-testId="resolved" className="selector-btn" onClick={() => selectUser(team.lead)}>
{userData(team.lead)} {userData(team.lead)}
</button> </button>
<h2>Team members</h2> <h2>Team members</h2>
<ul className='list'> <ul className="list">
{filteredMembers.map((member, index) => ( {filteredMembers.map((member, index) => (
<li className = 'list-item' key={index}> <li className="list-item" key={index}>
<button className='selector-btn' onClick={() => selectUser(member.id)}> <button className="selector-btn" onClick={() => selectUser(member.id)}>
{member.name} {member.name}
</button> </button>
</li> </li>
))} ))}
</ul> </ul>
</div> </div>
)} )
)}
</div> </div>
) )
} }

31
src/views/Team.test.js Normal file
View file

@ -0,0 +1,31 @@
import React from 'react'
import { render, waitForElement } from '@testing-library/react'
import '@testing-library/jest-dom/extend-expect'
import '@testing-library/react/cleanup-after-each'
import axiosMock from 'axios'
import Team from './Team'
describe('A team page', () => {
it('should render without crashing', () => {
const { getByTestId } = render(<Team />)
expect(getByTestId('loading')).toHaveTextContent('Loading...')
})
it('should fetch and display data', async () => {
const callData = {
teamProps: {
id: 3
},
usersProps: [{ name: 'UserName' }]
}
axiosMock.get.mockResolvedValueOnce({ data: callData })
const address = { url: '/team3' }
const { getByTestId } = render(<Team props={address} />)
const resolvedSpan = await waitForElement(() => getByTestId('resolved'))
expeted(resolvedSpan).toHaveContent('Team')
})
})

View file

@ -1,3 +1,3 @@
export default { export default {
get: jest.fn().mockResolvedValue({ data: {} }) get: jest.fn().mockResolvedValue({ data: {} })
} }