Trying to mock private method that is in the class could not get any success, I am using jasmine so in below code i have getDrug method that is making http call , Now i can mock core but how do i stub/mock getDrug so code coverage can be improve.
DrugPriceApi.node.ts
export class DrugPriceApi extends Types.ModuleBase < DrugPriceParam, DrugPriceResultSet[] > {
private _memberId: string = "";
private _dependencies: any;
private errorMessage: string = "There was an issue while retrieving drug price. Please try again.";
before(args: DrugPriceParam): Promise < DrugPriceParam > {
args.daysSupply = args.daysSupply ? args.daysSupply : args.appName === "VOYA" ? "90" : "BLNK";
return Promise.resolve(args);
}
core(args: DrugPriceParam, requestMethod: Interface.Core.RequestMethod, _dependencies: any): Promise < any > {
this._dependencies = _dependencies;
return new Promise < any > ((resolve: Function, reject: Function) => {
this.getDrug(function(resolve) {
resolve( //response here);});
}
}
}
}
}
private getDrug(args: DrugPriceParam, requestMethod: Interface.Core.RequestMethod) {
return requestMethod.http.makeRequest({
url: {
name: 'domain_getDrug',
params: {
version: '1.0',
appName: args.appName ? args.appName : 'WEB',
tokenId: args.tokenId,
refId: args.refId,
internalID: args.memberInfo.internalID,
searchText: args.drugName,
drugNdcId: 'BLNK'
}
},
body: {
memberInfo: args.memberInfo
}
});
}
DrugPriceApi.spec.ts
import {
DrugPriceApi
} from "./DrugPriceApi.node";
it("should get drugByName", function(done) {
let getDrug: any;
beforeEach((done) => {
function getMockData(url: string): Promise < any > {
const rtnval = {
"details": [],
"header": {
"statusDesc": "Success",
"statusCode": "0000",
"IndexOfRequestThatFailed": []
}
};
return Promise.resolve(rtnval);
}
let moderator: Interface.Mock.Handler = {
getMockData: getMockData
};
getDrug = moderator;
});
let param: any;
param.daysSupply = "BLNK";
param.quantity = "BLNK";
param.memberId = "1372";
const result: any = _sdkInstance.SDK.Pricing.getDrugPrice(param);
result.then(function(res: any) {
spyOn(DrugPriceApi.prototype, "core").and.callFake(() => {
expect(DrugPriceApi.prototype.getDrug).toHaveBeenCalled();
});
expect(res.Header.StatusCode).toBe("5000");
done();
});
});
I am a bit confused on what is happening here and why DrugPriceApi is being tested indirectly. It looks like we are testing Pricing.getDrugPrice instead of the DrugPriceApi.
If you want to test DrugPriceApi.core then you simple needs to create an instance of it and set DrugPriceApi.getDrug = jasmine.createSpy();
const api = new DrugPriceApi();
api.getDrug = jasmine.createSpy();
api.core(...whatever).then(() => {
expect(api.getDrug).toHaveBeenCalled();
});
Related
I’ve a typescript class which built like following
export default class myClass{
myns: any;
async initializing() {
…
this.myns = na.map(function (item) {
return item["name"];
});
// here we have value
console.log(this.myns);
}
search(test, input) {
input = input || "";
return new Promise(function (resolve) {
let fuz= fuzzy.filter(input, this.myns); //here I want to access myns but here it comes undefined in debug
resolve(
fuz.map(function (el) {
return el.original;
})
);
});
}
}
I want to access myns inside the function search (in the function search is undfiend but inside init it have data) search how can I do it ?
not just myns is undefined this is undefined also
Try doing (resolve) => { instead of function (resolve) { so it will bind this to the callback
EDIT:
Running this code worked for me:
class myClass {
myns: any;
async initializing() {
this.myns = [{ name: 'test1' }, { name: 'test2' }].map(function (item) {
return item["name"];
});
console.log(this.myns);
}
search(test, input) {
input = input || "";
return new Promise((resolve) => {
console.log('test');
console.log(this.myns);
resolve();
});
}
}
const test = new myClass();
test.initializing();
test.search('lala', 'lala2');
As expected the output was:
[ 'test1', 'test2' ]
test
[ 'test1', 'test2' ]
What is that fuzzy library you are using?
can any one please tell me why I can not loop through this array?
In ngOnInit, everything works fine. I got an array that I successfully display in the template.
But in ngAfterViewInit, console.log show the array but when looping through with "for of" or "forEach", nothing works.
import { JobsService } from '../jobs.service';
import {Job} from '../models/Job';
#Component({
selector: 'app-job',
templateUrl: 'job.component.html'
})
export class JobComponent implements OnInit, AfterViewInit {
title = 'Job';
jobs: Job[] = [];
InProcess = '';
CurrentPartner = '';
ShowProcess = false;
sended = '';
constructor(private jobsService: JobsService) {
}
ngOnInit() {
this.jobs = this.jobsService.getJobs();
}
ngAfterViewInit() {
console.log(this.jobs); // Show the array
// Nothing happened when looping through the array
this.jobs.forEach((oneJob) => {
console.log(oneJob);
});
}
}
Screenshot of the console in Google Chrome
The content of the service:
import { HttpClient, HttpErrorResponse } from '#angular/common/http';
import { Observable, throwError } from 'rxjs';
import { catchError } from 'rxjs/operators';
import {Job} from './models/Job';
interface IJob {
message: string;
jobs: any[];
}
#Injectable({
providedIn: 'root'
})
export class JobsService {
constructor(private httpClient: HttpClient) { }
private REST_API_SERVER = 'http://localhost:8080/myband/api/getjobs.php';
private REST_API_SERVER_SEND = 'http://localhost:8080/myband/api/sendjob.php';
jobList: Job[] = [];
errorMessage: any;
message: string;
static handleError(err: HttpErrorResponse) {
let errorMessage = '';
if (err.error instanceof ErrorEvent) {
errorMessage = `An error occurred: ${err.error.message}`;
} else {
errorMessage = `Server returned code: ${err.status}, error message is: ${err.message}`;
}
console.error(errorMessage);
return throwError(errorMessage);
}
public getJobs() {
this.requestJobs().subscribe(
iJob => {
this.message = iJob.message;
for (const job of iJob.jobs) {
const oneJob: Job = new Job(job);
this.jobList.push(oneJob);
}
},
error => this.errorMessage = error as any
);
return this.jobList;
}
public requestJobs(): Observable<IJob> {
return this.httpClient.get<IJob>(this.REST_API_SERVER).pipe(
catchError(JobsService.handleError)
);
}
}
The first thing I want to say to you is about isolation of responsibilities.
Your service must have just one job: provider one way to access your data; It means your logic inside getJobs() method could be done in your component.
export class JobsService {
constructor(
private httpClient: HttpClient,
) {}
private REST_API_SERVER = 'http://localhost:8080/myband/api/getjobs.php';
public requestJobs(): Observable<IJob> {
return this.httpClient.get<IJob>(this.REST_API_SERVER);
}
}
Now, you can handler your data in your component.
import { JobsService } from '../jobs.service';
#Component({
selector: 'app-job',
templateUrl: 'job.component.html'
})
export class JobComponent implements OnInit, AfterViewInit {
title = 'Job';
jobs$;
InProcess = '';
CurrentPartner = '';
ShowProcess = false;
sended = '';
constructor(private jobsService: JobsService) {
}
ngOnInit() {
this.jobs$ = this.jobsService.requestJobs();
}
ngAfterViewInit() {
this.jobs$
.pipe(
map(() => {}), // change your data here
catchError(() => {}) // handler your error here;
)
.subscribe(
() => {} // have access to your final data here.
);
}
}
Things to know:
You can remove the subscribe() execution and use the async pipe in your template;
The use of the operator map in pipe() is optional, you can handler your final data directly from your first callback subscribe().
You can convert your Observable to Promise using toPromise() method in one observable. Don't forgot async / await in your ngAfterViewInit.
Let me know if there is something I can help.
Try:
Object.keys(this.jobs).forEach(job => {
console.log(this.jobs[job]);
});
Try to assign an iterator function with below part replacement by this code:
// Nothing happened when looping through the array
this.jobs.forEach(oneJob, function(value, key) {
console.log(key + ': ' + value);
});
Usage of forEach in AngularJS:
For documentation try to check AngularJS forEach Docs
Syntax:
someIterable.forEach(object, iterator, [context])
Please check below example
class Job {
id: any;
status: any;
constructor(obj: any) {
this.id = obj.id;
this.status = obj.status;
}
}
let arr = [
{
id: 1,
status: "job"
}, {
id: 2,
status: "job2"
}
];
let newArr: any = [];
arr.forEach(a => {
let obj: Job = new Job(a);
newArr.push(obj);
})
console.log(newArr);
newArr.forEach((a: any) => {
console.log(a);
})
just wanted to avoid if statements is there way to assign values to object if they have similar keys in response instead of checking each object with if ?
what could be efficient approach here ?
main.ts
public responsehandler(#Body()data: any): any {
const response: Idetails = {} as Idetails;
if (data.details === undefined || data.details === null) {
return data;
}
if (data.details) {
if (data.details.primary) {
response.details.primary.beginningBalance = data.details.primary.beginningBalance;
response.details.primary.endingBalance = data.details.primary.endingBalance;
}
if (data.details.secondary) {
response.details.secondary.beginningBalance = data.details.secondary.beginningBalance;
response.details.secondary.endingBalance = data.details.secondary.endingBalance;
}
}
return response;
}
interface.ts
export interface Idetails {
primary:balanceDetails;
secondary: balanceDetails;
}
export interface balanceDetails {
beginningBalance: string;
endingBalance: string;
}
data
details: {
primary: {
beginningBalance: 458,
endingBalance: 890
},
secondary: {
beginningBalance: 47,
endingBalance: 871
}
}
Check this out: https://developer.mozilla.org/es/docs/Web/JavaScript/Referencia/Objetos_globales/Object/hasOwnProperty
You could try this approach:
public responsehandler(#Body()data: any): any {
const response: Idetails = {} as Idetails;
if (!data.details) {
return data;
}
for (const key in response.details) {
if (data.details.hasOwnProperty(key)) {
response.details[key] = data.details[key];
}
}
return response;
}
You should check more validations or conditions to make it work for you.
If your goal is just to avoid if statements, you could rewrite it like so:
// in js (sorry not a ts user)
function responseHandler(data) {
return data.details == null ? data : {details: {...data.details}};
}
console.log(responseHandler({details: {primary: {beginningBalance: 0, endingBalance: 1}}}));
console.log(responseHandler({details: {secondary: {beginningBalance: 0, endingBalance: 1}}}));
console.log(responseHandler({noDetails: 'oopsy'}));
this.listvalue;
list.forEach((v: any) => {
v.data.forEach((v2: any) => {
this.searchlist.push({
header: v.header,
value: v2.value_0
});
});
});
i want to pass the this.listvalue on the place of v2.value_0 =>v2.this.listvalue but this is not working giving syntax error I also tried v2.valueof(this.listvalue) but its also not working like that i want to change call the v2 via this.listvalue
How can I do this? what is the correct syntax for this scenario?
the whole code is here
export class Md2Component {
#Input() list: any;
#Input() listvalue: any;
public searchlist;
public placeholder: String = "Searct the JSON";
public switch: boolean = true;
public switch5: boolean = true;
public searchlistresult: any
public data: string;
public header1: String;
public resultant_list: any;
public lastone: user[] = [];
#Output() _onSelect = new EventEmitter<any>();
public anyinstance: any
public user2: user
s = '';
public index;
constructor() {
}
ngOnInit() {
this.data = this.listvalue;
this.createSearchList(this.list);
this.latest(this.searchlist);
}
private createSearchList(list: any) {
this.searchlist = [];
this.listvalue;
list.forEach((v: any) => {
v.data.forEach((v2: any) => {
this.searchlist.push({
header: v.header,
value: v2.value_0
});
});
});
}
search1(s) {
this.search(s);
if (this.switch != true) {
this.latest(this.searchlistresult)
}
}
search(s) {
this.switch = false;
this.searchlistresult = _.filter(this.searchlist, (o: any) => {
if (s) {
return _.startsWith(_.lowerCase(o.value), _.lowerCase(s));
}
this.switch = true;
return true;
});
}
latest(list: any) {
const arr = list;
const keys = [];
for (let i of arr) {
if (!keys.includes(i.header)) keys.push(i.header);
}
const result = keys
.map(k => Object.assign({header: k}, {
data: arr.filter(x => x.header === k)
.map(y => Object.assign({}, {value: y.value}))
}));
this.anyinstance = result;
}
generateArray(obj) {
return Object.keys(obj).map((key) => {return obj[key]});
}
onSelect(header: any, value: any) {
{
console.log(header);
console.log(value);
this.s = value;
this.user2 = {
header: header,
value: value
}
this.lastone.push({
'header': header,
'value': value,
}
);
this.switch = true;
this._onSelect.emit(this.user2);
}
}
}
You've said this.listvalue is an #Input() so we will assume it has been initialized with a value already.
UPDATE You can try passing as a parameter. As the global scope of listvalue is what's causing your issue, passing it into the function will bring it into the correct scope.
// Bringing listvalue into scope, to avoid use of 'this' accessor.
private createSearchList(list: any, listvalue: any) {
this.searchlist = [];
list.forEach((v: any) => {
v.data.forEach((v2: any) => {
this.searchlist.push({
header: v.header,
value: listvalue
});
});
});
}
I am having a problem that my promise isn't being bound to the correct this.
I have read many articles on this subject and I think I understand the problem, but the solution isn't clear.
Suggestions
Here is the code:
// AngleCouch.ts`enter code here`
namespace AngleCouchDb {
//Note this is not a ng Service
export class AngleCouch {
...
public getAllUsers(): ng.IPromise<any> {
let dbUrl: string = this.urlPrefix + "/_users/_all_docs? include_docs=true";
let status = new CouchStatus();
console.log("in getAllUsers");
return this.http.get(dbUrl);
}
...
}
}
// UserManagementController.ts
module app {
class UserManagementController {
static $inject = [
'$mdSidenav', '$mdToast', '$mdDialog',
'$mdMedia', '$mdBottomSheet', '$state'];
...
public fetchUsers = () => {
let aUser = AngleCouchDb.ActiveUser.getInstance();
if (aUser.loginStatus `enter code here`!== Shows.StaticData.LoggedIn) {
return;
}
console.log("userManagementController: ");
console.log(this.$state);
this.vm.couch = new AngleCouchDb.AngleCouch();
this.vm.version = {};
this.vm.docTypeList = [];
this.vm.couch.urlPrefix = Shows.StaticData.server;
this.vm.user = new AngleCouchDb.UserCred();
this.vm.couch = new AngleCouchDb.AngleCouch();
this.vm.couch.getAllUsers().then(this.getAllUsersCB, (response: any) => {
console.log(response);`enter code here`
});
}
public getAllUsersCB = (response) => {
this.vm.gridObj = this.vm.initGridOpt();
this.vm.gridObj.data = response.data.rows;
}
...
angular.module("app").
controller("app.userManagementController", UserManagementController );
}