I am writing unit tests for my component but having trouble in creating the instance of the component and showing following error:
TypeError: Cannot read property 'patientId' of null
I have tried mocking all the providers including router and active router
here is how I am calling the component:
public onSelectedOrganizationInsurance(organizationInsurance: OrganizationInsurance) {
this.router.navigate(['../search-insurance-plan'], {
relativeTo: this.activatedRoute,
state: {
selectedOrganizationInsurance: organizationInsurance,
patientId: this.patientId
}
});
My component.ts is
export class PatientInsurancePlanSearchComponent implements OnInit {
private patientId: number = -1;
public selectedOrganizationInsurance: OrganizationInsurance;
public organizationInsurancePlans$: Observable<OrganizationInsurancePlan[]>;
constructor(
private router: Router,
private activatedRoute: ActivatedRoute,
private biilingHttpService: BillingHttpService
) {
this.selectedOrganizationInsurance = new OrganizationInsurance();
}
ngOnInit() {
this.patientId = history.state.patientId as number;
this.selectedOrganizationInsurance = history.state.selectedOrganizationInsurance as OrganizationInsurance;
this.organizationInsurancePlans$ = this.biilingHttpService.getOrganizationInsurancePlans(this.selectedOrganizationInsurance.id);
}
spec.ts
class FakeInsurancePlanSearchComponent {
#Input() public organizationInsurancePlans: OrganizationInsurancePlan[] = [];
#Input() public selectedOrganizationInsurance: OrganizationInsurance;
}
beforeEach(async(() => {
TestBed.configureTestingModule({
declarations: [ PatientInsurancePlanSearchComponent
, FakeInsurancePlanSearchComponent ],
imports: [
StoreModule.forRoot({}),
HttpClientModule,
RouterTestingModule,
],
providers: [
Store,
{
provide: ActivatedRoute, useValue: {
state: of({ selectedorganizationInsurancePlan: 'AETNA'})
}
},
BillingHttpService
]
})
.compileComponents();
}));
beforeEach(() => {
fixture = TestBed.createComponent(PatientInsurancePlanSearchComponent);
component = fixture.componentInstance;
fixture.detectChanges();
});
it('should create', () => {
expect(component).toBeTruthy();
});
Kindly guide me whats I am missing.
you can access your routing state via "Location" injection of #angular/common.
Like this:
constructor(private readonly location: Location) {}
ngOnInit() {
this.patientId = this.location.getState().patientId as number;
}
now you can create a spy on location in your unit test:
let location: Location;
beforeEach(async(() => {
TestBed.configureTestingModule({
declarations: [ PatientInsurancePlanSearchComponent
, FakeInsurancePlanSearchComponent ],
imports: [
StoreModule.forRoot({}),
HttpClientModule,
RouterTestingModule,
],
providers: [
Store,
BillingHttpService
]
})
.compileComponents();
}));
beforeEach(() => {
location = TestBed.inject(Location);
fixture = TestBed.createComponent(PatientInsurancePlanSearchComponent);
component = fixture.componentInstance;
fixture.detectChanges();
});
it('should create', () => {
spyOn(location, 'getState').and.returnValue(yourObject);
expect(component).toBeTruthy();
});
Related
I am trying to test my router event this is what te code in the TS file look like:
constructor(
private router: Router
) {
router.events.subscribe(route => {
// I removed the code because it doesn`t matter for the solution
});
}
unittest:
describe('MainComponent', () => {
let methodSpy: jasmine.Spy;
const eventSubject = new ReplaySubject<RouterEvent>(1);
const routerMock = {
navigate: jasmine.createSpy('navigateByUrl'),
navigateByUrl: jasmine.createSpy('navigateByUrl'),
events: eventSubject.asObservable(),
url: 'test/url',
createUrlTree: (commands, navExtras = {}) => {},
serializeUrl: (commands, navExtras = {}) => {}
}
beforeEach(async(() => {
TestBed.configureTestingModule({
imports: [RouterTestingModule, FormsModule],
declarations: [],
providers: [
{ provide: Router, useValue: routerMock},
{ provide: ActivatedRoute, useValue: routerMock},
]
})
.compileComponents();
}));
beforeEach(() => {
fixture = TestBed.createComponent(MainComponent);
component = fixture.componentInstance;
methodSpy = spyOn(component, 'AdminPanelStarted');
//fixture.detectChanges();
});
it('should trigger the router event and hit the function "Panel"', () => {
eventSubject.next(new NavigationEnd(1, 'test', 'routeUrl'));
expect(methodSpy).toHaveBeenCalled();
});
});
this is the error I am getting:
I can`t find the solution. The only thing I want to test is if the correct function have been called after entering the router.events subscription. The observable is triggered but gives the error that startsWith can not be done on undefined. But what is undefined?
Thx a Lot!
I am trying to write a unit test of an angular 6 component which is initializing the bootstrap-daterangepicker in the ngAfterViewInit() method. When I run my unit test it gives the following error:
TypeError: $(...).daterangepicker is not a function
this is the code from the actual component(EmployeeComponent):
ngAfterViewInit(): void {
this.initializeDatePicker(this);
}
initializeDatePicker(that: any) {
const start = moment().subtract(7, 'days');
const end = moment();
$('#reportrange').daterangepicker({
startDate: start,
endDate: end,
maxDate: moment(),
ranges: {
'Today': [moment(), moment()],
'Yesterday': [moment().subtract(1, 'days'), moment().subtract(1, 'days')]
}
}, cb);
cb(start, end);
}
this is the code from my test class:
describe('EmployeeComponent', () => {
let component: EmployeeComponent;
let fixture: ComponentFixture<EmployeeComponent>;
let messageService: NotificationService;
beforeEach(async(() => {
TestBed.configureTestingModule({
declarations: [EmployeeComponent]
})
.overrideComponent(EmployeeComponent, {
set: {
template: '',
providers: [
{ provide: NotificationService, useValue: messageService },
{ provide: ActivatedRoute, useValue: { queryParams: of({ emp: "123" }) } }
]
}
})
.compileComponents();
}));
beforeEach(() => {
fixture = TestBed.createComponent(EmployeeComponent);
component = fixture.componentInstance;
fixture.detectChanges();
});
it('should create', () => {
expect(component).toBeTruthy();
});
You don't need to handle it in your test cases. That component should be initialized in a separate service and you can simply mock that method from the service. In the way you can avoid this error.
let say you move all the code of the initializeDatePicker() in a method in some service let say common-service.ts and you can simply call that service from this method like
this.commonServiceObj.initializeDatePicker();
Now after doing this, you can simply mock initializeDatePicker() from the service object and error should be gone.
So, I'm getting the error TypeError: Cannot read property 'subscribe' of undefined for all the test cases in my module. In my component I'm injecting "ActivatedRoute" and "Router" and in my ngOnInit(), I'm getting some data that I'm passing within the routing-module.
These are the files I have:
custom-routing.module.ts
const casesRoutes: Routes = [
{
path: '',
component: MainComponent,
children: [
{
path: '',
component: CustomComponent,
resolve: {
someData: CustomResolver
},
children: [
{
path: 'child',
component: ChildComponent
}
]
},
{
path: ':id/edit',
component: CaseEditComponent,
resolve: {
theCase: CaseDetailResolver
}
}
]
}
];
#NgModule({
imports: [
RouterModule.forChild(casesRoutes)
],
exports: [
RouterModule
],
providers: [
CustomResolver
]
})
export class CustomRoutingModule { }
custom.component.ts
#Component({
selector: 'my-custom',
styleUrls: ['./custom.component.css'],
templateUrl: './custom.component.html',
})
export class CustomComponent implements OnInit {
public someData: TheData;
constructor(private route: ActivatedRoute, private router: Router) { }
public ngOnInit(): void {
this.route.data.subscribe((data) => {
this.someData = data.someData;
});
}
public navigateTo(): void {
this.router.navigate(['child'], { relativeTo: this.route });
}
}
custom.component.spec.ts
describe('CustomComponent', () => {
let comp: CustomComponent;
let fixture: ComponentFixture<CustomComponent>;
let router = {
navigate: jasmine.createSpy('navigate')
}
beforeEach(async(() => {
TestBed.configureTestingModule({
imports: [
RouterTestingModule
],
declarations: [
CustomComponent
],
providers: [
{
provide: ActivatedRoute,
useValue: {
data: Observable.of({
someData: { id: 1, lastName: 'Last', firstName: 'First' }
})
}
},
{
provide: Router,
useValue: router
}
]
}).compileComponents();
}));
beforeEach(async(() => {
fixture = TestBed.createComponent(CustomComponent);
comp = fixture.componentInstance;
fixture.detectChanges();
}));
it('should create component', () => {
expect(comp).toBeDefined();
});
it('should initialize the component correctly and expect some data returned from ActivatedRoute', () => {
comp.ngOnInit();
expect(comp.someData).toBeDefined();
});
it('should verify the navigate method from router is called', () => {
comp.navigateTo();
expect(router.navigate).toHaveBeenCalled();
});
});
At first I thought it could be breaking because of the statement in ngOnInit() since it's the only case I'm using the subscribe method but even the first test where I check the component is defined, is failing. I even added some console.info() calls to review that this.route.data in the component has some data and it actually has so I have no idea what could be causing it.
I'm pretty new in unit testing in Angular 2 so i'm asking your help.
My logout function :
logOut() {
this.authService.logOut().subscribe(() => {
this.router.navigate(['login']);
});
}
And my unit test :
describe('HomeComponent', () => {
let component: HomeComponent;
let fixture: ComponentFixture<HomeComponent>;
let authenticationService: AuthenticationService;
let mockLogOut = {
logOut: () => { }
};
beforeEach(async(() => {
TestBed.configureTestingModule({
imports: [
FormsModule,
HttpModule,
CommonModule,
ReactiveFormsModule,
TranslateModule,
RouterTestingModule.withRoutes([
{ path: 'login', component: LoginComponent }
])
],
declarations: [HomeComponent, LoginComponent],
providers: [
{ provide: AuthenticationService, useValue: mockLogOut },
TranslateService,
TRANSLATION_PROVIDERS
],
schemas: [CUSTOM_ELEMENTS_SCHEMA]
})
.compileComponents();
}));
beforeEach(() => {
fixture = TestBed.createComponent(HomeComponent);
authenticationService = TestBed.get(AuthenticationService);
component = fixture.componentInstance;
fixture.detectChanges();
});
it('should create', () => {
expect(component).toBeTruthy();
});
describe('Authentication Tests', () => {
it('should log out the user', inject([AuthenticationService], (mockLogin: AuthenticationService) => {
fakeAsync(() => {
spyOn(authenticationService, 'logOut');
let navigateSpy = spyOn((<any>component).router, 'navigate');
component.logOut();
expect(mockLogin.logOut).toHaveBeenCalled();
expect(navigateSpy).toHaveBeenCalledWith(['/log1n']);
});
}));
});
});
I want to check if the user is redirected to the route /login but this test always success even if I put something else than /login
I have this function I need to test:
login(): void {
this.userService.setSessionAndDateOnlogin();
this.loginService.getLogin()
.subscribe(
octopusUrl => window.location.href = octopusUrl);
}
I use the window.location.href to navigate to an external URL.
This is my test:
it('login function should call the setSessionAndDateOnLogin function from the userservice and\
subscribe to the getLogin function of the loginService.',
fakeAsync(
inject(
[LoginComponent, LoginService, UserService],
(loginComponent: LoginComponent, loginService: LoginService, userService: UserService) => {
spyOn(userService, 'setSessionAndDateOnlogin');
loginComponent.login();
expect(userService.setSessionAndDateOnlogin).toHaveBeenCalled();
})
)
);
When I run this test, I get the following error:
Some of your tests did a full page reload!
So I tried to mock the window-object:
import { window } from '#angular/platform-browser/src/facade/browser';
...
class MockWindow {
location: {
href: ''
};
}
...
beforeEach(() => addProviders([
...
{ provide: window, useClass: MockWindow }
]));
This changed nothing and the error remains.
Does anyone has a solution for this issue?
Window is an interface and that cannot be injected. You should use OpaqueToken
import {Injectable, OpaqueToken, Inject} from '#angular/core';
export const WindowToken = new OpaqueToken('Window');
export const SomeServiceWithWindowDependencyToken = new OpaqueToken('SomeServiceWithWindowDependency');
export function _window(): Window {
return window;
}
export class SomeServiceWithWindowDependency {
private window: Window;
constructor(#Inject(WindowToken) window: Window) {
this.window = window;
}
}
Then in tests
describe('SomeServiceWithWindowDependency', () => {
beforeEach(() => {
let mockWindow: any = {
location: {
hostname: ''
}
};
TestBed.configureTestingModule({
providers: [
{provide: WindowToken, useValue: mockWindow},
{provide: SomeServiceWithWindowDependencyToken, useClass: SomeServiceWithWindowDependency}
]
});
});
it('should do something', inject([SomeServiceWithWindowDependencyToken, WindowToken], (tested: SomeServiceWithWindowDependency, window: Window) => {
window.location.hostname = 'localhost';
expect(tested.someMethod()).toBe('result');
}));
});
And remember to configure app module to use real window object
#NgModule({
declarations: [
...
],
imports: [
...
],
providers: [
...
{provide: WindowToken, useFactory: _window},
],
bootstrap: [AppComponent]
})
export class AppModule {
}