StaticInjectionError, запускающая ионные тесты с кармой - PullRequest
0 голосов
/ 10 октября 2018

Я пытаюсь запустить простой тест, чтобы проверить, что компонент создан.

Когда я запускаю тест с кармой karma start ./test-config/karma.conf.js, я получаю следующий вывод:

10 10 2018 10:50:22.316:ERROR [HeadlessChrome 0.0.0 (Linux 0.0.0) | Create account component | should be created]: Error: StaticInjectorError(t)[t -> t]: 
  StaticInjectorError(Platform: core)[t -> t]: 
    NullInjectorError: No provider for t!
error properties: Object({ ngTempTokenPath: null, ngTokenPath: [ 't', Function ], ngDebugContext: t({ view: Object({ def: Object({ factory: Function, nodeFlags: 33603585, rootNodeFlags: 33554433, nodeMatchedQueries: 0, flags: 0, nodes: [ Object({ nodeIndex: 0, parent: null, renderParent: null, bindingIndex: 0, outputIndex: 0, checkIndex: 0, flags: 33554433, childFlags: 49152, directChildFlags: 49152, childMatchedQueries: 0, matchedQueries: Object({  }), matchedQueryIds: 0, references: Object({  }), ngContentIndex: null, childCount: 1, bindings: [  ], bindingFlags: 0, outputs: [  ], element: Object({ ns: '', name: 'page-create-account', attrs: [  ], template: null, componentProvider: Object({ nodeIndex: 1, parent: <circular reference: Object>, renderParent: <circular reference: Object>, bindingIndex: 0, outputIndex: 0, checkIndex: 1, flags: 49152, childFlags: 0, directChildFlags: 0, childMatchedQueries: 0, matchedQueries: Object, matchedQueryIds: 0, references: Object, ngContentIndex: -1, childCount: 0,  ...
    at t.get (http://localhost:9876/base/test-config/karma-test-shim.js?6323aa11dcffe596b12ee89cf9d5010482d220c9:45:142)

Это компонент для тестирования (я сократил простейшую логику для определения проблемы):

import {Component} from '@angular/core';
import {NavController} from 'ionic-angular';
import {FormBuilder, FormGroup} from "@angular/forms";
import {UsernameValidator} from "../../validators/username";

@Component({
    selector: 'page-create-account',
    templateUrl: 'create-account.html',
})
export class CreateAccountPage {
    userForm: FormGroup;
    username;
    email;
    password;

    constructor(public navCtrl: NavController,
        public formBuilder: FormBuilder,
        public usernameValidator: UsernameValidator){
        this.userForm = this.formBuilder.group({});
    }
}

это тест:

import {async, TestBed} from '@angular/core/testing';
import {IonicModule, Nav, NavController} from 'ionic-angular';
import {
  UsernameValidatorMock,
  FormBuilderMock,
  NavControllerMock,
  NavMock
} from '../../../test-config/mocks-ionic';
import {CreateAccountPage} from "./create-account";
import {FormBuilder} from "@angular/forms";
import {UsernameValidator} from "../../validators/username";
import {UserService} from "../../services/user.service";
import {Observable} from "rxjs";

describe('Create account component', () => {
  let fixture;
  let component;

  beforeEach(async(() => {
    TestBed.configureTestingModule({
      declarations: [CreateAccountPage],
      imports: [
        IonicModule.forRoot(CreateAccountPage)
      ],
      providers: [
        { provide: Nav, useClass: NavMock},
        { provide: NavController, useClass: NavControllerMock},
        { provide: FormBuilder, useClass: FormBuilderMock},
        { provide: UserService, useClass: UserServiceMock},
        { provide: UsernameValidator, useClass: UsernameValidatorMock },
      ]
    })
  }));

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

  it('should be created', () => {
    expect(component instanceof CreateAccountPage).toBe(true);
  });

});

и это оригинальное имя пользователяValidator:

import { Injectable } from '@angular/core';
import { FormControl } from '@angular/forms';
import {UserService} from '../services/user.service';

@Injectable()
export class UsernameValidator {

  debouncer: any;
  object_username: any = {};
  constructor(public userService: UserService) {

  }
  checkUsername(control: FormControl): Promise<any> {

    clearTimeout(this.debouncer);

    return new Promise(resolve => {
      this.debouncer = setTimeout(() => {
        this.object_username = {username: control.value};
        this.userService.validateUsername(this.object_username).subscribe((res) => {
          console.log(res);
          if ( res === true) {
            resolve({'username taken': true});
          }
        }, (err) => {
          resolve(null);
        });
      }, 1000);

    });
  }
}

Похоже, что не может ввести некоторыепровайдеров, но я уже создал макеты для всех используемых зависимостей и даже для зависимостей второго уровня, таких как UserProvider для UsernameValidator.Тест проходит успешно без внедрения UsernameValidator.Любая идея, почему этот класс не может быть введен?

Версии:

Ionic:

   ionic (Ionic CLI)  : 4.1.1
   Ionic Framework    : ionic-angular 3.9.2
   @ionic/app-scripts : 3.2.0

Cordova:

   cordova (Cordova CLI) : 8.0.0
   Cordova Platforms     : android 6.4.0, ios 4.5.5

Ответы [ 2 ]

0 голосов
/ 23 октября 2018

Я наконец обнаружил проблему.UserService зависит от HttpClient, который макет не был включен в провайдеров.Это необходимо, потому что UsernameValidatorMock является дочерним классом UsernameValidator, тогда все зависимости исходного класса должны быть внедрены.

Я мог бы получить конкретную ошибку:

StaticInjectorError(Platform: core)[UserService -> HttpClient]: 
        NullInjectorError: No provider for HttpClient!

вместо:

  StaticInjectorError(Platform: core)[t -> t]: 
    NullInjectorError: No provider for t!

, удалив 4.2.0 версию webpack (поскольку карма уже зависит отwebpack) и понижение ts-loader с 5.4.1 до 3.4.0.

Несмотря на это, я наконец-то использовал шпион класса валидатора, как показано ниже:

 beforeEach(async(() => {

        userValidatorUsernameSpy = jasmine.createSpyObj('UsernameValidator', ['checkUsername']);
        TestBed.configureTestingModule({
          declarations: [CreateAccountPage],
          imports: [
            FormsModule,
            ReactiveFormsModule,
            IonicModule.forRoot(CreateAccountPage)
          ],
          providers: [
            {provide: NavController, useValue: navControllerSpy},
            {provide: NavParams, useFactory: () => NavParamsMock.instance()},
            {provide: Platform, useFactory: () => PlatformMock.instance()},
            {provide: UsernameValidator, useValue: usernameSpy},
          ]
        }).compileComponents();

    fixture = TestBed.createComponent(CreateAccountPage);
    component = fixture.componentInstance;
  }
  ));
0 голосов
/ 10 октября 2018

Я запустил ваш код без ваших пользовательских классов, и он работает хорошо. В прошлом у меня было несколько проблем с Ionic cli 4, когда я использовал ионно-угловой 3.9.2.

Пожалуйста, проверьте его снова с помощью ionic-cli 3.20.0:

[13:23:07]> (dev)$ionic info

cli packages: (E:\Usuarios\dceresa\AppData\Roaming\npm\node_modules)

    @ionic/cli-utils  : 1.19.2
    ionic (Ionic CLI) : 3.20.0

global packages:

    cordova (Cordova CLI) : 8.0.0

local packages:

    @ionic/app-scripts : 3.1.5
    Cordova Platforms  : android 6.2.3 browser 5.0.3
    Ionic Framework    : ionic-angular 3.9.2-201807062122

На всякий случай, если вам интересно узнать мой .spec:

import { async, TestBed } from '@angular/core/testing';
import { IonicModule, Nav, NavController } from 'ionic-angular';
import { CreateAccountPage } from "./create-account";
import { FormBuilder } from "@angular/forms";
import { Observable } from "rxjs";
import { NavControllerMock } from 'ionic-mocks';

fdescribe('Create account component', () => {
    let fixture;
    let component;

    beforeEach(async(() => {
        TestBed.configureTestingModule({
            declarations: [CreateAccountPage],
            imports: [
                IonicModule.forRoot(CreateAccountPage)
            ],
            providers: [
                { provide: NavController, useClass: NavControllerMock },
                FormBuilder
            ]
        })
    }));

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

    it('should be created', () => {
        expect(component instanceof CreateAccountPage).toBe(true);
    });

});

И компонент:

import { Component } from '@angular/core';
import { NavController } from 'ionic-angular';
import { FormBuilder, FormGroup } from "@angular/forms";

@Component({
  selector: 'page-create-account',
  templateUrl: 'create-account.html',
})
export class CreateAccountPage {
  userForm: FormGroup;
  username;
  email;
  password;

  constructor(public navCtrl: NavController,
    public formBuilder: FormBuilder) {
    this.userForm = this.formBuilder.group({});
  }
}
...