Enzyme unit test is passing test when it should fail - reactjs

I'm trying to test a component it has two props title, and url.
I'm unsure how to pass mock data, i made an attempt but it passes but im pretty sure its not reading whats in the data object
Both tests are passing.
Card.js
import React, {Component} from 'react';
const Styles = {
width: '300px',
height: '300px'
}
class Card extends React.Component {
render() {
return (
<div>
{/* Renders title of the GIY */}
<h1>{this.props.title}</h1>
<div >
<img alt="" src={this.props.url}/>
</div>
</div>
);
}
}
export default Card;
Card.test.js
import React from 'react';
import ReactDOM from 'react-dom';
import {shallow} from 'enzyme';
import Card from './Card';
describe('Should render Card Component', ()=> {
it('should render card component', ()=> {
const component = shallow(<Card />);
})
});
describe('Should render title/ url prop', ()=>{
it('should render title /url prop', ()=>{
// trying to mock data for the Card component
const data = {
title: "owl",
url:"https://giphy.com/gifs/bird-owl-qISaMW1xwmvNS"
}
const component = shallow(<Card title={data.title} url={data.url}/>)
})
})

You're not making any assertions. You need to expect some result to happen.
Card.js (this can be a pure function if it doesn't require state)
import React from "react";
import PropTypes from "prop-types";
const styles = {
width: "300px",
height: "300px"
};
const Card = ({ title, url }) =>
title && url ? ( // if a title and url are passed in, return <div>...</div>, else return "null"
<div className="card">
<h1>{title}</h1>
<div>
<img alt="" src={url} styles={styles} />
</div>
</div>
) : null;
// PropTypes will throw a warning if either of them is missing
PropTypes.propTypes = {
title: PropTypes.string.isRequired,
url: PropTypes.string.isRequired
};
export default Card;
Card.test.js
import React from "react";
import { shallow } from "enzyme";
import Card from "../index";
// we define initial props (empty strings)
const initialProps = {
title: "",
url: ""
};
// we shallow wrap the Card while passing in the "initialProps"
const wrapper = shallow(<Card {...initialProps} />);
// we define some props that will be passed in during our second test
const nextProps = {
title: "owl",
url: "https://media.giphy.com/media/qISaMW1xwmvNS/giphy.gif"
};
describe("Card Component", () => {
afterAll(() => wrapper.unmount());
it("shouldn't render a card without the required props", () => {
expect(wrapper.type()).toBeNull();
});
it("should render a card if the required props are present", () => {
wrapper.setProps({ ...nextProps }); // we update the component with "nextProps"
expect(wrapper.find("div.card")).toHaveLength(1); // expect "div.card" to be present
expect(wrapper.find("h1").text()).toContain(nextProps.title); // expect the "h1" element to contain "owl"
expect(wrapper.find("img").prop("src")).toBe(nextProps.url); // expect the "img"'s src to be "https://media.giphy.com/media/qISaMW1xwmvNS/giphy.gif"
});
});
Working example: https://codesandbox.io/s/k35zpqwk97

Related

React Jest testing : TestingLibraryElementError: Unable to find an element

i can't get the test id within my jest test. I am new to react testing. I want to test this component and get back for example the h3 text what was given before.
Tells me:
"TestingLibraryElementError: Unable to find an element by: [data-testid="testH3"]"
Can you help me?
// Component
import React from 'react';
import './Card.scss';
import Card from '#material-ui/core/Card';
import { Link } from "react-router-dom";
function MovieCard({title, image}) {
return (
<div className="card__container">
<Link to={"/details/" + title}>
<Card className="card">
<img src={image} alt=""/>
<div className="card__info">
<h3
data-testid="testH3"
className="card__title">{ title }
</h3>
</div>
</Card>
</Link>
</div>
)
}
export default MovieCard
// test
import React from 'react';
import { render, screen, cleanup } from '#testing-library/react';
import MovieCard from '../MovieCard';
import { BrowserRouter as Router } from "react-router-dom";
afterEach(cleanup);
describe('Test MovieCard', () => {
const tree = render(
<Router>
<MovieCard title="Batman" image="imagesrc"/>
</Router>
)
it('should match with snapshot', () => {
screen.debug();
expect(tree).toMatchSnapshot();
});
it('test h3', () => {
const {getByTestId} = tree;
const element = screen.getByTestId('testH3')
});
});
UPDATE:
Final code works now pretty well. Thank you guys
import React from 'react';
import { render, screen, cleanup } from '#testing-library/react';
import MovieCard from '../MovieCard';
import { BrowserRouter as Router } from "react-router-dom";
afterEach(cleanup);
describe('Test MovieCard', () => {
function tree() {
return render(
<Router>
<MovieCard title="Batman" image="imagesrc"/>
</Router>
)
}
it('should match with snapshot', () => {
expect(tree()).toMatchSnapshot();
});
it('test h3 text is Batman', () => {
const {getByTestId} = tree();
const element = screen.getByTestId('testH3')
expect(element.textContent).toEqual("Batman")
screen.debug();
});
});
use function instead of const
describe('Test MovieCard', () => {
function tree() {
return render(
<Router>
<MovieCard title="Batman" image="imagesrc"/>
</Router>
)
}
it('should match with snapshot', () => {
screen.debug();
expect(tree()).toMatchSnapshot();
});
it('test h3', () => {
const {getByTestId} = tree();
const element = screen.getByTestId('testH3')
});
});

Type '{ children: Element; }' has no properties in common with type 'IntrinsicAttributes' React -typescript Context

I'm currently coding a React -typescript App for practising FluentUI (a.k.a Fabric). Issue appears
with my App.tsx component.
import React, { useContext, useState } from 'react';
import logo from './logo.svg';
import './App.css';
import Search from './components/Search';
//import CategoriasProvider from './components/Context/CategoriasContext';
import Title from './components/Title';
import { ListGhostingExample } from '../src/components/DrinkList';
import { PrimaryButton } from 'office-ui-fabric-react';
import { CategoriasContext, ICategoriasContextInterface } from './components/Context/CategoriasContext';
import CategoriasProvider from './components/Context/CategoriasContext';
import axios from 'axios';
import './components/DrinkList.css'
import './components/Search.css'
interface IApp{
items:ICategoriasContextInterface[],
renderList:boolean
}
const App =()=> {
const contextValues=useContext(CategoriasContext);
return(
<CategoriasProvider>
<div className="App">
<div className="search">
<Search name={contextValues?.name} image={contextValues?.image} thumbnail={contextValues?.thumbnail} />
</div>
</div>
</CategoriasProvider>
);
}
export default App;
CategoriasProvider comes from a Context (CategoriasContext.tsx ). CategoriasProvider has the mentioned error Inside of CategoriasProvider there's a Search.tsx Component.Search's works as a "wrapper". Code is:
import React, { useEffect, useState } from 'react';
import { SearchBox,ISearchBoxStyles } from 'office-ui-fabric-react/lib/SearchBox';
import { PrimaryButton, IContextualMenuProps, Stack, IStackTokens, StackItem, initializeIcons } from 'office-ui-fabric-react';
import { ComboBox, DefaultPalette, Dropdown, DropdownMenuItemType, IComboBoxOption, IDropdownOption, IDropdownStyles, IStackItemStyles, SelectableOptionMenuItemType, Toggle } from '#fluentui/react';
import { getGlassesOriginal } from './Utils/Utils';
import axios from 'axios';
import '../Search.css';
import { CategoriasContext, ICategoriasContextInterface } from './Context/CategoriasContext';
initializeIcons();
const Search = (props:ICategoriasContextInterface) => {
//State
const [textContent, setTextContent] = useState("");
const [textBoxDisabled,disableTextBox]=useState(false);
const [comboBoxDisabled,disableComboBox]=useState(true);
const CategoriasContextInSearch=React.useContext(CategoriasContext);
const setTextContentInstate = (e: any) =>{
console.log("Contenido de e" + e.target.value);
setTextContent(e.target.value);
}
const showMessageInConsole = ():void => {
console.log(textContent);
setTextContent("");
}
// Example formatting
const stackTokens: IStackTokens = { childrenGap: 20 };
const searchBoxStyles: Partial<ISearchBoxStyles> = { root: { width: 200 } };
const dropdownStyles: Partial<IDropdownStyles> = {
dropdown: { width: 200 },
};
const options: IDropdownOption[] = [
{ key: 'glasses', text: 'Glasses', itemType: DropdownMenuItemType.Header },
];
function getGlasses () {
let outputArray:string[] = [];
console.log("getGlasses");
axios
.get("https://www.thecocktaildb.com/api/json/v1/1/list.php?g=list")
.then((response)=>{
let responseDataJson=response.data.drinks;
for (let element in responseDataJson) {
options.push({key:responseDataJson[element].strGlass,text:responseDataJson[element].strGlass});
}
}
)
return outputArray;
}
function selectSearch(){
if(textBoxDisabled){
disableTextBox(false);
disableComboBox(true);
} else {
disableTextBox(true);
disableComboBox(false);
};
}
useEffect(() => {
//TODO: No se debería llamar siempre a esta función. Solamente cuando se activa el sistmea de búsqueda (y además, cachearlo)
getGlasses()
});
return(
<div className="wrapper">
<div className="one"> <Toggle onClick={selectSearch}/></div>
<div className="two">
{
<SearchBox
name="searchBox"
className="searchBox"
styles={searchBoxStyles}
placeholder="Cheers!"
onChange={setTextContentInstate}
value={textContent}
disabled={textBoxDisabled}
/>
}
</div>
<div className="three">
<Dropdown
placeholder="Select a glass"
options={options}
styles={dropdownStyles}
disabled={comboBoxDisabled}
/>
</div>
<div className="four">
<div className="primaryButton">
<PrimaryButton text="Search" onClick={showMessageInConsole}/>
</div>
</div>
</div>
);
}
export default Search;
Hope you can help me!!! Thanks in advance!
The code which is causing the error in your title is in your comment. It's this line:
export const CategoriasProvider = () => {
You are defining CategoriasProvider as a component which takes no props. It can only accept IntrinsicAttributes which is basically just the key property.
But when you use CategoriasProvider in App you are calling it with JSX element children. You get an error because you have not said that the CategoriasProvider component can accept a children prop.
Any of the following types will solve your problem:
export const CategoriasProvider: React.FC = ({children}) => {
export const CategoriasProvider = ({children}: {children: React.ReactNode}) => {
export const CategoriasProvider = ({children}: React.PropsWithChildren<{}>) => {
Regardless, you'll want to pass the children down as children of the inner Provider component.
return (
<CategoriasContext.Provider value={hola}>
{children}
</CategoriasContext.Provider>
);
Your App component is not going to work as expected because the useContext hook which accesses the CategoriasContext is located outside of the CategoriasProvider. It will just get the default value for the context -- not the value from the provider.
You need to rearrange your components such that the hook call occurs in a component that is rendered inside of the CategoriasProvider.
Try this:
const Search = () => {
const contextValues = useContext(CategoriasContext);
return (
<div className="search">
<Search
name={contextValues?.name}
image={contextValues?.image}
thumbnail={contextValues?.thumbnail}
/>
</div>
);
};
const App = () => {
return (
<CategoriasProvider>
<div className="App">
<Search />
</div>
</CategoriasProvider>
);
};
export default App;

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

react - writting twice same test passes first but not second time

Im a bit new to the react ecosytem. Im having a weird behaviour with passing tests.
Im using CRA, prop-types and react-test-library.
Here is my component:
import React from 'react';
import PropTypes from 'prop-types';
export default function Navbar({
Logo, MenuItems, className,
}) {
return (
<nav aria-label="navigation bar" className={className}>
{Logo}
<div>
{ MenuItems.map((MenuItem) => MenuItem) }
</div>
</nav>
);
}
Navbar.defaultProps = {
className: '',
};
Navbar.propTypes = {
className: PropTypes.string,
Logo: PropTypes.node.isRequired,
MenuItems: PropTypes.arrayOf(PropTypes.node).isRequired,
};
I want to test that prop-types complains when params are not receiving the right type.
import React from 'react';
import { render } from '#testing-library/react';
import Navbar from './Navbar';
describe('<Navbar />', () => {
beforeAll(() => {
jest.spyOn(console, 'error').mockImplementation(() => {});
});
beforeEach(() => {
console.error.mockClear();
});
afterAll(() => {
console.error.mockRestore();
});
it('renders', () => {
render(<Navbar
Logo={<p data-test="logo">My logo</p>}
MenuItems={[
<p key="spanish">Spanish</p>,
<p key="english">english</p>,
]}
/>);
expect(console.error).not.toHaveBeenCalled();
});
it('errors to console when Logo is missing', () => {
render(<Navbar MenuItems={[
<p key="spanish">Spanish</p>,
<p key="english">English</p>,
]}
/>);
expect(console.error).toHaveBeenCalled();
});
it('does not error to console when Logo is missing', () => {
render(<Navbar MenuItems={[
<p key="spanish">Spanish</p>,
<p key="english">English</p>,
]}
/>);
expect(console.error).toHaveBeenCalled();
});
});
My thinking is that Im not resetting properly the mocks, they have some state that it is not clear or something similar.
What am i missing?
PropTypes.checkPropTypes(...) only console.errors a given message once. To reset the error warning cache in tests, call PropTypes.resetWarningCache()
Source
Try invoke resetWarningCache in your beforeEach hooks
import PropTypes from 'prop-types';
beforeEach(() => {
PropTypes.resetWarningCache()
});

Enzyme Mount Error - TypeError: Cannot read property 'find' of undefined

There is an error
TypeError: Cannot read property 'find' of undefined
when I tested my react component. I used jest and enzyme for react app testing.
I tried different methods but still got an undefined error.
test.js
import React from 'react';
import { mount } from 'enzyme';
import { StaticRouter } from 'react-router-dom';
import Button from '../index';
describe('<Button />', () => {
let renderComponent;
beforeEach(() => {
renderComponent = (props = {}) => {
mount(
// <MemoryRouter>
<Button href={href} {...props}>
{children}
</Button>,
// </MemoryRouter>,
);
};
});
it('should render an <a> tag if no handleRoute is provided', () => {
const renderedComponent = renderComponent();
expect(renderedComponent.find('a')).toHaveLength(1);
});
});
index.js (button component)
import React, { Children } from 'react';
import PropTypes from 'prop-types';
import A from './A';
// import StyledButton from './StyledButton';
import Wrapper from './Wrapper';
function Button(props) {
// render an anchor tag => a tag
let button = (
<A href={props.href} onClick={props.onClick}>
{Children.toArray(props.children)}
</A>
);
return <Wrapper>{button}</Wrapper>;
}
Button.propTypes = {
handleRoute: PropTypes.func,
href: PropTypes.string,
onClick: PropTypes.func,
children: PropTypes.node.isRequired,
};
export default Button;
You must return the component from your renderComponent function.
renderComponent = (props = {}) => {
return mount(
// <MemoryRouter>
<Button href={href} {...props}>
{children}
</Button>,
// </MemoryRouter>,
);
};

Resources