登录页面显示没有自定义AuthService Karma的存储提供商。

问题描述 投票:0回答:1

我发现很难调试为什么我的ionic页面会抱怨AuthService没有存储提供者。我试着在TestBed中创建一个新的AuthService,但是没有成功。你能不能也解释一下为什么这是一个问题,以便我可以从中学习?我找不到任何关于Injecting一个服务是注入存储模块的内容。

失败了。StaticInjectorError(DynamicTestModule)[AuthService -> Storage]。 StaticInjectorError(Platform: core)[AuthService -> Storage]: NullInjectorError.NullInjectorError(Platform: core)[AuthService -> Storage]: StaticInjectorError(Platform: core)[AuthService -> Storage]: NullInjectorError: 没有Storage的提供者!

import {
  async,
  ComponentFixture,
  TestBed,
  fakeAsync,
  tick,
} from '@angular/core/testing';
import { IonicModule } from '@ionic/angular';
import { RouterTestingModule } from '@angular/router/testing';
import { FormsModule, ReactiveFormsModule } from '@angular/forms';
import { HttpClient } from '@angular/common/http';
import {
  HttpClientTestingModule,
  HttpTestingController,
} from '@angular/common/http/testing';
import { SignInPage } from './sign-in.page';
import { User } from 'src/app/classes/user';
import { AuthService } from '../../services/auth-service/auth.service';
import { UsersDataPublic } from '../../services/users-service/users-data-public';
import { UserProfileService } from '../../services/user-profile/user-profile.service';
import { UserProfileDatabase } from '../../services/user-profile/user-profile-db.service';
import { AppConstants } from '../../constants/app.constants';
import { Storage } from '@ionic/Storage';
import { NO_ERRORS_SCHEMA, CUSTOM_ELEMENTS_SCHEMA, inject } from '@angular/core';

const storageIonicMock: any = {
  get: () => new Promise<any>((resolve, reject) => resolve('As2342fAfgsdr')),
  set: () => new Promise<any>((resolve, reject) => resolve('As2342fAfgsdr'))
};

describe('SignInPage', () => {
  let component: SignInPage;
  let httpTestingController: HttpTestingController;
  let fixture: ComponentFixture<SignInPage>;
  let httpClient: HttpClient;
  let service: UsersDataPublic;
  let userProfileservice: UserProfileService;
  let authService: AuthService;
  let auth;
  let userProfileDatabase: UserProfileDatabase;
  let constants: AppConstants;

  beforeEach(async(() => {
    TestBed.configureTestingModule({
      declarations: [SignInPage],
      providers: [
        UsersDataPublic,
        UserProfileService,
        UserProfileDatabase,
        AppConstants,
        AuthService,
        {
          provide: Storage,
          useValue: storageIonicMock
        }
      ],
      imports: [
        IonicModule.forRoot(),
        ReactiveFormsModule,
        FormsModule,
        RouterTestingModule,
        FormsModule,
        HttpClientTestingModule,
      ],
      schemas: [NO_ERRORS_SCHEMA, CUSTOM_ELEMENTS_SCHEMA],
    }).compileComponents();

    fixture = TestBed.createComponent(SignInPage);
    constants = TestBed.get(AppConstants);
    service = TestBed.get(UsersDataPublic);
    userProfileservice = TestBed.get(UserProfileService);
    authService = TestBed.get(new AuthService(storageIonicMock, httpClient, constants));
    userProfileDatabase = TestBed.get(UserProfileDatabase);
    httpClient = TestBed.get(HttpClient);
    httpTestingController = TestBed.get(HttpTestingController);
    component = fixture.componentInstance;
    fixture.detectChanges();
  }));

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

  it('form invalid when empty', () => {
    expect(component.signinForm.valid).toBeFalsy();
  });

  it('should run ngOnInit 1 time', fakeAsync(() => {
    fixture.detectChanges();
    spyOn(component, 'ngOnInit').and.callThrough();
    component.ngOnInit();
    tick(); // simulates the passage of time until all pending asynchronous activities finish
    fixture.detectChanges();
    expect(component.ngOnInit).toHaveBeenCalledTimes(1);
  }));

  it('should have a title of Sign In', () => {
    const title: HTMLInputElement = fixture.debugElement.nativeElement.querySelector(
      '#home-title'
    );
    expect(title.textContent).toEqual('Sign In');
  });

  it('should run signIn 1 time', fakeAsync(() => {
    fixture.detectChanges();
    spyOn(component, 'signIn').and.callThrough();
    component.signIn();
    tick(); // simulates the passage of time until all pending asynchronous activities finish
    fixture.detectChanges();
    expect(component.signIn).toHaveBeenCalledTimes(1);
  }));

  it('should set the user object to the values set by signIn', fakeAsync(() => {
    const user = {
      ppsn: '13322277P',
      day: '1',
      month: '1',
      year: '1970',
      password: 'Testing123!',
    };

    let ppsn: HTMLInputElement = fixture.debugElement.nativeElement.querySelector(
      '#ppsn'
    );
    let day: HTMLInputElement = fixture.debugElement.nativeElement.querySelector(
      '#day'
    );
    let month: HTMLInputElement = fixture.debugElement.nativeElement.querySelector(
      '#month'
    );
    let year: HTMLInputElement = fixture.debugElement.nativeElement.querySelector(
      '#year'
    );
    let password: HTMLInputElement = fixture.debugElement.nativeElement.querySelector(
      '#password'
    );

    ppsn.value = '13322277P';
    day.value = '1';
    month.value = '1';
    year.value = '1970';
    password.value = 'Testing123!';

    fixture.detectChanges();
    spyOn(component, 'signIn').and.callThrough();
    component.signIn();
    tick(); // simulates the passage of time until all pending asynchronous activities finish
    fixture.detectChanges();
    expect(component.signIn).toHaveBeenCalledTimes(1);
    expect(component.userDetails).toEqual(user);
  }));

  it('should not match the user object to the values set by signIn', fakeAsync(() => {
    const user = {
      ppsn: '13322277P',
      day: '1',
      month: '2',
      year: '1970',
      password: 'Testing123!',
    };

    let ppsn: HTMLInputElement = fixture.debugElement.nativeElement.querySelector(
      '#ppsn'
    );
    let day: HTMLInputElement = fixture.debugElement.nativeElement.querySelector(
      '#day'
    );
    let month: HTMLInputElement = fixture.debugElement.nativeElement.querySelector(
      '#month'
    );
    let year: HTMLInputElement = fixture.debugElement.nativeElement.querySelector(
      '#year'
    );
    let password: HTMLInputElement = fixture.debugElement.nativeElement.querySelector(
      '#password'
    );

    ppsn.value = '13322277P';
    day.value = '1';
    month.value = '1';
    year.value = '1970';
    password.value = 'Testing123!';

    fixture.detectChanges();
    spyOn(component, 'signIn').and.callThrough();
    component.signIn();
    tick(); // simulates the passage of time until all pending asynchronous activities finish
    fixture.detectChanges();
    expect(component.signIn).toHaveBeenCalledTimes(1);
    expect(component.userDetails).not.toEqual(user);
  }));
});

注入Storage的AuthService

import { Injectable } from '@angular/core';
import { HttpClient, HttpErrorResponse } from '@angular/common/http';
import { catchError } from 'rxjs/operators';
import { throwError, Observable, BehaviorSubject } from 'rxjs';
import { AppConstants } from '../../constants/app.constants';
import { Storage } from '@ionic/storage';

@Injectable({
  providedIn: 'root'
})
export class AuthService {
  authenticationState = new BehaviorSubject(false);
  authDetails = {authenticated: false, type: null, myAccountPortalAuthenticated: false };

  constructor(private storage: Storage, private httpClient: HttpClient, private constants: AppConstants) { }

  handleError(error: HttpErrorResponse) {
    let errorMessage = 'Unknown error!';
    if (error.error instanceof ErrorEvent) {
      errorMessage = `Error: ${error.error.message}`;
    } else {
      errorMessage = `Error Code: ${error.status}\nMessage: ${error.message}`;
    }
    return throwError(errorMessage);
  }

  login(url): Observable<any> {
    return this.httpClient.post(url, {})
    .pipe(
      catchError((err: HttpErrorResponse) => {
        return throwError(err);
      })
    );
  }

  devLogin(url): Observable<any> {
    return this.httpClient.get(this.constants.LOCAL_REST_API_SERVER + '/users')
    .pipe(
      catchError((err: HttpErrorResponse) => {
        return throwError(err);
      })
    );
  }

  logout(url): Observable<any> {
    return this.httpClient.post(url, {})
    .pipe(
      catchError((err: HttpErrorResponse) => {
        return throwError(err);
      })
    );
  }

  getAuthenticationDetails() {
    return this.storage.get('auth');
  }

  getAuthenticationState(): Observable<boolean> {
    return this.authenticationState.asObservable();
  }

  setIsAuthenticated(value, loginType) {
    this.authDetails.authenticated = value;
    this.authDetails.type = loginType;
    this.storage.set('auth', this.authDetails);
    this.authenticationState.next(value);
  }

}

登录模块

import { NgModule } from '@angular/core';
import { CommonModule } from '@angular/common';
import { FormsModule } from '@angular/forms';

import { IonicModule } from '@ionic/angular';
import { UserProfileDatabase } from '../../services/user-profile/user-profile-db.service';
import { UserProfileService } from '../../services/user-profile/user-profile.service';
import { AuthService } from '../../services/auth-service/auth.service';
import { SignInPageRoutingModule } from './sign-in-routing.module';
import { SignInPage } from './sign-in.page';
import { ReactiveFormsModule } from '@angular/forms';
import { Storage, IonicStorageModule } from '@ionic/Storage';


@NgModule({
  imports: [
    CommonModule,
    FormsModule,
    IonicModule,
    SignInPageRoutingModule,
    ReactiveFormsModule,
    IonicStorageModule.forRoot()
  ],
  declarations: [SignInPage],
  providers: [UserProfileDatabase, UserProfileService, AuthService]
})
export class SignInPageModule {}

angular jasmine ionic4 karma-jasmine
1个回答
1
投票

把你的脚本改成:-

import {
async,
ComponentFixture,
TestBed,
fakeAsync,
tick,
} from "@angular/core/testing";
import { IonicModule } from "@ionic/angular";
import { RouterTestingModule } from "@angular/router/testing";
import { FormsModule, ReactiveFormsModule } from "@angular/forms";
import { HttpClient } from "@angular/common/http";
import {
HttpClientTestingModule,
HttpTestingController,
} from "@angular/common/http/testing";
import { SignInPage } from "./sign-in.page";
import { User } from "src/app/classes/user";
import { AuthService } from "../../services/auth-service/auth.service";
import { UsersDataPublic } from "../../services/users-service/users-data-public";
import { UserProfileService } from "../../services/user-profile/user-profile.service";
import { UserProfileDatabase } from "../../services/user-profile/user-profile-db.service";
import { AppConstants } from "../../constants/app.constants";
import {
NO_ERRORS_SCHEMA,
CUSTOM_ELEMENTS_SCHEMA,
inject,
} from "@angular/core";

class MockAuthService {
constructor() {}
handleError(error) {}
login(url) {}
devLogin(url) {}
logout(url) {}
getAuthenticationDetails() {}
getAuthenticationState() {}
setIsAuthenticated() {}
}

describe("SignInPage", () => {
let component: SignInPage;
let httpTestingController: HttpTestingController;
let fixture: ComponentFixture<SignInPage>;
let httpClient: HttpClient;
let service: UsersDataPublic;
let userProfileservice: UserProfileService;
let authService: AuthService;
let auth;
let userProfileDatabase: UserProfileDatabase;
let constants: AppConstants;

beforeEach(async(() => {
TestBed.configureTestingModule({
declarations: [SignInPage],
providers: [
UsersDataPublic,
UserProfileService,
UserProfileDatabase,
AppConstants,
{ provide: AuthService, useClass: MockAuthService },
],
imports: [
IonicModule.forRoot(),
ReactiveFormsModule,
FormsModule,
RouterTestingModule,
FormsModule,
HttpClientTestingModule,
],
schemas: [NO_ERRORS_SCHEMA, CUSTOM_ELEMENTS_SCHEMA],
}).compileComponents();

fixture = TestBed.createComponent(SignInPage);
constants = TestBed.get(AppConstants);
service = TestBed.get(UsersDataPublic);
userProfileservice = TestBed.get(UserProfileService);
userProfileDatabase = TestBed.get(UserProfileDatabase);
httpClient = TestBed.get(HttpClient);
httpTestingController = TestBed.get(HttpTestingController);
authService = TestBed.get(AuthService);
component = fixture.componentInstance;
fixture.detectChanges();
}));

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

it("form invalid when empty", () => {
expect(component.signinForm.valid).toBeFalsy();
});

it("should run ngOnInit 1 time", fakeAsync(() => {
fixture.detectChanges();
spyOn(component, "ngOnInit").and.callThrough();
component.ngOnInit();
tick(); // simulates the passage of time until all pending asynchronous activities finish
fixture.detectChanges();
expect(component.ngOnInit).toHaveBeenCalledTimes(1);
}));

it("should have a title of Sign In", () => {
const title: HTMLInputElement = fixture.debugElement.nativeElement.querySelector(
"#home-title"
);
expect(title.textContent).toEqual("Sign In");
});

it("should run signIn 1 time", fakeAsync(() => {
fixture.detectChanges();
spyOn(component, "signIn").and.callThrough();
component.signIn();
tick(); // simulates the passage of time until all pending asynchronous activities finish
fixture.detectChanges();
expect(component.signIn).toHaveBeenCalledTimes(1);
}));

it("should set the user object to the values set by signIn", fakeAsync(() => {
const user = {
ppsn: "13322277P",
day: "1",
month: "1",
year: "1970",
password: "Testing123!",
};

let ppsn: HTMLInputElement = fixture.debugElement.nativeElement.querySelector(
"#ppsn"
);
let day: HTMLInputElement = fixture.debugElement.nativeElement.querySelector(
"#day"
);
let month: HTMLInputElement = fixture.debugElement.nativeElement.querySelector(
"#month"
);
let year: HTMLInputElement = fixture.debugElement.nativeElement.querySelector(
"#year"
);
let password: HTMLInputElement = fixture.debugElement.nativeElement.querySelector(
"#password"
);

ppsn.value = "13322277P";
day.value = "1";
month.value = "1";
year.value = "1970";
password.value = "Testing123!";

fixture.detectChanges();
spyOn(component, "signIn").and.callThrough();
component.signIn();
tick(); // simulates the passage of time until all pending asynchronous activities finish
fixture.detectChanges();
expect(component.signIn).toHaveBeenCalledTimes(1);
expect(component.userDetails).toEqual(user);
}));

it("should not match the user object to the values set by signIn", fakeAsync(() => {
const user = {
ppsn: "13322277P",
day: "1",
month: "2",
year: "1970",
password: "Testing123!",
};

let ppsn: HTMLInputElement = fixture.debugElement.nativeElement.querySelector(
"#ppsn"
);
let day: HTMLInputElement = fixture.debugElement.nativeElement.querySelector(
"#day"
);
let month: HTMLInputElement = fixture.debugElement.nativeElement.querySelector(
"#month"
);
let year: HTMLInputElement = fixture.debugElement.nativeElement.querySelector(
"#year"
);
let password: HTMLInputElement = fixture.debugElement.nativeElement.querySelector(
"#password"
);

ppsn.value = "13322277P";
day.value = "1";
month.value = "1";
year.value = "1970";
password.value = "Testing123!";

fixture.detectChanges();
spyOn(component, "signIn").and.callThrough();
component.signIn();
tick(); // simulates the passage of time until all pending asynchronous activities finish
fixture.detectChanges();
expect(component.signIn).toHaveBeenCalledTimes(1);
expect(component.userDetails).not.toEqual(user);
}));
});
© www.soinside.com 2019 - 2024. All rights reserved.