【问题标题】:Enzyme React Adapter mount is not a functionEnzyme React Adapter mount 不是函数
【发布时间】:2021-09-14 00:18:43
【问题描述】:

程序员节快乐!!! 我会庆祝给你带来一个测试问题,我发现这是我第一次尝试测试 React 组件。 在这个问题的上下文中,我收到了一个“样板文件”,如果我在我的应用程序增长时安装依赖项。我的代码运行良好,没有控制台错误并执行它必须执行的所有操作。我为后端添加了一些运行良好的小测试,但无法使其工作(不知道真的如何)来运行这个前端:

这是我的组件:( tnx @Sanish Joseph!)

import React, { useEffect, useState } from 'react';
import { useSelector,useDispatch} from 'react-redux';
import {Link} from 'react-router-dom';
import style from './form.module.css';
import { getTemperaments,postRaze } from '../../actions/index'



function Form() {
  const[errors,setErrors]= useState({name:""});
  const valueTemp = useSelector((state) => state.temperaments)
  const dispatch = useDispatch();
  
  function validate(input){
    let errors={};
   
    if(parseInt(input.height_min) >= parseInt(input.height_max)){
      errors.name = 'Initial value cant be greater than final value!'
    }else{
      setErrors({name:""});
    }
    
    if(parseInt(input.weight_min) >= parseInt(input.weight_max)){
      errors.name = 'Initial value cant be greater than final value!'
    }else{
      setErrors({name:""});
    }
    
    if(parseInt(input.life_min) >= parseInt(input.life_max)){
      errors.name = 'Initial value cant be greater than final value!'
    }else{
      setErrors({name:""});
    }
    
    return errors;
  }

  const [input, setInput] = useState({
    name: "",
    height_min: "",
    height_max: "",
    weight_min: "",
    weight_max: "",
    life_min: "",
    life_max: "",
    image: "",
    temperament: [],
  })
  

  async function handleSubmit(event) { 
    if(errors.name !== undefined){
      document.getElementById('form').reset();
      return alert('You have been warned, but attemp to create anyway. Now form will reset!');
    }
    const myModel={ 
      name:input.name,
      height: input.height_min + " - " + input.height_max,
      weight:input.weight_min + " - " + input.weight_max,
      life: input.life_min + " - " + input.life_max,
      image:input.image,
      temperament:input.temperament,
    } 
    event.preventDefault();
    dispatch(postRaze(myModel)); 
    alert('Your Dog has been created!')         ;
    setInput({
      name: "",
      height_min: "",
      height_max: "",
      weight_min: "",
      weight_max: "",
      life_min: "",
      life_max: "",
      image: "",
      temperament: [],  
    })
    setErrors({});

  }

  
  function handleSelect(e){  
    setInput({
      ...input, temperament:[...input.temperament, +e.target.value ]
    })  
  }
   
  function handleChange(e) {  
    setErrors(validate({
      ...input,
      [e.target.name]: e.target.value
    }));
    setInput({
      ...input,
      [e.target.name]: e.target.value
    })
  }
    
  useEffect(() => {
    dispatch(getTemperaments());
  },[dispatch]);

  return (
    <section className={style.container}>

      <form id="form" onSubmit={handleSubmit} className={style.formul}>

        <div>
          <input className={style.orderLarge}
            placeholder="Name"
            type="text"
            name="name"
            required="required"
            value={input.name}
            onChange={handleChange}
          />
        </div>
        
        <div className={style.MinMax}>
          <p>Height values:</p>
          <div className={style.areaMinMax}>
            <input className={style.order}
              placeholder="Min"
              type="text"
              name="height_min"
              required="required"
              value={input.height_min}
              onChange={handleChange}
            />
            <input className={style.order}
              placeholder="Max"
              type="text"
              name="height_max"
              required="required"
              value={input.height_max}
              onChange={handleChange}
            />
          </div>
        </div>

        <div className={style.MinMax}>
          <p>Weight values:</p>
          <div className={style.areaMinMax}>
            <input className={style.order}
              placeholder="Min"
              type="text"
              name="weight_min"
              required="required"
              value={input.weight_min}
              onChange={handleChange}
            />
          </div>
          <div>
            <input className={style.order}
              placeholder="Max"
              type="text"
              name="weight_max"
              required="required"
              value={input.weight_max}
              onChange={handleChange}
            />
          </div>
        </div>
        
        <div className={style.MinMax}>
        <p>Life.. values    :</p>
        <div className={style.areaMinMax}>
            <input className={style.order}
              placeholder="Min"
              type="text"
              name="life_min"
              required="required"
              value={input.life_min}
               onChange={handleChange}
            />
          </div >
          <div>
            <input className={style.order}
              placeholder="Max"
              type="text"
              name="life_max"
              required="required"
              value={input.life_max}
              onChange={handleChange}
            />
          </div >
        </div>


        <div>
          <input className={style.orderLarge}
          placeholder="Load image path"
            type="text"
            name="image"
            required="required"
            value={input.image}
            onChange={handleChange}
          />
        </div >
        {errors.name && (
          <h4 className={style.danger}>{errors.name}</h4>
        )}
        <select className={style.orderLarge} onChange={handleSelect}
          value={input.temperament[input.temperament.length - 1]}required>
          <option value="">Temperaments:</option>
          {valueTemp.map(e => (
            <option key={e.id} value={e.id}>{e.name}</option>
          ))}
        </select>
        <div style={{color:'burlywood'}}>{[input.temperament.map(i => valueTemp.find( v => v.id === i)?.name + ", ")]}</div>
    
        <div className={style.footer}>
          <input className={style.orderLarge} type="submit" value="Create Race" />
          <Link className={style.order} to='/home'>Home!</Link>
        </div>

      </form>
    </section>
  )
}



export default  Form;
 

关于测试,我只需要一个简单的代码来检查现有输入:

import React from 'react';
import { render } from '@testing-library/react';
import { mount } from '@wojtekmaj/enzyme-adapter-react-17';
import Form  from './index';

describe('<Form /> Mounted', () => {
  let wrapper;
  beforeEach(() => {
    wrapper = mount(<Form />);
  });
  

  it('El form debe tener un input con name "name" y type "text"', () => {
    const { container } = render(<Form />)
    const element = container.querySelectorAll('input')[0]
    expect(element.type).toBe('text');
    expect(element.name).toBe('username');
  });

  it('El form debe tener un input con name "height_min" y type "text"', () => {
    const { container } = render(<Form />)
    const element = container.querySelectorAll('input')[1]
    expect(element.type).toBe('text');
    expect(element.name).toBe('height_min');
  });
})

这是控制台错误:

 TypeError: (0 , _enzymeAdapterReact.mount) is not a function

       9 |   let wrapper;
      10 |   beforeEach(() => {
    > 11 |     wrapper = mount(<Form />);
         |               ^
      12 |   });
      13 |
      14 |

      at Object.<anonymous> (src/components/Form/Form.test.js:11:15)

这是 package.json:


  "name": "client",
  "version": "0.1.0",
  "private": true,
  "dependencies": {
    "@testing-library/jest-dom": "^5.11.6",
    "@testing-library/react": "^11.2.1",
    "@testing-library/user-event": "^12.2.2",
    "axios": "^0.21.1",
    "node-fetch": "^2.6.1",
    "react": "^17.0.1",
    "react-dom": "^17.0.1",
    "react-redux": "^7.2.4",
    "react-router-dom": "^5.2.1",
    "react-scripts": "4.0.0",
    "redux": "^4.1.1",
    "redux-thunk": "^2.3.0",
    "web-vitals": "^0.2.4"
  },
  "scripts": {
    "start": "react-scripts start",
    "build": "react-scripts build",
    "test": "react-scripts test",
    "eject": "react-scripts eject"
  },
  "eslintConfig": {
    "extends": [
      "react-app",
      "react-app/jest"
    ]
  },
  "browserslist": {
    "production": [
      ">0.2%",
      "not dead",
      "not op_mini all"
    ],
    "development": [
      "last 1 chrome version",
      "last 1 firefox version",
      "last 1 safari version"
    ]
  },
  "devDependencies": {
    "@wojtekmaj/enzyme-adapter-react-17": "^0.6.3",
    "redux-mock-store": "^1.5.4"
  }
}

提前问好!

【问题讨论】:

    标签: javascript reactjs testing enzyme mount


    【解决方案1】:

    @wojtekmaj/enzyme-adapter-react-17 只为 React 17 for Enzyme 提供了一个适配器。您应该从 enzyme 包中导入 mount 函数。应该是

    import { mount } from 'enzyme';
    import Enzyme from 'enzyme';
    import Adapter from '@wojtekmaj/enzyme-adapter-react-17';
    
    Enzyme.configure({ adapter: new Adapter() });
    
    // use mount function.
    

    【讨论】:

    • 我们似乎越来越近了!我已经添加了你的台词:现在我得到了这个:找不到 react-redux 上下文值;请确保组件在 ` 9 | 被包装在 中函数形式(){ 10 | const[errors,setErrors]= useState({name:""}); > 11 |常量 valueTemp = useSelector((state) => state.temperaments) | ^ 12 |常量调度 = useDispatch(); `
    • @MartinGonzalez 我建议你使用redux-mock-store 包来创建模拟商店并像mount(&lt;Provider store={store}&gt;&lt;Form/&gt;&lt;/Provider&gt;) 一样使用它
    • 已经有一个 来封装所有的 App。请原谅我问,但是:Provider store 不是已经声明了吗?
    • @MartinGonzalez 您正在测试Form 组件,而不是App,它没有被Provider 包裹。由于您在Form 组件中使用useSelector,因此您需要在测试用例中使用Provider 包装Form
    • 好的@slideshowp2,我添加了Provider:` beforeEach(() => { // wrapper = mount(
      ); mount() });` 现在 Form 内部的钩子会抛出这个错误:找不到 react-redux 上下文值;请确保组件包含在
    猜你喜欢
    • 1970-01-01
    • 2019-12-09
    • 1970-01-01
    • 2019-09-26
    • 2017-06-25
    • 2019-10-16
    • 2020-01-23
    • 1970-01-01
    • 2020-12-13
    相关资源
    最近更新 更多