如何使用 Jest 来测试带有 localStorage 的 React 组件?

How to use Jest for testing a react component with localStorage?

我有一个调用本地存储的组件,想用 jestJS 测试它。据我所知,jest 不支持调用 localStorage。

这是我需要测试的组件:

const NavBar: React.FC = () => {
  const history = useHistory();

  const handleCLick = () => {
    localStorage.clear();
    history.push('/login');
  };

  return (
    <div>
      <header>
        <div className="banner">
          <div className="container">
            <img
              className="icon "
              alt="icon"
              title="icon"
              src={favicon57}
            />
            <p>Official website of the Stuff</p>
          </div>
        </div>
        <nav className="navbar navbar-expand-md navbar-dark fixed-top">
          <div className="container">
            <div className="navbar-header">
              <img
                className="logo "
                alt="logo"
                title="Logo"
                src={Blah}
              />
            </div>
            <button
              className="navbar-toggler"
              type="button"
              data-toggle="collapse"
              data-target="#navbarCollapse"
              aria-controls="navbarCollapse"
              aria-expanded="false"
              aria-label="Toggle navigation"
            >
              <span className="navbar-toggler-icon" />
            </button>
            <div className="collapse navbar-collapse" id="navbarCollapse">
              <ul className="navbar-nav ml-auto">
                {isTokenAdmin() ? (
                  <li className="nav-item">
                    <a id="nav-users" className="nav-link" href={ADMIN_URL}>
                      View Users
                    </a>
                  </li>
                ) : (
                  <div> </div>
                )}
                {isTokenActive() ? (
                  <li className="nav-item">
                    <a id="nav-log-out" className="nav-link" href={APP_URL}>
                      Locations
                    </a>
                  </li>
                ) : (
                  <div> </div>
                )}
                {isTokenActive() ? (
                  <li className="nav-item">
                    <a
                      id="nav-log-out"
                      className="nav-link"
                      href={LOGIN_URL}
                      onClick={() => {
                        handleCLick();
                      }}
                    >
                      Logout
                    </a>
                  </li>
                ) : (
                  <div> </div>
                )}
              </ul>
            </div>
          </div>
        </nav>
      </header>
    </div>
  );
};

export default NavBar;

如您所见,我正在根据存储在 localStorage 中的令牌呈现按钮。您将如何达到 100% 的测试覆盖率?

编辑:

获取token的函数代码为:

export const isTokenActive = (): boolean => {
  const userToken: string | null = localStorage.getItem('exp');
  if (typeof userToken === 'string') {
    return new Date().getTime() < Number.parseInt(userToken, 10);
  }
  return false;
};

export const isTokenAdmin = (): boolean => {
  const userToken: string | null = localStorage.getItem('access_token');
  if (typeof userToken === 'string') {
    const decodedToken: TokenDetails = jwt_decode(userToken);
    return decodedToken.authorities[0] === 'ROLE_Administrator';
  }
  return false;
};

browserMocks.js

const localStorageMock = (function() {
  let store = {}

  return {
    getItem: function(key) {
      return store[key] || null
    },
    setItem: function(key, value) {
      store[key] = value.toString()
    },
    removeItem: function(key) {
      delete store[key]
    },
    clear: function() {
      store = {}
    }
  }
})()

Object.defineProperty(window, 'localStorage', {
  value: localStorageMock
})

Jest 配置(可以在您的 package.json 中)

  "jest": {
    "setupFiles": [
      "<rootDir>/__jest__/browserMocks.js",

然后查看是否调用了 localstorage 你可以这样监视它:

describe('signOutUser', () => {
  it('should sign out a user', async () => {
    const spyLoStoRemove = jest.spyOn(localStorage, 'removeItem')

    await signOutUser()
    
    expect(spyLoStoRemove).toHaveBeenCalled()
    expect(spyLoStoRemove).toHaveBeenCalledTimes(2)
  })
})