Sourabh Gupta
Sourabh Gupta

Reputation: 191

How to write jasmine unit test case for the function to be called upon onerror of img tag

Below is the code I am using but this test case is getting failed

//test case 
    it('should display default image if the image link in people finder result doesnot exist', fakeAsync(() => {
      debugger
      component.resultsItem = MOCK_RESULTSET.results[9];
      component.resultsItem.imageUrl = "https://domain/gxc3/files/Employee_Images/Test.jpg";
      fixture.detectChanges();
      tick(3000);
      el = fixture.debugElement.queryAll(By.css('.item-person-type'))[0].nativeElement;
      console.log(el);
      let src = el.getAttribute('src');
      expect(src).toBe("assets/img/user-icon.jpg");
    }));

//image tag

 <img class='item-person-type' title="{{resultsItem.text}}"
           [src]="resultsItem.imageUrl ? resultsItem.imageUrl : 'assets/img/user-icon.jpg'"
           (click)="onResultLinkClick(resultsItem)"
           (error)="getImageUrl()" />


//component function

getImageUrl() {
    try {
      var gxcUrl: string = this.resultsItem.imageUrl;
      this.resultsItem.imageUrl = 'assets/img/user-icon.jpg';
      var extensions = this._appSettingsService.appSettings.probableGxcImageExtensions;
      var imageExists = false;
      var probableImageUrls = [];
      extensions.forEach(function (extension) {
        let probableImageUrl = gxcUrl.replace(".jpg", extension);
        probableImageUrls.push(probableImageUrl);
      })
      let observables = probableImageUrls.map(probableImageUrl => this.checkImage(probableImageUrl))
      let source = Observable.forkJoin(observables);
      source.subscribe(response => {
        for (var i = 0; i < response.length; ++i) {
          if (response[i]) {
            imageExists = true;
            this.resultsItem.imageUrl = probableImageUrls[i];
            break;
          }
        }
        if (!imageExists) {
          this.resultsItem.imageUrl = 'assets/img/user-icon.jpg';
        }
      });
    }
    catch (e) {
      this.resultsItem.imageUrl = 'assets/img/user-icon.jpg';
    }
  }

  checkImage(src): Observable<Boolean> {
    return Observable.create((observer: Observer<boolean>) => {
      let img = new Image();
      // img.crossOrigin = 'Anonymous';
      img.src = src;
      if (!img.complete) {
        img.onload = () => {
          observer.next(true);
          observer.complete();
        };
        img.onerror = (err) => {
          observer.next(false);
          observer.complete();
        };
      } else {
        observer.next(true);
        observer.complete();
      }
    });
  };


The getImageUrl methods get called whenever the image is not loaded and it replaces the extension of the current image(.jpg) source and search it again with different extension like .png or .jpeg, if the image is not found with any of the extension then default image is displayed.

Upvotes: 2

Views: 328

Answers (1)

Xesenix
Xesenix

Reputation: 2548

General solution to testing parts of hard to access objects is to move their creation to factories so for example if you have:

class A {
  run() {
    const v = new B(x, y);
    v.doSomeStuff(z, t);
  }
}

you can do something like this:

class A {
  constructor(private bFactory) {}

  run() {
    const v = this.bFactory(x, y);
    v.doSomeStuff(z, t);
  }
}

and then in tests you can inject something like this:

const bMock = { doSomeStuff: jasmine.createSpy('doSomeStuff') }; 
const bFactoryMock = jasmine.createSpy('bFactoryMock').and.return(bMock);
const tested = new A(bFactoryMock);

tested.run():

expect(bFactoryMock).toHaveBeenCalledWith(something, something);
expect(bMock.doSomeStuff).toHaveBeenCalledWith(something, something);

Upvotes: 1

Related Questions