-3

Hi i have a react component expenses-total.js and a corresponding test case expenses-total.test.js as shown below.

expenses-total.js

     export default (expenses=[]) => {
      if (expenses.length === 0) {
        return 0;
      } else {
        return expenses
          .map(expense => expense.amount)
          .reduce((sum, val) => sum + val, 0);
      }
    };

expenses-total.test.js

import selectExpensesTotal from '../../selectors/expenses-total';
const expenses = [
    {
      id: "1",
      description: "gum",
      amount: 321,
      createdAt: 1000,
      note: ""
    },
    {
      id: "2",
      description: "rent",
      amount: 3212,
      createdAt: 4000,
      note: ""
    },
    {
      id: "3",
      description: "Coffee",
      amount: 3214,
      createdAt: 5000,
      note: ""
    }
  ];

test('Should return 0 if no expenses', ()=>{
    const res = selectExpensesTotal([]);
    expect(res).toBe(0);
});

test('Should correctly add up a single expense', ()=>{
    const res = selectExpensesTotal(expenses[0]);
    expect(res).toBe(321);
});

test('Should correctly add up multiple expenses',()=>{
    const res = selectExpensesTotal(expenses);
    expect(res).toBe(6747);
});

when i run the test case, its getting failed by giving an error

TypeError: expenses.map is not a function

I know the test case is correct but dont know what is wrong with thecomponent. Could anyone please help me in fixing this error?

kind user
  • 40,029
  • 7
  • 67
  • 77
Shivakumar H.G
  • 114
  • 2
  • 8

4 Answers4

2

The problem is with if (expenses.length === 0) and the test case that uses selectExpensesTotal(expenses[0]):

expenses[0] passes an object, which has no length property, so in the function being tested, expenses.length returns undefined. However, undefined === 0 evaluates to false so your code goes into the else block tries to use .map on the object, which doesn't have that function, thus it throws an error.

Herohtar
  • 5,347
  • 4
  • 31
  • 41
0

In a brief: you can't map over an object.

expenses is an array of objects, so expenses[0] is an object.

Condition expenses.length === 0 evaluates to false, since obviously .length property does not exist on Object.prototype, so the else condition takes place - your function tries to map over an object.

kind user
  • 40,029
  • 7
  • 67
  • 77
0

The problem is that expenses[0] is an object (you probably expected it to be an array) and an object does not have a map function. A quick hack would be to add another ifs into the loop to check if expenses is actually an object. So that:

export default (expenses=[]) => {
  if (expenses.length === 0) {
    return 0;
  } else {
    if (typeof expenses === 'object') {
      return expenses.amount
    } else {
    return expenses
      .map(expense => expense.amount)
      .reduce((sum, val) => sum + val, 0);
    }
  }
};

I hope this help.

0

To fix this error, you can pass in an array of object into

selectExpensesTotal([expenses[0]]) 

rather than just an object

selectExpensesTotal(expenses[0]) 

So your code show look like this:

test('Should correctly add up a single expense', ()=>{
    const res = selectExpensesTotal([expenses[0]]);
    expect(res).toBe(321);
});

.map function will now work on expenses. Because, this is now an array of object ( works with map function ) and not an object(This does not work with map function)