React testing library to cover the lazy load - reactjs

How to cover the lazy load component in react testing library.
import React, {lazy} from 'react';
const ownerInfo = lazy(() => import('../abc'))
const compone = () => {
return <Suspense><abc /></Suspense>
}
export default compone
test.spec.js
import React from 'react'
import {render, fireEvent} from '#testing-library/react'
import configureStore from 'redux-mock-store'
...

After watching the video, I am able to figure out how to cover the lazy load. Let assume that you have lazyload component.
LazyLoad.jsx:
import React, {lazy} from 'react'
const LazyComponent = lazy(() => import('./LazyComponent'))
const LazyLoad = () => {
return (
<div>
<div> Lazy component is here: </div>
<React.Suspense fallback={null}>
<LazyComponent />
</React.Suspense>
</div>
)
}
export default LazyLoad
LazyComponent.jsx:
import React from 'react'
export default () => <div>I am lazy ! </div>
LazyLoad.spec.jsx:
import React from 'react'
import {render, waitFor } from 'react-testing-library'
import LazyLoad from 'LazyLoad'
test('renders lazy component', async () => {
const { getByText } = render(<LazyLoad />)
await waitFor(() => expect(getByText('I am lazy !' )).toBeInTheDocument())
})

According to Kent Dodds, the React Testing Library creator, you should prefer using findByText rather than waitFor + expect.
Those two bits of code are basically equivalent (find* queries use waitFor under the hood), but the second is simpler and the error message you get will be better.
With that in mind, I suggest to refactor your test like this
import React from 'react'
import {render, waitFor } from 'react-testing-library'
import LazyLoad from 'LazyLoad'
test('renders lazy component', async () => {
const { getByText } = render(<LazyLoad />)
expect(
await screen.findByText('I am lazy !')
).toBeInTheDocument();
})

Related

SyntaxError: Cannot use import statement outside a module with dynamic import of Nextjs

I followed the doc of SunEditor, it's like:
import React from 'react';
import dynamic from "next/dynamic";
import 'suneditor/dist/css/suneditor.min.css'; // Import Sun Editor's CSS File
const SunEditor = dynamic(() => import("suneditor-react"), {
ssr: false,
});
const MyComponent = props => {
return (
<div>
<p> My Other Contents </p>
<SunEditor />
</div>
);
};
export default MyComponent;
It works well, but when I add setOptions into SunEditor:
import { buttonList } from "suneditor-react";
...
<SunEditor
setOptions={{buttonList:buttonList.complex}}
/>
I got this error:
SyntaxError: Cannot use import statement outside a module
Am I missing something, and how can I fix it?
For the same reason you have to dynamically import SunEditor, you also have to dynamically import buttonList.
One approach is to create a custom component where you add all the suneditor code.
import React from 'react';
import SunEditor, { buttonList } from 'suneditor-react';
const CustomSunEditor = () => {
return <SunEditor setOptions={{ buttonList: buttonList.complex }} />;
};
export default CustomSunEditor;
Then, dynamically import that component with next/dynamic where needed.
const CustomSunEditor = dynamic(() => import('../components/CustomSunEditor'), {
ssr: false,
});
const MyComponent = props => {
return (
<div>
<p> My Other Contents </p>
<CustomSunEditor />
</div>
);
};

Jest with Next.js 12.0.1: Element type is invalid

I've faced with an error
Error: Element type is invalid: expected a string (for built-in
components) or a class/function (for composite components) but got:
undefined. You likely forgot to export your component from the file
it's defined in, or you might have mixed up default and named imports.
Check the render method of ContactUsPage.
during testing like
import { render, screen } from '#testing-library/react'
import ContactUsPage from '../pages/contact-us'
import React from 'react'
describe('Contact page', () => {
it('renders a heading', () => {
render(<ContactUsPage />)
const heading = screen.getByRole('heading', {
name: /Let’s work together/i,
})
expect(heading).toBeInTheDocument()
})
})
I have no idea why and I'd appreciate for any help here
If I try to render not the next.js page but the inside component only, I receive the same error for inner components. Like in Header component I have
import { Row, useScreenClass } from 'react-grid-system'
Despite it is uncomfortable, I can change all destructure imports to defaults but with 3d-party libraries, there is no opportunity to do the same.
import ContactUs from 'routes/ContactUs'
import React from 'react'
import MetaTags from 'components/MetaTags/MetaTags'
const ContactUsPage = () => {
return (
<>
<MetaTags title='Contact us' />
<ContactUs />
</>
)
}
export default ContactUsPage
//ContactUs.jsx
import React from 'react'
import PageLayout from 'ui-kit/Layout/PageLayout'
import Section from 'ui-kit/Layout/Section'
import ContentContainer from './ContentContainer'
import HeaderHero from './HeaderHero'
import Waves from 'components/Waves/Waves'
import styles from './ContactUs.module.scss'
import violetBottomWave from 'images/waves/contact-right-bottom-wave.svg'
import topWaveDesktop from 'images/waves/contact-top-wave.svg'
const ContactUs = () => (
<PageLayout
greyBackground={false}
headerHero={<HeaderHero />}
withWaves={false}
wrapperClassName='page--about-us'
>
<Waves
className={`${styles.topWaveDesktop} z-index-max`}
src={topWaveDesktop}
/>
<Section className={styles.contactUsSection} fullWidth>
<ContentContainer />
</Section>
<div className={styles.contactUsMapWaves}>
<Waves
className={`${styles.waveBlue} z-index-max`}
src={violetBottomWave}
/>
</div>
</PageLayout>
)
export default ContactUs

How to test screen transition by Link component in react

I'm writing test code for my react app. I want to write test code that tests screen transition from Page A to Page B.
However, somehow the event to make user move to Page B from Page A doesn't work in my test code.
This is the test code.
Test code
import { fireEvent, render, screen } from '#testing-library/react';
import React from 'react';
import { StaticRouter } from 'react-router-dom';
import Routes from '../src/rouer';
const App = () => {
return (
<StaticRouter>
<Routes />
</StaticRouter>
);
};
describe('Test screen transition', () => {
it('Test screen transition', () => {
render(<App />);
screen.debug();
// I want this line makes the click event fired, but it doesn't
fireEvent.click(screen.getByText('Go to Page B from Page A'));
screen.debug();
});
});
This is my Page A component
import * as React from 'react';
import { Link } from 'react-router-dom';
const A = () => {
return (
<>
<div>
<Link to="/b">Go to Page B from Page A</Link>
</div>
</>
);
};
export default A;
This is my Page B component
import * as React from 'react';
import { Link } from 'react-router-dom';
const B = () => {
return (
<>
<div>
This is Page B
</div>
</>
);
};
export default B;

Why Enzyme test unworking in React?

I need to test Button component
it's Button :
import React from "react";
import './Button.css'
const Button = props => {
return(
<button className={"Button"}
onClick={props.onClick}
disabled={props.disabled}
>
{props.children}
</button>
)
}
export default Button
It's my Button.test.js:
import React from 'react';
import {shallow} from 'enzyme';
import Button from "./Button";
it('has a title class', () => {
const wrapper = shallow(<Button/>);
expect(wrapper.hasClass('Button')).to.equal(true);
I'm add enzyme to react. In the console I has an error:
enter image description here
tell me how to solve the problem, i'm new in React.
You need to call hasClass on the button element instead of the wrapper:
expect(wrapper.find('button').hasClass('Button')).to.equal(true);

ShallowWrapper is empty when running test

I'm new to testing so I'm trying to add Enzyme to one of my projects. My problem is that when using find(), the ShallowWrapper is empty. Also I'm using Material UI, so I don't know if this is part of the problem.
The component I'm testing
import React from "react";
import { withStyles } from "#material-ui/core/styles";
import AppBar from "#material-ui/core/AppBar";
import Toolbar from "#material-ui/core/Toolbar";
import Typography from "#material-ui/core/Typography";
const styles = theme => ({
root: {
flexGrow: 1
},
background: {
backgroundColor: "#2E2E38"
},
title: {
color: "#FFE600",
flexGrow: 1
}
});
const NavBar = ({ classes }) => {
return (
<div className={classes.root} data-test="nav-bar">
<AppBar className={classes.background}>
<Toolbar>
<Typography variant="h5" className={classes.title}>
App
</Typography>
</Toolbar>
</AppBar>
</div>
);
};
export default withStyles(styles)(NavBar);
The test
import React from "react";
import { shallow } from "enzyme";
import NavBar from "./NavBar";
describe("NavBar component", () => {
it("Should render without errors.", () => {
let component = shallow(<NavBar />);
let navbar = component.find("data-test", "nav-bar");
console.log("Log is", component);
expect(navbar).toBe(1);
});
});
Try changing your selector in find(selector) to the following to target the element with data-test="nav-bar". You may need to use dive() to be able to access the inner components of the style component:
import React from "react";
import { shallow } from "enzyme";
import NavBar from "./NavBar";
describe("NavBar component", () => {
it("Should render without errors.", () => {
const component = shallow(<NavBar />);
// Use dive() to access inner components
const navbar = component.dive().find('[data-test="nav-bar"]');
// Test that we found a single element by targeting length property
expect(navbar.length).toBe(1);
});
});
You can also use an object syntax if you prefer:
const navbar = component.find({'data-test': 'nav-bar'});
Alternatively to using dive(), you could instead mount() the component instead of shallow(), but it depends on your use case:
import React from "react";
import { mount } from "enzyme";
import NavBar from "./NavBar";
describe("NavBar component", () => {
it("Should render without errors.", () => {
const component = mount(<NavBar />);
// Use dive() to access inner components
const navbar = component.find('[data-test="nav-bar"]');
// Test that we found a single element by targeting length property
expect(navbar.length).toBe(1);
});
});
Hopefully that helps!
I ran into this issue for a different reason where I could not find a SingleDatePicker element. The example in 2. A React Component Constructor from the documentation fixed it for me.
https://enzymejs.github.io/enzyme/docs/api/selector.html#1-a-valid-css-selector
using
wrapper.find(SingleDatePicker).prop('onDateChange')(now);
instead of
wrapper.find('SingleDatePicker').prop('onDateChange')(now);
did the trick for me.

Resources