karmaTypeError "Cannot read property 'subscribe' of undefined"
karma TypeError "Cannot read property 'subscribe' of undefined"
在测试具有共享服务的简单组件时,出现以下错误消息,我无法使其正常工作,我已经尝试了所有方法!
TypeError: Cannot read property 'subscribe' of undefined
lr.component.ts
export class LrComponent implements OnDestroy {
currentRouter: string;
private subscription: Subscription;
constructor(private lrService: LrService) {
this.subscription = this.lrService.lrNavigation$.subscribe(
(currentNav: string) => {
this.currentRouter = currentNav;
},
(error) => {
console.warn(error);
}
);
}
ngOnDestroy() {
if (this.subscription) {
this.subscription.unsubscribe();
}
}
}
lr.service.ts
@Injectable()
export class LrService {
// Observables for our components to subscribe to.
lrNavigation$: Observable<string>;
// Subjects to return data to subscribed components
private lrNavigationSubject = new Subject<string>();
constructor() {
this.lrNavigation$ = this.lrNavigationSubject.asObservable();
}
// Triggers subscribed components
lrNavigate(currentNav: string) {
this.lrNavigationSubject.next(currentNav);
}
}
任意-random.component.ts
// In another component we send the string that we want the subscribed component (LrComponent) to receieve
this.lrService.lrNavigate('LR');
lr.component.spec.ts
class MockRouter {
navigate = jasmine.createSpy('navigate');
}
class MockActivatedRoute {
params = jasmine.createSpy('params');
}
class MockLrService extends LrService {
lrNavigation$: Observable<string> = new Subject<string>().asObservable();
constructor() {
super();
}
lrNavigate(currentRouter: string) {
return Observable.of(['LR']);
}
}
export function main() {
describe('LrComponent', () => {
let fixture: ComponentFixture<LrComponent>;
let component: LrComponent;
let lrService: LrService;
beforeEach(async(() => {
TestBed.configureTestingModule({
declarations: [
LrComponent,
LrMappingsComponent,
LrCategoriesComponent,
],
imports: [
RouterTestingModule,
CommonModule,
LrRoutingModule,
SharedModule,
AgGridModule.withComponents(
[
CaseSensitiveFilterComponent,
ButtonComponent,
ColumnHeaderComponent,
TypeaheadEditorComponent,
ButtonGroupComponent
]
)
],
providers: [
{ provide: LrService, useClass: MockLrService },
{ provide: Router, useClass: MockRouter },
{ provide: ActivatedRoute, useClass: MockActivatedRoute },
]
}).compileComponents();
}));
beforeEach(() => {
fixture = TestBed.createComponent(LrComponent);
component = fixture.componentInstance;
lrService = fixture.debugElement.injector.get(LrService);
});
it('should create LrComponent', () => {
fixture.detectChanges();
expect(component).toBeDefined();
});
it('should have the current router set', async(() => {
fixture.detectChanges();
expect(component.currentRouter).toEqual('LR', 'the data should be `LR`');
}));
});
}
错误
注意:
如果我使用 ONLY Jasmine,没有 Angular 测试框架的东西,它就可以工作。但这不是我想要测试 @Component
的方式。
示例:
export function main() {
describe('LrComponent', () => {
let fixture: ComponentFixture<LrComponent>;
let component: LrComponent;
let lrService: LrService;
beforeEach(() => {
lrService = new MockLrService();
component = new LrComponent(lrService);
});
it('should create LrComponent', () => {
fixture.detectChanges();
expect(component).toBeDefined();
});
});
}
这可行,但不是我想要的。
关于如何解决这个问题的任何线索?我真的尝试了很多东西并且 none 成功了...
好的,我会自己回答,以防有人遇到同样的问题。
结果是删除:
{ provide: Router, useClass: MockRouter }
问题已解决。我真的不知道为什么。我确信这是来自服务的 Observables 的一些问题...
这些依赖关系在这里是因为:
it('should be able to navigate through tabs',
fakeAsync((inject([Router, Location], (router: Router, location: Location) => {
router.initialNavigation();
let tabLinks, a1, a2;
fixture.detectChanges();
tabLinks = fixture.debugElement.queryAll(By.css('a.mappings'));
a1 = tabLinks[0];
a2 = tabLinks[1];
a1.triggerEventHandler('click', { button: 0 });
tick();
expect(location.path()).toEqual('lrMappings');
a2.nativeElement.click();
tick();
expect(location.path()).toEqual('categories');
}))));
但是,将它们从 providers
中移除并像此处所示那样注入它们就可以了。
在测试具有共享服务的简单组件时,出现以下错误消息,我无法使其正常工作,我已经尝试了所有方法!
TypeError: Cannot read property 'subscribe' of undefined
lr.component.ts
export class LrComponent implements OnDestroy {
currentRouter: string;
private subscription: Subscription;
constructor(private lrService: LrService) {
this.subscription = this.lrService.lrNavigation$.subscribe(
(currentNav: string) => {
this.currentRouter = currentNav;
},
(error) => {
console.warn(error);
}
);
}
ngOnDestroy() {
if (this.subscription) {
this.subscription.unsubscribe();
}
}
}
lr.service.ts
@Injectable()
export class LrService {
// Observables for our components to subscribe to.
lrNavigation$: Observable<string>;
// Subjects to return data to subscribed components
private lrNavigationSubject = new Subject<string>();
constructor() {
this.lrNavigation$ = this.lrNavigationSubject.asObservable();
}
// Triggers subscribed components
lrNavigate(currentNav: string) {
this.lrNavigationSubject.next(currentNav);
}
}
任意-random.component.ts
// In another component we send the string that we want the subscribed component (LrComponent) to receieve
this.lrService.lrNavigate('LR');
lr.component.spec.ts
class MockRouter {
navigate = jasmine.createSpy('navigate');
}
class MockActivatedRoute {
params = jasmine.createSpy('params');
}
class MockLrService extends LrService {
lrNavigation$: Observable<string> = new Subject<string>().asObservable();
constructor() {
super();
}
lrNavigate(currentRouter: string) {
return Observable.of(['LR']);
}
}
export function main() {
describe('LrComponent', () => {
let fixture: ComponentFixture<LrComponent>;
let component: LrComponent;
let lrService: LrService;
beforeEach(async(() => {
TestBed.configureTestingModule({
declarations: [
LrComponent,
LrMappingsComponent,
LrCategoriesComponent,
],
imports: [
RouterTestingModule,
CommonModule,
LrRoutingModule,
SharedModule,
AgGridModule.withComponents(
[
CaseSensitiveFilterComponent,
ButtonComponent,
ColumnHeaderComponent,
TypeaheadEditorComponent,
ButtonGroupComponent
]
)
],
providers: [
{ provide: LrService, useClass: MockLrService },
{ provide: Router, useClass: MockRouter },
{ provide: ActivatedRoute, useClass: MockActivatedRoute },
]
}).compileComponents();
}));
beforeEach(() => {
fixture = TestBed.createComponent(LrComponent);
component = fixture.componentInstance;
lrService = fixture.debugElement.injector.get(LrService);
});
it('should create LrComponent', () => {
fixture.detectChanges();
expect(component).toBeDefined();
});
it('should have the current router set', async(() => {
fixture.detectChanges();
expect(component.currentRouter).toEqual('LR', 'the data should be `LR`');
}));
});
}
错误
注意:
如果我使用 ONLY Jasmine,没有 Angular 测试框架的东西,它就可以工作。但这不是我想要测试 @Component
的方式。
示例:
export function main() {
describe('LrComponent', () => {
let fixture: ComponentFixture<LrComponent>;
let component: LrComponent;
let lrService: LrService;
beforeEach(() => {
lrService = new MockLrService();
component = new LrComponent(lrService);
});
it('should create LrComponent', () => {
fixture.detectChanges();
expect(component).toBeDefined();
});
});
}
这可行,但不是我想要的。
关于如何解决这个问题的任何线索?我真的尝试了很多东西并且 none 成功了...
好的,我会自己回答,以防有人遇到同样的问题。
结果是删除:
{ provide: Router, useClass: MockRouter }
问题已解决。我真的不知道为什么。我确信这是来自服务的 Observables 的一些问题...
这些依赖关系在这里是因为:
it('should be able to navigate through tabs',
fakeAsync((inject([Router, Location], (router: Router, location: Location) => {
router.initialNavigation();
let tabLinks, a1, a2;
fixture.detectChanges();
tabLinks = fixture.debugElement.queryAll(By.css('a.mappings'));
a1 = tabLinks[0];
a2 = tabLinks[1];
a1.triggerEventHandler('click', { button: 0 });
tick();
expect(location.path()).toEqual('lrMappings');
a2.nativeElement.click();
tick();
expect(location.path()).toEqual('categories');
}))));
但是,将它们从 providers
中移除并像此处所示那样注入它们就可以了。