簡體   English   中英

如何在React組件中嘲笑lodash.get的使用?

[英]How to Jest test use of lodash.get in React component?

錯誤

TypeError:無法讀取未定義的屬性“ length”

我的應用程序組件被利用的import get from 'lodash.get' https://lodash.com/docs/4.17.11#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.test.js

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

import { AppJest } from './App'
import listingsMock from '../__test__/mocks/listings-mock.json';


// Mock the services.
const mockLocate = jest.fn();
const mockDisplayListing = jest.fn();

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

describe('<App /> component', () => {
  describe('when rendering', () => {
    const wrapper = shallow(<AppJest
      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);
    });
  });
});

我以為是因為我不是在嘲笑清單,而是將其傳遞到淺層包裝的道具中,而是添加了模擬。

上市-mock.json

{
  "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
  }
}

App.js

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: {},
};

在此處輸入圖片說明

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM