【问题标题】:useState Hooks not working with enzyme mount()useState Hooks 不适用于酶 mount()
【发布时间】:2021-04-01 15:13:06
【问题描述】:

这个组件中的setWishlists 钩子似乎没有运行,即使承诺链中它之前和之后的所有东西都运行了。它只是不会改变wishlists。在我的测试设置中:handleGetWishlists 通过一个 jest mock 传递,以便它仍然可以在组件中使用,同时允许 jest 监视它。该实现仍然通过,以便Mock Service Worker 提供数据而不是模拟获取。

我在相关分支上的 repo 是here

相关部分:

//HomePage.js
import React, { useEffect, useState } from 'react';
import { makeStyles } from '@material-ui/core/styles';
import {
  Accordion,
  AccordionSummary,
  AccordionDetails,
  Typography,
  FormGroup,
  FormControlLabel,
  Checkbox,
} from '@material-ui/core/';
import ExpandMoreIcon from '@material-ui/icons/ExpandMore';

const useStyles = makeStyles(() => ({
  homeContainer: {
    display: 'flex',
    flexDirection: 'column',
    alignItems: 'center',
  },
  heading: {},
  accordion: {
    width: '50%',
  },
}));

const HomePage = ({ handleGetWishlists }) => {
  const classes = useStyles();
  const [wishlists, setWishlists] = useState([]);

  useEffect(() => {
    handleGetWishlists()
      .then((res) => res.json())
      .then((data) => {
        console.log('DATA BEFORE SET', data); //--> DATA BEFORE SET [...somedata...]
        return data;
      })
      .then(setWishlists) // --> console.error()
      .then(() => console.log('WISHLIST AFTER SET', wishlists)); // --> WISHLIST AFTER SET []
    console.log('END OF USE EFFECT');
  }, []);

  return (
    <div className={classes.homeContainer}>
      {wishlists.map((wishlist, index) => {
        return (
          <Accordion key={`Accordian${index}`} className={classes.accordion}>
            <AccordionSummary
              expandIcon={<ExpandMoreIcon />}
              aria-controls='panel1a-content'
              id='panel1a-header'
            >
              <Typography className={classes.heading}>
                {`${wishlist.name} by ${wishlist.author}`}
              </Typography>
            </AccordionSummary>
            <AccordionDetails>
              <FormGroup>
                {wishlist.items.map((item, index) => {
                  return (
                    <FormControlLabel
                      key={`WishlistItemCheckbox${index}`}
                      control={<Checkbox />}
                      label={item.name}
                    />
                  );
                })}
              </FormGroup>
            </AccordionDetails>
          </Accordion>
        );
      })}
    </div>
  );
};

export default HomePage;

//HomePage.test.js
import React from 'react';
import { mount } from 'enzyme';
import { handleGetWishlists } from '../../client/client';
import HomePage from './HomePage';
import { Accordion } from '@material-ui/core/';

describe('HomePage', () => {
  let component;

  const mockHandleGetWishlists = jest.fn();

  beforeEach(async () => {
    mockHandleGetWishlists.mockImplementation(handleGetWishlists);
    component = mount(<HomePage handleGetWishlists={mockHandleGetWishlists} />);
  });

  afterEach(() => {
    mockHandleGetWishlists.mockReset();
  });

  it('should load wishlists', async () => {
    expect(mockHandleGetWishlists).toBeCalled();
    mockHandleGetWishlists()
      .then((res) => res.json())
      .then(console.log);
    expect(component.exists(Accordion)).toBeTruthy();
  });
});
//client.jsconst
client = {
  //...
  handleGetWishlists: () =>
    fetch('http://localhost:3001/wishlist', {
      method: 'GET',
      headers: {
        'Content-Type': 'application/json',
      },
    }),
  //...
};

module.exports = client;

【问题讨论】:

    标签: javascript node.js reactjs jestjs enzyme


    【解决方案1】:

    当setWishlist 用作 Promise 链中的回调时,它的上下文会从您的 react 组件状态更改为 Promise 本身的状态。直接从处理程序调用setWishlist 应该按预期设置wishlist。

    handleGetWishlists()
          .then((res) => res.json())
          .then((data) => {
            console.log('DATA BEFORE SET', data); //--> DATA BEFORE SET [...somedata...]
            setWishlist(data);
          })
       
    

    【讨论】:

    • 如果我使用useEffect(() =&gt; {console.log('WISHLISTS', wishlists)}, [wishlists]); 来查看wishlists 何时更改,看起来对于这两种实现,它确实“更改”,但它似乎从[ ](空数组)更改到[ ](一个空数组)
    【解决方案2】:

    变量wishlists 将仅在useEffect() 的下一次运行 中包含更新的值,而不是在同一运行中,因此console.log('WISHLIST AFTER SET', wishlists) 仍然显示旧值。

    您的useEffect (有意)只被调用一次,因此您无法在useEffect 中控制台记录更新后的愿望清单。你只是从来没有在那里。

    但是,我希望您的wishlists.map() 应该正确使用更新后的wishlists,假设从handleGetWishlists() 返回的data 是正确的。

    如果你想控制台记录更新的wishlists,你需要使用2nd useEffect(),像这样:

    useEffect(() => {
      console.log( 'WISHLIST AFTER SET', wishlists );
    }, [ wishlists ]);
    

    【讨论】:

    • 我已经重构了我的代码,wishlists 在所有情况下都计算为一个空数组。
    猜你喜欢
    • 2021-02-11
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2017-07-19
    • 2019-06-06
    • 1970-01-01
    相关资源
    最近更新 更多