Is Jasmine's beforeEach synchronous?

大城市里の小女人 提交于 2019-12-06 05:50:48

问题


If you have multiple beforeEach's, will they always run one after another?

beforeEach(function() {});
beforeEach(function() {});
beforeEach(function() {});
beforeEach(function() {});
beforeEach(function() {});

It seems that they will. I tried testing it with my code:

describe('Directive: Statement', function() {
  var el, scope, statements;

  beforeEach(module('simulatedSelves'));
  beforeEach(module('templates'));
  beforeEach(inject(function($compile, $rootScope) {
    console.log(1);
    scope = $rootScope.$new();

    statements = [];
    scope.statement = {
      text: 'test',
      arr: []
    };
    scope.statement.parent = statements;
    statements.push(scope.statement);

    el = angular.element('<statement statement=statement></statement>');
    $compile(el)(scope);
    scope.$digest();
  }));
  beforeEach(function() {
    var counter = 0;
    console.log(2);
    for (var i = 0; i < 1000000; i++) {
      counter++;
    }
    console.log(counter);
  });
  beforeEach(function() {
    console.log(3);
  });

  it('test statement has correct properties', function() {
    // stuff
  });
});

It logs:

1
2
1000000
3

Since the beforeEach with the long for loop logs its stuff out before the one that logs 3, I'm thinking that the beforeEach's run synchronously. Is that true?


回答1:


Yes, all beforeEachs will execute in the order you define.

If you drill into Jasmine, you eventually get to this definition:

Suite.prototype.beforeEach = function(fn) {
  this.beforeFns.unshift(fn);
};

As you add describes, Suites get generated and nested. Each Suite is initialized with this.beforeFns = [], which is added to as you can see. Note that unshift adds to the left side of the array, so you'd expect later-defined beforeEachs to be run first. That's fixed later when Jasmine walks up the child suite's parents, gathers all beforeEach lists, and then reverses them to run in the order you want.

var beforeAndAfterFns = function(suite) {
  return function() {
    var befores = [],
      afters = [];

    while(suite) {
      befores = befores.concat(suite.beforeFns);
      afters = afters.concat(suite.afterFns);

      suite = suite.parentSuite;
    }

    return {
      befores: befores.reverse(),
      afters: afters
    };
  };
};

As Dan points out, we've so far assumed that all of your beforeEachs are synchronous. As of Jasmine 2, you can set up asynchronous beforeEachs like so:

beforeEach(function(done) {
  setTimeout(function() {
    console.log('Async');
    done();
  }, 1000)
});

At runtime, Jasmine sends you the done function and executes asynchronously if your function takes an argument. (Function.length returns the number of arguments the function expects).

for(iterativeIndex = recursiveIndex; iterativeIndex < length; iterativeIndex++) {
  var queueableFn = queueableFns[iterativeIndex];
  if (queueableFn.fn.length > 0) {
    attemptAsync(queueableFn);
    return;
  } else {
    attemptSync(queueableFn);
  }
}

attemptAsync waits for you to call done() before the QueueRunner moves on to the next beforeEach hook, so ordering still works! Pretty neat.

describe('beforeEach', function() {
  var data = null;

  beforeEach(function() { data = []; });
  beforeEach(function() { data.push(1); });
  beforeEach(function(done) {
    setTimeout(function() {
      data.push('Async');
      done();
    }, 1000);
  });
  beforeEach(function() { data.push(2); });
  beforeEach(function() { data.push(3); });

  it('runs in order', function(){
    expect(data).toEqual([1, 'Async', 2, 3]);
  });
});


来源:https://stackoverflow.com/questions/31492452/is-jasmines-beforeeach-synchronous

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!