Reputation: 1551
I am stuck and keep getting error while unit testing an Angular 4 component.
Here's my component:
order-detail.component.ts
@Component({
selector: 'order-detail',
templateUrl: 'order-detail.component.html',
providers: [OrderService]
})
export class OrderDetailComponent implements OnInit {
private order: Order;
constructor(
private orderService: OrderService,
private route: ActivatedRoute,
private router: Router
) {}
ngOnInit() {
this.getOrder();
}
private getOrder(): void {
this.route.paramMap
.map((params: ParamMap) => {
if (+params.get('id') === 0) {
this.router.navigateByUrl('/404', {skipLocationChange: true});
}
return params;
})
.switchMap((params: ParamMap) => this.orderService.getOrder(+params.get('id')))
.subscribe((order: Order) => this.order = order);
}
}
And here is a service:
order.service.ts
@Injectable()
export class OrderService {
private ordersUrl = `${environment.apiUrl}/orders/`;
constructor(private http: HttpClient) {}
getOrder(id: number): Observable<Order> {
return this.http.get(`${this.ordersUrl}${id}/`)
.map(response => response as Order);
}
}
And I want to set a spy on OrderServive
and unit test it with such test:
order-detail.component.spec.ts
describe('Order detail component', () => {
let fixture: ComponentFixture<OrderDetailComponent>;
let page: Page;
let activatedRoute: ActivatedRouteStub;
const fakeOrder: Order = {
id: 1,
title: 'Test 1',
contractor: {title: 'Contractor 1'} as Contractor,
} as Order;
class Page {
orderSpy: jasmine.Spy;
routerSpy: jasmine.Spy;
title: HTMLElement;
constructor() {
const orderService = fixture.debugElement.injector.get(OrderService);
this.orderSpy = spyOn(orderService, 'getOrder').and.returnValue(Observable.of(fakeOrder));
}
}
function createComponent() {
fixture = TestBed.createComponent(OrderDetailComponent);
page = new Page();
fixture.detectChanges();
return fixture.whenStable().then(() => {
fixture.detectChanges();
});
}
beforeEach(() => {
activatedRoute = new ActivatedRouteStub();
});
beforeEach(async(() => {
TestBed.configureTestingModule({
declarations: [OrderDetailComponent],
imports: [RouterTestingModule, HttpClientTestingModule],
providers: [
OrderService,
{provide: ActivatedRoute, useValue: activatedRoute},
{provide: Router, useClass: RouterStub},
],
schemas: [NO_ERRORS_SCHEMA],
}).compileComponents();
}));
describe('when navigate with existing id', () => {
beforeEach(async(() => {
activatedRoute.testParamMap = {id: fakeOrder.id};
createComponent();
}));
it('should show title', () => {
expect(page.orderSpy).toHaveBeenCalledWith(fakeOrder.id);
});
});
});
But I keep getting this error: TypeError: Cannot read property 'subscribe' of undefined
I took ActivatedRouteStub
and test structure from Agular documentation: https://angular.io/guide/testing
Component's code works fine with real data from backend and shows me order.
Also my codebase contains similar test which successfully does the same thing on another component with similar service, so this test is the only place which fails.
Using Angular 4.3.6, Karma 1.7.1 and Jasmine 2.6.4.
What could go wrong and how to get rid of this error?
Upvotes: 2
Views: 11540
Reputation: 1551
After some research I actually figured out what caused the error. I removed
{provide: Router, useClass: RouterStub},
and error was gone. Test is now working perfectly without this stub.
Not sure what was the problem, but I assume that RouterStub
class from docs is missing implementation of some necessary things. Class was taken from here:
https://angular.io/guide/testing#test-a-routed-component
https://angular.io/generated/live-examples/testing/app-specs.eplnkr.html
Upvotes: 4