Jasmine 2.0 async done() and angular-mocks inject() in same test it()

20,979

Solution 1

This should work; I ran into the same problem when I updated to Jasmine 2.0

it("should send get request", function(done) {
    inject(function(someServices) {
        //some async test
        done();
    })(); // function returned by 'inject' has to be invoked
});

Solution 2

An IMPORTANT note is the brackets after the inject call. Eg.

inject(function(someServices) {
   //some async test
   done();
})();  <-- these brackets here important.

If you look at the type of inject:

export declare function inject(tokens: any[], fn: Function): () => any;

You can see it returns a function, so you were getting no output because you forgot to call the function!!

If you think about it, it makes sense that it returns a function, because it takes a function!

So the extra parentheses should solve all problem!

Working Example:

  it('should allow you to observe for changes', function(done) {
    inject([GlobalStateService], (globalStateService: GlobalStateService) => {
      globalStateService.observe("user", storageType.InMemoryStorage, (user: string) => {
        expect(user).toBe("bla");
        done();
      });

      globalStateService.write({ user: "bla"}, storageType.InMemoryStorage);
    })();
  });

Solution 3

To add to the answer of @Scott Boring and to the comment of @WhiteAngel who mentionned that the code inside inject was never called.

This worked for me:

it("should send get request", function(done) {
    inject(function(someServices) {
       //some async test
       done();
    })();
});

Solution 4

You could write the test like that:

describe("Some service'", function () {    
    var service;
    var data;

    beforeEach(function (done) {   

        module('app');

        inject(function (someService) {
            service = someService;
        });

        service
            .getData()
            .then(function(result) {
                data = result;
                done();
            });
    }); 

    it('should return a result', function () {  
        expect(data).toBeDefined();
    }); 
}

Solution 5

For Angular 5.2.0: @scott-boring's approach did not work for me. What did work is using the TestBed.get() to get the services instead of inject(), as described in the docs:

describe('TooltipComponent', () => {
  let component: TooltipComponent;
  let fixture: ComponentFixture<TooltipComponent>;
  let myService: MyService;

  beforeEach(async(() => {
    const myServiceSpy = jasmine.createSpyObj('MyService', ['calc']);

    TestBed.configureTestingModule({
      declarations: [ MyComponent ],
      providers: [
        {provide: MyService, useValue: myServiceSpy}
      ]
    })
    .compileComponents();

    myService = TestBed.get(MyService);
  }));

  beforeEach(() => {
    fixture = TestBed.createComponent(MyComponent);
    component = fixture.componentInstance;
    fixture.detectChanges();
  });

  it('should render correctly', (done) => {
    component.render();

    setTimeout(() => {
      expect(myService.calc).toHaveBeenCalled();
      done();
    }, 1000);
  });
Share:
20,979
huston007
Author by

huston007

Updated on July 05, 2022

Comments

  • huston007
    huston007 almost 2 years

    My usual test case looks like

    it("should send get request", inject(function(someServices) {
         //some test
    }));
    

    And Jasmine 2.0 async test should look like

    it("should send get request", function(done) {
         someAsync.then(function(){
             done();
         });
    });
    

    How can I use both done and inject in one test?

  • WhiteAngel
    WhiteAngel about 8 years
    For me this doesn't work. The code inside inject is never being called at all.
  • lastoneisbearfood
    lastoneisbearfood almost 8 years
    @WhiteAngel, the last time I had the problem you described, it was because some of the required dependencies for my app was missing from karma.conf.js's files list. It was impossible to debug this with phantomJS because it gives nowhere near enough error messages. If you haven't figured out the source of your problem, try using Chrome or FF as your test browser.
  • Fabio says Reinstate Monica
    Fabio says Reinstate Monica over 7 years
    I think this is ok as an answer. In any case it would be too long for a comment.
  • dokkaebi
    dokkaebi over 7 years
    Makes sense. The normal usage of inject is to pass its return value (() => any) in as the second argument to it, where it is called by jasmine. So we have to call the function returned by inject if we want it to run!
  • dokkaebi
    dokkaebi over 7 years
    This didn't work for me. The return value of inject is a function, and needs to be called.
  • Mirko
    Mirko over 6 years
    I get inject is not a function with this
  • RMorrisey
    RMorrisey almost 6 years
    @WhiteAngel @dokkaebi In the code sample given, the method returned from inject is immediately invoked. This is super important! If you forget those two parens at the end, your test code will not be executed.