Getting TypeError: Cannot stub non-existent own property when stubbing async method
Asked Answered
C

2

6

I am trying to write unit tests for our small but soon to grow library of testcafe business functions - i.e. thos libraries which use the page files, to test any of the non-simple logic.

To this end I am trying to write my first unit test for this function entityTabs - which is an imported async module, ui is an imported non async module, accountAssignmentControls is a pagefile. Those functions mentioned by this. are defined further up in the module. t is a testcafe import.

Initially I want to stub out all the functions and test that statAccountAssignments is called once (After that I will be testing for various combinations of the data which is passed in, but I can't get beyond the first hurdle).

I UNIT tested our non Async headless test library, but

  • a) that was non-async and
  • b) it was older node, so some of the structures and so on are different.

One of the developers added some units tests using chair, mocha and sinon - but these were for non async portions of the project (file handling mostly) so I can't get what he wrote to apply.

FUT

     async assignAccounts(assignments) {
        await entityTabs.startAccountAssignment();
        ui.logWithTimeStamp('WAiting for Account assignment dialog to appear', 2);
            await t
              .expect(accountAssignmentControls.accountAssignmentHeader.innerText)
              .contains('Account Assignment', 'Header contains Account Assignment');
            ui.logWithTimeStamp('Header visible waiting for accounts list', 2);
            await this.checkAccountList();
        
            const assignmentsCount = assignments.length;
            ui.logWithTimeStamp('Doing ' + assignmentsCount + ' assignments: ', 1);
            for (let i=0; i<assignmentsCount; i++) {
              ui.logWithTimeStamp(i + ': ' + JSON.stringify(assignments[i]), 1);
              if (assignments[i].type === 'credit') {
                await this.assignCreditAccount(assignments[i]);
              } else if (assignments[i].type === 'debit') {
                await this.assignDebitAccount(assignments[i]);
              } else {
                await this.assignFullAccount(assignments[i]);
              }
              ui.logWithTimeStamp('Assignment done', 3);
              await t.takeScreenshot();
            };
          }

current failing test

    import chai from 'chai';
    import sinon from 'sinon';
    import sinonChai from 'sinon-chai';
    
    import AccountAssignment from '../../business-functions/account-assignment';
    
    let accountAssignmentControls;
    // let busyLoader;
    let entityTabs;
    let ui;
    let t;
    // Register the sinon-chai extensions.
    chai.use(sinonChai);
    const expect = chai.expect;
    
    // We must turn off the no-invalid-this rule because of how mocha uses this to be the current test fixture.
    /* eslint no-invalid-this: "off" */
    
    describe('business-functions - Account assignment', function() {
      describe('AccountAssignment class', function() {
        describe('assignAccounts', function() {
          let sandbox;
    
          before(() => {
            sandbox = sinon.sandbox.create();
          });
    
          after(() => {
            sandbox.restore();
          });
    
          describe('when one of each assignment', function() {
            it('starts assignment', async function() {
              const fakeResponse = 'dont care';
    
              const accountAssignment = new AccountAssignment();
              t = sinon.stub();
              entityTabs = sinon.stub();
              ui = sinon.stub();
              ui.logWithTimeStamp = sinon.stub();
              accountAssignmentControls = sinon.stub();
            //  let f = sinon.fake();
              let startAccountAssignment = sandbox
                .stub(entityTabs, 'startAccountAssignment')
                .resolves(fakeResponse);
             // sandbox.stub(t, 'expect');
              sandbox
                .stub(accountAssignment, 'checkAccountList')
                .resolves(fakeResponse);
              sandbox
                .stub(accountAssignment, 'assignCreditAccount')
                .resolves(fakeResponse);
              sandbox
                .stub(accountAssignment, 'assignDebitAccount')
                .resolves(fakeResponse);
              sandbox
                .stub(accountAssignment, 'assignFullAccount')
                .resolves(fakeResponse);
              sandbox
                .stub(accountAssignmentControls, 'accountAssignmentHeader')
                .resolves(fakeResponse);
    
              sandbox
                .stub(t, 'expect')
                .resolves(fakeResponse);
              sandbox
                .stub(t, 'contains')
                  .resolves(fakeResponse);
              sandbox
                .stub(t, 'takeScreenshot')
                  .resolves(fakeResponse);
    
              await accountAssignment.assignAccounts({});
              expect(startAccountAssignment).to.be.callledOnce;
            });
          });
        });
      });
    });

which when run gets

TypeError: Cannot stub non-existent own property startAccountAssignment at Sandbox.stub (node_modules\sinon\lib\sinon\sandbox.js:286:19) at Context._callee$ (C:/Projects/Platform/PlatformTesting/UITests-NotProtractor/unit-tests/business-functions/account-assignment.tests.js:49:14) at tryCatch (node_modules\regenerator-runtime\runtime.js:65:40) at Generator.invoke [as _invoke] (node_modules\regenerator-runtime\runtime.js:303:22) at Generator.prototype.(anonymous function) [as next] (node_modules\regenerator-runtime\runtime.js:117:21) at step (unit-tests\business-functions\account-assignment.tests.js:21:191) at C:\Projects\Platform\PlatformTesting\UITests-NotProtractor\unit-tests\business-functions\account-assignment.tests.js:21:437 at new Promise () at Context. (unit-tests\business-functions\account-assignment.tests.js:21:99)

Candis answered 3/7, 2018 at 16:43 Comment(0)
N
13

Use prototype keyword for stubbing out the instance method, i.e. sandbox.stub(deviceRegistryRepository.prototype, "getByName").resolve();

For static methods, no need to use the prototype keyword, i.e. sandbox.stub(myStaticClass.prototype, "getMyStaticMethod").resolve();

Nial answered 21/1, 2020 at 10:54 Comment(0)
P
4

You are not stubbing out entityTabs correctly, and the module you are testing is not using your stub.

To be more specific: you've declared a local var let entityTabs; and then later assigned that var, entityTabs = sinon.stub();. And finally you are attempting to stub out a method startAccountAssignment() on that object, but it has no such property because it's not the actual entityTabs module/object, and based on the code snippets you've included, it is not the one that the module you're testing will even use.

Depending on how the entityTabs object is written (is it in it's own module? is that a singleton? is it a class?), you will need to import it, and stub out the method's you wish to mock, or you want to use something like proxyquire to mock out entityTabs.

Palladic answered 3/7, 2018 at 17:4 Comment(1)
entityTabs is a class in its own module and is imported thus in the class that this function is in. import EntityNavigation from '../business-functions/entity-navigation'; const entityTabs = new EntityNavigation();Catchascatchcan

© 2022 - 2024 — McMap. All rights reserved.