首页 > 解决方案 > 测试 Redux 连接的 Typescript 文件

问题描述

我正在尝试测试连接的 TSX 组件。我之前测试过连接的组件,我完全知道如何实现它,但似乎 jest 和 typescript 交互的方式存在一些问题。

我试过什么?

  1. 我出于测试目的导出了一个未连接的组件
  2. 我创建了一个模拟商店并在测试文件中围绕提供者包装了组件
  3. 我按照错误的建议修改了 jest.config.js

我不断收到同样的错误!

Cannot find module 'react' from 'Provider.js'

However, Jest was able to find:
    'components/Provider.js'

You might want to include a file extension in your import, or update your 'moduleFileExtensions', which is currently ['web.js', 'js', 'web.ts', 'ts', 'web.tsx', 'tsx', 'json', 'web.jsx', 'jsx', 'node'].

See https://jestjs.io/docs/en/configuration#modulefileextensions-array-string

However, Jest was able to find:
    './App.test.tsx'
    './App.tsx'

You might want to include a file extension in your import, or update your 'moduleFileExtensions', which is currently ['web.js', 'js', 'web.ts', 'ts', 'web.tsx', 'tsx', 'json', 'web.jsx', 'jsx', 'node'].

See https://jestjs.io/docs/en/configuration#modulefileextensions-array-string

  at Resolver.resolveModule (node_modules/jest-resolve/build/index.js:259:17)
  at Object.<anonymous> (../node_modules/react-redux/lib/components/Provider.js:10:38)

我的组件如下(App.tsx):

import React from "react";
import { connect } from "react-redux";
import { Album, Photo, fetchAlbums, fetchPhotos } from "../actions";
import { StoreState } from "../reducers";

// *Notice: in this file we have used React.UseEffect and React.UseState instead of importing
// hooks directly from React. That's for the reasons of testing and how Enzyme has not yet adopted
// very well with hooks.

// the type of your action creators has been intentionally set to "any", as typescript does not play well with redux-thunk
interface AppProps {
  albums?: Album[];
  photos?: Photo[];
  fetchAlbums?(): any;
  fetchPhotos?(id: number): any;
}

export const _App = ({
  albums,
  photos,
  fetchAlbums,
  fetchPhotos
}: AppProps) => {
  // setting the initial state of the loader and thmbnail
  const [fetching, setFetching] = React.useState(false);
  const [image, setImage] = React.useState();

  // setting the state back to false once our data updates
  React.useEffect(() => {
    setFetching(false);
  }, [albums, photos]);

  // click evnet handler
  const ClickHandler = (): void => {
    fetchAlbums();
    setFetching(true);
  };

  // album entry event handler
  const AlbumClickHandler = (id: number): void => {
    fetchPhotos(id);
  };

  const display = (id: number): JSX.Element[] => {
    const relevantThumbs = photos.filter(photo => photo.albumId === id);

    return relevantThumbs.map((thumb, idx) => {
      return (
        <img
          onClick={() => setImage(thumb.id)}
          key={idx}
          alt={thumb.title}
          src={image === thumb.id ? thumb.url : thumb.thumbnailUrl}
        ></img>
      );
    });
  };

  // helper function to render jsx elements
  const renderList = (): JSX.Element[] =>
    albums.map(album => (
      <div className="albums" key={album.id}>
        <h2 onClick={() => AlbumClickHandler(album.id)}>{album.title}</h2>
        {display(album.id).length !== 0 ? (
          <div className="albums__thumbnails">{display(album.id)}</div>
        ) : null}
      </div>
    ));

  return (
    <section className="container">
      <button className="container__button" onClick={() => ClickHandler()}>
        Fetch Albums
      </button>
      {/* conditionally rendering the loader */}
      {fetching ? "loading" : null}
      {renderList()}
    </section>
  );
};

const mapStateToProps = ({
  albums,
  photos
}: StoreState): { albums: Album[]; photos: Photo[] } => {
  return { albums, photos };
};

export default connect(mapStateToProps, { fetchAlbums, fetchPhotos })(_App);

这是我的测试文件(App.test.tsx):

import React from "react";
import Enzyme, { mount } from "enzyme";
import Adapter from "enzyme-adapter-react-16";
import { findByClass } from "../test/Utils";

import App from "./App";

Enzyme.configure({ adapter: new Adapter() });

// setting our initial mount, we use mount here bcause of the hooks
const setup = () => mount(<App />);

describe("app", () => {
  it("renders succesfully", () => {
    // Arrange
    const wrapper = setup();
    const component = findByClass(wrapper, "container");

    // Assert & Act
    expect(component.length).toBe(1);
  });
});

我错过了什么?

标签: javascriptreactjstypescriptjestjsenzyme

解决方案


推荐阅读