lundi 21 décembre 2020

Why is my component variable undefined inside the subscribe block (Angular + Jest)?

I am receiving the following error when I run my test suite:

TypeError: Cannot read property 'map' of undefined

undefined is referring to this.playersInLobby.

game.component.ts:

import { Component, OnInit } from '@angular/core';
import { GameService } from './shared/services/game.service';
import { JoinGameService } from './shared/services/join-game.service';
import { ToastrService } from 'ngx-toastr';
import { MatDialog } from '@angular/material/dialog';
import { QuitGameDialogComponent } from './shared/components/quit-game-dialog/quit-game-dialog.component';

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

  public playersInLobby: Array<any>;

  constructor(
    public gameService: GameService,
    public dialog: MatDialog,
    private joinGameService: JoinGameService,
    private toastr: ToastrService
  ) { }

  ngOnInit() {
    console.log(this.playersInLobby); <-- LOGS THE PLAYERS, AS DEFINED IN THE TEST SPEC
    this.gameService.onTurnSet()
      .subscribe((data: any) => {
        this.toastr.info(data.message);
        const updatedPlayersInLobby = this.playersInLobby.map(player => { <-- ERROR THROWN HERE
          if (player.key === data.nextPlayersTurn.key) {
            return {
              key: player.key,
              username: player.username,
              isTurn: true
            };
          } else {
            return {
              key: player.key,
              username: player.username,
              isTurn: false
            };
          }
        });
        this.playersInLobby = updatedPlayersInLobby;
        this.currentPlayer = this.getCurrentPlayer(this.playersInLobby);
      });
  }
}

game.component.spec.ts:

import { ComponentFixture, TestBed, waitForAsync } from '@angular/core/testing';
import { GameComponent } from './game.component';
import { NO_ERRORS_SCHEMA } from '@angular/core';
import { JoinGameService } from './shared/services/join-game.service';
import { ToastrService } from 'ngx-toastr';
import { GameService } from './shared/services/game.service';
import { of } from 'rxjs';
import { MatDialogModule } from '@angular/material/dialog';

describe('GameComponent', () => {
  let component: GameComponent;
  let fixture: ComponentFixture<GameComponent>;
  let MOCK_USERNAME_AND_ID;
  const MOCK_PLAYERS = [
    { test: 'TEST' },
    { test2: 'TEST2' }
  ];

  const mockJoinGameService = {
    setUsername: jest.fn(),
    onSetUsername: jest.fn().mockReturnValue(of({room: { users: ['TEST1', 'TEST2']}})),
    isHost: jest.fn().mockReturnValue(of({data: 'test'})),
  };
  const mockToastrService = {
    info: jest.fn().mockReturnValue('INFO MESSAGE'),
    success: jest.fn().mockReturnValue('SUCCESS MESSAGE')
  };
  const mockGameService = {
    onTurnSet: jest.fn().mockReturnValue(of({data: 'test'})),
  };

  beforeEach(waitForAsync(() => {
    TestBed.configureTestingModule({
      imports: [
        MatDialogModule,
      ],
      declarations: [
        GameComponent
      ],
      providers: [
        { provide: GameService, useValue: mockGameService },
        { provide: JoinGameService, useValue: mockJoinGameService },
        { provide: ToastrService, useValue: mockToastrService }
      ],
      schemas: [ NO_ERRORS_SCHEMA ]
    })
      .compileComponents();
  }));

  beforeEach(() => {
    fixture = TestBed.createComponent(GameComponent);
    component = fixture.componentInstance;
    component.playersInLobby = MOCK_PLAYERS;
  });

  describe('Initialise component', () => {
    test('should create', () => {
      fixture.detectChanges();
      expect(component).toBeTruthy();
    });
  });

  describe('enterRoom', () => {
    beforeEach(() => {
      MOCK_USERNAME_AND_ID = {
        username: 'James',
        roomId: 'a1b2c3d4'
      };
      fixture.detectChanges();
    });

    test('should call the setUsername method in joinGameService', () => {
      component.enterRoom(MOCK_USERNAME_AND_ID);
      expect(mockJoinGameService.setUsername).toHaveBeenCalled();
    });
  });
});

Jest reporter, showing the error:

Screenshot of error

EDIT (screenshot displaying the value of playersInLobby; when logged on the first line inside ngOnInit):

enter image description here

Aucun commentaire:

Enregistrer un commentaire