1

I'm having an issue with using IT block inside a loop. The loop basically comes from the returned Promise, an exceljs module that reads data from an excel file.

Here' is the promise function.

var excelJs = require('exceljs');
var Excel = browser.params.Excel;

this.createProfile = function() {
        var arr = [];
        return new Promise(function(fulfill, reject){
        var workbook = new excelJs.Workbook();

        workbook.xlsx.readFile(Excel.filePath).then(function(){    
            worksheet = workbook.getWorksheet(1);
            worksheet.eachRow({includeEmpty: true}, function(row, rowNumber)
                try {
                    if (rowNumber != 1) {
                        arr.push(row.values);
                        fulfill(arr);
                    }
                } catch(ex){reject(ex);}
              }, reject);
            });
        });
};

And here is how I did to call inside a spec file.

describe('Bulk Purchase', function(){

        var cp = createProfile();
        cp.then(function(data){
            for (var i in data){
                it('Automate School Supplies Purchase', function(done){
                    console.log('Ballpen: ' + data[i][1]);
                    console.log('Notebook: ' + data[i][2]); //etc
                    done();
                });
            }
        })
    });

The spec will display the expected values if I removed the IT block from the code. Can somebody enlighten me on why would a simple IT block inside a promise would not work? Any help will be appreciated thank you :)

I have a workaround on this, if I converted the Excel to JSON, and require the json file and do the forEach, then I can easily do the data-driven automated test. But I would prefer not to move from other source file to fulfill my original approach.

// where I used xlsx-to-json npm to convert my excel to json
var jsonData = require('path to converted excel to json file');

jsonData.forEach(function(data){
   it('Automate School Supplies Purchase', function(){
      console.log(data.Ballpen);
      console.log(data.Notebook); //etc
   })
});
batuzai04123
  • 379
  • 5
  • 12

3 Answers3

0

All describe and it statements need to be synchronous. Mocha/Jasmine reads their information on script start. All your async stuff has to be inside the cb functions of it/beforeEach/afterEach etc.

You cannot create test cases based on async data. The only solution is having one big it-statement for all cases:

describe('Bulk Purchase', function() {
  it('Automate School Supplies Purchase', function(done) {
    var cp = createProfile();
    cp.then(function(data) {
      for (var i in data) {
        console.log('Ballpen: ' + data[i][1]);
        console.log('Notebook: ' + data[i][2]); //etc
      };
      done();
    });
  });
});
Johannes Merz
  • 3,252
  • 17
  • 33
  • Thank you for pointing it out. However, my goal is to do the data driven test where I iterate over the 'IT' block. – batuzai04123 Oct 21 '16 at 17:56
  • Doing my async function under a single block of 'IT' won't display my expected multiple results based from set of data retrieved from an excel source. That's why I'm trying to iterate the block inside of it. – batuzai04123 Oct 21 '16 at 18:03
  • well, the only other way is receiving the data synchronous (or at least the test cases) as you pretty much did already in your workaround – Johannes Merz Oct 21 '16 at 20:14
0

You can do data driven testing without any for loops using "jasmine-data-provider".

Data-Driven Testing in Protractor

Community
  • 1
  • 1
Vishal Aggarwal
  • 1,929
  • 1
  • 13
  • 23
-1

Found the best one, Node.js async to sync

deasync package has the solution for me. Update: for those who want how I did it with deasync.

/*** My function ***/
this.createProfile = function() {

    var arr = []; 
    // pseudo code goes here cont..
    arr.push = row.values

    // Deasync goes here
    while(arr === "undefined") {
      require('deasync').runLoopOnce();
    }
    return arr;
};

Now to use it in my spec test. It did what I'm expecting to do.

 describe('Bulk Purchase', function(){

    var cp = createProfile(); // cp value is now a SYNC one
    cp.forEach(function(data, index){
       for (var i in data) {
         it('School Supplies purchase', function(done){
            console.log('Ballpen: ' + data[i][0];
            console.log('Books: ' + data[i][1];
         })
       }

    })
});
Community
  • 1
  • 1
batuzai04123
  • 379
  • 5
  • 12
  • I can now return my data from an ASYNC function. – batuzai04123 Jan 07 '17 at 06:18
  • While this link may answer the question, it is better to include the essential parts of the answer here and provide the link for reference. Link-only answers can become invalid if the linked page changes. - [From Review](/review/low-quality-posts/14811213) – Gurwinder Singh Jan 07 '17 at 07:23
  • Updated my answer, apologies for not including my own solution. – batuzai04123 Jan 20 '17 at 14:25