Sinon stub - Cannot destructure property 'x' of 'undefined' or 'null' - sinon

I need to stub the following with Sinon :
const { clientId, dateString } = await parameterParser.prepareInputParameters(con, req);
I have tried using the following:
const retData = {
clientId: 872,
dateString: '1970-01-01',
};
sandbox.stub(parameterParser, 'prepareInputParameters').withArgs(con, req).returns(retData);
but I get the error:
TypeError: Cannot destructure property 'clientId' of 'undefined' or 'null'.
I have successfully stubbed the following elsewhere in my tests:
const { retData } = await sqlFileReader.read('./src/database/sql/getClientIdFromLoanId.sql', [`${req.query.loan_id}`], con, req.logger);
by using:
const retData = {
rowsCount: 1,
rows: [{ client_id: 872 }],
};
sandbox.stub(sqlFileReader, 'read').returns({ retData });
but I cannot get my head round how to stub const { clientId, dateString }

You need to be using resolves instead of returns for these stubs, since you are awaiting their return values, which should actually be Promises that resolve with your retData, and not the retData itself.
In sinon, resolves is a convenience for asynchronous methods. The following two lines are similar:
sinon.stub(foo, 'bar').returns(Promise.resolve('baz'));
sinon.stub(foo, 'bar').resolves('baz');
Your second sample may not be throwing an error, but if you log the value of retData after this line:
const { retData } = await sqlFileReader.read('./src/database/sql/getClientIdFromLoanId.sql', [`${req.query.loan_id}`], con, req.logger);
You'll notice that it is undefined. This is because await causes the result of the method call to be a Promise, which does not have a property called retData.
As for why your first sample is behaving differently, I'm not sure. I suspect that there's something else going on that isn't evident from your samples. Would you mind sharing more code?

Related

Unable to use AWS JS SDK V3 to list all tables

I am following the AWS SDK v3 for Javascript guide to display my DynamoDb table names.
https://docs.aws.amazon.com/sdk-for-javascript/v3/developer-guide/welcome.html
However, I am receiving the following error. Any help in understanding why I am receiving this error would be greatly appreciated! :-)
TypeError: Cannot read properties of undefined (reading 'ExclusiveStartTableName')
at serializeAws_json1_0ListTablesInput (C:\source\training\react\portfolio-app\finance_api\node_modules\#aws-sdk\client-dynamodb\dist-cjs\protocols\Aws_json1_0.js:3833:19)
at serializeAws_json1_0ListTablesCommand (C:\source\training\react\portfolio-app\finance_api\node_modules\#aws-sdk\client-dynamodb\dist-cjs\protocols\Aws_json1_0.js:357:27)
at serialize (C:\source\training\react\portfolio-app\finance_api\node_modules\#aws-sdk\client-dynamodb\dist-cjs\commands\ListTablesCommand.js:40:72)
at C:\source\training\react\portfolio-app\finance_api\node_modules\#aws-sdk\middleware-serde\dist-cjs\serializerMiddleware.js:12:27
at C:\source\training\react\portfolio-app\finance_api\node_modules\#aws-sdk\middleware-endpoint\dist-cjs\endpointMiddleware.js:20:16
at async C:\source\training\react\portfolio-app\finance_api\node_modules\#aws-sdk\middleware-logger\dist-cjs\loggerMiddleware.js:5:22
at async listTables (file:///C:/source/training/react/portfolio-app/finance_api/src/helper/listAWSTable.js:6:21)
at async file:///C:/source/training/react/portfolio-app/finance_api/src/helper/runAWSCommands.js:4:1
Here are the contents of the javascript file I am using to extract the list of tables, it's basically copied from the developer-guide.
NB I have substituted in my region and I have AWS credentials loaded in my VSCode.
listAWSTables.js
import { DynamoDBClient, ListTablesCommand } from "#aws-sdk/client-dynamodb";
async function listTables() {
const dbclient = new DynamoDBClient({ region: "ap-southeast-2" });
try {
const results = await dbclient.send(new ListTablesCommand());
results.Tables.forEach(function (item, index) {
console.log(item.Name);
});
} catch (err) {
console.error(err);
}
}
export { listTables };
I call it from another file "runAWSCommands.js":
runAWSCommands.js
import { listTables } from "./listAWSTables.js";
await listTables();
At the commandline I start it off using this command: node runAWSCommands.js
The error:
TypeError: Cannot read properties of undefined (reading 'ExclusiveStartTableName')
It is saying: "The ListTablesCommand cannot read a property from an input that is undefined"
If we look at the definition type of ListTablesCommand:
It expects an input value. If we look at the documentation, we can also see an input variable there.
This input object can be empty, in case you don't want to pass any configuration.
Hence, you can change the line:
const results = await dbclient.send(new ListTablesCommand());
to:
const results = await dbclient.send(new ListTablesCommand({}));
And it should work as expected.

Rxdb Plugin: Using the RxCollectionBase#insert method in a plugin

I am trying to create a plugin for rxdb.
I want to catch the exception raised by insert and return an hash with
{[fieldName: string] => [error:string]}
When using my new method though, I am getting an exception, and it seems like the method is getting called directly on the prototype rather than on each RxColletion<T, T2, T3> instance.
The error i am getting is:
TypeError: Cannot read property 'fillObjectWithDefaults' of undefined
which happens here: https://github.com/pubkey/rxdb/blob/ac9fc95b0eda276110f371afca985f949275c3f1/src/rx-collection.ts#L443
because this.schema is undefined.. The collection I am running this method on does have a schema though..
Here is my plugin code:
export const validatedInsertPlugin: RxPlugin = {
rxdb: true,
prototypes: {
RxCollection(proto: IRxCollectionBaseWithValidatedInsert) {
proto.validatedInsert = async function validatedInsert<T, D>(
doc: T
): Promise<Insert<T>> {
try {
// this is the line that raises:
const product = await proto.insert(doc);
return [true, product];
} catch (e) {
// extract errors
return [false, {} as Errors<T>];
}
};
},
},
overwritable: {},
hooks: {},
};
To answer my own question,
proto.insert is targeting the prototype, which is not what I want.
function(this: RxCollection) is what I want. I have to use this which will target the actual instance.
proto.validatedInsert = async function validatedInsert<T1>(
this: RxCollection,
doc: T1
): Promise<ValidatedInsert<T1>> {
try {
const product = await this.insert(doc); // this, not proto
return [true, product];
} catch (e) {
...

Meteor Async ValidatedMethod gets called with function parameters undefined

someMethod = new ValidatedMethod({
name: 'someMethodName',
validate: new SimpleSchema({
subId: {type: String, min:1},
planId: {type: String}
}).validator(),
async run(params){
try{
//params is undefined
}
}
});
Using async run(params) causes params to be undefined (seems like the context switches to Global context). Removing the async works fine (except that I cannot use await in the method body anymore obviously).
Why is this, and how can I still use await inside a ValidatedMethod?
Note1 : I call the method from the client like so -- and get the same result if I try to use a regular Meteor.methods({}) definition. I am calling the method using Meteor.apply from the client
ClientHelpers.callWithPromise = function(methodName, methodArgs){
//methodArgs must be an array
return new Promise(function(resolve, reject){
Meteor.apply(methodName, methodArgs, {wait:true}, function(error, result){
if (error){
reject(error);
}
console.log(result);
resolve(result);
});
});
}
Then, calling on client (am sure paramsObject is correct):
var myResult = await ClientHelpers.callWithPromise('someMethodName', [paramsObject]);
Note 2: I have also traced it through to the internals of Meteor.apply , where it is in fact sending the paramsObject over DDP, in debug session:
// Sends the DDP stringification of the given message object
_send(obj) {
this._stream.send(DDPCommon.stringifyDDP(obj));
}
Many thanks for any insight.

isomorphic-fetch and redux-saga, how to call it properly ? how to manage it with generators?

It tells me "promise is not a function". My problem is that with isomorphic fetch you have to put twice then to get your parsed result. What should I do to manage that properly with redux-saga generators ?
import { put, call, takeEvery, takeLatest } from 'redux-saga/effects'
import fetch from 'isomorphic-fetch'
import errorMessages from './../conf/errorMessages'
function *fetchBalances(address) {
try {
var request = fetch('/api/getBalances/rJnZ4YHCUsHvQu7R6mZohevKJDHFzVD6Zr').then(function(response) {
return response.json();
}). then(function(result) {
// finally my parsed result !
return result;
});
const balances = yield call(request)
yield put({ type: 'GET_BALANCES_SUCCEED', balances: balances})
}
catch(error) {
yield put({ type: 'GET_BALANCES_ERROR', error: error })
}
}
export function* watchGetBalances() {
yield takeEvery('GET_BALANCES', fetchBalances);
}
I could put that in a closure but is that the best idea ? =/
var request = function() {
return fetch('/api/getBalances/rJnZ4YHCUsHvQu7R6mZohevKJDHFzVD6Zr').then(function(response) {
return response.json();
}). then(function(result) {
return result;
});
}
The confusion here comes from the fact that the request variable that you're passing to the call effect holds a Promise. What you want, is the call effect to execute that Promise for you.
In other words, you have already manually called the fetch function, instead of passing call a function that will call and return it.
So, yes, wrapping your fetch calls in a, eg. callRequest function could be useful but if you do so, you must be careful to write const response = yield call(callRequest), and not const response = yield call(callRequest()), which would be equivalent to what you wrote.
A few precisions, in case it helps. From the docs, call receives as its first argument:
A Generator function, or normal function which either returns a Promise as result, or any other value.
Let's see how that works.
First a generator function.
const response = yield call(myFunction);
function* myFunction() {
yield delay(1000);
return true;
}
// response === true
Then a function returning some value (not the most useful, but…)
const response = yield call(myFunction);
function myFunction() {
return true;
}
// response === true;
Finally a function returning a Promise
const response = yield call(callRequest);
function callRequest() {
return fetch(…).then( r => r.json() )
}
// response holds your data
// if the Promise were to be rejected, you could catch
// the error in a try-catch block

Promises in angular2 with firebase

Can someone explain how to correctly implement promise in Angular2 and Firebase.
I've read some articles such as this https://www.firebase.com/blog/2016-01-21-keeping-our-promises.html
in my app.component.ts file i have this
export class AppComponent{
players: Player[];
constructor(private _playerService: PlayerService){}
getPlayers(){
this._playerService.getPlayers().then(res => this.players = res);
}
ngOnInit(){
this.getPlayers();
}
}
inside the player.service.ts file I have this
getPlayers() {
this.playersRef.once('value', function (snap){
return snap.val();
});
}
I always get TypeError: this._playerService.getPlayers(...) is undefined
I also tried this as the article on top suggests
getPlayers() {
var data;
this.playersRef.once('value').then( function (snap){
data = snap.val();
});
return data;
}
But then i get this: Error: Query.once failed: Was called with 1 argument. Expects at least 2. in [null]
I'm not sure how the article is working at all with .once('value').then()
Problem occurs because you are trying to using .then over a method which isn't using promise. Basically missed to return promise from getPlayers method, you should return promise from there to perform promise chaining using .then method over it.
Also don't use callback to return value from it(because callback are not capable of returning anything from it), use .then function over .once so that you can extend promise chain & will be able to return out data correctly.
Code
getPlayers() {
//returned promise here
return this.playersRef.once('value').then((snap) => {
return snap.val();
});
}

Resources