gpt4 book ai didi

reactjs - React Context 和 Hooks API 的 enzyme 错误

转载 作者:行者123 更新时间:2023-12-03 13:36:55 26 4
gpt4 key购买 nike

我创建了这个 RootContext 来处理我的小型 React Hooks 应用程序的身份验证。除了使用 Enzyme 的 shallowmount 出现奇怪的错误之外,一切都按预期工作。

我正在尝试这样测试:

const wrapper = mount(<Login />)

索引:

import RootContext from './RootContext'

function Root() {
return (
<RootContext>
<App />
</RootContext>
)
}

ReactDOM.render(<Root/>, document.getElementById('root'));

根上下文:

import React, { useEffect, useState } from 'react'
export const RootContext = React.createContext()

export default ({ children }) => {
const auth = window.localStorage.getItem('authenticated') || 'false'
const cred = window.localStorage.getItem('credentials') || null
const [authenticated, setAuthenticated] = useState(auth)
const [credentials, setCredentials] = useState(cred)

useEffect(
() => {
window.localStorage.setItem('authenticated', authenticated)
window.localStorage.setItem('credentials', credentials)
},
[authenticated, credentials]
)

const defaultContext = {
authenticated,
setAuthenticated,
credentials,
setCredentials
}

return (
<RootContext.Provider value={defaultContext}>
{children}
</RootContext.Provider>
)
}

登录、注销和注册都使用导致此问题的 useAuthenticate Hook 。 BmiForm 组件工作正常。

import AuthenticatedRoute from './AuthenticatedRoute'

export default function App() {

return (
<Router>
<Header />
<Switch>
<Container>
<Row>
<Col md={{ span: 4, offset: 4 }}>
<AuthenticatedRoute exact path="/" component={BmiForm} />
<Route exact path="/login" component={ Login } />
<Route exact path="/logout" component={ Logout } />
<Route exact path="/register" component={ Register } />
</Col>
</Row>
</Container>
</Switch>
</Router>
)
}

导致问题的 useAuthenticate Hook :

import useReactRouter from 'use-react-router';
import { RootContext } from './../RootContext'

export default function useAuthenticate() {
const { history } = useReactRouter()
const {
authenticated,
setAuthenticated,
credentials,
setCredentials
} = useContext(RootContext);

useAuthenticate Hook 添加到 BmiForm,会导致其测试以同样的方式失败。

import useAuthenticate from './custom/useAuthenticate'

export default function BmiForm(props) {
const { credentials, setAuthenticated } = useAuthenticate()

我得到的第一个错误:

    TypeError: Cannot read property 'authenticated' of undefined

5 | export default function useAuthenticate() {
6 | const {
> 7 | authenticated,
| ^
8 | setAuthenticated,
9 | credentials,
10 | setCredentials

堆栈跟踪的第二个错误:

   use-react-router may only be used within a react-router context.

4 |
5 | export default function useAuthenticate() {
> 6 | const { history } = useReactRouter()
| ^
7 | const {
8 | authenticated,
9 | setAuthenticated,

at useRouter (node_modules/use-react-router/src/use-react-router.ts:20:11)
at useAuthenticate (src/custom/useAuthenticate.js:6:23)
at BmiForm (src/BmiForm.js:15:45)
at renderWithHooks (node_modules/react-dom/cjs/react-dom.development.js:12839:18)
at mountIndeterminateComponent (node_modules/react-dom/cjs/react-dom.development.js:14816:13)
at beginWork (node_modules/react-dom/cjs/react-dom.development.js:15421:16)
at performUnitOfWork (node_modules/react-dom/cjs/react-dom.development.js:19108:12)
at workLoop (node_modules/react-dom/cjs/react-dom.development.js:19148:24)
at renderRoot (node_modules/react-dom/cjs/react-dom.development.js:19231:7)
at performWorkOnRoot (node_modules/react-dom/cjs/react-dom.development.js:20138:7)
at performWork (node_modules/react-dom/cjs/react-dom.development.js:20050:7)
at performSyncWork (node_modules/react-dom/cjs/react-dom.development.js:20024:3)
at requestWork (node_modules/react-dom/cjs/react-dom.development.js:19893:5)
at scheduleWork (node_modules/react-dom/cjs/react-dom.development.js:19707:5)
at scheduleRootUpdate (node_modules/react-dom/cjs/react-dom.development.js:20368:3)
at updateContainerAtExpirationTime (node_modules/react-dom/cjs/react-dom.development.js:20396:10)
at updateContainer (node_modules/react-dom/cjs/react-dom.development.js:20453:10)
at ReactRoot.Object.<anonymous>.ReactRoot.render (node_modules/react-dom/cjs/react-dom.development.js:20749:3)
at node_modules/react-dom/cjs/react-dom.development.js:20886:14
at unbatchedUpdates (node_modules/react-dom/cjs/react-dom.development.js:20255:10)
at legacyRenderSubtreeIntoContainer (node_modules/react-dom/cjs/react-dom.development.js:20882:5)
at Object.render (node_modules/react-dom/cjs/react-dom.development.js:20951:12)
at Object.render (node_modules/enzyme-adapter-react-16/build/ReactSixteenAdapter.js:382:114)
at new ReactWrapper (node_modules/enzyme/build/ReactWrapper.js:134:16)
at mount (node_modules/enzyme/build/mount.js:21:10)
at test (src/test/bmi_calculator.step.test.js:22:21)
at defineScenarioFunction (node_modules/jest-cucumber/src/feature-definition-creation.ts:155:9)
at test (src/test/bmi_calculator.step.test.js:20:3)
at Suite.<anonymous> (node_modules/jest-cucumber/src/feature-definition-creation.ts:279:9)
at defineFeature (node_modules/jest-cucumber/src/feature-definition-creation.ts:278:5)
at Object.<anonymous> (src/test/bmi_calculator.step.test.js:19:1)

我尝试了各种涉及 Enzyme 的 setContext 的解决方案。但不确定这是否与 Context 或 react-router 或两者有关。

最佳答案

由于您正在针对 context 进行测试,因此理想情况下,您需要在根级别进行测试,并对根级别的任何 DOM 更改进行断言。另请注意,您不能在路由器之外使用 Route(BrowserRouterRouterStaticRouter、. ..etc)也不是尚未连接到路由器的历史。虽然我从未使用过 use-react-router,但仔细一看,它仍然需要一个路由器。因此,您的测试必须包括 Provider、路由器和您的页面/组件。

这是在根级别进行测试的工作示例:

Edit Protected Route Root Context

src/root/index.js

import React from "react";
import { Provider } from "../hooks/useAuthentication";
import Routes from "../routes";

const Root = () => (
<Provider>
<Routes />
</Provider>
);

export default Root;

src/routes/index.js

import React from "react";
import { BrowserRouter, Route, Switch } from "react-router-dom";

import { Container, Header, ProtectedRoutes } from "../components";
import { About, Dashboard, Home } from "../pages";

const Routes = () => (
<BrowserRouter>
<Container>
<Header />
<Switch>
<Route exact path="/" component={Home} />
<Route exact path="/about" component={About} />
<ProtectedRoutes>
<Route exact path="/dashboard" component={Dashboard} />
</ProtectedRoutes>
</Switch>
</Container>
</BrowserRouter>
);

export default Routes;

src/root/__tests__/root.test.js

import React from "react";
import { mount } from "enzyme";
import Root from "../index";

describe("Authentication", () => {
let wrapper;
beforeAll(() => {
wrapper = mount(<Root />);
wrapper
.find("Router")
.prop("history")
.push("/dashboard");
wrapper.update();
});

afterAll(() => {
wrapper.unmount();
});

it("initially renders a Login component and displays a message", () => {
expect(wrapper.find("h1").text()).toEqual("Login");
expect(wrapper.find("h3").text()).toEqual(
"You must login before viewing the dashboard!"
);
});

it("authenticates the user and renders the Dashboard", () => {
wrapper.find("button").simulate("click");

expect(wrapper.find("h1").text()).toEqual("Dashboard");
});

it("unauthenticates the user and redirects the user to the home page", () => {
wrapper.find("button").simulate("click");
expect(wrapper.find("h1").text()).toEqual("Home");
});
});
<小时/>

Dashboard页面只要能够访问认证功能就可以隔离;但是,这可能会为后续页面/组件创建一些重复的测试用例,并且没有多大意义,因为它仍然需要在根级别和路由器上设置上下文(特别是如果组件/页面或 Hook 正在订阅) 历史)。

这是一个工作示例,其中仪表板页面已被隔离以进行测试:

Edit Protected Route Confined Context

src/routes/index.js

import React from "react";
import { BrowserRouter, Route, Switch } from "react-router-dom";

import { Container, Header, ProtectedRoutes } from "../components";
import { About, Dashboard, Home } from "../pages";

const Routes = () => (
<BrowserRouter>
<Container>
<Header />
<Switch>
<Route exact path="/" component={Home} />
<Route exact path="/about" component={About} />
<ProtectedRoutes>
<Route exact path="/dashboard" component={Dashboard} />
</ProtectedRoutes>
</Switch>
</Container>
</BrowserRouter>
);

export default Routes;

components/ProtectedRoutes/index.js

import React from "react";
import { useAuthentication } from "../../hooks";
import Login from "../Login";

const ProtectedRoutes = ({ children }) => {
const { isAuthenticated, login } = useAuthentication();

return isAuthenticated ? children : <Login login={login} />;
};

export default ProtectedRoutes;

pages/Dashboard/index.js

import React, { Fragment, useCallback } from "react";
import { useAuthentication } from "../../hooks";
import { Button, Description, Title } from "../../components";

const Dashboard = ({ history }) => {
const { logout } = useAuthentication();

const unAuthUser = useCallback(() => {
logout();
history.push("/");
}, [history, logout]);

return (
<Fragment>
<Title>Dashboard</Title>
<Description>
Ut wisi enim ad minim veniam, quis nostrud exerci tation ullamcorper
suscipit lobortis nisl ut aliquip ex ea commodo consequat. Duis autem
vel eum iriure dolor in hendrerit in vulputate velit esse molestie
consequat, vel illum dolore eu feugiat nulla facilisis at vero eros et
accumsan et iusto odio dignissim qui blandit praesent luptatum zzril
delenit augue duis dolore te feugait nulla facilisi.
</Description>
<Button onClick={unAuthUser}>Logout</Button>
</Fragment>
);
};

export default Dashboard;

pages/Dashboard/__tests__/Dashboard.test.js

import React from "react";
import { mount } from "enzyme";
import { BrowserRouter, Route } from "react-router-dom";
import { Provider } from "../../../hooks/useAuthentication";
import { ProtectedRoutes } from "../../../components";
import Dashboard from "../index";

describe("Dashboard Page", () => {
let wrapper;
beforeAll(() => {
wrapper = mount(
<Provider>
<BrowserRouter>
<ProtectedRoutes>
<Route exact path="/" component={Dashboard} />
</ProtectedRoutes>
</BrowserRouter>
</Provider>
);
});

afterAll(() => {
wrapper.unmount();
});

it("initially renders a login component and displays a message", () => {
expect(wrapper.find("h1").text()).toEqual("Login");
expect(wrapper.find("h3").text()).toEqual(
"You must login before viewing the dashboard!"
);
});

it("authenticates the user and updates the component", () => {
wrapper.find("button").simulate("click");

expect(wrapper.find("h1").text()).toEqual("Dashboard");
});

it("unauthenticates the user", () => {
wrapper.find("button").simulate("click");
expect(wrapper.find("h1").text()).toEqual("Login");
});
});

关于reactjs - React Context 和 Hooks API 的 enzyme 错误,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/54974634/

26 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com