简体   繁体   中英

Nested for loops in Node.js alongside Mocha test framework

I'm at a point in a test where I require a nested for loop, but I'm getting lost with the whole Async side of things. Basically what's happening now is I want to iterate through an array, and use values one by one and log the output. What's happening currently is that the only output being logged is that of the last values I want to use. It's hard to explain so I'll demo my code.

// For the sake of it, all these values are strings
var arr1 = [ [1, 2, 3, 4], [2, 3, 4, 1], [3, 4, 2, 1], [4, 1, 2, 3] ];
var arr2 = [ [a, b, c, d], [b, c, d, a], [c, d, a, b], [d, a, b, c] ];

for(var i = 0; i < arr1.length; i++){
    describe("Test", function(){
        it("Does something", function(done){
            for(var x = 0; x < arr2.length; x++){
                it("Does something else", function(done){
                    // Do stuff with arr1[i], arr2[x] etc.
                    testFunc(arr1[i], arr2[x], function(returnValue){
                        assert.strictEqual(returnValue, true, "Passed!");
                        done();
                    }
                });
            }
        });
    });
}

Now, I'm unable to fill in what the code actually does (privacy reasons), but if someone could point me to a way I can make this work (meaning the loop waits on the callback from testFunc() every time).

If we say that testFunc() is as follows:

function testFunc(arr1var, arr2var, callback){
    console.log(arr1var + " and " + arr2var); 
}

When I run it, all I see is the final values passed to the console ('3 and c').

I've been looking around for this but because peoples examples are so specific to their code, it's confusing to try and adapt. I looked at the Node.js Async module but didn't get very far either.

If someone could either talk me through it all step-by-step, or rewrite the above to work the way I want, I'd appreciate it.

Also, in my actual code, my arrays are different sizes at the top - in case that causes a difference.

Since a couple of people have pointed it out, I'll just add that I'm entirely open to suggestions if anyone has a better method. I'll be running ~40 tests, and this cuts it down to 10-15 lines of code as opposed to 200 calling each one individually, so whatever people think is best, feel free to advise me.

I don't see any code smell in your example. You just need to use async.each instead of your for loops. Also, I don't see why you need two it statements. I would instead do something like:

var async = require('async');
var expect = require('expect.js');
var _ = require('lodash');
var arr1 = [ [1, 2, 3, 4], [2, 3, 4, 1], [3, 4, 2, 1], [4, 1, 2, 3] ];
var arr2 = [ [1, 2, 3, 4], [2, 3, 4, 1], [3, 4, 2, 1], [4, 2, 2, 3] ];

describe('Array tests', function() {
  async.each(arr1, function(arr1Element, callback) {
    async.each(arr2, function(arr2Element, callback2) {
      it('Tests array elements', function(done) {
        expect(_.difference(arr1Element, arr2Element)).to.be.empty();
        done();
      });
      callback2();
    });
    callback();
  });
});

The problem is that the first async test check that gets executed will call done() and tell mocha that the entire test has completed. You need to the done() call with code that counts how many of the tests have completed, and then calls done after the last completes.

for(var i = 0; i < arr1.length; i++){
    describe("Test", function(){
        it("Does something", function(done){
            var remaining = arr2.length;
            for(var x = 0; x < arr2.length; x++){
                it("Does something else", function(done){
                    // Do stuff with arr1[i], arr2[x] etc.
                    testFunc(arr1[i], arr2[x], function(returnValue){
                        assert.strictEqual(returnValue, true, "Passed!");
                        remaining--;
                        if (remaining === 0) {
                            done();
                        }
                    }
                });
            }
        });
    });
}

That said, I don't know if mocha supports multiple simultaneous it() calls. You may need to move both of your loops inside the it().

It does seem odd to me that you have the for loops at different points and not next to each other, but that may just be a result of what you're testing.

Even better would be to switch to using promises instead of async callbacks, since promises can be easily aggregated, ie, it's easy to call a function when all promises in a set have completed.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM