Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
7 changes: 6 additions & 1 deletion src/reduce.js
Original file line number Diff line number Diff line change
Expand Up @@ -7,12 +7,17 @@
* @returns {*}
*/
function reduce(callback, startValue) {
let prev = startValue;
let prev;
let startIndex = 0;

if (arguments.length < 2) {
if (this.length === 0) {
throw new TypeError('Reduce of empty array with no initial value');
}
startIndex = 1;
prev = this[0];
} else {
prev = startValue;
}

for (let i = startIndex; i < this.length; i++) {
Expand Down
50 changes: 48 additions & 2 deletions src/reduce.test.js
Original file line number Diff line number Diff line change
@@ -1,6 +1,8 @@
'use strict';

const { reduce } = require('./reduce');
const arr = [0, 1, 2, 3, 4];
const sumCb = (acc, current, i, array) => acc + current;

describe('reduce', () => {
beforeAll(() => {
Expand All @@ -11,9 +13,53 @@ describe('reduce', () => {
delete Array.prototype.reduce2;
});

it('should ', () => {
it('should return a number', () => {
expect(typeof arr.reduce2(sumCb, 0)).toBe('number');
});

it('should return an accumulated value', () => {
expect(arr.reduce2(sumCb, 0)).toBe(10);
});

it('should return an initial value if array is empty', () => {
expect([].reduce2(sumCb, 0)).toBe(0);
});

it('should call cb for every item', () => {
const cb = jest.fn();

arr.reduce2(cb, 0);
expect(cb).toHaveBeenCalledTimes(5);
});

it('should call cb with all params', () => {
const cb = jest.fn(sumCb);

arr.reduce2(cb, 0);

expect(cb).nthCalledWith(1, 0, 0, 0, arr);
expect(cb).nthCalledWith(2, 0, 1, 1, arr);
expect(cb).nthCalledWith(3, 1, 2, 2, arr);
expect(cb).nthCalledWith(4, 3, 3, 3, arr);
expect(cb).nthCalledWith(5, 6, 4, 4, arr);
});

// Add tests here
it('should use first element as accumulator if it is not provided', () => {
const cb = jest.fn();

arr.reduce2(cb);
expect(cb).nthCalledWith(1, arr[0], arr[1], 1, arr);
});

it('throws TypeError if array and initial value are empty', () => {
expect(() => [].reduce2(sumCb)).toThrow(TypeError);
});

it("doesn't call cb for [1] without init", () => {
const cb = jest.fn();

[1].reduce2(cb);

expect(cb).not.toHaveBeenCalled();
Comment on lines +61 to +63

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Great job adding this test case for a single-element array without an initial value. You've correctly checked that the callback is not invoked. To fully cover this scenario, please also add an assertion to verify that the method returns the single element itself (in this case, 1).

});
});

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This is great! To make the test suite fully comprehensive, please add one more test case to cover an important edge case from the requirements: calling reduce on an array with a single element and no initialValue.

According to the MDN specification, in this situation, the single element should be returned directly, and the callback function should not be executed. A test for this would look something like this:

it('should return the element without calling the callback for a single-element array', () => {
  const cb = jest.fn();
  const singleElementArray = [42];

  expect(singleElementArray.reduce2(cb)).toBe(42);
  expect(cb).not.toHaveBeenCalled();
});