I have function in my application which returns the student details by making an ODATA call.
However the below code returns "this.edmOdataClient.query is not a function" error.
value of Id that is passed to the function is
4B199,9h7dH,ATC3S,fDB5Y,h33Ny,kousB,lTibg,nuGM
Below is my code snippet
async getStudent(Id) {
try {
if (Id != undefined) {
let index: number;
for (index = 0; index < Id.length; index++) {
const element = Id[index];
console.log("ELEMENT" +element);
this.student = await this.OdataClient.get<any>
(
this.edmOdataClient
.query(`CD_STUDENT`)
.filter(new FilterClause("SECTION").eq("A"))
.andFilter(new FilterClause("ID").eq(element))
.select(["NAME", "GRADE"])
.orderBy("ID")
).then(result => result.value[0])
}
}
return this.student;
}
catch (error) {
logger.info(error.message)
return error;
}
Also is there a way to check result.value.length?
When am trying to do so am getting error that result is undefined
this is only something you can call if your function belongs to a class (also note that arrow functions dont respond to this unless you bind the function)
const externalFunc = () => {
console.log('external func')
}
class MyClass {
constructor () {
this.externalFunc = externalFunc.bind(this)
}
myFuncOne () {
console.log('func one')
}
myFuncTwo () {
console.log('func two')
this.myFuncOne()
}
}
const klass = new MyClass()
klass.myFuncTwo()
// => func two
// => func one
klass.externalFunc()
// => external func
in your code, essentially the error is saying that getStudent is unable to reach edmOdataClient because its not bound to this
whatever class your code is running within doesnt have access to edmOdataClient
Related
I want to use the methods of the Minio class without specifying all their parameters, but substituting some of the parameters automatically. How do I do it...
I get all the class methods from the prototype of the Minio class and dynamically create wrappers for them in my class.
For each wrapper method, I get the parameter names from the original method of the Test class.
If there is one in the list of parameters that I want to omit when calling my wrapper method, then I add it to the list of arguments and call originalMethod.apply(this.minioClient, args).
Everything was fine until there were methods that were already wrapped.
I need to get the parameter list of the bucketExists method from outside the Minio class. Any idea how to get parameter names from such a wrapped method?
// minio/dist/main/helpers.js
exports function promisify(fn){
return function(){
const args = [...arguments];
fn.apply(this, args);
}
}
// minio/dist/main/minio.js
class Minio{
bucketExists(bucketName){
return bucketName;
}
methodThatNotWrappedByPromisifyAndWorksFine(bucketName){
return bucketName;
}
}
module.exports = Minio;
Minio.prototype.bucketExists = (0,helpers.promisify)(Minio.prototype.bucketExists)
I want to give an instance of my class with methods wrapped from the original class link the ability to work with only one bucket, that was passed to the my class constructor, without the ability to specify some other one after initialize.
My wrapper
const proxyHandler = () => {
return {
apply: (target, thisArg, argumentsList) => {
const funcParams = getMethodParamNames(target.source ? target.source.functionForWrap : target);
const bucketNameIndex = funcParams.indexOf("bucketName");
const regionNameIndex = funcParams.indexOf("region");
if (bucketNameIndex >= 0) {
argumentsList.splice(bucketNameIndex, 0, this.bucket.name);
}
if (regionNameIndex >= 0) {
argumentsList.splice(regionNameIndex, 0, this.bucket.region);
}
try {
return target.apply(this.minioClient, argumentsList);
} catch (error) {
logger.engine.error(`S3 '${this.bucket.name}' ${target} error: ${error.message}`, error.stack);
}
},
}
}
getMethods(this.minioClient).forEach(func => {
this[func] = new Proxy(this.minioClient[func], proxyHandler());
})
Solved the problem by overriding the method wrapper like this.
const MinioHelpers = require('minio/dist/main/helpers');
const origMinioPromisify = MinioHelpers.promisify;
MinioHelpers.promisify = (functionForWrap) => {
console.log("PATCHED!", functionForWrap);
var fn = origMinioPromisify(functionForWrap);
//from this i'll get all need information about wrapped function
fn.source = {
functionForWrap,
promisify: origMinioPromisify,
}
return fn
}
var Minio = require('minio');
I'm working on a pet project, a little front-end library for students. It reads variables/code in a JS file and tests it, outputting some panels. The code itself roughly follows the Jest framework.
My problem is that I'm trying to create a function that watches the execution of other functions, counts them, and lets me access the count.
function watchFunction(funcName){
let originalFunction = window[funcName];
let counter = 0;
// Wrap the function, counts when called
window[funcName] = function(...args){
console.log("watching");
counter++;
return originalFunction(...args);
}
return {
getCount: () => {return counter},
reset: () => {
// Unwrap the function
window[funcName] = originalFunction
}
}
}
This seems to work for methods like Number() or parseInt(), but I don't know how I would go about accessing methods like Math.floor(), or prototype methods like Array.prototype.map().
I've tried passing in the function reference instead of using window["funcNameString"], but that doesn't seem to work.
Does anyone have suggestions or tips for wrapping functions or watching functions like this?
EDIT:
It appears a solution was found!
function watchFunction(obj, fName) {
let counter = 0;
const originalFunction = obj[fName];
obj[fName] = (...args) => {
counter++;
return originalFunction.bind(obj)(...args);
};
return {
removeWatcher: () => (obj[fName] = originalFunction),
resetCount: () => (counter = 0),
getCount: () => counter,
};
}
Example of use:
// Array.prototype.push
const arrayPushWatcher = watchFunction(Array.prototype, "push");
let arr = [];
// 0
console.log("Array.prototype.push", arrayPushWatcher.getCount());
arr.push(1);
// 1
console.log("Array.prototype.push", arrayPushWatcher.getCount());
arr.push(1);
// 2
console.log("Array.prototype.push", arrayPushWatcher.getCount());
arrayPushWatcher.removeWatcher();
arr.push(1);
// 2 (stopped counting)
console.log("Array.prototype.push", arrayPushWatcher.getCount());
How to watch for any function call
Is that what you want? I can also write a block for this function so that it determines whether an object has been passed in or a string. If string -> run this function on window as a property "objectThatStoresFunction".
I've tried playing around with the Function.prototype, but it doesn't really work. So the function turned out a bit more complex.
This code below works both with functions / objects on window Array.prototype.map (Prototype / Class functions)
function watchFunction(objectThatStoresFunction, functionName) {
let counter = 0;
const originalFunction = objectThatStoresFunction[functionName];
objectThatStoresFunction[functionName] = (...args) => {
counter += 1;
return originalFunction(...args);
}
return {
getCount: () => {
return counter
}
}
}
const mathRoundWatcher = watchFunction(Math, 'round');
// 0
console.log(mathRoundWatcher.getCount());
// 1
Math.round(99666.9999999);
console.log(mathRoundWatcher.getCount());
// 2
Math.round(999999999.99);
console.log(mathRoundWatcher.getCount());
function watchFunction(objectThatStoresFunction, functionName, optionalOriginalFunction) {
const self = this;
if (optionalOriginalFunction) {
objectThatStoresFunction = this.window;
functionName = optionalOriginalFunction.name;
}
let counter = 0;
const originalFunction = objectThatStoresFunction[functionName] || optionalOriginalFunction;
objectThatStoresFunction[functionName] = (...args) => {
counter += 1;
return originalFunction.bind(self)(...args);
}
return {
// should it remove the watcher or reset the count?
reset: () => objectThatStoresFunction[functionName] = originalFunction,
getCount: () => {
return counter;
}
}
}
const arrayMapWatcher = watchFunction(Array.prototype, 'map');
// 0
console.log('Array.prototype.map', arrayMapWatcher.getCount());
[-99].map(() => {});
// 1
console.log('Array.prototype.map', arrayMapWatcher.getCount());
const mathRoundWatcher = watchFunction(Math, 'round');
// 0
console.log('Math.round', mathRoundWatcher.getCount());
// 1
Math.round(99666.9999999);
console.log('Math.round', mathRoundWatcher.getCount());
// 2
Math.round(999999999.99);
console.log('Math.round', mathRoundWatcher.getCount());
const alertWatcher = watchFunction(null, null, window.alert);
// 0
console.log('window.alert', alertWatcher.getCount());
// 1
window.alert('1');
console.log('window.alert', alertWatcher.getCount());
// 2
alert('2')
console.log('window.alert', alertWatcher.getCount());
// reset the alertWatcher counter
alertWatcher.reset();
This code above breaks the stacksnippets.com when used with Array.prototype.map for some reason, please see this JsFiddle link:
https://jsfiddle.net/ctbjnawz/3/
Do you mean a method of an instance or object? One way is to create a new function. e.g
function WatchInstanceMethods(instance, functionName){
let originalFunction = window[instance][funcName];
let counter = 0;
window[instance][functionName] = function(...args){
console.log("watching");
counter++;
return originalFunction(...args);
}
return {
getCount: () => {return counter},
reset: () => {
// Unwrap the function
window[funcName] = originalFunction
}
}
}
although adding support for chaining methods will get difficult with more nested methods but you can pass a string for functionName name and split it to have each layer of calling instance for function and repeat the logic above.
Up front I'm new to Node / Javascript an. What I am trying to do is to add a logging to my repository using a decorator function. Therefor I'm trying to iterate though each function from inside the constructor and override it with something like: "
Object.getOwnPropertyNames(Repository.prototype).forEach((func) => this.decorator(func));"
My problem is that "Object.getOwnPropertyNames" only returns the function names instead of the actual function. Is there a way to apply this decorator to each function?
"use strict"
const db = require("./Database/db_operations");
const logger = require("./utils/logger")
const {createTables} = require("./Database/db_operations");
const loggingTypes = require("./utils/logginTypes")
class Repository {
async saveTermin(Termin) {
}
async saveToDo(toDo) {
return await db.saveToDo(toDo);
}
async saveAppointment(Appointment) {
return await db.saveAppointment(Appointment);
}
async updateAppointment(Appointment) {
return await db.updateAppointment(Appointment);
}
async deleteAppointment(uuid) {
return await db.deleteAppointment(uuid);
}
async saveAppointmentParticipants(appointment) {
return await db.saveAppointmentParticipants(appointment);
}
async saveAppointmentFiles(appointment) {
return await db.saveAppointmentFiles(appointment)
}
async getAppointmentFiles(appointment) {
return await db.getAppointmentFiles(appointment)
}
async deleteToDo(todo) {
return await db.deleteToDo(todo)
}
}
// All functions will be mapped to there type to optimize logging. If a function is not mapped to its type,
// it will be automaticly assigned to the "unspecified type". Logging will still work, but depending on what
// arguments are given and what is returned, the output might not perfectly fit
const funcMapping = new Map();
// GET
funcMapping.set(Repository.prototype.getAppointmentFiles, loggingTypes.GET);
funcMapping.set(Repository.prototype.getAllDatas, loggingTypes.GET);
funcMapping.set(Repository.prototype.getAllToDos, loggingTypes.GET);
//SAVE
funcMapping.set(Repository.prototype.saveToDo, loggingTypes.SAVE);
funcMapping.set(Repository.prototype.saveAppointment, loggingTypes.SAVE);
funcMapping.set(Repository.prototype.saveAppointmentParticipants, loggingTypes.SAVE);
//DELETE
funcMapping.set(Repository.prototype.deleteAppointment, loggingTypes.DELETE);
funcMapping.set(Repository.prototype.deleteToDo, loggingTypes.DELETE);
Object.getOwnPropertyNames(Repository.prototype)
.forEach(name => {
const func = Repository.prototype[name];
// checking loggingTypes - if no type is assigned function will be assigned to "UNASSIGNED".
// console.log(funcMapping.has(func) +" "+ func.name)
if (!funcMapping.has(func)) {
funcMapping.set(func, loggingTypes.UNASSIGNED);
}
// function will only be wrapped if logging is enabled.
if (funcMapping.get(func)[1]) {
Repository.prototype[name] = async function (...args) {
// calls the original methode
const returnValue = await func.apply(this, args);
const argumentsInArray = Array.prototype.slice.call(args);
// Put any additional logic here and it will be applied -> magic
// Logging
db.writeLogging(logger(func, returnValue, funcMapping.get(func)[0]), args).then(() => {
console.log(`Function "${name}()" was successfully logged and saved to Database`)
}).catch(e => {
console.log(`Function "${name}()" could not be logged and saved to Database. ${func}`)
console.log(e)
})
return returnValue;
}
}
});
module.exports = new Repository();
const appointment_model = require('../models/Appointment');
const contact_model = require('../models/Contact');
const toDo_model = require('../models/ToDo');
const file_model = require('../models/File');
const loggingTypes = require("./logginTypes")
function log() {
// returns a function that returns an object. When this function is then called the object is returned
return function decorator(funcToLog, returnValue, funcType, ...args) {
// console.log("arguments in logger" + args);
// create prototype for object that later will be passed to database
const descriptor = function (user, change, changedAt) {
this.user = user; // some user id
this.change = change; //
this.changedAt = changedAt; // date when changes occoured
this.appointmentId = getUuid(appointment_model);
this.todoId = getUuid(toDo_model);
this.contactId = getUuid(contact_model);
this.fileId = getUuid(file_model);
};
// contains all logging Data about the function beeing called -> name of function, usedArguments and returnValue
function getChanges(func, funcType, returnValue, args) {
let changes = null;
switch (funcType) {
case loggingTypes.GET[0]:
changes = {
funcName: func.name, //
funcType: funcType, //
dataSetToChange: {...args},
newData: returnValue
}
break;
case loggingTypes.SAVE[0]:
changes = {
funcName: func.name, //
funcType: funcType, //
dataSetToChange: {...args}, // ?
newData: returnValue // could call function here
}
break;
case loggingTypes.UPDATE[0]:
changes = {
funcName: func.name, //
funcType: funcType, //
dataSetToChange: {...args},
newData: returnValue
}
break;
case loggingTypes.DELETE[0]:
changes = {
funcName: func.name, //
funcType: funcType, //
dataSetToChange: {...args},
newData: returnValue
}
break;
case loggingTypes.UNASSIGNED[0]:
changes = {
funcName: func.name, //
funcType: funcType, //
dataSetToChange: {...args},
newData: returnValue
}
}
return changes;
}
function getUuid(model_type) {
let uuid = null;
console.log(args)
for (let i = 0; i < args.length; i++) {
console.log(args[i])
if (args[i] instanceof model_type) {
uuid = parseInt(args[i].uuid);
}
return uuid;
}
}
return new descriptor("someUserId", JSON.stringify(getChanges(funcToLog, funcType, returnValue, args)), new Date())
}
}
module.exports = log();
You can easily map function names to their values using an intermediate step:
Object.getOwnPropertyNames(Repository.prototype)
.map(name => Repository.prototype[name])
.forEach((func) => this.decorator(func));
Anyway, the constructor is not the best place to do this, because you would end up applying the decorator every time a new instance of the class is created.
I would rather move the whole decorator logic after the class definition, before the assignment to module.exports.
Object.getOwnPropertyNames(Repository.prototype)
.forEach(name => {
const func = Repository.prototype[name];
Repository.prototype[name] = function (...args) {
console.log("Decorator was called");
const returnValue = func.apply(this, args);
// Put additional logging logic here...
return returnValue;
}
});
Update
In response to what noted in the comments, here is a somewhat more robust version of the code above, with additional precautions you may or may not need:
Preserve non-functions
Preserve non-value properties
Preserve the constructor
Preserve non-configurable properties
Include properties with symbol keys
Reflect.ownKeys(Repository.prototype).forEach(key => {
const descriptor = Reflect.getOwnPropertyDescriptor(Repository.prototype, key);
if (!descriptor.configurable) return;
const { value } = descriptor;
if (typeof value !== 'function') return;
if (value === Repository) return;
descriptor.value = function (...args) {
console.log("Decorator was called");
const returnValue = value.apply(this, args);
// Additional logging logic here...
return returnValue;
};
Object.defineProperty(Repository.prototype, key, descriptor);
});
Another thing I left out is additional logic to make sure that the decorated methods have the same length and name properties and the same prototype as the original functions. You may want to adjust even more details as you discover additional requirements while using your code.
I'm adding listeners to one link or multiple links, using the following code:
function getData() {
var context = {};
context['triggers'] = triggers();
context['msg'] = msg;
return context
}
function triggers() {
var arr = [];
document.querySelectorAll('.trigger').forEach(function (trigger, index) {
arr[index] = {};
arr[index]['trigger'] = trigger;
});
return arr;
}
function addListeners(data) {
data.triggers.forEach(function (trigger) {
trigger.addEventListener('click', change)
});
}
data = geData()
Trigger is an anchor:
I get the following error:
TypeError: trigger.addEventListener is not a function
The object in triggers isn't the anchor, it's an object that contains the anchor as a property called trigger. So:
function addListeners(data) {
data.triggers.forEach(function (entry) { // *** `entry` instead of `trigger`
entry.trigger.addEventListener('click', change)
// -----^^^^^^
});
}
We know this because of this code:
function triggers() {
var arr = [];
document.querySelectorAll('.trigger').forEach(function (trigger, index) {
arr[index] = {};
arr[index]['trigger'] = trigger;
});
return arr;
}
That's clearly creating an object, then setting the element as a trigger property on it.
Side note: You can use property initializers and property literal syntax in several places where you're using strings, and FWIW you can apply map to a NodeList:
function getData() {
return {
triggers: triggers(),
msg: msg
};
}
function triggers() {
return Array.prototype.map.call(
document.querySelectorAll('.trigger'),
function(anchor) {
return {trigger: anchor};
}
);
}
function addListeners(data) {
data.triggers.forEach(function (entry) {
entry.trigger.addEventListener('click', change)
});
}
data = geData();
When I try to set a spy on a imported function I get the following error msg TypeError: Cannot read property '_isMockFunction' of undefined
I don't understand what it's wrong with this code
Imported function is like below here
export
export
function myFn(){
let htmlEl = document.querySelector('html');
let el = document.querySelector('.target-el');
if(el){
el.addEventListener('click', myInternalFn, false);
}
function myInternalFn () {
isUserLoggedIn((isIn) => {
let logoutClassName = 'el--logout';
if (isIn) {
el.classList.remove(logoutClassName);
return;
}
el.classList.add(logoutClassName);
});
}
function isUserLoggedIn (fn) {
return fn(localStorage.getItem('userLoggedIn') === 'true');
}
}
document.addEventListener('DOMContentLoaded', () => {
myFn();
});
TDD:
import { betSlip } from "../src/main/javascript/custom/betslip-dialog";
describe('Testing bet slip button (only on mobile)', function () {
let htmlEl;
let el;
beforeEach(() => {
document.body.innerHTML =
`
<html>
<div class="target-el"></div>
</html>
`;
myFn();
htmlEl = document.querySelector('html');
});
it('When el button has been clicked for the first time', done => {
jest.spyOn(myFn, 'myInternalFn');
myInternalFn.click();
expect(true).toBe(true);
done();
});
});
According to Jest docs https://facebook.github.io/jest/docs/en/jest-object.html#jestspyonobject-methodname in your code
jest.spyOn(myFn, 'myInternalFn');
myFn needs to be an object and myInternalFn needs to be a property of this object.
In current realization myInternalFn is hidden in myFnscope, and isn't exposed to outside.
I suggest you to rewrite code (if it's possible) to use either prototype:
myFn.prototype.myInternalFn = function myInternalFn () { ... }
//and in tests
jest.spyOn(myFn.prototype, 'myInternalFn');
or direct assign to function object(not the best way as for me)
myFn.myInternalFn = function myInternalFn () { ... }
// and in tests
jest.spyOn(myFn, 'myInternalFn');
A main idea is - without public exposing myInternalFn you can't hang spy on it.