How to make Grunt wait for a task to finish before running another?

Here's my Gruntfile and the output.

As you can see in the output, there are a couple of issues related to asynchronous tasks:

  1. imagemin is called and the next one comes straight ahead. This makes its output appear in the end of the tasks, what's quite messy;
  2. build, which is a custom task, is using var done = this.async() and calling done() after finishing the command; however, this only works correctly if I run the task alone; running it with another tasks makes it run async too;
  3. With build running later, jasmine has nothing to test and thus is useless.

Is there a way to fix this behavior?

I believe your problem is with this task:

grunt.registerTask('prepare-dist', 'Creates folders needed for distribution', function() {
            var folders = ['dist/css/images', 'dist/imgs/icons'];
            for (var i in folders) {
                    var done = this.async();
                    grunt.util.spawn({ cmd: 'mkdir', args: ['-p', folders[i]] }, function(e, result) {
                            grunt.log.writeln('Folder created');
                            done();
                    });
            }
    });

If you have multiple folders, both async() and done() will be called multiple times. Async is implemented as a simple flag (true/false) and is meant to be called once. The first done() call allows any follow on tasks to run.

There are many ways to move the calls to async and done out of the loop. A quick google search on something like: nodejs how to callback when a series of async tasks are complete will give you some additional options. A couple of quick (& dirty) examples:

// Using a stack
(function() {
    var work = ['1','2','3','4','5']


    function loop(job) {
        // Do some work here
        setTimeout(function() {
            console.log("work done");

            work.length ? loop(work.shift()) : done();
        }, 500);
    }

    loop(work.shift());

    function done() {
        console.log('all done');
    }
})();

-- or --

// Using a counter (in an object reference)
(function() {
    var counter = { num: 5 }

    function loop() {
        // Do some work here
        setTimeout(function() {
            --counter.num;

            console.log("work done");

            counter.num ? loop() : done();
        }, 500);
    }

    loop();

    function done() {
        console.log('all done');
    }
})();