-1

tl;dr I need to test that my method adds a row to a spreadsheet on successful load of a Google spreadsheet.

saveDataToGoogleSpreadSheet(conversationData){
  return new Promise((resolve, reject) => {
    Spreadsheet.load(this.getGoogleAPISettings(), (err, spreadsheet) => {
      if (err) {
        return reject(err);
      }

      return spreadsheet.receive((receivedError, rows, info) => {
        if (receivedError) {
          return reject(receivedError);
        }
        const rowData = this.getSpreadsheetRowData(conversationData, info.totalRows);
        spreadsheet.add(rowData);
        return spreadsheet.send(sendError => (sendError ? reject(sendError) : resolve()));
      });
    });
  });
}

I tested the case one and case two of the function (the two first errors) but I couldn't do it for the last one, the case of success where we an add a row to a spreadsheet.

I need some help with the structure of the test, or a hint on how could my test be.

Edit: how the previous tests were made

it('should add a row to a Google Spreadsheet', (done) => {
      nock('https://spreadsheets.google.com')
      .post('/feeds/cells/1ZOd7Sysc-JNa-D5AHb7ZJkwBRMBGaeKpzIwEl7B8RbQ/1/private/full/batch')
      .replyWithError({ message: 'abcde' });
      api.saveDataToGoogleSpreadSheet({ data: 'some data' })
      .then(() => done(new Error('should not have made the call')))
      .catch((err) => {
        expect(err).to.equal('Error Reading Spreadsheet');
        done();
      });
    }).timeout(4000);
oligofren
  • 20,744
  • 16
  • 93
  • 180
  • As you have not told us what the function must do, nobody can tell you how to test it. – Raedwald Jun 14 '17 at 09:31
  • @Raedwald I agree that the question is a bit short on info, but it contains enough. He has asked how he can test if the `spreadsheet.add` method was called upon success of the `spreadsheet.receive` method. – oligofren Jun 14 '17 at 09:54
  • @laurent miller: could you clarify how you have tested the first two cases? I have tried to guess at it in my question, and I assume you have tested using actual network calls. Is this correct, and if not, how? You might also comment on the answer if it does not answer your question somehow. – oligofren Jun 14 '17 at 11:35
  • it('should add a row to a Google Spreadsheet', (done) => { nock('https://spreadsheets.google.com') .post('/feeds/cells/1ZOd7Sysc-JNa-D5AHb7ZJkwBRMBGaeKpzIwEl7B8RbQ/1/private/full/batch') .replyWithError({ message: 'abcde' }); api.saveDataToGoogleSpreadSheet({ data: 'some data' }) .then(() => done(new Error('should not have made the call'))) .catch((err) => { expect(err).to.equal('Error Reading Spreadsheet'); done(); }); }).timeout(4000); That's how I tested them, sorry for the strange format, couldn't change it. – laurent miller Jun 14 '17 at 13:24
  • Thanks, added the test to the question for you. PS. A stubbed response like that should be done in 2-3 ms. If it uses more than that you are probably not mocking the responses, but going against the real service! Try setting the timeout to 50 ms to check. PPS. Could you use the info in my answer? If so try upvoting :-) I got a downvote for some unknown reason... – oligofren Jun 14 '17 at 15:17
  • 1
    @oligofren thanks for your help mate, I'll totally use the info you provided me with. I upvoted your answer but I think it won't be change the publicly displayed score since I have a reputation<15 – laurent miller Jun 14 '17 at 16:56

1 Answers1

0

It is hard to tell what is the problem with the test from the little code you have, and no background on what the various objects are and how they come to be, so I will just assume that Spreadsheet is an object that is created through a library you require, and other than that, all other objects are created by the module. i.e. I assume you somewhere have a line resembling something like this:

const Spreadsheet = require('some-google-docs-spreadsheet-lib');

That means one problem is finding out how to control the Spreadsheet object so we can stub out its behavior.

Just to start you out, you might get some good pointers on general code and test structure for easy testing from these two answers, as they cover the two most relevant techniques: dependency injection and exploiting link seams.

For all I know, you might already utilize one of these techniques, as you say you have been able to test the two error situations. But maybe you have not really been unit testing and done the actual network calls to the service instead (which is more of an integration test)? Anyway, I'll assume no more than what I wrote above and show you how to do the testing using proxyquire:

const assert = require('assert');
const dummy = ()=> {};
const SpreadSheetStubLibrary = { load: dummy };
const MyClassToTest = proxyquire('../src/my-module', { 
    'some-google-docs-spreadsheet-lib': SpreadSheetStubLibrary
})
const config = {};
const conversationData = {};

let stubSetup;
let spreadsheet;
let myObj;

function setupStubs() {
    stubSetup = stubSpreadsheetLoadFunction();
    spreadsheet = stubSetup.spreadsheet;
    SpreadSheetStubLibrary.load = stubSetup.load;

    myObj = new MyClassToTest(config);
    conversationData = {};
};

function createSpreadsheetStubObj(){
    return {
        receive: sinon.stub(),
        add: sinon.stub(),
        send: sinon.stub()
    }
}

function stubSpreadsheetLoadFunction(){
    const spreadsheet = createSpreadsheetStubObj();

    return { 
        load: (settings, cb) => cb(null, spreadsheet),
        spreadSheetStubObj: spreadsheet
    };
}


it('should add a row to the spreadsheet on successful load', () => {
    // Arrange
    setupStubs();
    const rowData = { foo: 1, bar: 2};
    spreadsheet.receive.yields(); // calls any callback given
    myObj.getSpreadsheetRowData = () => rowData; // see lines below

    // if you want to use the real getSpreadsheetRowData, uncomment these lines
    //const rows = []; // not used in the method?
    //const info = { totalRows : 100 };
    //spreadsheet.receive.yields(null, rows, info);

    // Act
    return myObj.saveDataToGoogleSpreadSheet(conversationData).then(()=>{
        // Assert
        assert(spreadsheet.add.calledOnce);
        assert(spreadsheet.add.calledWith(rowData));
    });
});


it('should add a row to the spreadsheet on successful load', () => {
    // reuse the above
});

See the Sinon docs for the stub API.

Disclosure: I am part of the Sinon maintainer team.

oligofren
  • 20,744
  • 16
  • 93
  • 180
  • I have tried to keep it full of information, give all relevant information here (not in the links), and I answer the question. – oligofren Jun 14 '17 at 11:29