How do I mock a component variable/object in Angular2? - unit-testing

This is my template:
<ion-label stacked>{{"goal_settings.goalname" | translate }}</ion-label>
I am getting the error: No value accessor for ""
This is my test:
describe('Goal Settings', () => {
let tcb;
let navParams;
let viewController;
let events;
// Providers and Mock Providers
beforeEachProviders(() => [
TestComponentBuilder,
HTTP_PROVIDERS,
provide(NavParams, {useClass: MockNavParams}),
provide(ViewController, {useClass: MockViewController}),
provide(Events, {useClass: MockEvents}),
provide('goal_settings', { useValue: [ {
goalname: "Super",
amount:"Super",
monthlypayment:"Super",
choosefund:"Super",
date:"Super",
guaranteelevel:"Super"
}]}),
provide(TranslateService, {
useFactory: (http: Http) => new TranslateStaticLoader(http, 'assets/i18n', '.json'),
deps: [Http]
}),
provide(TranslateLoader, {
useFactory: (http: Http) => new TranslateStaticLoader(http, 'assets/i18n', '.json'),
deps: [Http]
}),
provide(XHRBackend, { useClass: MockBackend })
]);
beforeEach(inject(
[
TestComponentBuilder,
NavParams,
ViewController,
Events
],
(
_tcb,
_navParams,
_viewController,
_events
) => {
tcb = _tcb
navParams = _navParams
viewController = _viewController
events = _events
}));
it('should contain <ion-title> directive', () => {
return tcb.createAsync(GoalSettingsPage).then((fixture) => {
fixture.detectChanges();
var compiled = fixture.debugElement.nativeElement;
expect(compiled.innerHTML).toContain('ion-title');
});
});
I think the problem is that goal_settings is wrongly mocked by me..

Related

Angular8 Unittest Router Events

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!

ionic 5 unit test with popover controller

I am trying to spy popover present method in my ionic 5 / angular 11 project but getting an error
Unhandled Promise rejection: Cannot read property 'then' of undefined
Here is unit test code
describe('LoginPage', () => {
let popoverSpy = jasmine.createSpyObj('Popover', ['create', 'present', 'onDidDismiss', 'dismiss']);
let popoverCtrlSpy = jasmine.createSpyObj('PopoverController', ['create']);
popoverCtrlSpy.create.and.callFake(function () {
return popoverSpy;
});
beforeEach(waitForAsync(() => {
TestBed.configureTestingModule({
declarations: [LoginPage],
imports: [
IonicModule.forRoot(),
TranslateModule.forChild(),
ComponentsModule,
TranslateModule.forRoot({
loader: { provide: TranslateLoader, useClass: TranslateFakeLoader }
})
],
providers: [{ provide: PopoverController, useValue: popoverCtrlSpy }]
}).compileComponents()
it("check popover preset", () => {
component.openEntitySelection();
fixture.detectChanges();
expect(popoverSpy.present).toHaveBeenCalled()
})
}
private async openEntitySelection() {
let popover = await this.popoverCtrl.create({
component: PopoverPage
});
await popover.present();
popover.onDidDismiss().then((response) => {
//Handle response
})
}
Thanks in advance!
It seems you're not mocking onDidDismiss to return a promise. You also need to use fixture.whenStable or waitForAsync utilities to wait for the promise to be resolved before doing your assertion.
Try this:
describe('LoginPage', () => {
let popoverSpy = jasmine.createSpyObj('Popover', ['create', 'present', 'onDidDismiss', 'dismiss']);
// !! -- Add this line -- !!
// I am mock resolving it to a value of true, you can resolve it to any value
popOverSpy.onDidDismiss.and.returnValue(Promise.resolve(true));
// !! --- !!
let popoverCtrlSpy = jasmine.createSpyObj('PopoverController', ['create']);
popoverCtrlSpy.create.and.callFake(function () {
return popoverSpy;
});
beforeEach(waitForAsync(() => {
TestBed.configureTestingModule({
declarations: [LoginPage],
imports: [
IonicModule.forRoot(),
TranslateModule.forChild(),
ComponentsModule,
TranslateModule.forRoot({
loader: { provide: TranslateLoader, useClass: TranslateFakeLoader }
})
],
providers: [{ provide: PopoverController, useValue: popoverCtrlSpy }]
}).compileComponents()
it("check popover preset", (done) => { // add done to let jasmine know you're done
component.openEntitySelection();
fixture.detectChanges();
// you have to wait at least for one fixture.whenStable I am thinking
// because we are returning a promise and we have to ensure that the promises
// have completed before doing our assertion.
fixture.whenStable().then(() => {
expect(popoverSpy.present).toHaveBeenCalled();
done();
});
});
}
private async openEntitySelection() {
let popover = await this.popoverCtrl.create({
component: PopoverPage
});
await popover.present();
popover.onDidDismiss().then((response) => {
//Handle response
})
}
Argument of type 'Promise' is not assignable to parameter of type 'Promise<OverlayEventDetail>'.
Type 'boolean' has no properties in common with type 'OverlayEventDetail'

Jasmine/karma test case are not running in an orderly manner using Angular5

When running the test case using jasmine/karma test cases. I am facing n issue which is before starting with the Login spec test case the other spec files are all called before completing the Login. It need to happen in an orderly manner which is like
1.Login
2.Dashboard
3.Order
etc.
Is there a way to do this.
login.spec.ts file
import { async, ComponentFixture, TestBed } from '#angular/core/testing';
import { RouterModule, Router } from '#angular/router';
import { LoginComponent } from './login.component';
import { DebugElement } from '#angular/core';
import { FormsModule, ReactiveFormsModule } from '#angular/forms';
import { BrowserModule, By } from '#angular/platform-browser';
import { Ng2Bs3ModalModule } from 'ng2-bs3-modal/ng2-bs3-modal';
import { RouterTestingModule } from '#angular/router/testing';
import { APP_BASE_HREF } from '#angular/common';
import { LoginService } from './login.service';
import { HttpClientModule } from '#angular/common/http';
import { ApiService } from '../config/api.service';
import { ConfigService } from '../config/config.service';
import { Constants } from '../config/Constant';
import { SharedService } from '../shared/shared.service';
import { Http, BaseRequestOptions, ResponseOptions, Response, RequestMethod } from '#angular/http';
import { inject } from '#angular/core/testing';
import { MockBackend, MockConnection } from '#angular/http/testing';
describe('LoginComponent', () => {
let comp: LoginComponent;
let fixture: ComponentFixture<LoginComponent>;
let de: DebugElement;
let el: HTMLElement;
let userNameEl: DebugElement;
let passwordEl: DebugElement;
let submitEl: DebugElement;
let loginService: LoginService = null;
let backend: MockBackend = null;
TestBed.overrideComponent(LoginComponent, {
set: {
providers: [
{
provide: LoginService,
useValue: loginService
},
{
provide: Router,
useClass: class { navigate = jasmine.createSpy('navigate'); }
}
]
}
});
beforeEach(async(() => {
// loginService = loginService;
// backend = mockBackend;
TestBed.configureTestingModule({
declarations: [
LoginComponent
],
imports: [
RouterModule.forRoot([{
path: '',
component: LoginComponent
}]),
BrowserModule,
FormsModule,
ReactiveFormsModule,
Ng2Bs3ModalModule,
RouterTestingModule,
HttpClientModule
],
providers: [
MockBackend,
BaseRequestOptions,
{
provide: Http,
useFactory: (backendInstance: MockBackend, defaultOptions: BaseRequestOptions) => {
return new Http(backendInstance, defaultOptions);
},
deps: [MockBackend, BaseRequestOptions]
},
LoginService,
ApiService,
ConfigService,
Constants,
SharedService,
{ provide: APP_BASE_HREF, useValue: '/' }
]
}).compileComponents().then(() => {
fixture = TestBed.createComponent(LoginComponent);
comp = fixture.componentInstance;
de = fixture.debugElement.query(By.css('form'));
el = de.nativeElement;
userNameEl = fixture.debugElement.query(By.css('input[id=InputEmail1]'));
passwordEl = fixture.debugElement.query(By.css('input[id=InputPassword1]'));
submitEl = fixture.debugElement.query(By.css('.login-btn'));
});
}));
beforeEach(inject([LoginService, MockBackend], (Service: LoginService, mockBackend: MockBackend) => {
loginService = Service;
backend = mockBackend;
}));
it('should create', () => {
expect(comp).toBeTruthy();
});
it('To check the initial value', () => {
expect(comp.submitted).toBe(false);
expect(comp.spinnerlogo).toBeFalsy();
expect(comp.data).toEqual({});
});
it(`entering value in username and password input controls`, () => {
userNameEl.nativeElement.value = 'admin';
passwordEl.nativeElement.value = 'admin';
fixture.detectChanges();
});
it('after entering value the button should enabled and click Action should happen', () => {
expect(submitEl.nativeElement.disabled).toBeFalsy();
const loginButtonSpy = spyOn(comp, 'onSubmit');
submitEl.triggerEventHandler('click', null);
expect(loginButtonSpy).toHaveBeenCalled();
});
it('calling onSubmit method after clicked the login button', () => {
comp.submitted = true;
comp.spinnerlogo = true;
comp.errorDiagnostic = null;
comp.mailerrorDiagnostic = null;
expect(comp.submitted).toBeTruthy();
expect(comp.spinnerlogo).toBeTruthy();
expect(comp.errorDiagnostic).toBeNull();
expect(comp.mailerrorDiagnostic).toBeNull();
});
it('#login should call endpoint and return it\'s result', (done) => {
backend.connections.subscribe((connection: MockConnection) => {
const options = new ResponseOptions({
body: JSON.stringify({ success: true })
});
connection.mockRespond(new Response(options));
// Check the request method
expect(connection.request.method).toEqual(RequestMethod.Post);
// Check the url
expect(connection.request.url).toEqual('/auth/login');
// Check the body
// expect(connection.request.text())
expect(connection.request.text()).toEqual(JSON.stringify({ username: 'admin', password: 'admin' }));
// Check the request headers
expect(connection.request.headers.get('Content-Type')).toEqual('application/json');
});
loginService.login('admin', 'admin')
.subscribe((response) => {
console.log('response values are ---####------------ ', response);
// Check the response
expect(response.user.username).toEqual('admin');
expect(response.user.password).toEqual('admin');
// set value in sessionStorage
sessionStorage.setItem('currentUser', JSON.stringify(response));
sessionStorage.setItem('token', JSON.stringify(response.token));
sessionStorage.setItem('dismissOrders', 'false');
done();
},
(error) => {
expect(error).toThrowError();
});
});
});
the main problem is before executing the above file . The other spec file are executed
Thanks,
Kishan

How to test router.navigate with subscribe ? Angular2

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

Karma+jasmine+Angular2 unit testing http service error (No provider for [object Object])

I have set up a simple service and tried to run the test.
Service
//CustomerServiceTest.ts:
import { Injectable, Pipe } from '#angular/core';
import { Http, Response } from '#angular/http';
import { Observable } from 'rxjs/Observable';
import 'rxjs/Rx';
#Injectable()
export class CustomerServiceTest{
constructor(public http: Http) {}
query(URL: string, params?: Array<string>): Observable<any[]> {
let be_endpoint: string = 'http:\/\/localhost:44444\/';
let queryURL: string = `${be_endpoint}${URL}`;
if (params) {
queryURL = `${queryURL}?${params.join('&')}`;
}
return this.http.request(queryURL).map((res: any) => res.json());
}
searchBackEnd(query: string, type: string): Observable<any[]> {
return this.query(`/${type}`, [
`id=${query}`
]);
}
}
Test for the service
//CustomerServiceTest.spec.ts:
import {
TestBed,
getTestBed,
async,
inject
} from '#angular/core/testing';
import {
Headers, BaseRequestOptions,
Response, HttpModule, Http, XHRBackend, RequestMethod
} from '#angular/http';
import {ResponseOptions} from '#angular/http';
import {MockBackend, MockConnection} from '#angular/http/testing';
import { CustomerServiceTest } from '../../ts/components/CustomerServiceTest';
describe('CustomerServiceTest test suite', () => {
let mockBackend: MockBackend;
beforeEach(async(() => {
TestBed.configureTestingModule({
providers: [
CustomerServiceTest,
MockBackend,
BaseRequestOptions,
{
provide: Http,
deps: [MockBackend, BaseRequestOptions],
useFactory:
(backend: XHRBackend, defaultOptions: BaseRequestOptions) => {
return new Http(backend, defaultOptions);
}
}
],
imports: [
HttpModule
]
}).compileComponents();
mockBackend = getTestBed().get(MockBackend);
}));
it('should get data', async(inject([CustomerServiceTest], (CustomerServiceTest) => {
let crmSvc:CustomerServiceTest;
let ContactResponceBody:Object = {
body: [
{
id: '12345678',
cellPhNum: '+9273839222',
lastName: 'TestUser',
firstName: 'TestUser'
}
]
};
let contactResponceOptions:ResponseOptions = new ResponseOptions(ContactResponceBody);
let contactResponse:Response = new Response(contactResponceOptions);
mockBackend.connections.subscribe(
(connection: MockConnection) => {
connection.mockRespond(contactResponse);
});
crmSvc = getTestBed().get(CustomerServiceTest);
expect(crmSvc).toBeDefined();
})));
});
Executing npm run test results in error:
Chrome 49.0.2623 (Windows 7 0.0.0) CustomerServiceTest test suite should get data FAILED
Failed: No provider for [object Object]!
Error: DI Error
at NoProviderError.Error (native)
at NoProviderError.ZoneAwareError (karma.entry.js:43703:33)
at NoProviderError.BaseError [as constructor] (karma.entry.js:6062:34)
at NoProviderError.AbstractProviderError [as constructor] (karma.entry.js:32848:16)
at new NoProviderError (karma.entry.js:32879:16)
at ReflectiveInjector_._throwOrNull (karma.entry.js:53504:19)
at ReflectiveInjector_._getByKeyDefault (karma.entry.js:53532:25)
at ReflectiveInjector_._getByKey (karma.entry.js:53495:25)
at ReflectiveInjector_.get (karma.entry.js:53304:21)
at TestBed.get (karma.entry.js:9842:67)
Apparently, some dependency is missing, but I can't understand what it is. Could anyone explain where to look? At first glance - all providers are at place...
Worked it out:
//CustomerService.spec.ts
import {
TestBed,
getTestBed,
async,
inject
} from '#angular/core/testing';
import {
Headers, BaseRequestOptions,
Response, HttpModule, Http, XHRBackend, RequestMethod
} from '#angular/http';
import {ResponseOptions} from '#angular/http';
import {MockBackend, MockConnection} from '#angular/http/testing';
import { CustomerServiceTest } from '../../ts/components/CustomerServiceTest';
describe('CustomerServiceTest:', () => {
let mockBackend: MockBackend;
let ContactResponceBody:Object = {
body: [
{
id: '1-DR8C2SJ',
cellPhNum: '1111',
lastName: 'qqq',
firstName: 'www',
midName: 'eee',
sex: 'М',
age: 23,
email: 'test#test.com',
localtime: '12:00',
utcOffset:180
}
]
};
let contactResponceOptions:ResponseOptions = new ResponseOptions(ContactResponceBody);
let contactResponse:Response = new Response(contactResponceOptions);
beforeEach(async(() => {
TestBed.configureTestingModule({
providers: [
CustomerServiceTest,
MockBackend,
BaseRequestOptions,
{
provide: Http,
deps: [MockBackend, BaseRequestOptions],
useFactory:
(backend: XHRBackend, defaultOptions: BaseRequestOptions) => {
return new Http(backend, defaultOptions);
}
}
],
imports: [
HttpModule
]
});
mockBackend = getTestBed().get(MockBackend);
}));
it('Available',
async(
inject(
[CustomerServiceTest],
(custSvc:CustomerServiceTest) => {
expect(custSvc).toBeDefined();
}
)
)
)
it('Returns data',
async(
inject(
[TCSCustomerServiceTest],
(custSvc:TCSCustomerServiceTest) => {
//emulate contact response from real back-end
mockBackend.connections.subscribe(
(connection: MockConnection) => {
connection.mockRespond(contactResponse);
});
custSvc.searchBackEnd('1-DR8C2SJ', 'contact').subscribe(
(response: any) => {
expect(response[0].id).toBe('1-DR8C2SJ');
expect(response[0].cellPhNum).toBe('1111');
expect(response[0].lastName).toBe('qqq');
expect(response[0].firstName).toBe('www');
expect(response[0].midName).toBe('eee');
expect(response[0].sex).toBe('М');
expect(response[0].age).toBe(23);
expect(response[0].email).toBe('test#test.com');
expect(response[0].localtime).toBe('12:00');
expect(response[0].utcOffset).toBe(180);
}
);
}
)
)
)
});