2

I want to spyOn a promise and fake that promise in my unit test but the problem is that if I run first the contructor that the problem that he first run the promise and then run the Spyon.

But when i first run the spyOn and then the constructor it gives a error that storage is undefined.

Does someone know how to fix this?

Spec file:

   describe('Settings Service', () => {

    beforeEach(() => {
        settingsService = new SettingsService(); // This gives a error beceause it runs the promise 
        spyOn(settingsService.storage, 'get').and.callFake((key: String): Promise<string> => {
            return new Promise((resolve, reject) => { resolve('url'); });
        });
    });

constructor:

constructor() {
        this.storage = new Storage(LocalStorage);
        this.storage.get('url').then(data => {
            this.setLink(data);
        });
    }

UPDATE:

I tried also this:

let injector: any = ReflectiveInjector.resolveAndCreate([SettingsService]);
    settingsService = injector.get(SettingsService);

    spyOn(settingsService.storage, 'get').and.callFake((key: String): Promise<string> => {
        return new Promise((resolve, reject) => { resolve('https://secure.info/pascal'); });
    });
Martijn Bakker
  • 395
  • 1
  • 5
  • 15

1 Answers1

1

The problem you have is that you are instantiating Storage within the constructor, so you have no access to it from the outside. That means that you cannot mock it.

Setting spyOn before calling settingsService = new SettingsService(); doesn't work either because the field storage has not been created yet.

You have two ways to solve this:

Mocking the service $httpBackend using the following code. Take a look at this post as an example

beforeEach(inject(function($injector) {
    service = $injector.get('carService');
    $httpBackend = $injector.get('$httpBackend');

    $httpBackend.when('GET', "/api/cars/types").respond(["Toyota", "Honda", "Tesla"]);
}));

This way you can mock the promise you get when calling this.storage.get('url') and test the behaviour.

Making Storage a service and injecting it mocked: If you use this approach you could moke Storage and therefore mock the behaviour of this.storage.get('url'). The code of your class `` would look like this

static $inject = ['Storage'];
constructor(storage: Storage) {
    this.storage = storage;
    this.storage.get('url').then(data => {
        this.setLink(data);
    });
}

But this way depends on how do you define and use Storage so generally the first way will be better

Community
  • 1
  • 1
iberbeu
  • 15,295
  • 5
  • 27
  • 48