1

I am actually studying about enzyme integrated with jest to test stuff on applications. Other things I am using is react and moment.

My question is probably very noob, but I just want to know why there is two argument stuff on this line:

wrapper.find('SingleDatePicker').prop('onFocusChange')({ focused });

is the 'formula' of this, this: objectExample.methodExample('argument1')('argument2'); ?

I will provide down below the whole code divided in two: the test code and the code tested.

Code tested:

export default class ExpenseForm extends React.Component {
  constructor(props) {
    super(props);
    this.state = {
      calendarFocused: false,
    };
  }
  onFocusChange = ({ focused }) => {
    this.setState(() => ({ calendarFocused: focused }));
  };
  render() {
    return (
      <div>
        {this.state.error && <p>{this.state.error}</p>}
        <form onSubmit={this.onSubmit}>
          <SingleDatePicker
            date={this.state.createdAt}
            onDateChange={this.onDateChange}
            focused={this.state.calendarFocused}
            onFocusChange={this.onFocusChange}
            numberOfMonths={1}
            isOutsideRange={() => false}
          />
        </form>
      </div>
    )
  }
}

test code:

test('should set calendar focus on change', () => {
  const focused = false;
  const wrapper = shallow(<ExpenseForm />);
  wrapper.find('SingleDatePicker').prop('onFocusChange')({ focused });
  expect(wrapper.state('calendarFocused')).toBe(focused);
});

So basically, I can understand all the functionality of the code itself and everything.

I just do not understand this second argument ({ focused }).

I don't even know if this is called 'argument'.

I tweak a bit and took this thing out of the code and it worked the same way.

I am kind of confused if this is vanilla javascript or something of one of these libraries I am using.

...

What I expect: answer for what is this thing and why use it like this. some source of name or something I can browse about it and learn that.

nishi
  • 512
  • 1
  • 4
  • 19
  • As for the terms, `({ focused })` is function call and `{ focused }` is an argument. `wrapper.find('SingleDatePicker').prop('onFocusChange')` is an expression, in this case it doesn't matter what's written there, as long as an expression evaluates to a function. It could be `someFn({ focused })`. – Estus Flask Jun 07 '20 at 06:54

2 Answers2

2

wrapper.find('SingleDatePicker').prop('onFocusChange') returns a function.

This function is actually:

onFocusChange = ({ focused }) => {
    this.setState(() => ({ calendarFocused: focused }));
};

i.e. the one that you created in your component.

Now to execute this function you can do:

wrapper.find('SingleDatePicker').prop('onFocusChange')({ focused });

or

const onFocusChangeFn = wrapper.find('SingleDatePicker').prop('onFocusChange');
onFocusChangeFn({ focused });

In general if you have something like:

const myObject = {
    getFunction: function(y) {
        return function(x) {
            console.log(y, x);
        }
    }
}

Then you can do:

myObject.getFunction(10)(20) // prints (10,20)

where myObject.getfunction(10) will return the inner function that you can call with any argument like 20 in the example.

Returning a function is useful for various purposes like currying and partial functions

chiragrtr
  • 902
  • 4
  • 6
  • i will answer my question with the comment i wanted to answer just because its way to big – nishi Jun 08 '20 at 03:40
0

so i understood that I can call the inner function as you mentioned on the last example. and that this example:

const onFocusChangeFn = wrapper.find('SingleDatePicker').prop('onFocusChange');
onFocusChangeFn({ focused });

is as the jest documentation suggest

const mockFn = jest.fn();
mockFn(); 
expect(mockFn).toHaveBeenCalled();

and that is pretty much clear on my mind. problem is that when i get a piece of code like this:

  test('should handle date changes', () => {
  const startDate = moment(0).add(2, 'days');
  const endDate = moment(0).add(3, 'days');
  wrapper.find('DateRangePicker').prop('onDatesChange')({ startDate, endDate });
  expect(setStartDate).toHaveBeenLastCalledWith(startDate);
  expect(setEndDate).toHaveBeenLastCalledWith(endDate);
});

would this proceed like this?:

(...)
const wrapperFn  = wrapper.find('DateRangePicker').prop('onDatesChange');
wrapperFn({ startDate, endDate });

I was proceeding on the studies and i found another thing that is about the same subject but a bit different.

test('should sort by date', () => {
  const value = 'date';
  wrapper.find('select').simulate('change', { target: { value } });
  expect(sortByDate).toHaveBeenCalled();
});

he defined the target value for the 'e' event inside the simulate() arguments. this could be defined separately too ? Like this:

test('should sort by date', () => {
  const value = 'date';
  const wrapperFn = wrapper.find('select').simulate('change')
  wrapperFn({ target: { value } });
  expect(sortByDate).toHaveBeenCalled();
});

or they are completely different things?

below, i will provide the full code I am testing

import React from 'react';
import { connect } from 'react-redux';
import { DateRangePicker } from 'react-dates';
import { setTextFilter, sortByDate, sortByAmount, setStartDate, setEndDate } from '../actions/filters';

export class ExpenseListFilters extends React.Component {
  state = {
    calendarFocused: null
  };
  onDatesChange = ({ startDate, endDate }) => {
    this.props.setStartDate(startDate);
    this.props.setEndDate(endDate);
  };
  onFocusChange = (calendarFocused) => {
    this.setState(() => ({ calendarFocused }));
  }
  onTextChange = (e) => {
    this.props.setTextFilter(e.target.value);
  };
  onSortChange = (e) => {
    if (e.target.value === 'date') {
      this.props.sortByDate();
    } else if (e.target.value === 'amount') {
      this.props.sortByAmount();
    }
  };
  render() {
    return (
      <div>
        <input
          type="text"
          value={this.props.filters.text}
          onChange={this.onTextChange}
        />
        <select
          value={this.props.filters.sortBy}
          onChange={this.onSortChange}
        >
          <option value="date">Date</option>
          <option value="amount">Amount</option>
        </select>
        <DateRangePicker
          startDate={this.props.filters.startDate}
          endDate={this.props.filters.endDate}
          onDatesChange={this.onDatesChange}
          focusedInput={this.state.calendarFocused}
          onFocusChange={this.onFocusChange}
          showClearDates={true}
          numberOfMonths={1}
          isOutsideRange={() => false}
        />
      </div>
    );
  }
};

const mapStateToProps = (state) => ({
  filters: state.filters
});

const mapDispatchToProps = (dispatch) => ({
  setTextFilter: (text) => dispatch(setTextFilter(text)),
  sortByDate: () => dispatch(sortByDate()),
  sortByAmount: () => dispatch(sortByAmount()),
  setStartDate: (startDate) => dispatch(setStartDate(startDate)),
  setEndDate: (endDate) => dispatch(setEndDate(endDate))
});

export default connect(mapStateToProps, mapDispatchToProps)(ExpenseListFilters);

fixtures:

import moment from 'moment';

const filters = {
  text: '',
  sortBy: 'date',
  startDate: undefined,
  endDate: undefined
};

const altFilters = {
  text: 'bills',
  sortBy: 'amount',
  startDate: moment(0),
  endDate: moment(0).add(3, 'days')
};

export { filters, altFilters };

thanks for helping.

nishi
  • 512
  • 1
  • 4
  • 19
  • Answer to your first Q is yes, it will proceed like that. You understood that fine. For 2nd Q, they are 2 different things - 2nd code will not work as it's not a function. `wrapper.simulate(event, args)` is different from `wrapper.prop(propName)` as the former will trigger the given event with passed args whereas the latter will return your prop which in your case is a function that you can execute. Refer signature of these 2 functions: https://enzymejs.github.io/enzyme/docs/api/ShallowWrapper/simulate.html and https://enzymejs.github.io/enzyme/docs/api/ShallowWrapper/prop.html – chiragrtr Jun 08 '20 at 03:53