Угловой шпион Жасмин не вызывается при вызове next () для субъекта в тестовом компоненте - PullRequest
1 голос
/ 08 июля 2019

Обычно, когда вы ожидаете, что вызов службы был вызван, он делает это успешно.Теперь у меня есть следующая ситуация, когда в основном весь код запускается, но ожидание вызова шпиона не проходит.

Я использую последнюю версию Karma (4.1.0) и Jasmine (3.4.0)) и версия Angular 8.x.

У меня есть следующая конфигурация testBed и один комплект тестов.

fdescribe('DetailComponent', () => {
  let component: DetailComponent;
  let fixture: ComponentFixture<DetailComponent>;
  let mockedResolvedData: TimesheetResolved;
  let mockedTimesheet: Timesheet;
  let mockedPermissions;
  let mockTimesheetService;
  let mockNotificationService;
  let mockPermissionsService;
  let mockRouter;
  let mockActivatedRoute: ActivatedRoute;

  beforeEach(async(() => {
    mockedTimesheet = mockTimesheet();
    mockedPermissions = mockPermissions();
    mockedResolvedData = { timesheet: mockedTimesheet, error: null };

    mockTimesheetService = jasmine.createSpyObj([
      'patchTimesheet',
      'getTimesheet',
    ]);
    mockNotificationService = jasmine.createSpyObj(['showNotification']);
    mockAuthenticationService = jasmine.createSpyObj(['getRole']);

    TestBed.configureTestingModule({
      imports: [
        // left out MaterialDesign imports
        NoopAnimationsModule,
        FormsModule,
      ],
      declarations: [
        DetailComponent,
        // list of MockComponents
      ],
      providers: [
        { provide: TimesheetService, useValue: mockTimesheetService },
        { provide: NotificationService, useValue: mockNotificationService },
        { provide: AuthenticationService, useValue: mockAuthenticationService },
        { provide: NgxPermissionsService, useValue: mockPermissionsService },
      ],
    });

    mockRouter = TestBed.get(Router);
    mockActivatedRoute = TestBed.get(ActivatedRoute);
  }));

  describe('when the resolvedData is filled: happy-flow (regular behavior)', () => {
    beforeEach(() => {
      fixture = TestBed.createComponent(TimesheetDetailComponent);
      mockTimesheetService.getTimesheet.and.returnValue(of(mockedRefreshedTimesheet));
      mockPermissionsService.getPermissions.and.returnValue(mockedPermissions);
      mockTimesheetService.patchTimesheet.and.returnValue(of(new HttpResponse<Object>()));
      component = fixture.componentInstance;
    });

fit('should call the patch if the value from the remarkSubject is changed', () => {
    // Arrange
    fixture.detectChanges();

    // Act
    component.timesheetRemarksSubject.next('new value');

    // Assert
    expect(mockTimesheetService.patchTimesheet).toHaveBeenCalled();
  });
});

Компонент имеет следующий код:

// left out imports

@Component({
  selector: 'detail-cmp',
  templateUrl: './detail.component.html',
  styleUrls: ['./detail.component.scss'],
})
export class DetailComponent implements OnInit, AfterViewInit, OnDestroy {
  private readonly destroyed = new Subject();
  timesheetRemarksSubject: Subject<string> = new Subject<string>();
  timesheet: Timesheet;

  constructor(
    private readonly timesheetService: TimesheetService,
    private readonly notificationService: NotificationService,
    private readonly changeDetectorRef: ChangeDetectorRef,
  ) {}

  ngOnInit(): void {;
    this.route.data.subscribe(data => {
      const resolvedData: TimesheetResolved = data['resolvedData'];
      this.errorMessage = resolvedData.error;
      this.onTimesheetReceived(resolvedData.timesheet);
    });
  }

  onTimesheetReceived(timesheet: Timesheet): void {
    this.timesheet = timesheet;

    if (timesheet) {
        // do something
    }
  }

  ngAfterViewInit(): void {
    if (this.timesheet) {
      console.log('ngAfterViewInit!');
      this.changeDetectorRef.detectChanges();
      this.setupTimesheetRemarksSubjectSubscription();
    }
  }

  private setupTimesheetRemarksSubjectSubscription(): void {
    console.log('setupTimesheetRemarksSubjectSubscription');
    this.timesheetRemarksSubject
      .pipe(
        takeUntil(this.destroyed),
        debounceTime(500),
        distinctUntilChanged(),
      )
      .subscribe(remark => {
        console.log('succesfully remark object added');
        console.log('value of the remark is: ', remark);
        this.timesheet.remarks = remark;
        this.patchTimesheetRemark();
      });
  }

  ngOnDestroy(): void {
    console.log('ngOnDestroy!');
    this.destroyed.next();
    this.destroyed.complete();
  }

  private patchTimesheetRemark(): void {
    console.log('patching timesheet remarks!');
    this.timesheetService.patchTimesheet(this.timesheet.id, this.timesheet.remarks).subscribe(
      () => {
        console.log('succesfully patched');
        this.notificationService.showNotification(//custom message);
      },
    );
  }
}

При изготовлении нестандартного компонента «из коробки», шпионские системы с теми же типами зависимостей, которые вызывал мой шпион… Что странно, потому что мои настройки в основном такие же.https://stackblitz.com/edit/angular-bv7oj2 <- вот проект barebones.Вероятно, лучше всего скопировать и вставить это в простой CLI-проект CLI и запустить <code>ng test.

Суть в том, что что-то в моей настройке / конфигурации отличается, потому что в barebone-системах это работает.Шпион вызывается.В моем собственном тесте это не так.Я получаю следующие журналы консоли:

enter image description here

это в сочетании с ошибочным дисплеем теста:

enter image description here

Я немного не понимаю, почему шпиону не звонят.Я упустил из кода самые незначительные вещи из кода, поэтому, если я что-то упустил, пожалуйста, сообщите мне, и я предоставлю.

Заранее спасибо!

1 Ответ

1 голос
/ 08 июля 2019

Имея асинхронный тест, вы должны убедиться, что тест ожидает, особенно если ваш тест включает debounceTime.Для этого вы можете использовать fakeAsync тестовую настройку и вызвать tick(500), где 500 - это время, которое вы указали в качестве времени отладки.

Тик говорит тесту, чтобы он действительно ждал завершения этого debounceTime.и только когда это закончится, ваш шпион будет вызван.

Посмотрите здесь: https://angular.io/api/core/testing/fakeAsync

...