Testing react component - reactjs

I have a simple app where I use an axios to get UserList from the API.
Here is my App component:
import React,{useState,useEffect} from 'react';
import axios from 'axios';
import UserList from './components/Users/UserList';
function App() {
const [users,setUsers] = useState([]);
useEffect(()=>{
axios.get('https://reqres.in/api/users?page=2')
.then(response =>{
setUsers(response.data.data);
console.log(response.data);
})
.catch(error =>{
console.log(error)
})
}, [])
return (
<div>
<UserList users={users} />
</div>
);
}
export default App;
And I have the UserList component:
import React from 'react';
import classes from './UserList.module.css';
import Card from '../UI/Card';
const UserList = (props) => {
return (
<Card className={classes.users}>
<ul data-testid="ultest">
{props.users.map(user => <li key={user.id}>
<img src={user.avatar} alt={user.id}></img>
<div>{user.first_name} {user.last_name}
<p><a href={`mailto:${user.email}`}>{user.email}</a></p>
</div>
</li>)}
</ul>
</Card>
)
}
export default UserList;
I don't understand how to test UserList component. I want to test if it renders correctly but I always get:
TypeError: Cannot read property 'map' of undefined
When I use render.
What is the best way to test this component? Jest or testing library.
Any advice would be appreciated.
import React from 'react';
import { render} from '#testing-library/react';
import UserList from '../components/Users/UserList';
import '#testing-library/jest-dom/extend-expect';
test('to check if it renders', () => {
render (<UserList />)
});

Hey – You need to do it like so:
test('to check if it renders', () => {
render(<UserList users={someUsersDataHere}/>)
});
So your component can have users to map over. You will need to manually define some array of users or import the data from elsewhere if you have it already by any chance
const someUsersDataHere = [
{name: 'SomeName'},
....and so on
]

Related

Axios doesnt download users from API

I wanted to download users from API with axios but I get an error and when I remove {} from UsersProvider it doesn't download anything for me. How could this be fixed or changed?
Error
File Main:
import {UsersProvider} from "../../contexts/Users";
const Main:React.FC= () => {
const [showUser, setShowUser] = useState("");
return (
<div>
<div>
<Header/>
</div>
<UsersProvider>
<UsersList/>
<Debounce onChange={setShowUser}/>
</UsersProvider>
</div>
)
}
export default Main
File Users:
import React, {useState, useEffect} from 'react';
import axios from 'axios';
type Users = Person[];
type Person = {
name:string;
username:string;
}
export const UsersContext = React.createContext<Users>([]);
const UsersProvider:React.FC= ({children}) => {
const [users, setUsers] = useState<Person[]>([]);
useEffect(() => {
axios
.get(`https://jsonplaceholder.typicode.com/users`)
.then((response) =>{
setUsers(response.data);
})
.catch((error) => {
console.log(error);
});
},[]);
return (
<UsersContext.Provider value={users}>
{children}
</UsersContext.Provider>
)
}
export default UsersProvider
import { UsersProvider } from "../../contexts/Users";
Above import is called named import. But, in your code, you have exported UsersProvider as the default export in the ../../contexts/Users file. Hence you're getting that error.
This would work only if you have exported the UsersProvider as below in the ../../contexts/Users file.
export const UsersProvider: React.FC= ({children}) => {
// rest of the code...
But, If you don't want to have named exports then you can write your import like this:
import UsersProvider from "../../contexts/Users";
I just did that only I still have no idea why it is not downloading my user list from axios. Everything was working a few months ago, but now it doesn't download at all
import React from 'react';
import './style.css';
type Props = {
filteredUsers?:Array<Person>;
}
type Person = {
name:string;
username:string;
}
const UsersList: React.FC<Props> = ({filteredUsers = []}) =>{
return(
<div className="ListHead">
<ol className="list">
{filteredUsers.map((Person) => (
<li key={Person.name}>
<span>{Person.name}</span>
#{Person.username}
</li>
))}
</ol>
</div>
)}
export default UsersList
UsersProvider is a default export .
you need to do
import UsersProvider from "../../contexts/Users";
Since we are using the context now , we can consume the users in the UsersList as
import React, { useContext } from 'react';
import UsersContext from 'your path'
const UsersList: React.FC = () => {
const users = useContext(UsersContext);
return(
<div className="ListHead">
<ol className="list">
{users.map((Person) => (
<li key={Person.name}>
<span>{Person.name}</span>
#{Person.username}
</li>
))}
</ol>
</div>
)}
export default UsersList
I have this, but maybe something must change here?
import React from 'react';
import {DebounceInput} from 'react-debounce-input';
import './style.css';
type Props ={
onChange:Function;
}
const Debounce:React.FC<Props> = ({onChange}) => {
return(
<DebounceInput
onChange={(e) => onChange(e.target.value)}
debounceTimeout={500}
className="SearchInput"
placeholder="Search by user name..."
/>
)
}
export default Debounce

Passing down Props to "Single Page Views" through components

Hey still new to React but I'm grinding my way through it slowly by building my own personal app/platform. I have a quick question of passing down props to single page views. This is my overview page that will pull in all the teams from my database as such:
import React, { useState, useEffect } from 'react';
import firebase from '../../firebase/firebase.utils'
import Button from '../../Components/GeneralComponents/Button.component'
import * as GoIcons from 'react-icons/go';
import TeamList from '../../Components/Teams/TeamList.Component'
function TeamsPage() {
const [teams, setTeams] = useState([]);
const [loading, setLoading] = useState(false);
const ref = firebase.firestore().collection("teams");
function getTeams() {
setLoading(true);
ref.onSnapshot((querySnapshot) => {
const items = [];
querySnapshot.forEach((doc) => {
items.push(doc.data());
});
setTeams(items);
setLoading(false);
console.log(items);
});
}
useEffect(() => {
getTeams();
},[])
if(loading) {
return <h1>Loading...</h1>
}
return (
<div className="content-container">
<h2>Team Page</h2>
<div className="add-section">
<div className="actions">
<Button
className="bd-btn outlined add-team"
><GoIcons.GoGear/>
Add Team
</Button>
</div>
</div>
<TeamList teams={teams} />
</div>
)
}
export default TeamsPage;
This gets passed into my TeamList Component:
import React from 'react';
import { Link } from 'react-router-dom'
import { TeamCard } from './TeamCard.Component';
const TeamList = props => {
return(
<div className='teams-overview'>
{props.teams.map(team => (
<Link to={`/teams/${team.id}`}>
<TeamCard key={team.id} team={team}/>
</Link>
))}
</div>
)
}
export default TeamList;
Which maps through and then list the Team as a card component with a link that is supposed to route to their id and pass through their data.
Now in my single page view of a team I'm struggling to gain access to that prop data:
import React from 'react'
function TeamSinglePage(team) {
return (
<div className="content-container">
<h1>Single Page View</h1>
<p>Welcome, {team.teamName}</p>
</div>
)
}
export default TeamSinglePage;

Properly LogOut button React

can't get the logout button to work properly. I'm using React and Firebase.
Here is a portion of the code from App.js, where the function was declared
imports
import React, { useState, useEffect } from "react";
import { fire } from './fire';
import LogIn from './LogIn';
import Hero from './Hero';
import './App.css';
declaration
const handleLogout = () => {
fire.auth().signOut();
};
And here is the code from the Hero.js, where the function is used
import React from 'react';
import Contact from "./components/Contact";
const Hero = (handleLogout) => {
return(
<section className="hero">
<nav>
<h2>Welcome</h2>
<button onClick = {handleLogout}>Log Out</button>
</nav>
<div id="contact-form">
<Contact />
</div>
</section>
)
}
export default Hero;
What I'm doing wrong?
you need to get the handleLogout from props properly:
const Hero = ({handleLogout}) => {...}

Is it Possible to use Enzyme testing with Next js (SSR)?

It's My first Nextjs project with SSR.
When Integrating Enzyme For Reactjs UI Testing. it could not run due to "React' refers to a UMD global, but the current file is a module. Consider adding an import instead."
but it's works when i am using normal Reactjs Component(Functional or Class). Anyone Please give suggestions.
SandBox Link - https://codesandbox.io/s/currying-moon-gdk09
Full code From GitHub - https://github.com/Rizz13/nextJs-with-Enzyme
to run testing Use "npm test"
pages/Index.tsx
import Head from 'next/head'
import Link from 'next/link'
import { GetStaticProps } from 'next'
export default function Home({
allPostsData
}: {
allPostsData: {
title: string
id: string
}[]
}) {
return (
<>
<Head>
<title>Sample Page</title>
</Head>
<section className="icon-stars">
<p>[Your Self Introduction]</p>
<p>
(This is a sample website - you’ll be building a site like...)
</p>
</section>
<section>
<h2>Blog</h2>
<ul>
{allPostsData.map(({ id, title }) => (
<li key={id}>
<Link href="#">
<a>{title}</a>
</Link>
<br />
</li>
))}
</ul>
</section>
</>
)
}
export const getStaticProps: GetStaticProps = async () => {
const allPostsData = [{id: 0, title:"Sample1"}, {id: 1, title:"Sample2"}]
return {
props: {
allPostsData
}
}
}
_tests_/Index.tsx
import * as React from 'react'
import { expect as expect1 } from 'chai';
import IndexPage from '../pages/index'
import {/*mount,*/ shallow} from 'enzyme'
const setUp1 = (data) => {
return shallow(<IndexPage {...data} />);
}
let wrapper;
describe('props Check', () => {
beforeEach(() => {
wrapper = setUp1({});
});
it('should render an `.icon-stars`', () => {
expect1(wrapper.find('.icon-stars')).to.have.length(1);
});
});
When I using the Above Code Testing could not run due to below Error.
tests/Index.tsx
import * as React from 'react'
import { expect as expect1 } from 'chai';
import IndexPage from '../pages/index'
import {/*mount,*/ shallow} from 'enzyme'
const setUp1 = (data) => {
return shallow(<IndexPage {...data} />);
}
let wrapper;
describe('props Check', () => {
beforeEach(() => {
wrapper = setUp1(allPostsData={[]});
});
it('should render an `.icon-stars`', () => {
expect1(wrapper.find('.icon-stars')).to.have.length(1);
});
});
You have to pass props inside the testing component & use
import * as React from 'react'
In pages/Index.tsx for rendering react components

How to show my data in Unordered list format in React?

I am working on a React project, In my project I have four components those are App, Componentc,
Componente, Componentf. Now I am trying to pass an Array from App to Componentf using Context API
I successfuly passed an Array, but the problem is in output the Array is showing like side by
side. but what I am expecting it has to show like Unordered list in html
Please help me to acheive this
This is App.js
import React from 'react';
import Componentc from './Componentc/Componentc';
// import './App.css';
export const UserContext = React.createContext()
const fruits = ['Apple','Orange','Banana','Grapes']
function App() {
return (
<div className="App">
<UserContext.Provider value={fruits}>
<Componentc></Componentc>
</UserContext.Provider>
</div>
);
}
export default App;
This is Componentc
import React from 'react';
import './Componentc.css';
import Componente from '../Componente/Componente';
const Componentc = () => {
return(
<Componente></Componente>
)
}
export default Componentc
This is Componente
import React from 'react';
import './Componente.css';
import Componentf from '../Componentf/Componentf';
const Componente = () => {
return(
<Componentf></Componentf>
)
}
export default Componente
This is Componentf
import React from 'react';
import './Componentf.css';
import { UserContext } from '../App'
const Componentf = () => {
return (
<div>
<UserContext.Consumer>
{
user => {
return <div className='d-block'>{user}</div>
}
}
</UserContext.Consumer>
<h1>Component F</h1>
</div>
)
}
export default Componentf
The value of your context is an array, but you are treating it like an object in the context consumer.
You only need to change return <div className='d-block'>{user}</div> by :
{user => {
return user.map(t => (
<div key={t} className="d-block">
{t}
</div>
));
}}
Although your variables should have meaningful names; I recommend changing the name of the user context and variable to be fruits.
Also, If you are using a recent react version (> 16.8), I also recommend that you use React.useContext API to receive values from context, code become more readable.
const Componentf = () => {
const fruits = React.useContext(FruitContext);
return (
<div>
{fruits.map(fruit => (
<div key={fruit} className="d-block">
{fruit}
</div>
))}
<h1>Component F</h1>
</div>
);
};
Here is a codesandbox demo

Resources