Search code examples
angularunit-testingjasminekarma-jasmine

Unit test assignment of property inside ngOnInit after service gets data


When unit-testing in angular, how can I test that property in map.component.ts userRole = 'Admin'? Right now it fails on Expected undefined to equal 'Admin'. I try to mock service that gets the real data with testData. I am complete beginner in unit testing, please help. Thanks!

map.component.ts

export class MapComponent implements OnInit, OnDestroy {
userRole:string
...
constructor(
    private zone: NgZone,
    public deskDialog: MatDialog,
    private userFloorService: UserFloorService,
    private _snackBar: MatSnackBar,
    private route: ActivatedRoute,
    private router: Router
  ) {}

async ngOnInit(): Promise<void> {
    const userData = await this.userFloorService.getUser().toPromise();
    this.userRole = userData.records[0].user_role; 
    ...
}

user-floor.service.ts

export class UserFloorService {
public getUser(): Observable<any> {
    return this.http.get(
      `https://XXX`);
  }
}

map.component.spec.ts

class UserService {
  testData = {
    message: 'Succes',
    records: [
      {
        floor_id: 3,
        reservations: [
          {
            desk_id: 11,
            reservation_date: '2021-02-22',
            reservation_id: 585,
            user_id: 7,
          },
        ],
        user_gid: 'xxx',
        user_id: 7,
        user_role: 'Admin',
      },
    ],
  };
  public getUser(): Observable<any> {
    return of(this.testData);
  }
}

describe('MapComponent', () => {
  let component: MapComponent;
  let fixture: ComponentFixture<MapComponent>;
  let userService: UserFloorService;

  beforeEach(() => {
    userService = jasmine.createSpyObj(['getUser']);

    TestBed.configureTestingModule({
      declarations: [MapComponent],
      imports: [
        MatSnackBarModule,
        AppRoutingModule,
        HttpClientModule,
        BrowserModule,
        MatDialogModule,
        HttpClientTestingModule,
      ],
      providers: [{ provide: UserFloorService, useClass: UserService }],
    }).compileComponents();
    fixture = TestBed.createComponent(MapComponent);
    component = fixture.componentInstance;
    userService = TestBed.inject(UserFloorService);
    fixture.detectChanges();
  });

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

  describe('Given the component is loaded', () => {
    describe('When getUser returns mock data', () => {
      it('Then the userRole should be Admin', (done) => {
        userService.getUser().subscribe(() => {
          expect(component.userRole).toEqual('Admin');
          done();
        });
      });
    });
  });
});

Solution

  • So I was able to get it working without making changes to ngOnInit by using beforeEach with async and done() callback in it() :

    describe('MapComponent', () => {
      let component: MapComponent;
      let fixture: ComponentFixture<MapComponent>;
      let userService: UserFloorService;
    
      beforeEach(async() => {
        await TestBed.configureTestingModule({
          declarations: [MapComponent],
          imports: [
            MatSnackBarModule,
            AppRoutingModule,
            BrowserModule,
            MatDialogModule,
            HttpClientTestingModule,
          ],
          providers: [{ provide: UserFloorService, useClass: MockService }],
        }).compileComponents();
        fixture = TestBed.createComponent(MapComponent);
        component = fixture.componentInstance;
        userService = TestBed.inject(UserFloorService);
        fixture.detectChanges();
      });
    
      it('should be created', () => {
        expect(component).toBeTruthy();
      });
    
      it('userRole should be Admin', (done) => { 
        console.log(done);
        expect(component.userRole).toEqual('Admin');
        done();
      });
    
    });
    

    But thanks for help, you've ponited me in the right direction.