使用MOBX商店测试React/打字稿组件

发布于 2025-02-13 10:52:57 字数 7869 浏览 0 评论 0原文

我正在使用JEST和React Testing-Library在使用MOBX作为状态管理器时测试React/TypeScript组件。

我知道RTL具有创建 自定义渲染 用于测试,但不确定在使用MOBX时如何执行此操作。我认为我必须在测试时在组件周围创建一个包装器。

目前,我只是想渲染组件。

当我运行此测试时,我会得到参考错误:未定义工人

test('AppRouter renders all routes and I can navigate to those pages', () => {
    render(
        <AppRouter />
    )
})

应用程序路由器组件

mport { BrowserRouter, Switch, Route, Redirect } from 'react-router-dom'
import { useState } from 'react'

import useLocalStorage from './hooks/useLocalStorage'
import * as Constants from './constants'

import Header from './layout/header/header'
import MainPage from './pages/mainPage/mainPage'
import PostPage from './pages/postPage/postPage'
import UserPage from './pages/userPage/userPage'
import LoginPage from './pages/loginPage/loginPage'
import SignupPage from './pages/signupPage/signupPage'
import NewPage from './pages/newPage/newPage'
import FeedbackPage from './pages/feedbackPage/feedbackPage'
import AdminPage from './pages/adminPage/adminPage'
import SettingPage from './pages/settingPage/settingPage'

import { WebContext } from './context/WebContext'
import Favicon from 'react-favicon'

const AppRouter = () => {
    const [adminCode, setAdminCode] = useLocalStorage('admin', '')
    const [isMenuOpen, setIsMenuOpen] = useState(false)
    const [page, setPage] = useState(Constants.Page.Home)

    return (
        <BrowserRouter>
            <div>
                <Favicon url={require('../public/favicon.ico')} />
                <WebContext.Provider
                    value={{
                        isMenuOpen,
                        setIsMenuOpen,
                        page,
                        setPage,
                        adminCode,
                        setAdminCode,
                    }}
                >
                    <Header />

                    <Switch>
                        <Route component={MainPage} path="/" exact={true} />
                        <Route component={PostPage} path="/post/:id" />
                        <Route component={UserPage} path="/user" />
                        <Route component={LoginPage} path="/login" />
                        <Route component={SignupPage} path="/signup" />
                        <Route component={NewPage} path="/new" />
                        <Route component={FeedbackPage} path="/feedback" />
                        <Route component={AdminPage} path="/admin" />
                        <Route component={SettingPage} path="/setting" />
                        <Route component={() => <Redirect to="/" />} />
                    </Switch>
                </WebContext.Provider>
            </div>
        </BrowserRouter>
    )
}

export default AppRouter

由Applouter渲染的标题组件可能会丢弃错误,因为标题使用了商店。

标题组件

mport { useContext, useState } from 'react'
import { NavLink, useHistory, useLocation } from 'react-router-dom'
import { observer } from 'mobx-react-lite'

import { WebContext } from '../../context/WebContext'
import UnirepContext from '../../context/Unirep'
import UserContext from '../../context/User'

const Header = () => {
    const history = useHistory()
    const location = useLocation()
    const { isMenuOpen, setIsMenuOpen } = useContext(WebContext)
    const [searchInput, setSearchInput] = useState<string>('')
    const unirepConfig = useContext(UnirepContext)
    const userContext = useContext(UserContext)

    const gotoNewPage = () => {
        if (
            userContext.userState &&
            userContext.netReputation >= unirepConfig.postReputation
        ) {
            history.push(`/new`, { isConfirmed: true })
        }
    }

    const gotoUserPage = () => {
        history.push(`/user`, { isConfirmed: true })
    }

    const openMenu = () => {
        if (!isMenuOpen) {
            console.log('open menu!')
            setIsMenuOpen(true)
        }
    }

    const handleSearchInput = (event: any) => {
        console.log('search input : ' + event.target.value)
    }

    return (
        <header>
            <div className="navLinks">
                <NavLink to="/" className="link" activeClassName="active" exact>
                    <img
                        src={require('../../../public/images/unirep-title.svg')}
                    />
                </NavLink>
            </div>
            {/* <div className="search-bar">
                <div className="search-icon"><FaSearch /></div>
                <form>
                    <input type="text" name="searchInput" placeholder="Search by keyword, user names or epoch key" onChange={handleSearchInput} />
                </form>
            </div> */}
            {userContext.userState ? (
                <div className="navButtons">
                    <div id="rep" onClick={gotoUserPage}>
                        <img
                            src={require('../../../public/images/lighting.svg')}
                        />
                        {userContext.netReputation}
                    </div>
                    <div
                        id="new"
                        className={
                            location.pathname === '/new'
                                ? 'navBtn chosen'
                                : 'navBtn'
                        }
                    >
                        <img
                            src={require('../../../public/images/newpost.svg')}
                            onClick={gotoNewPage}
                        />
                    </div>
                    <div
                        id="user"
                        className={
                            location.pathname === '/user'
                                ? 'navBtn chosen'
                                : 'navBtn'
                        }
                    >
                        <img
                            src={require('../../../public/images/user.svg')}
                            onClick={gotoUserPage}
                        />
                    </div>
                    <div className="navBtn">
                        <img
                            src={require('../../../public/images/menu.svg')}
                            onClick={openMenu}
                        />
                    </div>
                </div>
            ) : (
                <div className="navButtons">
                    <div
                        id="login"
                        className="whiteButton"
                        onClick={() => history.push('/login')}
                    >
                        Sign in
                    </div>
                    <div
                        id="join"
                        className="blackButton"
                        onClick={() => history.push('/signup')}
                    >
                        Join
                    </div>
                    <div id="menu" className="navBtn">
                        <img
                            src={require('../../../public/images/menu.svg')}
                            onClick={openMenu}
                        />
                    </div>
                </div>
            )}
        </header>
    )
}

export default observer(Header)

请提供帮助!谢谢。

I am testing a React/Typescript component using Jest and React Testing-Library while using MobX as a state manager.

I am aware that RTL has docs for creating a custom render for testing, but not sure how to do this while using MobX. I think I have to create a wrapper around the component when testing.

Currently, I am just trying to render the component.

When I run this test I get Reference Error: Worker is not defined

test('AppRouter renders all routes and I can navigate to those pages', () => {
    render(
        <AppRouter />
    )
})

App Router component

mport { BrowserRouter, Switch, Route, Redirect } from 'react-router-dom'
import { useState } from 'react'

import useLocalStorage from './hooks/useLocalStorage'
import * as Constants from './constants'

import Header from './layout/header/header'
import MainPage from './pages/mainPage/mainPage'
import PostPage from './pages/postPage/postPage'
import UserPage from './pages/userPage/userPage'
import LoginPage from './pages/loginPage/loginPage'
import SignupPage from './pages/signupPage/signupPage'
import NewPage from './pages/newPage/newPage'
import FeedbackPage from './pages/feedbackPage/feedbackPage'
import AdminPage from './pages/adminPage/adminPage'
import SettingPage from './pages/settingPage/settingPage'

import { WebContext } from './context/WebContext'
import Favicon from 'react-favicon'

const AppRouter = () => {
    const [adminCode, setAdminCode] = useLocalStorage('admin', '')
    const [isMenuOpen, setIsMenuOpen] = useState(false)
    const [page, setPage] = useState(Constants.Page.Home)

    return (
        <BrowserRouter>
            <div>
                <Favicon url={require('../public/favicon.ico')} />
                <WebContext.Provider
                    value={{
                        isMenuOpen,
                        setIsMenuOpen,
                        page,
                        setPage,
                        adminCode,
                        setAdminCode,
                    }}
                >
                    <Header />

                    <Switch>
                        <Route component={MainPage} path="/" exact={true} />
                        <Route component={PostPage} path="/post/:id" />
                        <Route component={UserPage} path="/user" />
                        <Route component={LoginPage} path="/login" />
                        <Route component={SignupPage} path="/signup" />
                        <Route component={NewPage} path="/new" />
                        <Route component={FeedbackPage} path="/feedback" />
                        <Route component={AdminPage} path="/admin" />
                        <Route component={SettingPage} path="/setting" />
                        <Route component={() => <Redirect to="/" />} />
                    </Switch>
                </WebContext.Provider>
            </div>
        </BrowserRouter>
    )
}

export default AppRouter

The Header component that is being rendered by the AppRouter may be throwing the error because the Header uses a store.

Header component

mport { useContext, useState } from 'react'
import { NavLink, useHistory, useLocation } from 'react-router-dom'
import { observer } from 'mobx-react-lite'

import { WebContext } from '../../context/WebContext'
import UnirepContext from '../../context/Unirep'
import UserContext from '../../context/User'

const Header = () => {
    const history = useHistory()
    const location = useLocation()
    const { isMenuOpen, setIsMenuOpen } = useContext(WebContext)
    const [searchInput, setSearchInput] = useState<string>('')
    const unirepConfig = useContext(UnirepContext)
    const userContext = useContext(UserContext)

    const gotoNewPage = () => {
        if (
            userContext.userState &&
            userContext.netReputation >= unirepConfig.postReputation
        ) {
            history.push(`/new`, { isConfirmed: true })
        }
    }

    const gotoUserPage = () => {
        history.push(`/user`, { isConfirmed: true })
    }

    const openMenu = () => {
        if (!isMenuOpen) {
            console.log('open menu!')
            setIsMenuOpen(true)
        }
    }

    const handleSearchInput = (event: any) => {
        console.log('search input : ' + event.target.value)
    }

    return (
        <header>
            <div className="navLinks">
                <NavLink to="/" className="link" activeClassName="active" exact>
                    <img
                        src={require('../../../public/images/unirep-title.svg')}
                    />
                </NavLink>
            </div>
            {/* <div className="search-bar">
                <div className="search-icon"><FaSearch /></div>
                <form>
                    <input type="text" name="searchInput" placeholder="Search by keyword, user names or epoch key" onChange={handleSearchInput} />
                </form>
            </div> */}
            {userContext.userState ? (
                <div className="navButtons">
                    <div id="rep" onClick={gotoUserPage}>
                        <img
                            src={require('../../../public/images/lighting.svg')}
                        />
                        {userContext.netReputation}
                    </div>
                    <div
                        id="new"
                        className={
                            location.pathname === '/new'
                                ? 'navBtn chosen'
                                : 'navBtn'
                        }
                    >
                        <img
                            src={require('../../../public/images/newpost.svg')}
                            onClick={gotoNewPage}
                        />
                    </div>
                    <div
                        id="user"
                        className={
                            location.pathname === '/user'
                                ? 'navBtn chosen'
                                : 'navBtn'
                        }
                    >
                        <img
                            src={require('../../../public/images/user.svg')}
                            onClick={gotoUserPage}
                        />
                    </div>
                    <div className="navBtn">
                        <img
                            src={require('../../../public/images/menu.svg')}
                            onClick={openMenu}
                        />
                    </div>
                </div>
            ) : (
                <div className="navButtons">
                    <div
                        id="login"
                        className="whiteButton"
                        onClick={() => history.push('/login')}
                    >
                        Sign in
                    </div>
                    <div
                        id="join"
                        className="blackButton"
                        onClick={() => history.push('/signup')}
                    >
                        Join
                    </div>
                    <div id="menu" className="navBtn">
                        <img
                            src={require('../../../public/images/menu.svg')}
                            onClick={openMenu}
                        />
                    </div>
                </div>
            )}
        </header>
    )
}

export default observer(Header)

Please help! Thanks.

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。
列表为空,暂无数据
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文