admin管理员组文章数量:1400096
Given a simple App containing multiple lazy loaded routes,
import React, { lazy, Suspense } from "react";
import { Route } from "react-router-dom";
import "./styles.css";
const Component = lazy(() => import("./Component"));
const PageNotFound = lazy(() => import("./PageNotFound"));
export default function App() {
return (
<div className="App">
<Route
path="/ponent"
exact
render={() => (
<Suspense fallback={<div>Loading..</div>}>
<Component />
</Suspense>
)}
/>
<Route
path="*"
render={() => (
<Suspense fallback={<div>Loading..</div>}>
<PageNotFound />
</Suspense>
)}
/>
</div>
);
}
How can tests be made to check if those ponents are being rendered on that specific route?
Here's the App.test with what I tried:
import { configure, shallow, mount } from "enzyme";
import Adapter from "@wojtekmaj/enzyme-adapter-react-17";
import React from "react";
import { MemoryRouter } from "react-router-dom";
import App from "./App";
import Component from "./Component";
import PageNotFound from "./PageNotFound";
configure({ adapter: new Adapter() });
describe("App", () => {
it("renders without crashing", () => {
shallow(<App />);
});
it("renders lazy loaded PageNotFound route", () => {
// Act
const wrapper = mount(
<MemoryRouter initialEntries={["/random"]}>
<App />
</MemoryRouter>
);
// Assert
// expect(wrapper.containsMatchingElement(<PageNotFound />)).toEqual(true);
// expect(wrapper.find(PageNotFound)).toHaveLength(1);
expect(wrapper.exists(PageNotFound)).toEqual(true);
});
});
All 3 assertions don't seem to be working due to Suspense; A working snippet can be found at codesandbox here - Make sure to go on the 'tests' tab in order to see the failing tests.
Any suggestion is highly appreciated, thank you in advance!
Given a simple App containing multiple lazy loaded routes,
import React, { lazy, Suspense } from "react";
import { Route } from "react-router-dom";
import "./styles.css";
const Component = lazy(() => import("./Component"));
const PageNotFound = lazy(() => import("./PageNotFound"));
export default function App() {
return (
<div className="App">
<Route
path="/ponent"
exact
render={() => (
<Suspense fallback={<div>Loading..</div>}>
<Component />
</Suspense>
)}
/>
<Route
path="*"
render={() => (
<Suspense fallback={<div>Loading..</div>}>
<PageNotFound />
</Suspense>
)}
/>
</div>
);
}
How can tests be made to check if those ponents are being rendered on that specific route?
Here's the App.test with what I tried:
import { configure, shallow, mount } from "enzyme";
import Adapter from "@wojtekmaj/enzyme-adapter-react-17";
import React from "react";
import { MemoryRouter } from "react-router-dom";
import App from "./App";
import Component from "./Component";
import PageNotFound from "./PageNotFound";
configure({ adapter: new Adapter() });
describe("App", () => {
it("renders without crashing", () => {
shallow(<App />);
});
it("renders lazy loaded PageNotFound route", () => {
// Act
const wrapper = mount(
<MemoryRouter initialEntries={["/random"]}>
<App />
</MemoryRouter>
);
// Assert
// expect(wrapper.containsMatchingElement(<PageNotFound />)).toEqual(true);
// expect(wrapper.find(PageNotFound)).toHaveLength(1);
expect(wrapper.exists(PageNotFound)).toEqual(true);
});
});
All 3 assertions don't seem to be working due to Suspense; A working snippet can be found at codesandbox here - Make sure to go on the 'tests' tab in order to see the failing tests.
Any suggestion is highly appreciated, thank you in advance!
Share Improve this question asked Jan 16, 2021 at 10:20 ale917kale917k 1,7887 gold badges22 silver badges42 bronze badges2 Answers
Reset to default 7 +100This is an interesting question which is hard to have a best way to mock since the lazy(() => import('path/to/file'))
takes a function as argument so we can't detect the value of anonymous function.
But I think I have a solution for you but it's not best to test all cases but a specific case it would work. You would mock as following:
jest.mock('react', () => {
const React = jest.requireActual('react');
// Always render children as our lazy mock ponent
const Suspense = ({ children }) => {
return children;
};
const lazy = () => {
// `require` ponent directly as we want to see
// Why? Above reason
return require('./PageNotFound').default;
}
return {
...React,
lazy,
Suspense
};
});
Update a new way to mock lazy
function
I think I have a better idea to invoke the lazy
argument then return as a ponent as following:
jest.mock('react', () => {
const React = jest.requireActual('react');
const Suspense = ({ children }) => {
return children;
};
const lazy = jest.fn().mockImplementation((fn) => {
const Component = (props) => {
const [C, setC] = React.useState();
React.useEffect(() => {
fn().then(v => {
setC(v)
});
}, []);
return C ? <C.default {...props} /> : null;
}
return Component;
})
return {
...React,
lazy,
Suspense
};
});
Then you have to wait the ponent updated which is returned in mock lazy
so we wait ponent to re-paint as following:
// keep warning `act` removed
import { act } from 'react-dom/test-utils';
// A helper to update wrapper
const waitForComponentToPaint = async (wrapper) => {
await act(async () => {
await new Promise(resolve => setTimeout(resolve));
wrapper.update();
});
};
it("renders PageNotFound", async () => {
const wrapper = mount(
<MemoryRouter initialEntries={["/random"]}>
<App />
</MemoryRouter>
);
await waitForComponentToPaint(wrapper);
expect(wrapper.exists(PageNotFound)).toEqual(true);
});
it("renders Component", async () => {
const wrapper = mount(
<MemoryRouter initialEntries={["/ponent"]}>
<App />
</MemoryRouter>
);
await waitForComponentToPaint(wrapper);
expect(wrapper.exists(Component)).toEqual(true);
});
Another update for link
I've created a repl.it
link for you to check how it works: https://repl.it/@tmhao2005/js-cra
You can run the test: yarn test -- lazy
. And browse the code under src/Lazy
.
Below is my working version :
import { act, } from 'react-dom/test-utils';
const waitForComponentToPaint = async (wrapper) => {
await act(async () => {
await new Promise((resolve) => setTimeout(resolve));
wrapper.update();
});
};
jest.mock('react', () => {
const ReactActual = jest.requireActual('react');
// Always render children as our lazy mock ponent
const Suspense = ({
children,
}) => children;
const lazyImport = jest.fn().mockImplementation(() => {
class SpyComponent extends ReactActual.Component {
ponentDidMount() {}
render() {
const {
path,
} = this.props;
const LazyComponent = require(path).default;
return (
<>
{LazyComponent ? <LazyComponent {...this.props} /> : null}
</>
);
}
}
return SpyComponent;
});
return {
...ReactActual,
lazy: lazyImport,
Suspense,
};
});
describe('Render <Header />', () => {
it('should render a Header', async () => {
const wrapper = mount(
<Header />
);
await waitForComponentToPaint(wrapper);
expect(wrapper.find('XXXXXX')).to.have.length(1);
});
});
And I added a path
props when calling the lazy ponent :
<CustomLazyComponent
path="./CustomLazyComponent"
/>
本文标签: javascriptTest lazy loaded components in EnzymeStack Overflow
版权声明:本文标题:javascript - Test lazy loaded components in Enzyme - Stack Overflow 内容由网友自发贡献,该文观点仅代表作者本人, 转载请联系作者并注明出处:http://www.betaflare.com/web/1744257606a2597556.html, 本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌抄袭侵权/违法违规的内容,一经查实,本站将立刻删除。
发表评论