Skip to content

Commit

Permalink
[Fix] reduce/reduceRight: follow Array#reduce when omitting the…
Browse files Browse the repository at this point in the history
… initialValue.
  • Loading branch information
ljharb committed Nov 11, 2016
1 parent bdff1b8 commit d45ee73
Show file tree
Hide file tree
Showing 8 changed files with 159 additions and 28 deletions.
3 changes: 1 addition & 2 deletions docs/api/ReactWrapper/reduce.md
Original file line number Diff line number Diff line change
Expand Up @@ -12,8 +12,7 @@ following arguments:
- `node` (`ReactWrapper`): A wrapper around the current node being processed
- `index` (`Number`): The index of the current node being processed

2. `initialValue` (`T` [optional]): If provided, this will be passed in as the first argument to the
first invocation of the reducing function.
2. `initialValue` (`T` [optional]): If provided, this will be passed in as the first argument to the first invocation of the reducing function. If omitted, the first `node` will be provided and the iteration will begin on the second node in the collection.



Expand Down
3 changes: 1 addition & 2 deletions docs/api/ReactWrapper/reduceRight.md
Original file line number Diff line number Diff line change
Expand Up @@ -12,8 +12,7 @@ following arguments:
- `node` (`ReactWrapper`): A wrapper around the current node being processed
- `index` (`Number`): The index of the current node being processed

2. `initialValue` (`T` [optional]): If provided, this will be passed in as the first argument to the
first invocation of the reducing function.
2. `initialValue` (`T` [optional]): If provided, this will be passed in as the first argument to the first invocation of the reducing function. If omitted, the first `node` will be provided and the iteration will begin on the second node in the collection.



Expand Down
3 changes: 1 addition & 2 deletions docs/api/ShallowWrapper/reduce.md
Original file line number Diff line number Diff line change
Expand Up @@ -12,8 +12,7 @@ following arguments:
- `node` (`ShallowWrapper`): A wrapper around the current node being processed
- `index` (`Number`): The index of the current node being processed

2. `initialValue` (`T` [optional]): If provided, this will be passed in as the first argument to the
first invocation of the reducing function.
2. `initialValue` (`T` [optional]): If provided, this will be passed in as the first argument to the first invocation of the reducing function. If omitted, the first `node` will be provided and the iteration will begin on the second node in the collection.



Expand Down
3 changes: 1 addition & 2 deletions docs/api/ShallowWrapper/reduceRight.md
Original file line number Diff line number Diff line change
Expand Up @@ -12,8 +12,7 @@ following arguments:
- `node` (`ShallowWrapper`): A wrapper around the current node being processed
- `index` (`Number`): The index of the current node being processed

2. `initialValue` (`T` [optional]): If provided, this will be passed in as the first argument to the
first invocation of the reducing function.
2. `initialValue` (`T` [optional]): If provided, this will be passed in as the first argument to the first invocation of the reducing function. If omitted, the first `node` will be provided and the iteration will begin on the second node in the collection.



Expand Down
36 changes: 26 additions & 10 deletions src/ReactWrapper.jsx
Original file line number Diff line number Diff line change
Expand Up @@ -734,11 +734,19 @@ class ReactWrapper {
* @param {*} initialValue - the initial value
* @returns {*}
*/
reduce(fn, initialValue) {
return this.getNodes().reduce(
(accum, n, i) => fn.call(this, accum, this.wrap(n), i),
initialValue,
);
reduce(fn, initialValue = undefined) {
if (arguments.length > 1) {
return this.getNodes().reduce(
(accum, n, i) => fn.call(this, accum, this.wrap(n), i),
initialValue,
);
}
return this.getNodes().reduce((accum, n, i) => fn.call(
this,
i === 1 ? this.wrap(accum) : accum,
this.wrap(n),
i,
));
}

/**
Expand All @@ -749,11 +757,19 @@ class ReactWrapper {
* @param {*} initialValue - the initial value
* @returns {*}
*/
reduceRight(fn, initialValue) {
return this.getNodes().reduceRight(
(accum, n, i) => fn.call(this, accum, this.wrap(n), i),
initialValue,
);
reduceRight(fn, initialValue = undefined) {
if (arguments.length > 1) {
return this.getNodes().reduceRight(
(accum, n, i) => fn.call(this, accum, this.wrap(n), i),
initialValue,
);
}
return this.getNodes().reduceRight((accum, n, i) => fn.call(
this,
i === 1 ? this.wrap(accum) : accum,
this.wrap(n),
i,
));
}

/**
Expand Down
36 changes: 26 additions & 10 deletions src/ShallowWrapper.js
Original file line number Diff line number Diff line change
Expand Up @@ -837,11 +837,19 @@ class ShallowWrapper {
* @param {*} initialValue - the initial value
* @returns {*}
*/
reduce(fn, initialValue) {
return this.getNodes().reduce(
(accum, n, i) => fn.call(this, accum, this.wrap(n), i),
initialValue,
);
reduce(fn, initialValue = undefined) {
if (arguments.length > 1) {
return this.getNodes().reduce(
(accum, n, i) => fn.call(this, accum, this.wrap(n), i),
initialValue,
);
}
return this.getNodes().reduce((accum, n, i) => fn.call(
this,
i === 1 ? this.wrap(accum) : accum,
this.wrap(n),
i,
));
}

/**
Expand All @@ -852,11 +860,19 @@ class ShallowWrapper {
* @param {*} initialValue - the initial value
* @returns {*}
*/
reduceRight(fn, initialValue) {
return this.getNodes().reduceRight(
(accum, n, i) => fn.call(this, accum, this.wrap(n), i),
initialValue,
);
reduceRight(fn, initialValue = undefined) {
if (arguments.length > 1) {
return this.getNodes().reduceRight(
(accum, n, i) => fn.call(this, accum, this.wrap(n), i),
initialValue,
);
}
return this.getNodes().reduceRight((accum, n, i) => fn.call(
this,
i === 1 ? this.wrap(accum) : accum,
this.wrap(n),
i,
));
}

/**
Expand Down
52 changes: 52 additions & 0 deletions test/ReactWrapper-spec.jsx
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,9 @@ import {
import { ITERATOR_SYMBOL } from '../src/Utils';
import { REACT013, REACT014, REACT15 } from '../src/version';

const getElementPropSelector = prop => x => x.props[prop];
const getWrapperPropSelector = prop => x => x.prop(prop);

describeWithDOM('mount', () => {
describe('context', () => {
it('can pass in context', () => {
Expand Down Expand Up @@ -2254,6 +2257,10 @@ describeWithDOM('mount', () => {
});

describe('.reduce(fn[, initialValue])', () => {
it('has the right length', () => {
expect(ReactWrapper.prototype.reduce).to.have.lengthOf(1);
});

it('should call a function with a wrapper for each node in the wrapper', () => {
const wrapper = mount(
<div>
Expand Down Expand Up @@ -2294,9 +2301,33 @@ describeWithDOM('mount', () => {
baz: 'foo hoo',
});
});

it('allows the initialValue to be omitted', () => {
const one = (<div id="bax" className="foo qoo" />);
const two = (<div id="bar" className="foo boo" />);
const three = (<div id="baz" className="foo hoo" />);
const wrapper = mount(
<div>
{one}
{two}
{three}
</div>,
);
const counter = (<noscript id="counter" />);
const result = wrapper
.find('.foo')
.reduce((acc, n) => [].concat(acc, n, new ReactWrapper(counter)))
.map(getWrapperPropSelector('id'));

expect(result).to.eql([one, two, counter, three, counter].map(getElementPropSelector('id')));
});
});

describe('.reduceRight(fn[, initialValue])', () => {
it('has the right length', () => {
expect(ReactWrapper.prototype.reduceRight).to.have.lengthOf(1);
});

it('should call a function with a wrapper for each node in the wrapper in reverse', () => {
const wrapper = mount(
<div>
Expand Down Expand Up @@ -2337,6 +2368,27 @@ describeWithDOM('mount', () => {
baz: 'foo hoo',
});
});

it('allows the initialValue to be omitted', () => {
const one = (<div id="bax" className="foo qoo" />);
const two = (<div id="bar" className="foo boo" />);
const three = (<div id="baz" className="foo hoo" />);
const wrapper = mount(
<div>
{one}
{two}
{three}
</div>,
);

const counter = (<noscript id="counter" />);
const result = wrapper
.find('.foo')
.reduceRight((acc, n) => [].concat(acc, n, new ReactWrapper(counter)))
.map(getWrapperPropSelector('id'));

expect(result).to.eql([three, two, counter, one, counter].map(getElementPropSelector('id')));
});
});

describe('.slice([begin[, end]])', () => {
Expand Down
51 changes: 51 additions & 0 deletions test/ShallowWrapper-spec.jsx
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,9 @@ import { describeIf, itIf, itWithData, generateEmptyRenderData } from './_helper
import { ITERATOR_SYMBOL, withSetStateAllowed } from '../src/Utils';
import { REACT013, REACT014, REACT15 } from '../src/version';

const getElementPropSelector = prop => x => x.props[prop];
const getWrapperPropSelector = prop => x => x.prop(prop);

describe('shallow', () => {
describe('context', () => {
it('can pass in context', () => {
Expand Down Expand Up @@ -2032,6 +2035,10 @@ describe('shallow', () => {
});

describe('.reduce(fn[, initialValue])', () => {
it('has the right length', () => {
expect(ShallowWrapper.prototype.reduce).to.have.lengthOf(1);
});

it('should call a function with a wrapper for each node in the wrapper', () => {
const wrapper = shallow(
<div>
Expand Down Expand Up @@ -2075,9 +2082,33 @@ describe('shallow', () => {
baz: 'foo hoo',
});
});

it('allows the initialValue to be omitted', () => {
const one = (<div id="bax" className="foo qoo" />);
const two = (<div id="bar" className="foo boo" />);
const three = (<div id="baz" className="foo hoo" />);
const wrapper = shallow(
<div>
{one}
{two}
{three}
</div>,
);
const counter = (<noscript id="counter" />);
const result = wrapper
.find('.foo')
.reduce((acc, n) => [].concat(acc, n, new ShallowWrapper(counter)))
.map(getWrapperPropSelector('id'));

expect(result).to.eql([one, two, counter, three, counter].map(getElementPropSelector('id')));
});
});

describe('.reduceRight(fn[, initialValue])', () => {
it('has the right length', () => {
expect(ShallowWrapper.prototype.reduceRight).to.have.lengthOf(1);
});

it('should call a function with a wrapper for each node in the wrapper in reverse', () => {
const wrapper = shallow(
<div>
Expand Down Expand Up @@ -2121,6 +2152,26 @@ describe('shallow', () => {
baz: 'foo hoo',
});
});

it('allows the initialValue to be omitted', () => {
const one = (<div id="bax" className="foo qoo" />);
const two = (<div id="bar" className="foo boo" />);
const three = (<div id="baz" className="foo hoo" />);
const wrapper = shallow(
<div>
{one}
{two}
{three}
</div>,
);
const counter = (<noscript id="counter" />);
const result = wrapper
.find('.foo')
.reduceRight((acc, n) => [].concat(acc, n, new ShallowWrapper(counter)))
.map(getWrapperPropSelector('id'));

expect(result).to.eql([three, two, counter, one, counter].map(getElementPropSelector('id')));
});
});

describe('.slice([begin[, end]])', () => {
Expand Down

0 comments on commit d45ee73

Please sign in to comment.