Why isn't http request being picked up in angular test - javascript

I have a simple service:
import { Injectable } from '#angular/core';
import { HttpClient } from '#angular/common/http';
import { ApiConfiguration } from '../../api/api-configuration';
import { BaseService } from '../../api/base-service';
import { Observable } from 'rxjs';
const TIMER = 120000;
#Injectable({
providedIn: 'root'
})
export class AppService extends BaseService {
constructor(
config: ApiConfiguration,
http?: HttpClient,
) {
super(config, http);
}
getContextualHelp(id, helpType): Observable<Object> {
return this.http.get(`${this.rootUrl}/api/v2/contextual-help`, {
params: { id, helpType }
});
}
}
I have tests that make sure the service returns some mocked data:
import { AppService } from '../app.service';
import { TestBed } from '#angular/core/testing';
import { HttpTestingController, HttpClientTestingModule } from '#angular/common/http/testing';
import { StoreModule } from '#ngrx/store';
import { ApiConfiguration } from '../../../api/api-configuration';
fdescribe('app.service', () => {
let service: AppService;
let httpMock: HttpTestingController;
beforeEach(() => {
TestBed.configureTestingModule({
imports: [
HttpClientTestingModule,
StoreModule.forRoot({}),
],
providers: [
AppService,
{
provide: ApiConfiguration, useValue: ''
},
]
});
service = TestBed.get(AppService);
httpMock = TestBed.get(HttpTestingController);
});
describe('getContextualHelp', () => {
it('should be created', () => {
expect(service).toBeTruthy();
});
it('calls the contextual help route with the expected params', () => {
const mockData = '<div></div>';
service.rootUrl = 'https://www.mock.com';
service.getContextualHelp('foo', 'bar').subscribe((html) => {
expect(html).toEqual('<div></div>');
});
const req = httpMock.expectOne('https://www.mock.com/api/v2/contextual-help');
req.flush(mockData);
});
});
});
It seems like I have everything hooked up correctly but when I run the test I get:
Error: Expected one matching request for criteria "Match URL: https://www.mock.com/api/v2/contextual-help", found none.
When I debug the test and go into the code context I see that http client is being called, and it's being called with the url I expect. So I guess somehow I misconfigured the test modules somehow? Does anyone see what I might have done wrong?

Note that expectOne() matches the url as well as the url params. Try to pass the complete url to the function, like:
const req = httpMock.expectOne('https://www.mock.com/api/v2/contextual-help?id=foo&helpType=bar');
Take a look at this question and the answer.

Related

How to read subscribe in Angular Unit Test?

I am trying to write test cases of a component where at first I tried to check if a basic test case is working or not. There I encountered some errors related to Dependency Injection and solved those. Now the first issue that I am facing is mocking the API calls.
Below is my component code for which I am writing test cases:
import { Component, OnInit } from '#angular/core';
import { FormBuilder, FormGroup, Validators } from '#angular/forms';
import { HttpClientService } from '#service/http-client.service';
import { CustomErrorStateMatcher } from '#validator/error-state-matcher';
import { ToastrService } from 'ngx-toastr';
#Component({
selector: 'app-prep-card',
templateUrl: './prep-card.component.html',
styles: ['legend { width: fit-content !important; }']
})
export class PrepCardComponent implements OnInit {
constructor(private fb: FormBuilder, private _http: HttpClientService, private toastr: ToastrService) { }
foamTypeList: string[] = [];
colorList: string[] = [];
ngOnInit() { this.getFoam_ColorList() }
private getFoam_ColorList() {
this._http.getFoamType_ColorList('ABC').subscribe(response => {
this.foamTypeList = response.data.foamTypesAndColors.foamTypes;
this.colorList = response.data.foamTypesAndColors.colors;
});
}
}
At first, I tried to run a simple test case to check if it is working correctly or not. Below is the test case I wrote:
import { ComponentFixture, inject, TestBed } from "#angular/core/testing";
import { FormsModule, ReactiveFormsModule } from "#angular/forms";
import { RouterTestingModule } from '#angular/router/testing';
import { HttpClientService } from "#service/http-client.service";
import { ToastrService } from "ngx-toastr";
import { MaterialModule } from "src/app/material/material.module";
import { PrepCardComponent } from "./prep-card.component";
describe('PrepCardComponent', () => {
let component: PrepCardComponent, fixture: ComponentFixture<PrepCardComponent>,
_httpSpy: jasmine.SpyObj<HttpClientService>, _toastrSpy: jasmine.SpyObj<ToastrService>;
beforeEach(async () => {
const _httpSpyObj = jasmine.createSpyObj('HttpClientService', ['getFoamType_ColorList']),
_toastrSpyObj = jasmine.createSpyObj('ToastrService', ['success', 'error']);
await TestBed.configureTestingModule({
declarations: [PrepCardComponent],
imports: [
RouterTestingModule, FormsModule, ReactiveFormsModule, MaterialModule
],
providers: [
{ provide: HttpClientService, useValue: _httpSpyObj },
{ provide: ToastrService, useValue: _toastrSpyObj },
]
}).compileComponents();
fixture = TestBed.createComponent(PrepCardComponent);
component = fixture.componentInstance;
fixture.detectChanges();
});
it('test', () => expect('a').toBe('a'));
});
The above code snippet threw the following error:
TypeError: Cannot read properties of undefined (reading 'subscribe')
at PrepCardComponent.getFoam_ColorList (http://localhost:9876/karma_webpack/webpack:/src/app/pages/prep-card/prep-card.component.ts:57:52)
at PrepCardComponent.setFormFieldValidator (http://localhost:9876/karma_webpack/webpack:/src/app/pages/prep-card/prep-card.component.ts:65:10)
at PrepCardComponent.createForm (http://localhost:9876/karma_webpack/webpack:/src/app/pages/prep-card/prep-card.component.ts:48:10)
at PrepCardComponent.ngOnInit (http://localhost:9876/karma_webpack/webpack:/src/app/pages/prep-card/prep-card.component.ts:28:10)
at callHook (http://localhost:9876/karma_webpack/webpack:/node_modules/#angular/core/fesm2015/core.mjs:2542:1)
at callHooks (http://localhost:9876/karma_webpack/webpack:/node_modules/#angular/core/fesm2015/core.mjs:2511:1)
at executeInitAndCheckHooks (http://localhost:9876/karma_webpack/webpack:/node_modules/#angular/core/fesm2015/core.mjs:2462:1)
at refreshView (http://localhost:9876/karma_webpack/webpack:/node_modules/#angular/core/fesm2015/core.mjs:9499:1)
at renderComponentOrTemplate (http://localhost:9876/karma_webpack/webpack:/node_modules/#angular/core/fesm2015/core.mjs:9598:1)
at tickRootContext (http://localhost:9876/karma_webpack/webpack:/node_modules/#angular/core/fesm2015/core.mjs:10829:1)
To solve this, I searched different questions here and saw common solution mentioned below to get an observable.
it('Call Service', inject([HttpClientService], (_http: HttpClientService) => {
spyOn(_http, 'getFoamType_ColorList').and.returnValue({subscribe: () => {}})
}));
Writing the above test case was throwing an error (mentioned below) in the subscribe position.
Type 'void' is not assignable to type 'Subscription'.ts(2322)
Service code
getFoamType_ColorList(cardType: string) {
return this.http.get<{ message: string, data: { foamTypesAndColors: { foamTypes: string[], colors: string[] } } }>
(`${this.URL}/validate/foam-type-and-color/${cardType}`);
}
Can anyone help me out with how I can solve this issue?
UPDATE
As per dmance's answer am not getting any error while writing the test case but the test cases are still failing giving the same error. For reference refer below the full error log:
I will suggest this:
import { of } from 'rxjs';
spyOn(httpclientservice, 'getFoamType_ColorList').and.returnValue(of(YOUR VALUE));
This is a more complete answer:
describe('PrepCardComponent', () => {
let component: PrepCardComponent, fixture: ComponentFixture<PrepCardComponent>;
let httpClientService: HttpClientService;
let toastService: ToastrService;
beforeEach(async () => {
await TestBed.configureTestingModule({
declarations: [PrepCardComponent],
imports: [
RouterTestingModule, FormsModule, ReactiveFormsModule, MaterialModule
]
}).compileComponents();
httpClientService = TestBed.inject(HttpClientService);
toastService= TestBed.inject(ToastrService);
fixture = TestBed.createComponent(PrepCardComponent);
component = fixture.componentInstance;
fixture.detectChanges();
});
it('test', () => {
spyOn(httpClientService, 'getFoamType_ColorList').then.returnValue(of(YOUR VALUE));
// MAKE YOUR TEST
});
});
Try this maybe
spyOn(_http,'getFoamType_ColorList').and.returnValue(Observable.of(Your_Value));

how to test a function with condition in ngOnInit

I want to test a function with condition that comes from a service in ngOnInit. I tried many way but no success. i have all kinds of mistakes.
my component
export class MainSectionComponent implements OnInit {
propertiesFrDb: PropertyPost[];
constructor(
private getPropertiesFrDbService: GetPropertiesFrDbService,
private propertyWarehouseService: PropertyWarehouseService,
private router: Router,
config: NgbCarouselConfig,
private userService: UserService,
private sharedFunctionService: SharedFunctionService,
private returnResponseAfterUserLoginService: ReturnResponseAfterUserLoginService,
private localStorageService: LocalStorageServiceService,
private dialogLoginService: DialogLoginService,
#Inject(PLATFORM_ID) private platformId: Object
) {
// this.isBrowser = isPlatformBrowser(platformIds);
}
ngOnInit() {
this.getPropertiesFrDb();
}
getPropertiesFrDb() {
if (this.propertyWarehouseService.currentValuesProperties) {
this.propertyWarehouseService.getPropertyHome$.subscribe(
prop => {
console.log(prop);
return this.propertiesFrDb = prop
}
)
} else {
this.getPropertiesFrDbService.getHomeProperties()
.subscribe(property => {
// console.log(property['results']);
this.propertyWarehouseService.setPropertiesHome(property['results'])
return this.propertiesFrDb = property['results']
},
)
}
}
I want to test this.getPropertiesFrDb() in ngOnInit
i would like to test the case with this.propertyWarehouseService.currentValuesProperties !== ''and checked that this.getPropertiesFrDbService.getHomeProperties() is called and checked the value of propertiesFrDb
and my spec.ts file
import { async, ComponentFixture, TestBed, fakeAsync, tick } from '#angular/core/testing';
import { MainSectionComponent } from './home-properties.component';
import { CUSTOM_ELEMENTS_SCHEMA } from '#angular/core';
import { MaterialModule } from 'src/app/material/material.module';
import { HttpClientTestingModule } from '#angular/common/http/testing';
import { RouterTestingModule } from '#angular/router/testing';
import { GetPropertiesFrDbService } from 'src/app/services/getPropertiesFromDb/get-properties-fr-db.service';
import { MOCKPROPERTIES, MockPropertyWarehouseService } from 'src/app/mocks/property-post';
import { NgxPaginationModule, PaginatePipe } from 'ngx-pagination';
import { PropertyWarehouseService } from 'src/app/services/propertyWarehouse/property-warehouse.service';
import { BsDropdownModule } from 'ngx-bootstrap';
import { NgbModule } from '#ng-bootstrap/ng-bootstrap';
import { StorageServiceModule } from 'angular-webstorage-service';
import { of } from 'rxjs/internal/observable/of';
fdescribe('MainSectionComponent', () => {
let component: MainSectionComponent;
let fixture: ComponentFixture<MainSectionComponent>;
const PROPERTYMODEL = MOCKPROPERTIES;
const spyPropertyWarehouseService = jasmine.createSpyObj('spypropertyWarehouseService', ['currentValuesProperties', 'getPropertyHome$']);
beforeEach(async(() => {
TestBed.configureTestingModule({
imports: [
MaterialModule,
HttpClientTestingModule,
RouterTestingModule.withRoutes([]),
NgxPaginationModule,
BsDropdownModule.forRoot(),
NgbModule,
StorageServiceModule,
],
declarations: [
MainSectionComponent,
],
providers: [
{
provide: PropertyWarehouseService,
useValue: spyPropertyWarehouseService
}
],
schemas: [CUSTOM_ELEMENTS_SCHEMA],
})
.compileComponents();
}));
beforeEach(() => {
fixture = TestBed.createComponent(MainSectionComponent);
component = fixture.componentInstance;
fixture.detectChanges();
});
it('should create', (() => {
// console.log('properties', component);
expect(component).toBeTruthy();
}));
it('Should get propertiesFrDb from GetPropertiesFrDbService', async(() => {
spyPropertyWarehouseService.currentValuesProperties.and.returnValue(PROPERTYMODEL);
spyPropertyWarehouseService.getPropertyHome$.and.returnValue(of(PROPERTYMODEL));
expect(component.propertiesFrDb).toBe(PROPERTYMODEL);
console.log('spy',spyPropertyWarehouseService);
}));
});
Try creating a stub as below:
export class PropertyWarehouseServiceStub{
currentValuesProperties = '';
getPropertyHome$ = new BaheviorSubject<any>('someObj');
setPropertiesHome(){ }
}
export class GetPropertiesFrDbServiceStub{
getHomeProperties(){
return of({results: 'val'})
}
}
in component file make the service public in constructor so that we can override some of its behaviors:
constructor(...,
public propertyWarehouseService: PropertyWarehouseService,
public getPropertiesFrDbService: GetPropertiesFrDbService,
....)
and in spec file as :
providers: [
{
provide: PropertyWarehouseService,
useClass: PropertyWarehouseServiceStub
},{
provide: GetPropertiesFrDbService,
useClass: GetPropertiesFrDbServiceStub
}
],
......
....
..
it('should call getPropertiesFrDb() in ngOnInit',()=>{
spyOn(component,'getPropertiesFrDb').and.callThrough();
component.ngOnInit();
expect(component.getPropertiesFrDb).toHaveBeenCalled();
})
it('inside getPropertiesFrDb() should call getPropertiesFrDbService.getHomeProperties() when "propertyWarehouseService.currentValuesProperties" is empty,()=>{
spyOn(component.getPropertiesFrDbService,'getHomeProperties').and.callThrough();
spyOn(component.propertyWarehouseService,'setPropertiesHome').and.callThrough();
component.getPropertiesFrDb();
expect(component.getPropertiesFrDbService.getHomeProperties).toHaveBeenCalled();
expect(component.propertyWarehouseService.setPropertiesHome).toHaveBeenCalledWith('val');
expect(component.propertiesFrDb).toBe('someObj');
})
it('inside getPropertiesFrDb() should not call getPropertiesFrDbService.getHomeProperties() when "propertyWarehouseService.currentValuesProperties" is NOT empty,()=>{
component.propertyWarehouseService.currentValuesProperties = 'Not empty';
spyOn(component.getPropertiesFrDbService,'getHomeProperties').and.callThrough();
spyOn(component.propertyWarehouseService,'setPropertiesHome').and.callThrough();
component.getPropertiesFrDb();
expect(component.getPropertiesFrDbService.getHomeProperties).not.toHaveBeenCalled();
expect(component.propertyWarehouseService.setPropertiesHome).not.toHaveBeenCalledWith('val');
expect(component.propertiesFrDb).toBe('val');
})
You can refer to this intro article written by me on Karma-jasmine which contains more article references for several test use cases.
This one is very much similar to what you are looking for. I am planning to write some more articles, in case you wanna follow.
Also, I have no clue on why you are using return as below inside getPropertiesFrDb()
return this.propertiesFrDb = prop
which is of no use because no value of this function has been assigned to any variable inside ngOnInit.

How do I test a JSONP HTTP request in Angular?

I'm using the HttpClientModule and HttpClientJsonpModule to make a JSONP HTTP request in a service.
app.module.ts
import { BrowserModule } from '#angular/platform-browser';
import { NgModule } from '#angular/core';
import { HttpClientModule, HttpClientJsonpModule } from '#angular/common/http';
import { AppComponent } from './app.component';
#NgModule({
declarations: [
AppComponent
],
imports: [
BrowserModule,
HttpClientModule,
HttpClientJsonpModule
],
providers: [],
bootstrap: [AppComponent]
})
export class AppModule { }
This service uses the jsonp method from the HttpClient class to get a JSONP response from the specified URL. I think that this response is intercepted by JsonpInterceptor and sent to the JsonpClientBackend where the request is handled.
example.service.ts
import { Injectable } from '#angular/core';
import { HttpClient } from '#angular/common/http';
#Injectable()
export class ExampleService {
url = "https://archive.org/index.php?output=json&callback=callback";
constructor(private http: HttpClient) { }
getData() {
return this.http.jsonp(this.url, 'callback');
}
}
Using the HttpClientTestingModule, I inject the HttpTestingController so I can mock and flush my JSONP HTTP request.
example.service.spec.ts
import { TestBed, inject } from '#angular/core/testing';
import {
HttpClientTestingModule,
HttpTestingController
} from '#angular/common/http/testing';
import { ExampleService } from './example.service';
describe('ExampleService', () => {
let service: ExampleService;
let httpMock: HttpTestingController;
beforeEach(() => {
TestBed.configureTestingModule({
imports: [HttpClientTestingModule],
providers: [ExampleService]
});
service = TestBed.get(ExampleService);
httpMock = TestBed.get(HttpTestingController);
});
describe('#getData', () => {
it('should return an Observable<any>', () => {
const dummyData = { id: 1 };
service.getData().subscribe(data => {
expect(data).toEqual(dummyData);
});
const req = httpMock.expectOne(service.url); // Error
expect(req.request.method).toBe('JSONP');
req.flush(dummyData);
});
});
});
In the end, I get the error
Error: Expected one matching request for criteria "Match URL: https://archive.org/index.php?output=json&callback=callback", found none.
If I change the request method to GET, this test works as expected.
From what I can tell, the HttpClientTestingModule uses the HttpClientTestingBackend but there is no JsonpClientTestingBackend or corresponding interceptor.
How do I test a JSONP HTTP request in Angular?
According to an Angular developer this is a bug. Here's a workaround for now.
example.service.spec.ts
import { TestBed, inject } from '#angular/core/testing';
// Import the HttpClientJsonpModule, HttpBackend, and JsonpClientBackend
import { HttpClientJsonpModule, HttpBackend, JsonpClientBackend } from '#angular/common/http';
import { HttpClientTestingModule, HttpTestingController } from '#angular/common/http/testing';
import { ExampleService } from './example.service';
describe('ExampleService', () => {
let service: ExampleService;
let httpMock: HttpTestingController;
beforeEach(() => {
TestBed.configureTestingModule({
imports: [HttpClientTestingModule],
// Use the HttpBackend instead of the JsonpClientBackend
providers: [ExampleService, { provide: JsonpClientBackend, useExisting: HttpBackend }]
});
service = TestBed.get(ExampleService);
httpMock = TestBed.get(HttpTestingController);
});
describe('#getData', () => {
it('should return an Observable<any>', () => {
const dummyData = { id: 1 };
service.getData().subscribe(data => {
expect(data).toEqual(dummyData);
});
// Pass a function to the expectOne method
const req = httpMock.expectOne(request => request.url === service.url);
expect(req.request.method).toBe('JSONP');
req.flush(dummyData);
});
});
});

ngModel not updated with input value angular 2 test karma

I have a problem during my units test with angular 2. I just want to test an input to check if my model can't be more than 16 chars. (I have indeed use a maxlength in my html). So I enter a new value in my input and use dispatchEvent to set the input in the model but the model is nether update...
Here is my test :
/* tslint:disable:no-unused-variable */
import { EditRequestComponent } from './edit-request.component';
import 'rxjs/add/operator/map';
import 'rxjs/add/observable/of';
import { async, ComponentFixture, TestBed, fakeAsync, tick } from '#angular/core/testing';
import { By } from '#angular/platform-browser';
import { __platform_browser_private__ as _ } from '#angular/platform-browser';
import { DebugElement } from '#angular/core';
import { MvpSelector } from './mvpSelector/mvpSelector.component';
import { MockBackend, MockConnection } from '#angular/http/testing';
import { FormsModule } from '#angular/forms';
import { ActivatedRoute } from '#angular/router';
import { Observable } from 'rxjs/Observable';
import { HttpModule, Http, BaseRequestOptions, Response } from '#angular/http';
import { InMemoryWebApiModule } from 'angular-in-memory-web-api';
import { InMemoryWebApiService } from '../../services/in-memory.service';
import { MyDatePickerModule } from 'mydatepicker/dist/my-date-picker.module';
import { ReferentialService, RequestService, ConfigurationService } from '../../services';
import { MvpRequestClass } from '../../models';
//////// SPECS /////////////
describe('EditRequestComponent', function () {
let comp: EditRequestComponent;
let fixture: ComponentFixture<EditRequestComponent>;
beforeEach(() => {
TestBed.configureTestingModule({
providers: [
ReferentialService,
ConfigurationService,
RequestService,
MockBackend,
BaseRequestOptions,
{
provide: Http,
useFactory: (backend: MockBackend, options: BaseRequestOptions) => {
return new Http(backend, options);
},
deps: [ MockBackend, BaseRequestOptions ]
},
{
provide: ActivatedRoute,
useValue: {
snapshot: {
params: {id: 1},
data: {request: new MvpRequestClass()}
}
}
}
],
declarations: [ MvpSelector, EditRequestComponent ],
imports: [ FormsModule, FormsModule, MyDatePickerModule,
HttpModule ]
}).compileComponents();
fixture = TestBed.createComponent(EditRequestComponent);
comp = fixture.componentInstance;
});
it('should create component', () => expect(comp).toBeDefined() );
it('should have a mvpRequestComponent', () =>
{
fixture.detectChanges();
expect(comp.mvpReq).toBeDefined();
});
it('should not have more than 16 char in moInCharge input', fakeAsync(() => {
comp.mvpReq.moInCharge = "oldValue";
fixture.detectChanges();
var field = fixture.debugElement.query(By.css('.input-moInCharge')).nativeElement;
field.value = "aaaaaaaaaaaaaaaaaaaaaa";
_.getDOM().dispatchEvent(field, _.getDOM().createEvent("input"));
tick();
console.log(field.value);
expect(comp.mvpReq.moInCharge.length).toBeLessThanOrEqual(16);
}));
});
Here are the Log print in my console:
LOG LOG: 'oldValue'
You can also see that I have a weird way to use dispatchEvent. That's because when I import and use it directly from '#angular/platform-browser/testing/browser_util' I have an error message :
Uncaught SyntaxError: Unexpected token import
at webpack:///~/#angular/platform-browser/testing/browser_util.js:8:0 <- karma.entry.js:49907
It seems that there was imports directly in the file browser_util.d.ts that our webpack doesn't appreciate. But the dispatchEvent function is sensibly used the same way. So I don't understand why the model doesn't update.
Here are few test that I made to make it work:
use async() function rather than fakeAsync
use the dispatchEvent function of MDN
use fixture.whenStable() with a then()
change the number of 'a' to check if the value doesn't update because
there are too many
a combination of all this points
And that's all. I must admit that I don't know how to proceed differently to make it work. If you can help me or you want more details, don't hesitate.
Thanks in advance.

Cannot read property '_getPortal' of undefined in ionic 2 Unit testing

I am a beginner to ionic 2 unit testing. I followed angular 2 documentation (https://angular.io/docs/ts/latest/guide/testing.html) to test my ionic 2 application with karma and jasmine.
But now I am stuck in an error called
'Cannot read property '_getPortal' of undefined'
here is my LocationSearchModal.ts file
import { Component } from '#angular/core';
import { NavController, ViewController } from 'ionic-angular';
import { Location } from '../../services/domain/Location';
import { LocationService } from '../../services/LocationService';
import { LoadingController } from 'ionic-angular';
#Component({
selector: 'location-search-modal',
templateUrl: 'location-search-modal.html'
})
export class LocationSearchModal {
locationList: Array<Location> = new Array<Location>();
selectedLocation: number;
temp: any = "test";
constructor(public navCtrl: NavController, public locationService: LocationService, public viewController: ViewController, public loadingController: LoadingController) {
this.filterLocationsForString();
}
filterLocations(event: any): void {
const searchString: string = event.target.value;
this.filterLocationsForString(searchString);
console.log(this.filterLocationsForString(searchString));
}
filterLocationsForString(searchString?: string) {
let loader = this.loadingController.create({
content: "loading"
});
loader.present();
this.locationService.getLocationsForLikeSearchString(searchString)
.subscribe((result) => {
loader.dismissAll();
this.locationList = result
});
console.log(this.locationList);
}
closeLocationSearch() {
this.locationService.getLocationById(this.selectedLocation)
.subscribe((location) => this.viewController.dismiss(location[0]));
}
}
and I used service called locationService.ts there and this is that service
import { Injectable } from '#angular/core';
import { Location } from './domain/Location';
import { DatabaseAccessor } from '../database/DatabaseAccessor';
import { Observable } from 'rxjs/Rx';
#Injectable()
export class LocationService {
locationList:Array<Location> = new Array<Location>();
constructor(public databaseAccessor: DatabaseAccessor) {}
getLocationsForLikeSearchString(searchString: string) : Observable<Array<Location>> {
const searchValue = (searchString == null) ? '%' : searchString.trim() + '%';
return <Observable<Array<Location>>> Observable.fromPromise(this.databaseAccessor.runSelectQuery(Location, new Location(), 'WHERE name LIKE ?', [searchValue]));
}
getLocationById(id: number): Observable<Location> {
return <Observable<Location>> Observable.fromPromise(this.databaseAccessor.runSelectQuery(Location, new Location(), 'WHERE id = ?', [id]));
}
saveLocations(locations: Array<Location>){
this.databaseAccessor.runInsertBatchQuery(Location.prototype, locations);
}
}
Finally, I wrote a spec.ts file to unit testing and here is that,
import { ComponentFixture, async } from '#angular/core/testing';
import { LocationSearchModal } from './LocationSearchModal';
import { LocationService } from '../../services/LocationService';
import { TestUtils } from '../../test';
import { TestBed } from '#angular/core/testing';
import { App, NavController, Platform, Config, Keyboard, Form, IonicModule, GestureController, ViewController, LoadingController } from 'ionic-angular';
import { ConfigMock } from '../../mocks';
import { TranslateModule } from 'ng2-translate';
import { DatabaseAccessor } from '../../database/DatabaseAccessor';
let comp: LocationSearchModal;
let fixture: ComponentFixture<LocationSearchModal>;
let instance: any = null;
describe('LocationSearchModal', () => {
beforeEach(async(() => {
TestBed.configureTestingModule({
declarations: [LocationSearchModal], // declare the test component
providers: [App, Platform, Form, Keyboard, NavController, GestureController, LoadingController, LocationService, DatabaseAccessor,
{ provide: ViewController, useClass: class { ViewController = jasmine.createSpy("viewController"); } },
{ provide: Config, useClass: ConfigMock },
],
imports: [
IonicModule,
TranslateModule.forRoot(),
],
});
fixture = TestBed.createComponent(LocationSearchModal);
comp = fixture.componentInstance;
}));
console.log(comp);
it('Testing Location Component', () => {
expect(comp.temp).toBe('test');
})
});
when I am running the following error comes from the terminal.
(my unit testing configuration are correct and I tested it with another simple .spec.ts file)
the error
SUMMARY:
✔ 1 test completed
✖ 1 test failed
FAILED TESTS:
LocationSearchModal
✖ Testing Location Component
Chrome 54.0.2840 (Linux 0.0.0)
Failed: Error in ./LocationSearchModal class LocationSearchModal_Host - inline template:0:0 caused by: Cannot read property '_getPortal' of undefined
TypeError: Cannot read property '_getPortal' of undefined
at App.present (webpack:/media/dilanka/Stuff/CODE%20BASE/Inspection/Unit%20Testing/Inspection-Rewrite/~/ionic-angular/components/app/app.js:78:0 <- src/test.ts:2091:35)
at Loading.present (webpack:/media/dilanka/Stuff/CODE%20BASE/Inspection/Unit%20Testing/Inspection-Rewrite/~/ionic-angular/components/loading/loading.js:31:0 <- src/test.ts:38779:26)
at LocationSearchModal.filterLocationsForString (webpack:/media/dilanka/Stuff/CODE%20BASE/Inspection/Unit%20Testing/Inspection-Rewrite/src/pages/location-search/LocationSearchModal.ts:9:4184 <- src/test.ts:18993:4170)
at new LocationSearchModal (webpack:/media/dilanka/Stuff/CODE%20BASE/Inspection/Unit%20Testing/Inspection-Rewrite/src/pages/location-search/LocationSearchModal.ts:9:3407 <- src/test.ts:18993:3391)
at new Wrapper_LocationSearchModal (/DynamicTestModule/LocationSearchModal/wrapper.ngfactory.js:7:18)
at _View_LocationSearchModal_Host0.createInternal (/DynamicTestModule/LocationSearchModal/host.ngfactory.js:16:35)
at _View_LocationSearchModal_Host0.AppView.create (webpack:/media/dilanka/Stuff/CODE%20BASE/Inspection/Unit%20Testing/Inspection-Rewrite/~/#angular/core/src/linker/view.js:84:0 <- src/test.ts:52350:21)
at _View_LocationSearchModal_Host0.DebugAppView.create (webpack:/media/dilanka/Stuff/CODE%20BASE/Inspection/Unit%20Testing/Inspection-Rewrite/~/#angular/core/src/linker/view.js:294:0 <- src/test.ts:52560:44)
at ComponentFactory.create (webpack:/media/dilanka/Stuff/CODE%20BASE/Inspection/Unit%20Testing/Inspection-Rewrite/~/#angular/core/src/linker/component_factory.js:152:0 <- src/test.ts:32035:36)
at initComponent (webpack:/media/dilanka/Stuff/CODE%20BASE/Inspection/Unit%20Testing/Inspection-Rewrite/~/#angular/core/bundles/core-testing.umd.js:855:0 <- src/test.ts:7416:53)
Mock the LoadingController if the problem is from using LoadingController
export class LoadingControllerMock {
_getPortal(): any { return {} };
create(options?: any) {
return new LoadingMock()
};
}
class LoadingMock {
present() { };
dismiss() { };
dismissAll() { };
}
Import the Mock and the actual from wherever
import { LoadingController } from 'ionic-angular';
import { LoadingControllerMock } from '../../../../test-config/mocks-ionic';
Substitute
providers: [
{ provide: LoadingController, useClass: LoadingControllerMock }
]
I Solved this problem finally. I used a mock and defined required methods in that mock. Then It works :)
here is an example for a mock.
export class ViewControllerMock {
public _setHeader(): any { return {} };
public _setNavbar(): any { return {} };
public _setIONContent(): any { return {} };
public _setIONContentRef(): any { return {} };
}
then have to import that mock into your .spec.ts file as follows
import {ViewControllerMock} from '../../mocks';
then have to define that mock in your providers in spec.ts file as follows
providers: [{ provide: ViewController, useClass: ViewControllerMock}],

Categories