Угловой испытательный шпион не вызывается - PullRequest
0 голосов
/ 25 января 2019

У меня проблемы с настройкой моего углового теста для правильной работы. Конкретная проблема заключается в том, что мой шпион, похоже, не работает. Я новичок в Angular и пытаюсь понять, как писать тесты. Фоном является то, что это для моего первого приложения Angular (с использованием последней версии CLI, 7.x). Это простое слайд-шоу. Слайд-шоу работает нормально, но я просто пытаюсь заставить тесты работать.

Первая часть этого заключается в том, что приложение должно получить ссылку на JavaScript из window.location. Основываясь на предложениях по Stackoverflow и в других местах, я создал класс для переноса окна, чтобы его можно было протестировать. Вот как это выглядит в службе с именем windowobject.service.ts:

import { Injectable } from '@angular/core';

function getWindow (): any {
  return window;
}

@Injectable({
  providedIn: 'root'
})
export class WindowObjectService {

  constructor() { }

  get browserWindow(): any {
    return getWindow();
  }
}

Это отлично работает, но проблема заключается в том, что это проблема в тесте. Мой тест называется photos.component.spec.ts:

import { async, ComponentFixture, TestBed } from '@angular/core/testing';
import { HttpClientTestingModule } from '@angular/common/http/testing';
import { PhotosComponent } from './photos.component';
import { NgbModule } from '@ng-bootstrap/ng-bootstrap' ;
import { WindowObjectService } from '../services/windowobject.service';
import { environment } from '../../environments/environment';

const expectedId = 916;

class MockWindowObjectService {
  browserWindow(): any {
    return { window: {
                        location: {
                            href: environment.baseUrl + '/angular/slideshow/index.html?id=' + expectedId
                        }
                      }
    };
  }
}

describe('PhotosComponent', () => {
  let component: PhotosComponent;
  let fixture: ComponentFixture<PhotosComponent>;
  let windowService: MockWindowObjectService;
  let windowSpy;

  beforeEach(async(() => {
    TestBed.configureTestingModule({
      imports: [ HttpClientTestingModule, NgbModule ],
      declarations: [PhotosComponent],
      providers: [ { provide: WindowObjectService, useClass: MockWindowObjectService } ]
    })
    .compileComponents().then(() => {

      windowService = TestBed.get(WindowObjectService);
      fixture = TestBed.createComponent(PhotosComponent);
      component = fixture.componentInstance;
    });
  }));

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

  it('should call window object service', () => {
    windowSpy = spyOn(windowService, 'browserWindow').and.callThrough();
    expect(windowService.browserWindow).toHaveBeenCalled();
  });

});

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

Обновление, добавление photos.component.ts. При этом используется карусель ng-bootstrap & pagination для отображения слайд-шоу, в котором показано по одному изображению за раз, и на которое можно перемещаться либо с помощью стрелок карусели, либо с помощью компонента нумерации страниц. Идентификатор коллекции фотографий взят из значения строки запроса в URL.

import { Component, OnInit, ViewChild } from '@angular/core';
import { PhotosService } from '../services/photos.service';
import { IPhoto } from '../models/photo';
import { NgbCarousel, NgbCarouselConfig, NgbPaginationConfig  } from '@ng-bootstrap/ng-bootstrap';
import { WindowObjectService } from '../services/windowobject.service';

@Component({
  selector: 'app-photos',
  templateUrl: './photos.component.html',
  styleUrls: ['./photos.component.scss'],
  providers: [NgbCarouselConfig, WindowObjectService]
})
export class PhotosComponent implements OnInit {

  // reference to "photosCarousel"
  @ViewChild('photosCarousel') photosCarousel: NgbCarousel;

  private _photosService: any;
  private _windowService: WindowObjectService;

  errorMessage: string;
  photos: IPhoto[] = new Array;
  page = 1;
  collectionSize: number;
  tripReportId: string;

  constructor(carouselConfig: NgbCarouselConfig, paginationConfig: NgbPaginationConfig, phototsService: PhotosService,
              windowService: WindowObjectService) {

    carouselConfig.showNavigationArrows = true;
    carouselConfig.showNavigationIndicators = false;
    carouselConfig.interval = 0; // Amount of time in milliseconds before next slide is shown.
    carouselConfig.wrap = false;

    paginationConfig.pageSize = 1;
    paginationConfig.maxSize = 5;
    paginationConfig.size = 'sm';
    paginationConfig.boundaryLinks = false;

    this._photosService = phototsService;
    this._windowService = windowService;
  }

  ngOnInit() {

    console.log('this._windowService.browserWindow.location.href', this._windowService.browserWindow.location.href);

    this.tripReportId = this._windowService.browserWindow.location.href.split('?')[1].split('=')[1];

    this._photosService.getPhotos(this.tripReportId).subscribe(
      photos => {
        this.photos = photos;
        this.collectionSize = photos.length;
      },
      error => this.errorMessage = <any>error
    );

    this.collectionSize = this.photos.length;
  }

  pageChanged(pageNumber: number): void {

    this.photosCarousel.select(pageNumber.toString());
  }

  public onSlide(slideData) {
    this.page = slideData.current;
  }
}

1 Ответ

0 голосов
/ 26 января 2019

Хорошо, вот что я нашел, когда поместил ваш код в этот StackBlitz .

  • Как я и подозревал, вам нужно было вызвать fixture.detectChanges() для выполнения ngOnInit ().
  • Поскольку у вас объявлено WindowObjectService в массиве провайдеров декоратора @Component, вы не можете заменить на макет в массиве провайдеров по умолчанию. Скорее вам нужно использовать overrideComponent(), как показано в StackBlitz.
  • Ваш компонент устанавливает windowService для переменной компонента в конструкторе. Из-за этого очень трудно издеваться над классом, поэтому я изменил макет на объект.
  • Опять же, поскольку вы устанавливаете переменную в конструкторе, spyOnProperty () необходимо выполнить очень рано, до создания компонента.
  • Если вы шпионите за windowService.browserWindow напрямую, это вызовет проблему, поэтому используйте переменную шпиона, которая была установлена.
  • Я также показал, как издеваться над PhotosService с некоторыми данными, чтобы вы тоже начали с этого.

Как видите, тесты сейчас проходят. Надеюсь, это поможет.

...