Testing HOC wrapped React Component - reactjs

I'm trying to test hoc wrapped component.
The component calls an apollo query inside.
const Header: React.FC<IProps> = ({}) => {
const { data, loading } = useMeQuery();
return (
<>
{!data?.me.verified && (
<div className="bg-red-500 p-3 text-center text-sm text-white font-bold">
<span>Please verify your email</span>
</div>
)}
<header className="py-4">
<div className="w-full px-5 xl:px-0 max-w-screen-xl bg-yellow-500 mx-auto">
<Image
src="/pineapple.png"
alt="pineapple-logo"
width="64"
height="64"
/>
{data ? (
<NextLink href="edit-profile">
<Link>
<span className="text-sm">
<FontAwesomeIcon className="text-xl" icon={faUser} />
{data?.me.email}
</span>
</Link>
</NextLink>
) : (
<div>Login</div>
)}
</div>
</header>
</>
);
};
export { Header as PureHeader };
export default withApollo()(Header);
import { render, waitFor } from "#testing-library/react";
import React from "react";
import Header, { PureHeader } from "../../src/components/Header";
import { ApolloProvider } from "#apollo/client";
import { createMockClient } from "mock-apollo-client";
import { MockedProvider } from "#apollo/client/testing";
import withApolloMocked from "../../src/apollo/__mock__/withApolloMocked";
describe("<Header />", () => {
it("renders ok", async () => {
const mockedClient = createMockClient();
render(
<ApolloProvider client={mockedClient}>
<PureHeader />
</ApolloProvider>
);
});
});
Even if I imported Pure Component without hoc, I get the same error when running the test.
However, if remove the hoc and export default Header (which is a pure component), it then passes the test... ;;;
import React from "react";
import Image from "next/image";
import { useMeQuery } from "../generated/graphql";
import { FontAwesomeIcon } from "#fortawesome/react-fontawesome";
import { faUser } from "#fortawesome/free-solid-svg-icons";
import NextLink from "next/link";
import { Link } from "#chakra-ui/react";
import withApollo from "../apollo/withApollo";
interface IProps {}
const Header: React.FC<IProps> = ({}) => {
const { data, loading } = useMeQuery();
return (
<>
{!data?.me.verified && (
<div className="bg-red-500 p-3 text-center text-sm text-white font-bold">
<span>Please verify your email</span>
</div>
)}
<header className="py-4">
<div className="w-full px-5 xl:px-0 max-w-screen-xl bg-yellow-500 mx-auto">
<Image
src="/pineapple.png"
alt="pineapple-logo"
width="64"
height="64"
/>
{data ? (
<NextLink href="edit-profile">
<Link>
<span className="text-sm">
<FontAwesomeIcon className="text-xl" icon={faUser} />
{data?.me.email}
</span>
</Link>
</NextLink>
) : (
<div>Login</div>
)}
</div>
</header>
</>
);
};
// export { Header as PureHeader };
// export default withApollo()(Header);
export default Header;
import { render, waitFor } from "#testing-library/react";
import React from "react";
// import Header, { PureHeader } from "../../src/components/Header";
import Header from "../../src/components/Header";
import { ApolloProvider } from "#apollo/client";
import { createMockClient } from "mock-apollo-client";
import { MockedProvider } from "#apollo/client/testing";
import withApolloMocked from "../../src/apollo/__mock__/withApolloMocked";
describe("<Header />", () => {
it("renders ok", async () => {
const mockedClient = createMockClient();
render(
<ApolloProvider client={mockedClient}>
<Header />
</ApolloProvider>
);
});
});
Did I miss something? OR Is it just a bug?
I'm not quite sure how to deal with this problem...

Related

Full-height column using Tailwind CSS

I have a React project using Tailwind CSS and I want the sidebar to take the full height below the logo and have the links to the left with a specific width, but it is not working
profile.jsx
import { useContext, useState } from "react";
import { useLocation } from "react-router-dom";
import { UserContext } from "../App";
import ProfileView from "./profileView"
function Profile() {
const location = useLocation();
const msg = location.state?.mes;
const [success, setSuccess] = useState(msg === undefined ? "" : msg);
const [cancel, setCancel] = useState(msg === undefined ? "" : "X");
const [name, setName] = useState(
msg === undefined
? "h-0"
: "h-10 flex justify-around items-center bg-green-200 text-black"
);
const { state, dispatch } = useContext(UserContext);
function handleClick() {
setSuccess("");
setCancel("");
setName("h-0");
}
return (
<>
<div className={name}>
{success}
<button onClick={handleClick}>{cancel}</button>
</div>
{state.logStatus ? (
<div className="h-full">
<ProfileView />
</div>
) : (
<div className="h-96 bg-red-200 flex justify-center items-center text-3xl font-bold">
<div>You need to login in order to view your profile!</div>
</div>
)}
</>
);
}
export default Profile;
profileView.jsx
import { Component, useContext, useEffect, useState } from "react";
import { UserContext } from "../App";
import AdminProfile from "./adminProfile";
import StudentProfile from "./studentProfile";
import TeacherProfile from "./teacherProfile";
function ProfileView() {
const { state, dispatch } = useContext(UserContext);
return (
<div className="h-full">
{state.identity.id === "admin" ? (
<AdminProfile />
) : state.identity.id === "teacher" ? (
<TeacherProfile />
) : (
<StudentProfile />
)}
</div>
);
}
export default ProfileView;
studentProfile.jsx
import { SiGoogleclassroom } from "react-icons/si";
import { FaHouseUser } from "react-icons/fa";
import { MdGrade } from "react-icons/md";
import { MdManageAccounts } from "react-icons/md";
import { Link } from "react-router-dom";
const side = [
{ title: "Class", icon: <SiGoogleclassroom />, link: "/class" },
{ title: "Dormitory", icon: <FaHouseUser />, link: "/dormitory" },
{ title: "Grade", icon: <MdGrade />, link: "/grade" },
{ title: "Account", icon: <MdManageAccounts />, link: "/account" },
];
function StudentProfile() {
return (
<div className="bg-[#2f4050] text-white box-border w-1/4 h-full">
{side.map((val, index) => {
return (
<Link to={val.link} key={index}>
<div>{val.icon}</div>
<div>{val.title}</div>
</Link>
);
})}
</div>
);
}
export default StudentProfile;
The section is not taking the full height because you haven't defined a height for the parent of the following component (which is react fragment)
<div className="h-full">
<ProfileView />
</div>
So giving a value for the height of the above component would get your job done.
Note: Since a fragment is the parent of the above component, you have to replace it with a JSX element.
<div className="h-[100vh]">
<div className="h-full">
<ProfileView />
</div>
</div>

Unable to test a component with useLocation hook

I have a Headercomponent as follows:
const Header = () => {
const data = useDataContext().header;
return <div data-testid="header" className="w-full h-[80px] bg-white">
<div className="h-1 bg-green-400 w-full"/>
<div className="flex items-center w-full h-[80px] shadow-sm">
<div className="flex items-center flex-1 h-full">
<Navigation applications={data.apps}/>
</div>
<div className="flex items-center pl-4 h-full">
<Account />
</div>
</div>
</div>
}
The Navigation component is as follows:
import React, {useState} from 'react';
import {App} from "../../../../interfaces/interfaces";
import {map, find, filter} from "lodash";
import NavigationItem from "./NavigationItem";
import { useLocation, useNavigate } from 'react-router-dom';
interface NavigationProps {
applications: App[]
}
const Navigation:React.FC<NavigationProps> = ({applications}: NavigationProps) => {
const [expanded, setExpanded] = useState<boolean>(false)
const location = useLocation();
const navigate = useNavigate();
const activeApplication = find(applications, application => application.url === location.pathname);
const inactiveApplications = filter(applications, application => application.url !== location.pathname)
return (
<div className="flex h-full">
<div className="z-[2]">
<NavigationItem application={activeApplication}
handleClick={() => setExpanded(expanded => !expanded)}
expanded={expanded}
/>
</div>
<div className={`flex transform transition transition-transform ${expanded ? 'translate-x-0' : '-translate-x-full'}`}>
{map(inactiveApplications, application => {
return <NavigationItem application={application}
handleClick={() => {
setExpanded(false);
navigate(application.url);
}}
/>
})}
</div>
</div>
);
};
export default Navigation;
Thus the Navigation component uses the useLocation hook from react-router-dom.
I want to write some tests for Header component and the header.test.tsx is as follows:
import Header from "./Header";
import {MemoryRouter} from "react-router-dom";
import {describe, it} from "#jest/globals";
import {render, screen} from "#testing-library/react";
describe("<Header/>", () => {
it("renders the header component with Home link", () => {
render(<MemoryRouter initialEntries={["/home"]}>
<Header/>
</MemoryRouter>);
const textElement = screen.getByText(/Home/i);
expect(textElement).toBeInTheDocument();
const headerElement = screen.getByTestId("header");
expect(headerElement).toBeInTheDocument()
// expect(screen.getByRole('link')).toHaveAttribute('href', 'https://www.test.com');
});
});
Thus I wrap the header component with MemoryRouter but it still gives me an error as follows:
useLocation() may be used only in the context of a <Router> component.
What do I do wrong?
Thanks in advance.
Your render should look like this
render(
<MemoryRouter initialEntries={["/home"]}>
<Routes>
<Route path="/home" element={<Header/>} />
</Routes>
</MemoryRouter>
)

NextJs router seems very slow

The problem is about that is taking long time to response another route. It seems next router's error and it can cause by this ("getServerSideProps"). How can I change with this code to another or did I need to change react router instead? This is index which used ("getServerSideProps") -
import axios from 'axios';
import VideoCard from '../components/VideoCard';
import { BASE_URL } from '../utils';
import { Video } from '../types';
import NoResults from '../components/NoResults';
interface IProps {
videos: Video[];
}
const Home = ({ videos }: IProps) => {
return (
<div className='flex flex-col gap-10 videos h-full'>
{videos.length
? videos?.map((video: Video) => (
<VideoCard post={video} isShowingOnHome key={video._id} />
))
: <NoResults text={`No Videos`} />}
</div>
);
};
export default Home;
export const getServerSideProps = async ({
query: { topic },
}: {
query: { topic: string };
}) => {
let response = await axios.get(`${BASE_URL}/api/post`);
if(topic) {
response = await axios.get(`${BASE_URL}/api/discover/${topic}`);
}
return {
props: { videos: response.data },
};
};
This is from another code with that used next router
import React, { useState } from 'react';
import { NextPage } from 'next';
import { useRouter } from 'next/router';
import Link from 'next/link';
import { AiFillHome, AiOutlineMenu } from 'react-icons/ai';
import { ImCancelCircle } from 'react-icons/im';
import SuggestedAccounts from './SuggestedAccounts';
import Discover from './Discover';
import Footer from './Footer';
import useAuthStore from '../store/authStore';
const Sidebar: NextPage = () => {
const [showSidebar, setShowSidebar] = useState<Boolean>(true);
const { pathname } = useRouter();
const { fetchAllUsers, allUsers }: any = useAuthStore();
const activeLink = 'flex items-center gap-3 hover:bg-primary p-3 justify-center xl:justify-start cursor-pointer font-semibold text-[#F51997] rounded';
const normalLink = 'flex items-center gap-3 hover:bg-primary p-3 justify-center xl:justify-start cursor-pointer font-semibold rounded';
return (
<div>
<div
className='block xl:hidden m-2 ml-4 mt-3 text-xl'
onClick={() => setShowSidebar(!showSidebar)}
>
{showSidebar ? <ImCancelCircle /> : <AiOutlineMenu />}
</div>
{showSidebar && (
<div className='xl:w-400 w-20 flex flex-col justify-start mb-10 border-r-2 border-gray-100 xl:border-0 p-3 '>
<div className='xl:border-b-2 border-gray-200 xl:pb-4'>
<Link href='/'>
<div className={pathname === '/' ? activeLink : normalLink}>
<p className='text-2xl'>
<AiFillHome />
</p>
<span className='capitalize text-xl hidden xl:block'>
For You
</span>
</div>
</Link>
</div>
<Discover />
<SuggestedAccounts
fetchAllUsers={fetchAllUsers}
allUsers={allUsers}
/>
<Footer />
</div>
)}
</div>
);
};
export default Sidebar;

React render an element corectly

I have a little problem, I try to build a language learning website using React,
this is my initial homepage, and when i try to search for a word and that word doesn't exist in the database my website it s supposed to say "we can't find the word in our database" but that message it's generated on the top on my slideshow.. like
And i literally don't know what can i do..
my homepage code:
import React from 'react';
import Carousel from 'react-bootstrap/Carousel';
import pozika from '../images/telescop.png';
import '../../src/Ceseseu.css';
import pozika2 from '../images/door.png';
import pozika3 from '../images/threeword.png';
import pozaAbout from '../images/learnkorean.jpg';
import { FontAwesomeIcon } from '#fortawesome/react-fontawesome';
import NavbarFunction from '../pages/NavBarAndSearchSentence';
import { faCheckSquare } from '#fortawesome/free-solid-svg-icons';
function HomePageSlideShow() {
return (
<>
<div className='test '>
<Carousel>
{/* <div className='letsDoIt'> */}
<Carousel.Item interval={1000}>
<img
className='d-block w-100'
width={900}
height={500}
src={pozika}
alt='First slide'
/>
<Carousel.Caption>
<h3></h3>
<p></p>
</Carousel.Caption>
</Carousel.Item>
{/* </div> */}
<Carousel.Item interval={1000}>
<img
className='d-block w-100 '
src={pozika2}
alt='Third slide'
width={100}
height={500}
/>
<Carousel.Caption>
<h3></h3>
<p></p>
</Carousel.Caption>
</Carousel.Item>
<Carousel.Item interval={1000}>
<img
className='d-block w-100'
src={pozika3}
alt='Third slide'
width={900}
height={500}
/>
<Carousel.Caption>
<h3></h3>
<p></p>
</Carousel.Caption>
</Carousel.Item>
</Carousel>
</div>
</>
);
}
function HomePage() {
return (
<>
<HomePageSlideShow />
</>
);
}
export default HomePage;
and my function for searching process it s in another class, same class with my nav bar
import React from 'react';
import SentencesByWord from './SentencesByWord';
import { useState } from 'react';
import { Redirect } from 'react-router-dom';
import { useHistory } from 'react-router-dom';
import 'bootstrap/dist/css/bootstrap.min.css';
import { Navbar, Nav, Form, FormControl, Button } from 'react-bootstrap';
function NavbarFunction() {
const [sentence, setSentence] = useState('');
const [fetchu, setFetchu] = useState('');
const [error, setError] = useState('');
let history = useHistory();
const FetchData = () => {
fetch(`http://localhost:8080/words/showSentences?word=` + sentence)
.then((response) => response.json())
.then(setFetchu)
.then(console.log(fetchu))
.catch(function (error) {
console.log('mergi');
setError("We can't find the word in our database");
});
history.push('/home');
};
const OnChangerr = (e) => {
setSentence(e.target.value);
};
const HandleKeypress = (e) => {
if (e.keyCode === 13) {
FetchData();
}
};
return (
<>
<div className='inlineu'>
<Navbar bg='dark' variant='dark'>
<Navbar.Brand href='Home'>LearningVocab</Navbar.Brand>
<Nav className='mr-auto'>
<Nav.Link href='GiveMeSentences'>
Random Sentences
</Nav.Link>
<Nav.Link href='SendEmail'>
Send us your thoughts
</Nav.Link>
<Nav.Link href='SearchByWord'>Pricing</Nav.Link>
</Nav>
<Form inline>
<FormControl
type='text'
placeholder='Search'
className='mr-sm-2'
onChange={OnChangerr}
onKeyDown={HandleKeypress}
/>
<Button variant='outline-info' onClick={FetchData}>
Search
</Button>
</Form>
</Navbar>
</div>
{fetchu ? (
<div>
<h1> {fetchu.korfirstSentence} </h1>
<h1>{fetchu.kosecondSentence}</h1>
<h1>{fetchu.kothirdSentence}</h1>
<h1>{fetchu.kowordTranslation}</h1>
<h1>{fetchu.kowordId}</h1>
</div>
) : (
// <h1> {fetchu.kosecondSentence} </h1>
<h1 className='someSpace'>{error}</h1>
)}
</>
);
}
export default NavbarFunction;
i used boostrap for css
My react component tree:

redux function not able to implement in the react app

First of all, I like to apologize for writing such a long post.I'm new to react and redux and I have created an ecommerce app. After implementing redux, I'm getting this error.
./src/Main.js
36:12-26 './redux/configureStore' does not contain an export named 'ConfigureStore'.
My code:
index.js
import React from "react";
import ReactDOM from "react-dom";
import Main from "./Main";
import "./index.css";
import 'bootstrap/dist/css/bootstrap.css';
import {BrowserRouter} from 'react-router-dom';
ReactDOM.render((
<BrowserRouter>
<Main/>
</BrowserRouter>
)
,
document.getElementById("root")
);
Main.js
import React, { Component } from "react";
import 'bootstrap/dist/css/bootstrap.min.css';
import $ from 'jquery';
import Popper from 'popper.js';
import 'bootstrap/dist/js/bootstrap.bundle.min';
import { Route, Switch, withRouter} from 'react-router-dom';
import Navigation from "./components/topNavigation";
import Footer from "./components/Footer";
import Banner from "./components/Banner";
import PLPMenu from "./components/PLPMenu";
import PDP from "./components/PDP";
import Login from "./components/Login"
import Home from "./components/Home";
import { Provider } from 'react-redux';
import { ConfigureStore } from './redux/configureStore';
import {connect} from 'react-redux';
const mapStateToProps = state =>{
return {
topnavigation: state.topnavigation,
plpmenu: state.plpmenu,
pdpmenu : state.pdpmenu
}
}
const store = ConfigureStore();
class Main extends Component {
render() {
return (
<Provider store={store}>
<div>
<Login />
<Navigation />
<Switch>
<Route exact path="/" component={Home} />
<Route path="/Apparel/:category/:subCategory/:id" component={PLPMenu} />
<Route path="/Apparel/:product/:id" component={PDP} />
<Route path="/login" component={Login} />
<Route path="/Banner" component={Banner} />
<Route path="/Footer" component={Footer} />
</Switch>
</div>
</Provider>
)
}
}
export default withRouter(connect(mapStateToProps)(Main));
topNavigation.js
import React, { Component } from 'react';
import axios from 'axios';
import SubMenu from './subMenu';
class Navigation extends Component {
state = {
mainCategory: []
}
componentDidMount() {
axios.get('http://localhost:3030/topCategory')
.then(res => {
// console.log(res.data.express);
this.setState({
mainCategory: res.data.express.catalogGroupView
})
})
}
render() {
const { mainCategory } = this.props;
return (
<nav className="navbar navbar-expand-lg navbar-dark bg-dark mainmenu">
<a className="navbar-brand" href="#">iFashion</a>
<button className="navbar-toggler" type="button" data-toggle="collapse" data-target="#navbarNav" aria-controls="navbarNav" aria-expanded="false" aria-label="Toggle navigation">
<span className="navbar-toggler-icon"></span>
</button>
<div className="collapse navbar-collapse" id="navbarNav">
<ul className="navbar-nav ml-auto">
{
mainCategory.map(navList => (
<li className="nav-item dropdown" key={navList.uniqueID}>
<a className="nav-link dropdown-toggle" id="navbarDropdown" role="button" data-toggle="dropdown" aria-haspopup="true" aria-expanded="false">{navList.name} </a>
<ul className="dropdown-menu secondDropdown" aria-labelledby="navbarDropdown">
<SubMenu below={navList.catalogGroupView} />
</ul>
</li>
))
}
</ul>
</div>
</nav>
)
}
}
export default Navigation;
PLPMenu.js
import React, { Component } from "react";
import { Link } from "react-router-dom";
import Footer from "./Footer";
import axios from "axios";
class PLPMenu extends Component {
state = {
shoeCategory: []
};
fetchData = id => {
axios
.get(`http://localhost:3030/category/` + id)
.then(response => {
console.log(response.data.express.catalogEntryView);
this.setState({
shoeCategory: response.data.express.catalogEntryView
});
})
.catch(err => {
console.log(err);
});
};
componentDidMount() {
let { id } = this.props.match.params;
this.fetchData(id);
}
componentDidUpdate(prevProps) {
let currentId = this.props.match.params.id;
let previousId = prevProps.match.params.id;
if (currentId !== previousId) {
this.fetchData(currentId);
}
}
render() {
const { shoeCategory } = this.props;
const picUrl = "https://149.129.128.3:8443";
return (
<div>
<div className="container">
<div className="row">
{shoeCategory &&
shoeCategory.map(shoeList => {
return (
<div key={shoeList.uniqueID} className="col-md-4">
<h2 key={shoeList.uniqueID} />
<img className="plpImage" src={picUrl + shoeList.thumbnail} />
<Link to={`/Apparel/${shoeList.name}/${shoeList.uniqueID}`}>
<p className="pdp">{shoeList.name}</p>
</Link>
<p>
Price : {shoeList.price[0].value}{" "}
{shoeList.price[0].currency}
</p>
</div>
);
})}
</div>
</div>
<Footer/>
</div>
);
}
}
export default PLPMenu;
PDP.js
import React, { Component } from "react";
import { Route, Link, BrowserRouter } from "react-router-dom";
import axios from "axios";
class PDP extends Component {
state = {
pdpCategory: []
};
fetchData = id => {
axios
.get(`http://localhost:3030/product/` + id)
.then(response => {
console.log(response.data.express.catalogEntryView);
this.setState({ pdpCategory: response.data.express.catalogEntryView });
})
.catch(err => {
console.log(err);
});
};
componentDidUpdate(prevProps) {
let currentId = this.props.match.params.id;
let previousId = prevProps.match.params.id;
if (currentId !== previousId) {
this.fetchData(currentId);
}
}
componentDidMount() {
let { id } = this.props.match.params;
this.fetchData(id);
}
render() {
const { pdpCategory } = this.props;
console.log(pdpCategory);
const picUrl = "https://149.129.128.3:8443";
return (
<div>
<div className="container">
<div className="row">
{pdpCategory &&
pdpCategory.map(pdpList => {
return (
<div key={pdpList.uniqueID} className="col-md-4">
<h2 key={pdpList.uniqueID} />
<img className="pdpImage " src={picUrl + pdpList.thumbnail} />
<p>
Price : {pdpList.price[0].value}{" "}
{pdpList.price[0].currency}
</p>
<p>
Description: {pdpList.longDescription}
</p>
<button type="submit">Add to Cart</button>
</div>
);
})}
</div>
</div>
</div>
);
}
}
export default PDP;
For the redux to implement, I have created a redux folder inside ./src folder and have created two files reducer.js and configureStore.js
import PLPMenu from "../components/PLPMenu";
import PDP from "../components/PDP";
import Navigation from "../components/topNavigation";
export const initialState = {
topnavigation: Navigation,
plpmenu: PLPMenu,
pdpmenu : PDP
};
export const Reducer = ( state = initialState , action) => {
return state;
};
configureStore.js
import { createStore} from 'redux';
import {Reducer, initialState} from './reducer';
export const Configuration = () =>{
const store = createStore(
Reducer,
initialState,
);
return store;
}
I don't know where my code is getting wrong. There is only a single error in the console browser window, which I have shared above. Can anyone please help me on this or given an insight how to perfectly implement a redux store.
change import { ConfigureStore } from './redux/configureStore';
to
import { Configuration } from './redux/configureStore'; in Main.js

Resources