Я использую следующий код для имитации зависимости с authservice:
login.component.spec
import { LoginComponent } from "./login.component";
import { ComponentFixture, inject, TestBed } from "@angular/core/testing";
import { async } from "q";
import { MatCardModule } from "@angular/material";
import { AuthService } from "../../services/auth/auth.service";
import { Log } from "@angular/core/testing/src/logger";
import { NO_ERRORS_SCHEMA } from "@angular/core";
class MockAuthService extends AuthService {
isAuthenticated() {
return "Mocked";
}
}
describe("LoginComponent", () => {
let component: LoginComponent;
let fixture: ComponentFixture<LoginComponent>;
let componentService: AuthService;
beforeEach(async(() => {
TestBed.configureTestingModule({
declarations: [LoginComponent],
providers: [AuthService],
imports: [MatCardModule]
});
TestBed.overrideComponent(LoginComponent, {
set: { providers: [{ provide: AuthService, useClass: MockAuthService }] }
});
fixture = TestBed.createComponent(LoginComponent);
component = fixture.componentInstance;
componentService = fixture.debugElement.injector.get(AuthService);
}));
it("Service injected via component should be and instance of MockAuthService", () => {
expect(componentService instanceof MockAuthService).toBeTruthy();
});
});
login.component
import {Component, OnInit} from '@angular/core';
import {AuthService} from '../../services/auth/auth.service';
import {Router} from '@angular/router';
import {GithubService} from '../../services/github/github.service';
import {Errorcode} from './errorcode.enum';
@Component({
selector: 'app-login',
templateUrl: './login.component.html',
styleUrls: ['./login.component.sass'],
})
export class LoginComponent implements OnInit {
public loginError: string | boolean = false;
constructor(public authService: AuthService, public router: Router, private data: GithubService) {
}
public signInWithGithub(): void {
this.authService.loginwithGithubProvider()
.then(this.loginError = null)
.catch(err => {
if (err === Errorcode.FIREBASE_POPUP_CLOSED) {
this.loginError = 'The popup has been closed before authentication';
}
if (err === Errorcode.FIREBASE_REQUEST_EXESS) {
this.loginError = 'To many requests to the server';
}
}
);
}
public logout(): void {
this.authService.logout();
}
ngOnInit() {
}
}
Но если я посмотрю на результаты, я продолжу получать следующую ошибку:
Error: StaticInjectorError(DynamicTestModule)[AuthService -> AngularFireAuth]: StaticInjectorError(Platform: core)[AuthService -> AngularFireAuth]: NullInjectorError: No provider for AngularFireAuth! in http://localhost:9876/_karma_webpack_/vendor.js (line 59376)
Есть идеи, как я могу это решить?
@dmcgrandle, конечно, я добавил!
Я воспроизвел вашу проблему в Stackblitz. В настоящее время в Stackblitz все тесты проходят, но вы заметите, что я закомментировал ваше объявление MockAuthService следующим образом:
// class MockAuthService extends AuthService {
// isAuthenticated() {
// return "Mocked";
// }
// }
и заменил его на:
class MockAuthService implements Partial<AuthService> {
isAuthenticated() {
return "Mocked";
}
loginwithGithubProvider() {
return new Promise((resolve, reject) => resolve())
}
logout() {}
}
Следует отметить ключевое отличие: я заменил extends
на implements
.
Чтобы воспроизвести свою ошибку, просто закомментируйте мое новое объявление MockAuthService и раскомментируйте исходное. Ошибка, которую вы описали выше, появится снова.
Причина этого в том, что при расширении класса вы получаете все объекты, свойства, методы и т. д. Существующего класса включая конструктор. В вашем случае я совершенно уверен, что конструктор исходного класса AuthService
внедрил AngularFireAuth, как и я в Stackblitz в файле support.service.ts
, где я реализовал заглушку AuthService
. Когда вы расширили класс, а затем внедрили его в TestBed, когда вы переопределили компонент, а затем попытались создать компонент, он попытался выполнить конструктор в этом исходном классе. Однако для AngularFireAuth не был указан поставщик, поэтому он выдал ошибку, которую вы видите. Простое добавление AngularFireAuth в массив поставщиков было бы неправильным решением, потому что вы пытаетесь протестировать компонент, а не службу.
Когда я хочу внедрить фиктивный класс в набор тестов, как вы это сделали здесь, я обычно использую implements
, а затем Partial<>
, чтобы мне не приходилось реализовывать все методы и свойства исходного класса, и чтобы я только издевался над тем, что я хочу, а не тащил за собой детали реализации исходного класса.
Существует довольно хорошее обсуждение различий между implements
и extends
здесь.
Еще несколько примечаний:
Router
и GithubService
. Обратите внимание, что я сделал это как шпион, а не как насмешку над классом обслуживания, просто чтобы показать другой способ сделать это. Я заметил, что вы импортировали NO_ERRORS_SCHEMA
, вероятно, чтобы не определять их. Я сам не использую эту схему, хотя она кажется довольно популярной, поскольку я не хочу маскировать ошибки - я бы предпочел, чтобы они были обнаружены и исправлены. :)signInWithGithub()
.Надеюсь, это поможет.
Спасибо! я уверен, что это мне поможет!
работал отлично! Еще один вопрос, раз уж вы мне так помогли. Как вы можете проверить, установлено ли для loginError определенное сообщение об ошибке после того, как обещание было отклонено?
@KevinvanSchaijk - не знаю, как я так долго пропустил этот комментарий, приношу свои извинения! Я обновил Stackblitz несколькими примерами того, как тестировать различные значения loginError
, возвращаемые из отклоненного обещания. Надеюсь, это все еще помогает. :) Примечание: это также выявило ошибку в том, как вы настроили .then()
в компоненте - это должна быть функция, например: подробности .then(() => this.loginError = null)
в Stackblitz.
Подскажите пожалуйста код в
login.component.ts
?