Javascript 如何在React组件中测试lodash.get的使用?

Javascript 如何在React组件中测试lodash.get的使用?,javascript,reactjs,unit-testing,jestjs,Javascript,Reactjs,Unit Testing,Jestjs,错误 TypeError:无法读取未定义的属性“length” 我的应用程序组件正在使用import-get from'lodash.get' 我在渲染函数中使用get,如下所示: const getLabel = (listings, label) => { const componentsMap = { Deliveries: Delivery, Dispensaries: Dispensary, Doctors: Doctor }; const D

错误

TypeError:无法读取未定义的属性“length”

我的应用程序组件正在使用
import-get from'lodash.get'

我在渲染函数中使用
get
,如下所示:

const getLabel = (listings, label) => {
  const componentsMap = {
    Deliveries: Delivery,
    Dispensaries: Dispensary,
    Doctors: Doctor
  };
  const DynamicIcon = componentsMap[label];

  if (get(listings, 'listings').length) {
    return (
      <div key={label}>
        <DynamicIcon fill={DARK_GRAY} /> <strong> {label} </strong>
      </div>
    );
  }
  return <div />;
};
App.js
import React,{Component}来自'React';
从'react redux'导入{connect};
从“道具类型”导入道具类型;
从“lodash.get”导入get;
从“../actions”导入{locate,displayListing};
从“./头”导入头;
从“./Hero”导入Hero;
从“./partials/Ripple”导入涟漪;
从“./listing_cards”导入列表卡;
从“../icons/Delivery”导入交货;
从“../icons/Dispensary”导入药房;
从“../icons/Doctor”导入医生;
从“../constants/colors”导入{DARK_GRAY};
进口{
AppWrapper,
AppContent,
列表组,
}来自“./样式”;
const regionTypes=[“交货”、“药房”、“医生”];
常量区域标签={
交付:“交付”,
药房:“药房”,
医生:“医生”,
};
导出类应用程序扩展组件{
建造师(道具){
超级(道具);
此.state={
加载时间:0,
IsLocationStarted:false,
地理坐标:空,
宽度:0
};
this.locateMe=this.locateMe.bind(this);
this.gotoListing=this.gotoListing.bind(this);
}
componentDidMount(){
//提前获取地理位置。
navigator.geolocation.getCurrentPosition(位置=>
this.setState({geoCoords:position.coords}));
this.updateWindowDimensions();
window.addEventListener(“resize”,this.updateWidowDimensions);
}
组件将卸载(){
removeEventListener(“resize”,this.updateWind维);
}
updateWindowDimensions=()=>this.setState({width:window.innerWidth});
locateMe(){
console.log('locateMe')
const{dispatch}=this.props;
const{geoCoords}=this.state;
if(navigator.geolocation&&!geoCoords){
navigator.geolocation.getCurrentPosition(位置=>
调度(定位(位置协调));
}否则{
调度(定位(地理坐标));
}
this.setState({isLocationStarted:true});
};
全球上市(上市){
const{dispatch}=this.props;
调度(显示列表(列表));
const link=`/listing/${listing.wmid}`;
这个.props.history.push(链接);
}
render(){
const{islocation,location,regions,error}=this.props;
const{islocationstarted,width}=this.state;
const{state\u abv:state}=location!==null&&location;
const isLoading=islocationstarted&&islocation;
const getLabel=(列表,标签)=>{
常量组件映射={
交付:交付,
药房:药房,
医生:医生
};
常量dynamiccon=组件映射[标签];
if(获取(列表,'列表').length){
返回(
{label}
);
}
回来
};
返回(

啊,我需要将所有道具添加到包装器组件中:

import React from 'react'
import { shallow } from 'enzyme'
import toJson from 'enzyme-to-json'

import { AppJest } from './App'
import Header from './header';
import Hero from './hero';
import Ripple from './partials/ripple';
import listingsMock from '../__test__/mocks/listings-mock.json';

// Mock the services.
const mockLocate = jest.fn();
const mockDisplayListing = jest.fn();
const mockGeolocation = {
  getCurrentPosition: jest.fn(),
  watchPosition: jest.fn()
};

global.navigator.geolocation = mockGeolocation;

jest.mock('../actions', () => ({
  locate: () => mockLocate(),
  displayListing: () => mockDisplayListing()
}));

describe('<App /> component', () => {
  describe('when rendering', () => {
    const wrapper = shallow(<AppJest
      navigator={mockGeolocation}
      isLocating={false}
      location={null}
      regions={null}
      dispatch={null}
      error={null}
      listings={listingsMock}
      locate={mockLocate}
      displayListing={mockDisplayListing}
    />);

    it('should render a component matching the snapshot', () => {
      const tree = toJson(wrapper);
      expect(tree).toMatchSnapshot();
      expect(wrapper).toHaveLength(1);
      expect(wrapper.find(Header)).toHaveLength(1);
      expect(wrapper.find(Hero)).toHaveLength(1);
    });
  });
});

{
  "bottom_right": {
    "latitude": 32.618865,
    "longitude": -96.555516
  },
  "id": 1390,
  "latitude": 32.78143692016602,
  "listings": [
    {
      "avatar_image": {
        "small_url": "https://images.weedmaps.com/deliveries/000/028/448/avatar/square_fill/1510581750-1507658638-Knox_Medical_Logo.png"
      },
      "city": "Dallas",
      "distance": 2,
      "id": 28448,
      "license_type": "medical",
      "name": "Knox Medical (Delivery Now Available)",
      "online_ordering": {
        "enabled_for_pickup": false,
        "enabled_for_delivery": false
      },
      "package_level": "listing_plus",
      "rating": 5,
      "region_id": 1390,
      "retailer_services": [
        "delivery"
      ],
      "slug": "knox-medical-dallas",
      "state": "TX",
      "static_map_url": "https://staticmap.weedmaps.com/static_map/13/32.7736/-96.795108/402/147/map.png",
      "wmid": 459977538
    }
  ],
  "longitude": -96.7899169921875,
  "name": "Dallas",
  "region_path": "united-states/texas/dallas",
  "slug": "dallas",
  "top_left": {
    "latitude": 33.016492,
    "longitude": -96.999319
  }
}
import React, { Component } from 'react';
import { connect } from 'react-redux';
import PropTypes from 'prop-types';
import get from 'lodash.get';

import { locate, displayListing } from '../actions';
import Header from './header';
import Hero from './hero';
import Ripple from './partials/ripple';
import ListingCards from './listing_cards';
import Delivery from '../icons/delivery';
import Dispensary from '../icons/dispensary';
import Doctor from '../icons/doctor';
import { DARK_GRAY } from '../constants/colors';

import {
  AppWrapper,
  AppContent,
  ListingGroups,
} from './styles';

const regionTypes = ['delivery', 'dispensary', 'doctor'];
const regionLabels = {
  delivery: 'Deliveries',
  dispensary: 'Dispensaries',
  doctor: 'Doctors',
};

export class App extends Component {
  constructor(props) {
    super(props);

    this.state = {
      loadingTimer: 0,
      isLocatingStarted: false,
      geoCoords: null,
      width: 0
    };

    this.locateMe = this.locateMe.bind(this);
    this.gotoListing = this.gotoListing.bind(this);
  }

  componentDidMount() {
    // Fetch geolocation ahead of time.
    navigator.geolocation.getCurrentPosition(position =>
      this.setState({ geoCoords: position.coords }));

    this.updateWindowDimensions();
    window.addEventListener("resize", this.updateWindowDimensions);
  }

  componentWillUnmount() {
    window.removeEventListener("resize", this.updateWindowDimensions);
  }

  updateWindowDimensions = () => this.setState({ width: window.innerWidth });

  locateMe() {
    console.log('locateMe')
    const { dispatch } = this.props;
    const { geoCoords } = this.state;

    if (navigator.geolocation && !geoCoords) {
      navigator.geolocation.getCurrentPosition(position =>
        dispatch(locate(position.coords)));
    } else {
      dispatch(locate(geoCoords));
    }

    this.setState({ isLocatingStarted: true });
  };

  gotoListing(listing) {
    const { dispatch } = this.props;
    dispatch(displayListing(listing));
    const link = `/listing/${listing.wmid}`;
    this.props.history.push(link);
  }

  render() {
    const { isLocating, location, regions, error } = this.props;
    const { isLocatingStarted, width } = this.state;
    const { state_abv: state } = location !== null && location;
    const isLoading = isLocatingStarted && isLocating;

    const getLabel = (listings, label) => {
      const componentsMap = {
        Deliveries: Delivery,
        Dispensaries: Dispensary,
        Doctors: Doctor
      };
      const DynamicIcon = componentsMap[label];

      if (get(listings, 'listings').length) {
        return (
          <div key={label}>
            <DynamicIcon fill={DARK_GRAY} /> <strong> {label} </strong>
          </div>
        );
      }
      return <div />;
    };

    return (
      <AppWrapper>
        <Header history={this.props.history} />
        <Hero
          location={location}
          isLocating={isLocating}
          locateMe={this.locateMe}
        />
        { isLoading ? <Ripple /> :
          <AppContent>
            {error && <div> {error.message} </div>}
            {regions && (
              <React.Fragment>
                {regionTypes.map(regionType => (
                  <ListingGroups key={regionType}>
                    <h2>
                      {getLabel(regions[regionType], regionLabels[regionType])}
                    </h2>
                    <ListingCards
                      listings={get(regions[regionType], 'listings')}
                      state={state}
                      isMobileSize={width < 769}
                      gotoListing={this.gotoListing}
                    />
                  </ListingGroups>
                ))}
              </React.Fragment>
            )}
          </AppContent>
        }
      </AppWrapper>
    );
  }
}

const mapStateToProps = state => state.location;

App.propTypes = {
  isLocating: PropTypes.bool.isRequired,
  location: PropTypes.object,
  regions: PropTypes.object,
  dispatch: PropTypes.any,
  error: PropTypes.object,
};

App.defaultProps = {
  isLocating: false,
  location: {},
  regions: {},
  error: {},
};

export const AppJest = App

export default connect(mapStateToProps)(App);
import React from 'react'
import { shallow } from 'enzyme'
import toJson from 'enzyme-to-json'

import { AppJest } from './App'
import Header from './header';
import Hero from './hero';
import Ripple from './partials/ripple';
import listingsMock from '../__test__/mocks/listings-mock.json';

// Mock the services.
const mockLocate = jest.fn();
const mockDisplayListing = jest.fn();
const mockGeolocation = {
  getCurrentPosition: jest.fn(),
  watchPosition: jest.fn()
};

global.navigator.geolocation = mockGeolocation;

jest.mock('../actions', () => ({
  locate: () => mockLocate(),
  displayListing: () => mockDisplayListing()
}));

describe('<App /> component', () => {
  describe('when rendering', () => {
    const wrapper = shallow(<AppJest
      navigator={mockGeolocation}
      isLocating={false}
      location={null}
      regions={null}
      dispatch={null}
      error={null}
      listings={listingsMock}
      locate={mockLocate}
      displayListing={mockDisplayListing}
    />);

    it('should render a component matching the snapshot', () => {
      const tree = toJson(wrapper);
      expect(tree).toMatchSnapshot();
      expect(wrapper).toHaveLength(1);
      expect(wrapper.find(Header)).toHaveLength(1);
      expect(wrapper.find(Hero)).toHaveLength(1);
    });
  });
});
App.propTypes = {
  isLocating: PropTypes.bool.isRequired,
  location: PropTypes.object,
  regions: PropTypes.object,
  dispatch: PropTypes.any,
  error: PropTypes.object,
};

App.defaultProps = {
  isLocating: false,
  location: {},
  regions: {},
  error: {},
};