Access class property in typescript - javascript

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?

Related

Unit testing monkey patch in Angular (Cannot read properties of undefined (reading 'checkABC'))

I'm attempting to unit test my setStep() method in angular using Jasmine but I keep getting Cannot read properties of undefined (reading 'checkBusiness') thrown which prevents me from continuing the test.
This is the function in the component.ts:
get userBusiness(): string { return this.auth && this.auth.user && this.auth.user.Source; }
setSteps() {
if (this.userBusiness.checkBusiness('ABC')) {
this.items = steps['ABC'];
if (this.application.process.onboarding.status !== 'complete') { this.show = true; }
} else {
this.items = steps['DEF'];
}
}
checkBusiness() method is defined as a monkey patch to the String prototype class:
Interface String {
checkBusiness(...args: string[]): boolean;
}
String.prototype.checkBusiness = function(...args: string[]): boolean {
let result = false;
for (let arg of args) {
const currentBusinessArray = business[this];
if (!currentBusinessArray) {
result = false;
continue;
}
if (currentBusinessArray.includes(arg)) {
result = true;
}
}
return result;
};
Business is an array defined as:
const lob = Object.freeze( <any> {
ABC : ['ABC', 'ABC1', 'ABC2', 'ABC3'],
DEF : ['DEF', 'DEF1', 'DEF2', 'DEF3']
});
Testing/spec file:
it('should confirm that "show" is set to true in setSteps()', () => {
const testUserBusiness = {...testDataSvc.userABC}
const userBusinessSpy = spyOnProperty(component, 'userBusiness').and.returnValue(testUserBusiness);
console.log(component['userBusiness']);
component.setSteps();
})
Problem::
I keep getting Cannot read properties of undefined (reading 'checkBusiness') thrown
Any idea how to get past this? I've tried to search everywhere but there isn't something like this scenerio that I can follow.

How do we mock private method using jasmine?

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();
});

ES6: Super class doesn't hold state

I'm trying to figure out what's going on here, as the Parent/Super class does not have data after the initial construction.
// imports/server/a-and-b.js
class A {
constructor(id) {
// make MongoDB call and store inside this variable
// ...
this._LocalVariable = FieldFromMongo;
console.log(`this._LocalVariable: ${this._LocalVariable}`); // => This has a good value, ie: 'Test'
}
get LocalVar() {
console.log(`this._LocalVariable: ${this._LocalVariable}`); // => This has a undefined value when called from child class
return this._LocalVariable;
}
}
export class B extends A {
constructor(id) {
super(id);
this.TEST = 'THIS IS A TEST';
}
get THE_Variable() {
console.log(`super.LocalVar: ${super.LocalVar}`); // => This has a undefined value when called
return super.LocalVar;
}
get GETTHEVAR() {
return this.TEST; // => This returns 'THIS IS A TEST'
}
}
// imports/server/factory.js
import { B } from 'imports/server/a-and-b.js';
class Factory {
constructor() {
this._factory = new Map();
}
BuildInstances(id, cls) {
let instance = this._factory.get(cls);
if (!instance) {
if (cls === 'B') {
instance = new B(id);
this._factory.set(cls, instance);
return instance;
}
}
else {
return instance;
}
}
}
export let OptsFactory = new Factory();
// imports/server/test.js
import { OptsFactory } from 'imports/server/factory.js'
const B = OptsFactory.BuildInstances(id, 'B');
const THE_Variable = B.THE_Variable; // => always undefined
const TEST = B.GETTHEVAR; // => Always returns 'THIS IS A TEST'
Why does class A not keeping state?
This is what I found:
class A {
constructor(id) {
// make MongoDB call and store inside this variable
// ...
this._LocalVariable = FieldFromMongo;
}
get LocalVar() {
return this._LocalVariable;
}
GetThatLocalVar() {
return this._LocalVariable;
}
}
export class B extends A {
constructor(id) {
super(id);
}
get Style1() {
// Reference to Parent get function
return super.LocalVar; // => This has a undefined value when called
}
get Style2() {
// Reference to Parent property
return super._LocalVariable; // => This has a undefined value when called
}
get Style3() {
// Reference to local Property that is declared in Parent
return this._LocalVariable; // => This works
}
get Style4() {
// Reference to Parent without the getter
return super.GetThatLocalVar(); // => This works
}
get GETTHEVAR() {
return this.TEST; // => This returns 'THIS IS A TEST'
}
}
So basically the thing that works is Style3 Style 4 work.

Best way to update html after promise result

I wonder to know the best way of binding result of a promise which is as an injection to html tag using angular 2(I use ionic 2)...
As you know the main problem with async coding is loosing reference to the current object. It seems I should pass current object as a prameter to Promise function generator.
I searched internet for better solution but nothing I found! So is there any better approch?
Ionic 2 itself use observation and subscribe to do async proccess. But the major problem is that for existing functions which are not observable it couldn't work!
My approch:
Injectable class:
export class PromiseComponent {
doPromise = function (obj: any) {
return new Promise(function (resolve2) {
setTimeout(function () {
resolve2({ num: 3113, obj: obj });
}, 5000);
});
}
}
Call on click:
promiseVal = 0
doMyPromise() {
this.myPromise.doPromise(this).then(this.secondFunc);//UPDATED HERE
}
//UPDATED HERE
secondFunc = function (res) {
this.promiseVal = res.num
}
Html:
<div>{{promiseVal}} </div>
<button (click)="doMyPromise()">Do Promise</button>
If you want to consume a promise inside your component:
promiseVal = 0
doMyPromise() {
this.myPromise.doPromise().then((res) => {
this.promiseVal = res.num
});
}
And I don't know the reasoning behind your Service but it usually is like this (optional):
export class PromiseComponent {
doPromise() { //This method will return a promise
return new Promise(function (resolve2) {
setTimeout(function () {
resolve2({ num: 3113, obj: obj });
}, 5000);
});
}
}
After OP edited the post:
You can change this:
doMyPromise() {
this.myPromise.doPromise(this).then(this.secondFunc);//UPDATED HERE
}
to
doMyPromise() {
this.myPromise.doPromise(this).then(this.secondFunc.bind(this));//UPDATED HERE
}
As you know the main problem with async coding is losing reference to the current object
That's not true, the arrow function does not bind its own this therefore you don't need to send this to doPromise
export class PromiseComponent {
doPromise () {
return new Promise(function (resolve) {
setTimeout(function () {
resolve({ num: 3113 })
}, 5000)
})
}
}
promiseVal = 0
doMyPromise() {
this.myPromise.doPromise()
.then(res => {
this.promiseVal = res.num
})
}

Unit testing Typescript decorators

I have an application built on typescript with decorators for some convenience property assignments and wondering how I can go about writing unit tests for them.
export function APIUrl() {
return function (target: any, key: string) {
let _value = target[key];
function getter() {
return _value;
}
function setter(newValue) {
_value = getApiURL();
}
if (delete target[key]) {
Object.defineProperty(target, key, {
get: getter,
set: setter
});
}
};
}
In a spec class I have,
it("should return url string", ()=> {
#APIUrl();
let baseURL:string;
expect(baseURL typeOf string).toBe(true)
})
Since decorators are just functions I would suggest to just test them like any other function. And only if you really need to, add one tests that shows how to use the decorator with a class/member/...
Here is an example such a test could look like:
import test from 'ava';
import { APIUrl } from './path';
const decorate = new APIUrl();
test.before(t => {
let obj = { someProp: 'foo' };
decorate(obj, 'someProp');
t.context.foo = obj;
});
test('should return original value', t => {
t.is(t.context.foo.someProp, 'foo');
});
Another approach could be to setup some properties and/or methods that use your decorators and test their usage directly.
Note: decorators can only be used on class methods and members so you'd need to create a dummy class in your test.
Here's an example:
//Test Setup
class Test {
#APIUrl()
url: string;
#AnotherDecorator()
anotherFunction() {}
}
//Unit tests
describe('Decorator Tests', () => {
it('should work', () => {
const t = new Test();
expect(t.url).toEqual("something");
expect(t.anotherFunction()).toReturn("something else");
});
}

Categories

Resources