Cloud-CV/EvalAI

View on GitHub
frontend_v2/src/app/components/challenge/challenge.component.spec.ts

Summary

Maintainability
F
5 days
Test Coverage
import { async, ComponentFixture, TestBed } from '@angular/core/testing';
import { HeaderStaticComponent } from '../../components/nav/header-static/header-static.component';
import { ChallengeComponent } from './challenge.component';
import { ApiService } from '../../services/api.service';
import { GlobalService } from '../../services/global.service';
import { ChallengeService } from '../../services/challenge.service';
import { HttpClientModule } from '@angular/common/http';
import { ChallengeoverviewComponent } from '../../components/challenge/challengeoverview/challengeoverview.component';
import { ChallengeevaluationComponent } from '../../components/challenge/challengeevaluation/challengeevaluation.component';
import { ChallengephasesComponent } from '../../components/challenge/challengephases/challengephases.component';
import { ChallengeparticipateComponent } from '../../components/challenge/challengeparticipate/challengeparticipate.component';
import { ChallengeleaderboardComponent } from '../../components/challenge/challengeleaderboard/challengeleaderboard.component';
import { ChallengesubmitComponent } from '../../components/challenge/challengesubmit/challengesubmit.component';
import { ChallengesubmissionsComponent } from '../../components/challenge/challengesubmissions/challengesubmissions.component';
import { PhasecardComponent } from '../../components/challenge/challengephases/phasecard/phasecard.component';
import { RouterTestingModule } from '@angular/router/testing';
import { AuthService } from '../../services/auth.service';
import { EndpointsService } from '../../services/endpoints.service';
import { ForceloginComponent } from '../../components/utility/forcelogin/forcelogin.component';
import { FooterComponent } from '../../components/nav/footer/footer.component';
import { TeamlistComponent } from '../../components/publiclists/teamlist/teamlist.component';
import { SelectphaseComponent } from '../../components/utility/selectphase/selectphase.component';
import { InputComponent } from '../../components/utility/input/input.component';
import { NO_ERRORS_SCHEMA } from '@angular/core';
import { Router, ActivatedRoute } from '@angular/router';
import { Observable, of } from 'rxjs';
import { MatTableModule } from '@angular/material';
import { FormsModule } from '@angular/forms';

describe('ChallengeComponent', () => {
  let component: ChallengeComponent;
  let fixture: ComponentFixture<ChallengeComponent>;
  let router, authService, authServiceSpy;
  const fakeActivatedRoute = {
    id: 1,
  };
  let challengeService, challengeServiceSpy;
  let globalService, apiService, endpointsService;

  beforeEach(async(() => {
    TestBed.configureTestingModule({
      declarations: [
        ChallengeComponent,
        HeaderStaticComponent,
        ChallengeoverviewComponent,
        ChallengeevaluationComponent,
        ChallengephasesComponent,
        ChallengeparticipateComponent,
        ChallengeleaderboardComponent,
        ChallengesubmitComponent,
        ChallengesubmissionsComponent,
        PhasecardComponent,
        ForceloginComponent,
        FooterComponent,
        TeamlistComponent,
        SelectphaseComponent,
      ],
      providers: [
        ApiService,
        GlobalService,
        ChallengeService,
        AuthService,
        EndpointsService,
        {
          provide: ActivatedRoute,
          useValue: {
            snapshot: {},
            params: of(fakeActivatedRoute),
          },
        },
      ],
      imports: [HttpClientModule, RouterTestingModule, FormsModule, MatTableModule],
      schemas: [NO_ERRORS_SCHEMA],
    }).compileComponents();
  }));

  beforeEach(() => {
    fixture = TestBed.createComponent(ChallengeComponent);
    router = TestBed.get(Router);
    challengeService = TestBed.get(ChallengeService);
    globalService = TestBed.get(GlobalService);
    authService = TestBed.get(AuthService);
    apiService = TestBed.get(ApiService);
    endpointsService = TestBed.get(EndpointsService);
    component = fixture.componentInstance;

    spyOn(router, 'navigate');
    spyOn(globalService, 'handleApiError');
    spyOn(globalService, 'showToast');
    spyOn(globalService, 'showModal');
    spyOn(globalService, 'showConfirm');
    spyOn(endpointsService, 'editChallengeDetailsURL');
  });

  it('should create', () => {
    expect(component).toBeTruthy();
  });

  it('Global variables', () => {
    expect(component.isStarred).toBeFalsy();
    expect(component.isChallengeHost).toBeFalsy();
    expect(component.publishChallenge).toEqual({
      state: 'Not Published',
      icon: 'fa fa-eye-slash red-text',
    });
    expect(component.isParticipated).toBeFalsy();
    expect(component.isLoggedIn).toBeFalsy();
  });

  it('check if user is logged in', () => {
    authServiceSpy = spyOn(authService, 'isLoggedIn').and.returnValue(true);
    fixture.detectChanges();
    expect(authServiceSpy).toHaveBeenCalled();
    expect(component.isLoggedIn).toBeTruthy();
  });

  it('check activated routed subscribe method called on init', async(() => {
    challengeServiceSpy = spyOn(challengeService, 'fetchChallenge');
    fixture.detectChanges();
    expect(component.id).toBe(fakeActivatedRoute['id']);
    expect(challengeServiceSpy).toHaveBeenCalledWith(fakeActivatedRoute['id']);
  }));

  it('should call `starToggle` method when user is logged in', () => {
    challengeServiceSpy = spyOn(challengeService, 'starToggle');
    const challengeId = 1;
    component.isLoggedIn = true;
    component.starToggle(challengeId);
    expect(challengeServiceSpy).toHaveBeenCalledWith(challengeId);
  });

  it('should show login to star the challenge message when user is not logged in', () => {
    const challengeId = 1;
    component.isLoggedIn = false;
    component.starToggle(challengeId);
    expect(globalService.showToast).toHaveBeenCalledWith('error', 'Please login to star the challenge!', 5);
  });

  it('should toggle the publish challenge state from public to private', async(() => {
    component.publishChallenge = {
      state: 'Published',
      icon: 'fa fa-eye green-text',
    };
    const expectedSuccessMsg = 'The challenge was successfully made private';
    spyOn(apiService, 'patchUrl').and.returnValue(
      new Observable((observer) => {
        observer.next({ results: [{}] });
        observer.complete();
        return { unsubscribe() {} };
      })
    );

    component.togglePublishChallengeState();
    fixture.detectChanges();
    expect(globalService.showConfirm).toHaveBeenCalled();
    component.apiCall();
    expect(apiService.patchUrl).toHaveBeenCalled();
    expect(component.publishChallenge.state).toEqual('Not Published');
    expect(component.publishChallenge.icon).toEqual('fa fa-eye-slash red-text');
    expect(globalService.showToast).toHaveBeenCalledWith('success', expectedSuccessMsg, 5);
  }));

  it('should toggle the publish challenge state from private to public', async(() => {
    component.publishChallenge = {
      state: 'Not Published',
      icon: 'fa fa-eye-slash red-text',
    };
    const expectedSuccessMsg = 'The challenge was successfully made public';
    spyOn(apiService, 'patchUrl').and.returnValue(
      new Observable((observer) => {
        observer.next({ results: [{}] });
        observer.complete();
        return { unsubscribe() {} };
      })
    );

    component.togglePublishChallengeState();
    fixture.detectChanges();
    expect(globalService.showConfirm).toHaveBeenCalled();
    component.apiCall();
    expect(apiService.patchUrl).toHaveBeenCalled();
    expect(component.publishChallenge.state).toEqual('Published');
    expect(component.publishChallenge.icon).toEqual('fa fa-eye green-text');
    expect(globalService.showToast).toHaveBeenCalledWith('success', expectedSuccessMsg, 5);
  }));

  it('should handle the API error for `togglePublishChallengeState` method', async(() => {
    const expectedApiError = {
      error: 'Api error',
    };
    spyOn(apiService, 'patchUrl').and.returnValue(
      new Observable((observer) => {
        observer.error({ error: expectedApiError.error });
        observer.complete();
        return { unsubscribe() {} };
      })
    );

    component.togglePublishChallengeState();
    fixture.detectChanges();
    expect(globalService.showConfirm).toHaveBeenCalled();
    component.apiCall();
    expect(apiService.patchUrl).toHaveBeenCalled();
    expect(globalService.handleApiError).toHaveBeenCalledWith(expectedApiError, true);
    expect(globalService.showToast).toHaveBeenCalledWith('error', expectedApiError);
  }));

  it('should show the modal and successfully edit the title of a challenge', async(() => {
    component.challenge = {
      id: 1,
      title: 'Challenge title',
      creator: 'Host user',
      description: 'Challenge description',
    };
    const expectedUpdateTitle = 'Updated challenge title';
    const expectedSuccessMsg = 'The challenge title is  successfully updated!';
    spyOn(apiService, 'patchUrl').and.returnValue(
      new Observable((observer) => {
        observer.next({ title: expectedUpdateTitle });
        observer.complete();
        return { unsubscribe() {} };
      })
    );

    component.editChallengeTitle();
    fixture.detectChanges();
    expect(globalService.showModal).toHaveBeenCalled();
    component.apiCall();
    expect(apiService.patchUrl).toHaveBeenCalled();
    expect(component.challenge.title).toEqual(expectedUpdateTitle);
    expect(globalService.showToast).toHaveBeenCalledWith('success', expectedSuccessMsg, 5);
  }));

  it('should handle the API error for `editChallengeTitle` method', async(() => {
    component.challenge = {
      id: 1,
      title: 'Challenge title',
      creator: 'Host user',
      description: 'Challenge description',
    };
    const expectedApiError = {
      error: 'Api error',
    };
    spyOn(apiService, 'patchUrl').and.returnValue(
      new Observable((observer) => {
        observer.error({ error: expectedApiError.error });
        observer.complete();
        return { unsubscribe() {} };
      })
    );

    component.editChallengeTitle();
    fixture.detectChanges();
    expect(globalService.showModal).toHaveBeenCalled();
    component.apiCall();
    expect(apiService.patchUrl).toHaveBeenCalled();
    expect(globalService.handleApiError).toHaveBeenCalledWith(expectedApiError, true);
    expect(globalService.showToast).toHaveBeenCalledWith('error', expectedApiError);
  }));

  it('should show the modal with the form fields and successfully delete the challenge', async(() => {
    const expectedSuccessMsg = 'The Challenge is successfully deleted!';
    spyOn(apiService, 'postUrl').and.returnValue(
      new Observable((observer) => {
        observer.next({ results: [{}] });
        observer.complete();
        return { unsubscribe() {} };
      })
    );

    component.deleteChallenge();
    fixture.detectChanges();
    expect(globalService.showModal).toHaveBeenCalled();
    component.apiCall();
    expect(apiService.postUrl).toHaveBeenCalled();
    expect(router.navigate).toHaveBeenCalledWith(['/challenges/all']);
    expect(globalService.showToast).toHaveBeenCalledWith('success', expectedSuccessMsg, 5);
  }));

  it('should handle the API error for `deleteChallenge` method', async(() => {
    const expectedApiError = {
      error: 'Api error',
    };
    spyOn(apiService, 'postUrl').and.returnValue(
      new Observable((observer) => {
        observer.error({ error: expectedApiError.error });
        observer.complete();
        return { unsubscribe() {} };
      })
    );

    component.deleteChallenge();
    fixture.detectChanges();
    expect(globalService.showModal).toHaveBeenCalled();
    component.apiCall();
    expect(apiService.postUrl).toHaveBeenCalled();
    expect(globalService.handleApiError).toHaveBeenCalledWith(expectedApiError, true);
    expect(globalService.showToast).toHaveBeenCalledWith('error', expectedApiError);
  }));
});