- html - 出于某种原因,IE8 对我的 Sass 文件中继承的 html5 CSS 不友好?
- JMeter 在响应断言中使用 span 标签的问题
- html - 在 :hover and :active? 上具有不同效果的 CSS 动画
- html - 相对于居中的 html 内容固定的 CSS 重复背景?
我创建了这个 RootContext 来处理我的小型 React Hooks 应用程序的身份验证。除了使用 Enzyme 的 shallow
和 mount
出现奇怪的错误之外,一切都按预期工作。
我正在尝试这样测试:
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
(BrowserRouter
、Router
、StaticRouter
、. ..etc)也不是尚未连接到路由器的历史
。虽然我从未使用过 use-react-router,但仔细一看,它仍然需要一个路由器。因此,您的测试必须包括 Provider
、路由器和您的页面/组件。
这是在根级别进行测试的工作示例:
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 正在订阅) 历史
)。
这是一个工作示例,其中仪表板页面已被隔离以进行测试:
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/
这是关于非标准属性的。 https://facebook.github.io/react/docs/tags-and-attributes.html 在 react 中我做了这个: React.cr
我制作了 2 个组件:1)内容(使用 fetch() 显示数据)2)分页(共5页,每页16个对象) 我创建了 2 个状态变量,分别称为 start:0 和 end:16。现在,每当用户单击页码时,我都
我们正在使用 ReactJS 创建一个搜索前端。要求是当用户单击文档名称时,该文档必须在嵌入式查看器中打开。有人为此使用过任何 ReactJS 组件吗?否则,我应该使用 JQuery 查看器组件吗?请
关闭。这个问题不符合Stack Overflow guidelines .它目前不接受答案。 我们不允许提问寻求书籍、工具、软件库等的推荐。您可以编辑问题,以便用事实和引用来回答。 关闭 1 年前。
我现有的项目: 前端框架 - PHP Codeigniter 和 PHP Laravel 后端框架 - JAVA Springboot 我正在尝试将前端框架更改为 ReactJS。我想知道与 Reac
我有一个实现刷新授权 token 的方案。在这种情况下,我为每种操作(发布、获取、删除)实现了一个通用操作,并使用参数调用它们。 export function Get(param) { return
我现在有 { _this.setState({startDate: input})}}/> 无论我一直在改变什么(onChange 部分到 ref 等等),当我 console.log 我的状态时,
我在两个不同的文件中有两个单独的组件 组件A 和 组件B 我在 中有一个按钮组件B 现在我想测试当 中的特定按钮时组件B 被点击,组件A 应呈现如下: import { render, screen,
我有一个包含几个问题的表格。一些问题有一组子问题。 这些是使用以下代码呈现的。 { Object.keys(this.props.moduleDetails.questions).map(
我有两个组件。第一个状态初始化: import React from 'react'; class One extends React.Component { constructor(prop
我的项目是一个对象数组,我只获取名称并在 3 in 3 的屏幕上渲染,使用“下一个”和“上一个”按钮更改名称,并且可以过滤字母。 我想要添加一个新值,在输入中键入并单击按钮添加。 我的代码按钮: ad
我有一个组件实例,应该从不同的地方更新。如何从其他几个组件中更新此组件的 props? class ParentComponent extends React.Component { ...
我想问,是否可以基于变量返回一个组件,我的想法是否可以: var location = this.props.location // Eg. Asia,Australia 我的问题是我需要单独手动导
有没有办法在渲染后立即选择要覆盖的文本?我的意思是选择 - 最佳答案 您可以尝试使用两种方法.focus和.select .focus() method sets focus on the speci
我渲染了以下内容: 这是事件处理程序: handleCompanySubmit(event) { console.log("company submit") e
作为ReactJS的初学者,我现在使用出色的ReactJS Datepicker。有关我的自定义日期格式的问题: 我没有找到任何文档来解释所有可能性,例如M是月份,MM是2个字母的月份,依此类推。(我
我创建了一个表并正在对其进行过滤,但是当我清除搜索查询时,表数据不会显示,并且表会卡在查询结果上。SearchBox 是文本框,TableData 是表格,在 Container 中我正在更改 Sea
我在表格设置中有图标,这样当单击图标时,会呈现不同的图标。现在这工作正常,但我想为我单击的行中的特定行重新呈现不同的图标,而不是在每一行中重新呈现不同的图标。不知道我将如何去做这件事。这是我的代码:
我正在尝试使用 React 构建一个简单的应用程序,它有两个组件,一个嵌入另一个组件。子组件是一个收缩的菜单,单击它时,它会展开。我希望能够在单击父元素或子元素失去焦点时重新收缩它。 这是父组件的样子
我需要知道 REACT JS 或 HTML5 中是否有任何 API 可以提供用户不活动时自动注销的功能。我的代码如下,我不知道出了什么问题,它给了我错误 startTimer 未定义和不必要的绑定(b
我是一名优秀的程序员,十分优秀!