title: angular 2 test a component with forkJoin
body: <p>I have a <strong>LogComponent</strong> in my application. Inside <strong>ngOnInit</strong> I retrieve logs from a server via <strong>LogService</strong> and display them in a grid.</p>
  
  <p>Here are 2 ways of how to do it:</p>
  
  <p>The 1st:</p>
  
  <pre><code>import { Component, OnInit } from '@angular/core';
  import { Router } from '@angular/router';
  import { Observable } from 'rxjs/Observable';
  
  import { Log } from './log';
  import { LogService } from './log.service';
  import * as globals from '../../globals';
  import { DataTransformService, HttpHandlerService, StateManagerService } from '../../shared';
  
  @Component({
    selector: 'app-log',
    templateUrl: 'log.component.html',
    styleUrls: ['log.component.css'],
    providers: [ DataTransformService, HttpHandlerService, LogService, StateManagerService]
  })
  export class LogComponent implements OnInit {
  
    localGlobals: any = globals;
  
    logs: Log[];
  
    currentPage: number;
    totalRecords: number = 0;
    firstRowIndex: number = 0;
  
    constructor(
      private stateManagerService: StateManagerService,
      private httpHandlerService: HttpHandlerService,
      private logService: LogService,
      private dataTransformService: DataTransformService,
      private router: Router
    ) {}
  
    ngOnInit() {
  
      //get page number from local storage
      this.currentPage = this.stateManagerService.getParamFromState(this.router.url, 'page');
      this.firstRowIndex = this.currentPage * this.localGlobals.ROWS_PER_PAGE - this.localGlobals.ROWS_PER_PAGE;
  
      //get total count 
      let respHandler = (res: any) =&gt; {
        this.totalRecords = res.headers.get('X-Pagination-Total-Count');
        return this.httpHandlerService.extractData(res);
      };
  
      this.logService.search(this.currentPage, respHandler).subscribe(
        logs =&gt; {
          this.logs = logs;
        },
        err =&gt; console.error(err) 
      );
  
    }
  
  }
  </code></pre>
  
  <p>The 1st approach uses this function to retrieve logs:</p>
  
  <pre><code>this.logService.search(this.currentPage, respHandler).subscribe(
    logs =&gt; {
      this.logs = logs;
    },
    err =&gt; console.error(err) 
  );
  </code></pre>
  
  <p>The 2nd way to retrieve logs is via <strong>Observable.forkJoin</strong>:</p>
  
  <pre><code>import { Component, OnInit } from '@angular/core';
  import { Router } from '@angular/router';
  import { Observable } from 'rxjs/Observable';
  
  import { Log } from './log';
  import { LogService } from './log.service';
  import * as globals from '../../globals';
  import { DataTransformService, HttpHandlerService, StateManagerService } from '../../shared';
  
  @Component({
    selector: 'app-log',
    templateUrl: 'log.component.html',
    styleUrls: ['log.component.css'],
    providers: [ DataTransformService, HttpHandlerService, LogService, StateManagerService]
  })
  export class LogComponent implements OnInit {
  
    localGlobals: any = globals;
  
    logs: Log[];
  
    currentPage: number;
    totalRecords: number = 0;
    firstRowIndex: number = 0;
  
    constructor(
      private stateManagerService: StateManagerService,
      private httpHandlerService: HttpHandlerService,
      private logService: LogService,
      private dataTransformService: DataTransformService,
      private router: Router
    ) {}
  
    ngOnInit() {
  
      //get page number from local storage
      this.currentPage = this.stateManagerService.getParamFromState(this.router.url, 'page');
      this.firstRowIndex = this.currentPage * this.localGlobals.ROWS_PER_PAGE - this.localGlobals.ROWS_PER_PAGE;
  
      //get total count 
      let respHandler = (res: any) =&gt; {
        this.totalRecords = res.headers.get('X-Pagination-Total-Count');
        return this.httpHandlerService.extractData(res);
      };
  
      Observable.forkJoin(
          this.logService.search(this.currentPage, respHandler)
      ).subscribe(
        data =&gt; {
          this.logs = data[0];
        },
        err =&gt; console.error(err) 
      );
  
    } 
  
  }
  </code></pre>
  
  <p>The 2nd approach uses this function to retrieve logs:</p>
  
  <pre><code>Observable.forkJoin(
          this.logService.search(this.currentPage, respHandler)
      ).subscribe(
        data =&gt; {
          this.logs = data[0];
        },
        err =&gt; console.error(err) 
      );
  </code></pre>
  
  <p>I have a test for this component that checks that properties are initialized after init:</p>
  
  <pre><code>import { DebugElement, NO_ERRORS_SCHEMA }    from '@angular/core';
  import { async, ComponentFixture, TestBed } from '@angular/core/testing';
  import { FormsModule } from '@angular/forms';
  import { By } from '@angular/platform-browser';
  import { Router } from '@angular/router';
  import { ReplaySubject } from 'rxjs/Rx';
  
  import { Log } from './log';
  import { LogComponent } from './log.component';
  import { LogService } from './log.service';
  import { DataTransformService, HttpHandlerService, LocalStorageService, StateManagerService } from '../../shared';
  
  let comp:    LogComponent;
  let fixture: ComponentFixture&lt;LogComponent&gt;;
  let de:      DebugElement;
  
  describe('LogComponent', () =&gt; {
  
    // async compile html and css
    beforeEach(async(() =&gt; {
  
      let project = new ReplaySubject(1);
      let logServiceStub = {
          search: (pageNum: number, respHandler: any) =&gt; {
              let logs = [
                  { id: 1, ip: '127.0.0.1', user_id: 1, notification_event_id: 1, created_at: 1 },
                  { id: 2, ip: '127.0.0.2', user_id: 2, notification_event_id: 2, created_at: 2 }
              ];
              project.next(logs);
              return project;
          }
      };
  
      let routerStub = {
          url: 'log_url'
      };
  
      TestBed.configureTestingModule({
          declarations: [ LogComponent ],
          imports: [ FormsModule ],
          providers: [
              DataTransformService,
              HttpHandlerService,
              LocalStorageService,
              { provide: Router, useValue: routerStub },
              StateManagerService
          ],
          schemas: [ NO_ERRORS_SCHEMA ]
      })
      .overrideComponent(LogComponent, {
        set: {
          providers: [
            { provide: LogService, useValue: logServiceStub }
          ]
        }
      })
      .compileComponents();
  
    }));
  
    // synchronous 
    beforeEach(() =&gt; {
  
      fixture = TestBed.createComponent(LogComponent);
  
      // LogComponent test instance
      comp = fixture.componentInstance;
  
      de = fixture.debugElement;
  
    });
  
    it('initial variables are set after init', () =&gt; {
  
        fixture.detectChanges(); 
  
        console.log(comp.logs);
  
        //TODO: test not working when requests are in forkJoin
        expect(comp.currentPage).toBe(1);
        expect(comp.firstRowIndex).toBe(0);
        expect(comp.logs).not.toBeUndefined();
        expect(comp.logs.length).toBe(2);
  
    });
  
  });
  </code></pre>
  
  <p><strong>Problem</strong>: when I run test using the 1st approach(<strong>without Observable.forkJoin</strong>) it works fine. <strong>BUT</strong> when I run test using the 2nd approach(<strong>with Observable.forkJoin</strong>) it fails with the error:</p>
  
  <pre>Expected undefined not to be undefined.</pre>
  
  <p>So logs are not initialized after fixture.detectChanges(). It seems like if a request is inside the Observable.forkJoin() then the initialization does not run. I understand that there is only 1 request in Observable.forkJoin() and I can go with the 1st approach but I have other components in the system that uses more than 1 request so I need this problem to be solved.</p>
  
  <p>Hope you got what I mean.</p>
  
  <p>Thanks in advance.</p>