vendredi 12 février 2021

@Select property is undefined during Angular test

I'm trying to do a unit test on a method in my component:

@Component({
  selector: 'app-workspaces',
  templateUrl: './workspaces.component.html',
  styleUrls: ['./workspaces.component.css']
})
export class WorkspacesComponent implements OnInit, AfterViewInit {

  @Input() workspaceList: Observable<WorkSpace[]>;
  @Output() OnWorkSpaceSelected = new EventEmitter<void>();
  @Select(AuthState.getUserData) loadCurrentUser: Observable<User>;
  @Select(WorkSpaceState.getWorkSpaces) workspaces: Observable<WorkSpace[]>;

  selectedWorkspace: WorkSpace;

  constructor(private store: Store, private router: Router, private workspaceController: WorkspacedetailService) { }

  ngOnInit() {
    this.LoadWorkSpaceFromStorage();
  }

  /** Called after ngAfterContentInit when the component's view has been initialized. Applies to components only.
   * Add 'implements AfterViewInit' to the class.
   */
  ngAfterViewInit(): void {
    this.LoadWorkSpaceFromStorage();
  }

  private LoadWorkSpaceFromStorage(): void {
    const storedWorkspace = JSON.parse(localStorage.getItem('SelectedWorkspace'));
    this.NotifyWorkSpaceSelection(storedWorkspace);
  }

  private SaveWorkSpaceIntoStorage(workspace: WorkSpace): void {
    this.selectedWorkspace = workspace;
    this.NotifyWorkSpaceSelection(this.selectedWorkspace);
  }

  private NotifyWorkSpaceSelection(workspace: WorkSpace): void {
    // Ensure that workspace on localStorage has the latest updates
    this.workspaceController.LoadWorkSpace(workspace.id, (data) => {
      localStorage.setItem('SelectedWorkspace', JSON.stringify(data))
      sessionStorage.setItem('SelectedWorkspace', JSON.stringify(data));
      this.selectedWorkspace = data;
      let currentUser = new User();
      this.loadCurrentUser.subscribe(userData => currentUser = userData);
      this.store.dispatch(new SelectWorkSpace(this.selectedWorkspace));
      this.OnWorkSpaceSelected.emit();
    }, () => { });
  }

  OnWorkSpaceSelection(selectedWorkSpace: WorkSpace) {
    this.SaveWorkSpaceIntoStorage(selectedWorkSpace);
    this.NotifyWorkSpaceSelection(selectedWorkSpace);
    // TODO add modal to confirm
    this.router.navigateByUrl('/');
  }
}

In particular, I want to test the "OnWorkSpaceSelection" method, that basically call the "NotifyWorkSpaceSelection" and wait for a response from the controller.

I'm using Jasmine with ngMocks to make it easier. And this is my test now:

describe('Workspace component unit tests', () => {
    let component: WorkspacesComponent;
    let fixture: ComponentFixture<WorkspacesComponent>;
    let helper = new BaseHelper();
    beforeEach(() => {
        TestBed.configureTestingModule({
            // our component for testing
            declarations: [WorkspacesComponent],
            providers: [
                MockProviders(Store, Router, WorkspacedetailService, LoggingService)
            ],
            imports: [MatMenuModule, TranslateModule.forRoot(), NgxsModule.forRoot([AuthState], {
                developmentMode: true,
                selectorOptions: { suppressErrors: true }
            }), HttpClientTestingModule],
        });
    });

    it('OnWorkSpaceSelection should select workspace', () => {
        // arrange
        let workspace = helper.BuildEntities<WorkSpace>(new WorkSpace()) as WorkSpace;
        workspace.id = -1;
        localStorage.setItem('SelectedWorkspace', JSON.stringify(workspace));
        MockInstance(WorkspacedetailService, () => ({
            // comment the next line to check the failure.
            LoadWorkSpace: (workSpaceID: number, successCallback: any, errorCallback: any) => {
                if (workSpaceID >= 0) {
                    const workspace = helper.BuildEntities<WorkSpace>(new WorkSpace()) as WorkSpace;
                    successCallback(workspace);
                }
                else {
                    errorCallback();
                }
            }
        }));
        fixture = MockRender(WorkspacesComponent); // Rend service
        component = fixture.componentInstance; // Take service istance
        Object.defineProperty(component, 'loadCurrentUser', { writable: true });
        component.loadCurrentUser = of(new User());
        fixture.detectChanges();

        // act
        workspace.id = 0;
        component.OnWorkSpaceSelection(workspace); // Call the method that we want to test

        // assert
        expect(component.selectedWorkspace).toBeTruthy();
    });
});

The problem that I have now, is that I get "TypeError: Cannot read property 'subscribe' of undefined" from the run because the "loadCurrentUser" property, inside "NotifyWorkSpaceSelection" method is undefined.

undefined

As you can see, I tried to re-initialize it after the build of the component, but I get the same result. Could you suggest me something to solve this issue?

Thank you very much in advance :)

Aucun commentaire:

Enregistrer un commentaire