Collectives™ on Stack Overflow

Find centralized, trusted content and collaborate around the technologies you use most.

Learn more about Collectives

Teams

Q&A for work

Connect and share knowledge within a single location that is structured and easy to search.

Learn more about Teams

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.

         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)

    Not related to this but for information - use prototype keyword for stubbing out the instance method i-e sandbox.stub(deviceRegistryRepository.prototype, "getByName").resolve(); and for static method no need to use the prototype keyword i-e sandbox.stub(myStaticClass.prototype, "getMyStaticMethod").resolve();

    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.

    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(); – Zoë Jobson Jul 4, 2018 at 8:13

    Thanks for contributing an answer to Stack Overflow!

    • Please be sure to answer the question. Provide details and share your research!

    But avoid

    • Asking for help, clarification, or responding to other answers.
    • Making statements based on opinion; back them up with references or personal experience.

    To learn more, see our tips on writing great answers.