简体   繁体   中英

How to bootstrap angular at the start of each karma/jasmine test file?

Is it possible to have angular bootstrap the app at the beginning of each test file? Instead of the current behavior, which has the app bootstrap at the beginning of the series of tests, and then the same instance is used throughout all the test files (we have about 600 tests throughout ~60 files right now)?

We have beforeEach statements to handle clean-up and that doesn't help. In fact, seems sometimes the beforeEach statements are altogether skipped for no apparent reason (possible memory leak with test runner).

So the route I would like to take this is to have each test file bootstrap the angular app, so that the state is completely reset, instead of reusing dependency injection (ie. services) that had state set by a different test.

You don't need to bootstrap the app for the tests. That's why we have angular-mock . With angular.module('app.module') we load the module we need for our test and that module contains the component we want to test. Since angular-mock is not the cause for the memory leaks, there can be several reasons for them. One of the most common reasons for memory leaks is jasmine itself and the way we usually write the tests. The variables we use for the dependencies we inject in our test and are defined on the describe scope and cannot be collected by the GC when the tests finish. This is because there are references of those variables in the it blocks that cannot be garbage collected because the variables still live in some other scope of the tests tree. Another problem can be the compiled elements that should also be cleaned up after each test. So you probably need to clean-up the following things:

  • compiled element when using $compile for testing directives
  • all variables in the describe functions scope

You can do something like this:

 describe('testSuite', function () { var suite = {}; beforeEach(module('app')); beforeEach(inject(function ($rootScope, $compile, heavyLoad) { suite.$rootScope = $rootScope; suite.$compile = $compile; suite.heavyLoad = heavyLoad; suite.$scope = $rootScope.$new(); spyOn(suite.heavyLoad, 'getHeavyString').and.callThrough(); spyOn(suite.heavyLoad, 'getHeavyObject').and.callThrough(); spyOn(suite.heavyLoad, 'getHeavyList').and.callThrough(); })); // NOTE: cleanup afterEach(function () { // NOTE: prevents DOM elements leak suite.element.remove(); }); afterAll(function () { // NOTE: prevents memory leaks because of JavaScript closures created for // jasmine syntax (beforeEach, afterEach, beforeAll, afterAll, it..). suite = null; }); suite.compileDirective = function (template) { suite.element = suite.$compile(template)(suite.$scope); suite.directiveScope = suite.element.isolateScope(); suite.directiveController = suite.element.controller('heavyLoad'); }; it('should compile correctly', function () { // given var givenTemplate = '<div heavy-load></div>'; // when suite.compileDirective(givenTemplate); // then expect(suite.directiveScope.title).toBeDefined(); expect(suite.directiveScope.items).toBeDefined(); expect(suite.heavyLoad.getHeavyString).toHaveBeenCalled(); expect(suite.heavyLoad.getHeavyList).toHaveBeenCalled(); }); }); 

Taken from here .

This should reduce your memory leaks significantly. You should also take a look at your module structure and the dependency graph your modules have, cause you might have some modules that are not needed for some tests but they are loaded anyway. They can be heavy on memory or contain memory leaks in them and can make you additional problems. You can also take a look at this github project .

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