Не удается прочитать свойство 'doc' из неопределенного, когда имитация класса обслуживания через шпион / карму - PullRequest
0 голосов
/ 29 мая 2019

Я пытаюсь проверить свое угловое приложение через Карму. Мое приложение подключено к базе данных Firebase FireStore. Я пытаюсь смоделировать коллекцию и использовать ее для проверки функций компонентов.

Я использую следующие фрагменты кода:

sprint.service.ts:

export class SprintService {

  getSprints() {
    return this.firestore.collection('sprints').snapshotChanges();
  }
  constructor(private firestore: AngularFirestore) { }
}

sprints.component.ts

sprints : Sprint[];

constructor(private sprintService: SprintService) { }

ngOnInit() {
    this.sprintService.getSprints().subscribe(data => {
      this.sprints = data.map(e => {
        return {
          id: e.payload.doc.id, //HERE IT ERRORS
          ...e.payload.doc.data()
        } as Sprint;
      })
    });
  }

sprints.component.spec.ts

//Mock class
class MockSprintServce
{
  getSprints(){
    return of([
      {id: "1", name:"TestSprint", description:"TestSprint", startDate:new Date(2000, 0, 1), endDate:new Date(2001, 0, 1), isActive:true},
      {id: "2", name:"TestSprint2", description:"TestSprint2", startDate:new Date(2000, 0, 1), endDate:new Date(2001, 0, 1), isActive:false},
    ])
    }
}

beforeEach(async(() => {
    TestBed.configureTestingModule({
      imports: [ FormsModule, AngularFireModule.initializeApp(environment.firebase) ],
      declarations: [ ArchivedUserstoriesComponent,SprintDetailComponent, SprintsComponent, UserDetailComponent, UsersComponent, UserstoriesComponent, UserstoryDetailComponent ],
      providers: [AngularFirestore, {provide: SprintService, useClass: MockSprintServce}]
    })
    .compileComponents();
  }));

beforeEach(() => {
    app.sprints = [
      {id: "1", name:"TestSprint", description:"TestSprint", startDate:new Date(2000, 0, 1), endDate:new Date(2001, 0, 1), isActive:true},
      {id: "2", name:"TestSprint2", description:"TestSprint2", startDate:new Date(2000, 0, 1), endDate:new Date(2001, 0, 1), isActive:false},
    ]
  });


it(`should return all Sprints`, async(() => {

    //arrange
    let getSpy = spyOn(mockSprintServiceObject, 'getSprints').and.returnValue({ subscribe: () => {} });

    //act
    app.ngOnInit({});

    //assert
    expect(getSpy).toHaveBeenCalled();
    expect(getSpy).toContain(app.sprints[1]);
  }));

Я хочу, чтобы код работал без ошибок. Я, вероятно, думаю, что мне нужно переписать метод getSprints в моем MockSprintService. Кто-нибудь знает, что я должен вернуть или сгенерировать в методе getSprints(), чтобы мой ngOnInit снова заработал? Помощь будет оценена.

Ответы [ 2 ]

1 голос
/ 29 мая 2019

Я вижу, вы импортируете и инициализируете AngularFireModule в своем модуле динамического тестирования. Это означает, что он на самом деле подключается к бэкэнду Firebase каждый раз, когда вы запускаете тест… что обычно является очень плохой идеей. Что если в ваших тестовых примерах нужно проверить редактирование или удаление записей? Это будет означать, что они будут делать это на реальных данных каждый раз.

В идеале вы хотите высмеивать все ваши зависимости и избегать импорта реальных в максимально возможной степени (я знаю, что в мире Angular это не всегда возможно).

Одно решение, которое я нашел для себя, это использовать библиотеку ts-mockito . Это позволяет легко имитировать классы, часто это работает из коробки. Есть пост в блоге, который я написал некоторое время назад, если вы хотите узнать больше: Насмешка с помощью ts-mockito

...

Вернемся к вашему конкретному примеру. Похоже, что ваша фиктивная форма данных не соответствует тому, что возвращает служба Firebase.

      this.sprints = data.map(e => {
        return {
          id: e.payload.doc.id, //HERE IT ERRORS
          ...e.payload.doc.data()
        } as Sprint;
      })

Вы сопоставляете каждый элемент данных, и ожидается, что у него будет объект payload с объектом doc, который имеет свойство id и метод data().

Однако в вашем MockSprintServce вы возвращаете наблюдаемое с массивом элементов с формой:

{
  id: "1",
  name:"TestSprint",
  description:"TestSprint",
  startDate:new Date(2000, 0, 1),
  endDate:new Date(2001, 0, 1),
  isActive:true
}

Это просто не совпадает. Если вы хотите продолжить текущую настройку и заставить ее работать, попробуйте изменить элементы в вашем

  getSprints(){
    return of(...

до

[{
  payload: {
    doc: {
      id: '1',
      data: () => ({id: "1", name:"TestSprint", description:"TestSprint", startDate:new Date(2000, 0, 1), endDate:new Date(2001, 0, 1), isActive:true})
    }
  }
}]

0 голосов
/ 29 мая 2019

В вашем смоделированном методе getSprints () вы должны вернуть массив объектов со следующей структурой:

{ payload: { doc: { id: some_id }} }

потому что сейчас ваш e.payload не определен в вашем смоделированном массиве.

...