问题
I am relatively new to testing in Angular2+ and am setting up my files for testing. Since building the project, I've written a lot of code and am now trying to test parts of it. However, lots of those tests are now broken so I am now trying to delete the unneeded default tests or fix the ones that are useful.
This particular test won't run because it fails before it hits the It() testing method. I'm not sure what I'm missing, any help would be appreciated.
I am receiving this error:
Failed: Cannot read property 'subscribe' of undefined
TypeError: Cannot read property 'subscribe' of undefined
at AppComponent../src/app/app.component.ts.AppComponent.setupLanguageTranslation (src/app/app.component.ts:48:26)
at AppComponent../src/app/app.component.ts.AppComponent.ngOnInit (src/app/app.component.ts:32:14)
at checkAndUpdateDirectiveInline (node_modules/@angular/core/fesm5/core.js:22089:1)
at checkAndUpdateNodeInline (node_modules/@angular/core/fesm5/core.js:23353:1)
at checkAndUpdateNode (node_modules/@angular/core/fesm5/core.js:23315:1)
at debugCheckAndUpdateNode (node_modules/@angular/core/fesm5/core.js:23949:1)
at debugCheckDirectivesFn (node_modules/@angular/core/fesm5/core.js:23909:1)
at Object.eval [as updateDirectives] (ng:///DynamicTestModule/AppComponent_Host.ngfactory.js:9:9)
at Object.debugUpdateDirectives [as updateDirectives] (node_modules/@angular/core/fesm5/core.js:23901:1)
at checkAndUpdateView (node_modules/@angular/core/fesm5/core.js:23297:1)
I've tried a variety of articles with similar issues including, but not limited to:
- Cannot read property 'subscribe' of undefined after running npm test (Angular 2 unit testing)
- https://www.reddit.com/r/Angular2/comments/87w8su/what_am_im_doing_wrong_with_observables_and/
- karma TypeError "Cannot read property 'subscribe' of undefined"
App.component.ts
export class AppComponent implements OnInit, OnDestroy {
title = 'planox';
showError = false;
errorMessage = '';
translatedText: string;
constructor(private _translate: TranslateService,
private utils: Utils) {}
ngOnInit(): void {
this.setupLanguageTranslation();
}
ngOnDestroy(): void {
this._translate.onLangChanged.unsubscribe();
}
setupLanguageTranslation() {
this.subscribeToLangChanged();
// set language
this._translate.setDefaultLang('en'); // set English as default
this._translate.enableFallback(true); // enable fallback
// set current language
this.selectLang('en');
this.utils.error.subscribe(response => {
this.errorMessage = response;
this.showError = true;
setTimeout( () => {
this.showError = false;
}, 2000);
});
}
selectLang(lang: string) {
// set default;
this._translate.use(lang);
}
subscribeToLangChanged() {
// refresh text
this.refreshText();
return this._translate.onLangChanged.value;
}
refreshText() {
// refresh translation when language change
this.translatedText = this._translate.instant('hello world');
}
}
app.component.spec.ts
import {TestBed, async, ComponentFixture, inject} from '@angular/core/testing';
import { RouterTestingModule } from '@angular/router/testing';
import { AppComponent } from './app.component';
import {TranslateService} from './translate/translate.service';
import Utils from './shared/utils';
import {MockTranslateService} from './mocks/mockTranslateService';
import {MockUtils} from './mocks/mockUtils';
import {TRANSLATIONS} from './translate/translation';
describe('AppComponent', () => {
let fixture: ComponentFixture<AppComponent>;
beforeEach(async(() => {
const mockTranslate = new MockTranslateService(TRANSLATIONS);
TestBed.configureTestingModule({
imports: [
RouterTestingModule
],
declarations: [
AppComponent
],
providers: [
{provide: TranslateService, useValue: mockTranslate},
{provide: Utils, useValue: MockUtils},
]
});
fixture = TestBed.createComponent(AppComponent);
fixture.detectChanges();
}));
it('should create the app', () => {
fixture = TestBed.createComponent(AppComponent);
const app = fixture.debugElement.componentInstance;
expect(app).toBeTruthy();
});
});
Utils.ts:
import {Subject, throwError} from 'rxjs';
import {Injectable} from '@angular/core';
import {Router} from '@angular/router';
import {Role} from '../classes/role/role.enum';
export enum KEY_CODE {
ENTER = 13,
RIGHT_ARROW = 39,
LEFT_ARROW = 37
}
@Injectable({
providedIn: 'root'
})
export default class Utils {
error: Subject<string> = new Subject<string>();
constructor(private router: Router) {}
handleError(service: string, error: Response | any, customMessage?: string) {
const err = service + '::handleError' + '= ' + error;
this.error.next(customMessage);
return throwError(error);
}
encodeBase64(value: any) {
return btoa(JSON.stringify(value));
}
decodeBase64(value: any) {
return atob(value);
}
navigateToDefaultPage(usersRole: Role) {
if (usersRole === Role.Employee) {
this.router.navigate(['/dashboardNavigation', {outlets: {dashNav: ['productionDashboard']}}]);
} else if (usersRole === Role.Client) {
this.router.navigate(['/clientDashboard']);
} else if (usersRole === Role.OfficeAdmin) {
this.router.navigate(['/dashboardNavigation', {outlets: {dashNav: ['enterpriseDashboard']}}]);
} else {
this.router.navigate(['/auth']);
}
}
validateEmail(inputText: string) {
const mailFormat = /^\w+([\.-]?\w+)*@\w+([\.-]?\w+)*(\.\w{2,3})+$/;
if (inputText.match(mailFormat)) {
return true;
} else {
return false;
}
}
}
mockUtils.ts
import Utils from "../shared/utils";
import {Subject} from "rxjs";
export class MockUtils extends Utils {
error = new Subject<string>();
}
Basically I need help setting up the structure of the testing page so that I can start writing useful tests.
I can provide any additional code you may need to help, wasn't sure what all would be needed for this.
回答1:
delete fixture.detectChanges() from the beforeEach method, remove it from there, and moving it into each test if needed will fix it for you, i think it's a bug, seen it on Angular 6 and Angular 7
so your beforeEach will change to:
beforeEach(async(() => {
const mockTranslate = new MockTranslateService(TRANSLATIONS);
TestBed.configureTestingModule({
imports: [
RouterTestingModule
],
declarations: [
AppComponent
],
providers: [
{provide: TranslateService, useValue: mockTranslate},
{provide: Utils, useValue: MockUtils},
]
});
fixture = TestBed.createComponent(AppComponent);
// detection deleted here
}));
来源:https://stackoverflow.com/questions/55958449/why-am-i-getting-a-failed-cannot-read-property-subscribe-of-undefined-while