0

Need help for writing test cases for dynamic content in Angular 6 and using Karma packages.

spec.ts:

I wrote test case for checking the views of the article. Before executing the function, it is passing but after getting the data it is not passing. How to write test cases for dynamic content.

describe('SingleArticleVideoComponent', () => {
    let originalTimeout;
  let debugTest: DebugElement[];
  let el: HTMLElement;
  let component: SingleArticleVideoComponent;
  let fixture: ComponentFixture<SingleArticleVideoComponent>;

  beforeEach(async(() => {
    TestBed.configureTestingModule({
      declarations: [ SingleArticleVideoComponent,
          PollsComponent,
          AdBannerComponent],
        imports: [
            RouterTestingModule,
            NavModule,
        FooterModule,
            VgCoreModule,
            VgControlsModule,
            VgOverlayPlayModule,
            VgBufferingModule,
        FormsModule,
        ReactiveFormsModule,
        MatFormFieldModule,
        MatRadioModule,
        MatDialogModule,
            HttpModule,
            HttpClientModule,
            BrowserAnimationsModule,
            BrowserModule
        ],
        providers: [
            ArticleService,
            AdService,
            UserServiceService
        ]
    })
    .compileComponents();
  }));

  beforeEach(() => {
    fixture = TestBed.createComponent(SingleArticleVideoComponent);
    component = fixture.componentInstance;
    fixture.detectChanges();
      originalTimeout = jasmine.DEFAULT_TIMEOUT_INTERVAL;
      jasmine.DEFAULT_TIMEOUT_INTERVAL = 100000;
  });
    afterEach(function() {
        jasmine.DEFAULT_TIMEOUT_INTERVAL = originalTimeout;
        fixture = TestBed.createComponent(SingleArticleVideoComponent);
        component = fixture.componentInstance;
        fixture.detectChanges();
    });
    it('views should be more than 100', async(() => {
        expect(component.anchor).toEqual('before');
        expect(component.anchor).toEqual('after');
    }));
  it('should create', () => {
    expect(component).toBeTruthy();
  });
});

component.ts:

It is giving the correct result when I use ng serve, but it is not working for testing using ng test.

ngOnInit() {
     this.get_single_video('emcure-csi-tv-dr-pk-dep-ACE-inhibitor-or-ARNI-what-should-be-used-in-heart-failure-with-reduced-ejection-fraction', this.category);
}
get_single_video(slug, category) {
    console.log('get one video calling');
    this.anchor ='before';
    this.service.get_single_video(slug, category).subscribe(
      data => {
        if(data['success'])
        {
            this.anchor='after';
          this.load_data = true;
            if(data['data']['guest3'].length > 0 || data['data']['guest4'].length > 0){
                this.gus = true;
            }
        }
});

component.html:

Views is giving null when I console it. Views are displaying normally if I run it using ng serve, but not for ng test.

<li class="views"><code>{{single_article['anchor']}}</code><br>Views</li>

user-service.service.ts:

I can able to see the data.json() in map function, but I unable to get inside the subscribe function in component.ts file as I mentioned above.

import 'rxjs/Rx';
get_single_video(slug, catagory) {
    console.log('in article service single video');
    const final_url = this.api_url + '/' + slug + '?key=' + this.api_key;
    console.log(final_url);
    return this._http.get(final_url)
      .map(data => {
        data.json();
        // the console.log(...) line prevents your code from working
        // either remove it or add the line below (return ...)
        console.log(' I CAN SEE DATA HERE: ', data.json());
        return data.json();
      }).catch(error => observableThrowError(error.json()));
  }

enter image description here

mruanova
  • 6,351
  • 6
  • 37
  • 55

2 Answers2

0

You typically do NOT want your unit tests to make http calls to a backend, but rather mock that functionality. In fact in the component test you even want to mock the functionality of your service (so the component unit test can pass even if the service is messed up). See the accepted answer to the following question for a good explanation of the difference between 'ng test' and 'ng e2e': question.

Assuming you want to do unit testing, and just of the component at this stage, then I would set up a spy to mock your service call and return various values so you can test through the logic of your 'get_single_video' component method. I have set up a STACKBLITZ to demonstrate this using your own code from your question. I set up a minimal amount of code to show what I mean. (MCVE)

One thing to note - I pulled fixture.detectChanges() out of the beforeEach() and put it inside the 'it' function. This is because fixture.detectChanges() invokes ngOnInit(), and the return value from your service call needs to be set up BEFORE ngOnInit() is called so you can control the path through your logic.

From that stackblitz, here is the describe I set up to test two paths. You should be able to extend this to get complete coverage of your function.

describe('SingleArticleVideoComponent', () => {
    let component: SingleArticleVideoComponent;
    let fixture: ComponentFixture<SingleArticleVideoComponent>;
    let userServiceSpy = jasmine.createSpyObj('UserServiceService', ['get_single_video']);

    beforeEach(async(() => {
        TestBed.configureTestingModule({
          declarations: [ SingleArticleVideoComponent],
            providers: [
                { provide: UserServiceService, useValue: userServiceSpy }
            ]
        })
        .compileComponents();
    }));
    beforeEach(() => {
        fixture = TestBed.createComponent(SingleArticleVideoComponent);
        component = fixture.componentInstance;
    });

    it('should change anchor to "after" if get_single_video() has success set', () => {
        userServiceSpy.get_single_video.and.returnValue(of({success: 'yes', data: {guest3: ['1']}}));
        fixture.detectChanges();
        expect(component.anchor).toEqual('after');
    });
    it('should not change anchor if get_single_video() does not have success set', () => {
        userServiceSpy.get_single_video.and.returnValue(of({})); // Observable of an empty object
        fixture.detectChanges();
        expect(component.anchor).toEqual('before');
    });
});
dmcgrandle
  • 5,934
  • 1
  • 19
  • 38
0

You DO NOT test API calls and it's data on a Unit Test. Coming back to the component, taking out the line fixture.detectChanges(); from beforeEach to it will provide you control on data flow. You can add the mocked service,

providers: [{ provide: UserServiceService, useValue: userServiceSpy }]

Make sure you are having get_single_video in userServiceSpy service spy which is returning Observable typed data.

On beforeEach method, initialize the component by passing the mocked service in it. e.g.

videoComponent = new SingleArticleVideoComponent(userServiceSpy)

You can use this videoComponent for your test cases.