Search code examples
javascriptunit-testingmockingsinon

Sinon stub - mocking a function which returns an array of objects


I am trying to stub the following code

async function logUpdate(client) {
  const results = await client.query(query.toParam());
  const { count, timestamp } = results.rows[0];

  await db.updateDatasourceLogs(destdb, DB.src, TABLES.src, timestamp, count);
}

This is the following code i am using to stub the above code

  fakeClient = {
      query: sinon.stub().resolves(fakeRows),
    };

   const rowData = {
      count: 1,
      timestamp: ''
   };

    fakeRows = {
      rows: sinon.stub().returns([rowData]),
    };

   fakeSequel = {
       useFlavour: sinon.stub().returns(toParam: () => false,),
   };

I am getting an error for destructuring

TypeError: Cannot destructure property count of 'undefined' or 'null'.

at line

const { count, timestamp } = results.rows[0];

how to stub the above line?


Solution

  • If we look at the body of your logUpdate function, we see it begins with the following two lines:

    const results = await client.query(query.toParam());
    const { count, timestamp } = results.rows[0];
    

    This code says:

    1. Await the Promise returned by the call to client.query and assign it to a variable called results.
    2. results is an Object with a property called rows which is an Array whose 0th element should be an Object with count and timestamp properties - which we destructure into local variables.

    This implies that the value of results looks like:

    {
      "rows": [
        {
          "count": 1
          "timestamp": "0"
        }
      ]
    }
    

    However, in our stubbing code, we have the following:

    fakeRows = {
      rows: sinon.stub().returns([rowData]),
    };
    

    Which says that fakeRows is an Object with a rows property whose value is a function that returns [rowData].

    If we were to implement this Object without sinon, it would look like:

    {
      "rows": function () {
        return [
          {
            "count": 1
            "timestamp": "0"
          }
        ];
      }
    }
    

    Notice the difference between the structure that logUpdate is expecting and what fakeRows actually provides. Specifically, logUpdate expects results to have a rows Array, but, with our stubbed code, it has a rows Function!

    We can fix this simply by having fakeRows reference our rowData directly:

    const fakeRows = {
      rows: [rowData]
    };