admin管理员组

文章数量:1287803

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($pile, $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>');
    $pile(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?

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($pile, $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>');
    $pile(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?

Share Improve this question asked Jul 18, 2015 at 14:59 Adam ZernerAdam Zerner 19.3k17 gold badges101 silver badges172 bronze badges
Add a ment  | 

1 Answer 1

Reset to default 11

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]);
  });
});

本文标签: javascriptIs Jasmine39s beforeEach synchronousStack Overflow