Karma TestBed.configureTestingModule: модульные тесты проходят, но выдают ОШИБКУ: «Отклонение необработанного обещания:», «недействительная ссылка: LoginPage» - PullRequest
0 голосов
/ 28 мая 2018

У меня есть ионное приложение, к которому я пытаюсь добавить модульные тесты, тесты проходят, но, тем не менее, у меня всегда есть ошибка, которую я не могу устранить.

Однако мой модуль выглядит хорошо определенным и импортированным.

Вот файл, который я тестирую:

app.component.ts

import { Component, ViewChild } from '@angular/core';
import { Nav, Platform } from 'ionic-angular';
import { StatusBar } from '@ionic-native/status-bar';
import { SplashScreen } from '@ionic-native/splash-screen';

import {BackendClient} from "../backend/client.service";

@Component({
  templateUrl: 'app.html',
  providers: [BackendClient]
})
/**
 * Main class of Alignak App Mobile
 */
export class MyApp {
  @ViewChild(Nav) nav: Nav;
  rootPage:any = 'LoginPage';

  /**
   * @param {Platform} platform - platform Object
   * @param {StatusBar} statusBar - status bar Object
   * @param {SplashScreen} splashScreen - splash screen Object
   * @param {BackendClient} backend - backend client
   */
  constructor(public platform: Platform, public statusBar: StatusBar,
              public splashScreen: SplashScreen, public backend: BackendClient) {
    this.initializeApp()

  }

  /**
   * Initialize application
   */
  private initializeApp() {
    this.platform.ready().then(() => {
      // Okay, so the platform is ready and our plugins are available.
      // Here you can do any higher level native things you might need.
      this.statusBar.styleDefault();
      this.splashScreen.hide();
    });
  }

  /**
   * Set as root the given page and reset content nav (to avoid get back button)
   * @param {string} page
   */
  public openPage(page: string) {
    this.nav.setRoot(page);
  }

  /**
   * Log out of backend, reset token
   */
  public logOut(): void {
    this.backend.token = '';
    this.nav.setRoot(this.rootPage);
  }

}

app.component.spec.ts

import { async, TestBed } from '@angular/core/testing';
import {IonicModule, Platform} from 'ionic-angular';
import {PlatformMock, StatusBarMock, SplashScreenMock} from '../../test-config/mocks-ionic';
import {HttpClient} from "@angular/common/http";

import { StatusBar } from '@ionic-native/status-bar';
import { SplashScreen } from '@ionic-native/splash-screen';

import { MyApp } from './app.component';
import {BackendClient} from "../backend/client.service";


describe('MyApp Component', () => {
  let fixture;
  let component;

  beforeEach(async(() => {
    TestBed.configureTestingModule({
      declarations: [MyApp],
      imports: [
        IonicModule.forRoot(MyApp),
      ],
      providers: [
        { provide: StatusBar, useClass: StatusBarMock },
        { provide: SplashScreen, useClass: SplashScreenMock },
        { provide: Platform, useClass: PlatformMock },
        { provide: BackendClient },
        { provide: HttpClient},
      ],
    }).compileComponents();
  }));

  beforeEach(() => {
    fixture = TestBed.createComponent(MyApp);
    component = fixture.componentInstance;
    // component =
  });

  it('Initialize MyApp',
    () => {
    expect(component instanceof MyApp).toBe(true);
  });

  it('RootPage is equal to LoginPage', () => {
    expect(component.rootPage).toBe('LoginPage');
  });

  // UNIT TEST     who trigger error
  it('Log Out reset token',() => {
    component.logOut();
    expect(component.backend.token).toEqual('');
  });

});

Неудачный тест является третьим «жетоном сброса выхода из системы».И вот файл, который, кажется, вызывает эту ошибку:

login.ts

import { Component } from '@angular/core';
import {IonicPage, NavController} from 'ionic-angular';
import {HttpClient} from "@angular/common/http";

import { BackendClient} from "../../backend/client.service";
import { WrongLogin } from "../badlogin/wrong";

@IonicPage()
@Component({
  selector: 'page-home',
  templateUrl: 'login.html'
})
/**
 * Class who manage user login (Homepage of application)
 */
export class LoginPage {
  private readonly backend_url: string;
  private readonly username: string;
  private readonly password: string;

  /**
   * @param {NavController} navCtrl - navigator controller
   * @param {HttpClient} http - http client for backend service
   */
  constructor(public navCtrl: NavController, private http: HttpClient
  ) {
    if (localStorage.getItem('url')) {
      this.backend_url = localStorage.getItem('url')
    }
    if (localStorage.getItem('username')) {
      this.username = localStorage.getItem('username')
    }
  }

  /**
   * Login to backend with current url, username and password
   */
  public doLogin(): void {
    localStorage.setItem("url", this.backend_url);
    localStorage.setItem('username', this.username);

    let client = new BackendClient(this.http);
    client.login(this.username, this.password)
      .subscribe(
        function(data) {
          localStorage.setItem("token", data['token']);

          this.navCtrl.setRoot(LoginPage);
          this.navCtrl.setRoot('Dashboard');
        }.bind(this),
          err => this.navCtrl.push(
            WrongLogin, {error: err.message || "Can't join the server."}
            )
      );
    }
}

И его файл модуля:

login.module.ts

import { NgModule } from '@angular/core';
import { IonicPageModule } from 'ionic-angular';
import {LoginPage} from "./login";

@NgModule({
  declarations: [
    LoginPage,
  ],
  imports: [
    IonicPageModule.forChild(LoginPage),
  ],
  entryComponents: [
    LoginPage
  ]

})
export class LoginPageModule {}

Итак, мой класс хорошо объявлен в файле модуля.Я пробовал много решений и способов импортировать эту страницу внутри app.component.ts и внутри соответствующего spec файла, но ничего не поделаешь, я всегда сталкиваюсь с одной и той же ошибкой:

28 05 2018 10:53:46.411:INFO [Chrome 66.0.3359 (Linux 0.0.0)]: Connected on socket XJsL7iiRTkumZOd9AAAA with id 38260713
....ERROR: 'Unhandled Promise rejection:', 'invalid link: LoginPage', '; Zone:', 'ProxyZone', '; Task:', 'Promise.then', '; Value:', 'invalid link: LoginPage', undefined

ERROR: 'Unhandled Promise rejection:', 'invalid link: LoginPage', '; Zone:', 'ProxyZone', '; Task:', 'Promise.then', '; Value:', 'invalid link: LoginPage', undefined
Chrome 66.0.3359 (Linux 0.0.0): Executed 4 of 4 SUCCESS (1.06 secs / 1.031 secs)

Я не понимаю, в чем моя ошибка ... Для запуска тестов я использую следующую команду:

karma start ./test-config/karma.conf.js --single-run

Ответы [ 2 ]

0 голосов
/ 28 мая 2018

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

  beforeEach(() => {
    fixture = TestBed.createComponent(MyApp);
    component = fixture.componentInstance;
    spyOn(component.nav, 'setRoot'); 
  });

  it('Log Out reset token',() => {
    component.logOut();
    expect(component.backend.token).toEqual('');
    expect(component.nav.setRoot).toHaveBeenCalledWith('LoginPage');
  });

Stub - это некая зависимость, которую мы используем для тестирования.В вашем случае Nav это зависимость.Вместо использования Nav от Ionic, вы можете использовать в своем тестировании простой макет / заглушку Nav, например:

 component.nav = {setRoot: location=>{}}

Альтернативным способом будет настройка тестовой маршрутизации.сценарий с маршрутами, к которым вы можете получить доступ с этой страницы: может быть сделано :

beforeEach(() => {
  TestBed.configureTestModule({
    imports: [
      RouterTestingModule.withRoutes(
        [{path: '', component: BlankCmp}, {path: 'simple', component: SimpleCmp}]
      )
    ]
  });
});
0 голосов
/ 28 мая 2018

Эта ошибка является ошибкой маршрутизации:

'Отклонение необработанного обещания:', 'недействительная ссылка: LoginPage'

Означает, что вы пытались перенаправить на LoginPage но его не существует

Чтобы решить эту проблему, рассмотрите возможность использования логики маршрутизации вместо использования модуля маршрутизации.Я знаю, что вы можете использовать RouterTestingModule в Angular, но я не знаю насчет Ionic, извините.

...