protractor timed out only when ignoreSynchronization is set to false - node.js

I couldn't figure out why protractor timed out when it reach to the code with ignoreSynchronization set to false;
this.countSubscribers = function () {
this.subscriberCount().then(function (count) {
totalSubscribers = count;
});
};
the method works correctly and totalSubscribers variable is getting correct value when
ignoreSynchronization = true;
Code below is a sample of my spec page:
describe("subscriber page test", function () {
"use strict";
var selectedCount = 10;
var subscriberCount;
describe("This test script selects no. of subscribers to be displayed on subscriber page", function () {
/**
* Step-1#Select number of items to be displayed
* Step-2#Get the count of subscribers displayed
* Step-3#check whether the number of subscribers displayed is equal to 10
*/
it("should select the no. of items to displayed and get the count", function () {
browser.ignoreSynchronization = false;
subscriber_page.selectItems(selectedCount);
subscriber_page.countSubscribers();
});
it("should check whether the selected no. of subscribers are displayed", function () {
expect(subscriber_page.getSubscribers()).toBe(10);
});
});
});
and the code below is a sample of my page object:
var SubscriberPage = function () {
"use strict";
this.subscriberCount = function() { return element...};
this.selectOption = function(count) {return element...};
var totalSubscribers;
/**
* This method selects items in list box
*/
this.selectItems = function (count) {
this.selectOption(count).click(); //selects the items from list box
};
/**
* This method sets the number of subscribers listed
*/
this.countSubscribers = function () {
this.subscriberCount().count().then(function (count) {
totalSubscribers = count;
});
};
/**
* This method returns the subscriber count
*/
this.getSubscribers = function () {
return totalSubscribers;//returns the count of subscribers.
};
};
module.exports = new SubscriberPage();
The code select items successfully, but it makes long pause afterward then produce
following error message:
Failed: Timed out waiting for Protractor to synchronize with the page after 5 seconds. Please see https://github.com/angular/protractor/blob/master/docs/faq.md
While waiting for element with locator - Locator: By(css selector, ...)
What I found out so far:
If I comment out following line from spec page countSubscribers method rather works correctly:
subscriber_page.selectItems(selectedCount);
or if I temporarily flip the ignoreSynchronization variable to true before countSubscribers method is executed, it works fine.
Can anyone explain what the protractor is doing at this point and what the best solution is while browser.ignoreSynchronization is set to false?

Keep a reference of "this" before your function. And then call it whenever you want.
Also if you do element.all(...) You'll be able to use the native .count() which will resolve the promise for you.
//Reference to this
var self = this;
//element.all with .count()
this.subscriberCount = function() { return element.all(...).Count()};
//This method returns the number of subscribers listed
this.countSubscribers = function () {
return self.subscriberCount();
});

Related

Web3.js pair contract events.Swap not correctly subscribing to swap event

I am trying to run a section of (nodejs using Web3.js) code whenever a swap occurs on a given pair contract (qPair is the pair contract derived from Quickswap's router contract (Polygon blockchain) and sPair is the same pair contract derived from Sushiswap's router contract (also Polygon blockchain)) but the code doesn't work as intended when implented as a class. I have it working in one file, but when I try to create a class for crypto pairs, the code wont work.
Here is the working code:
const main = async () => {
qPair = await getPairContract(quickswapFactoryContract, token0.address, token1.address)
sPair = await getPairContract(sushiswapFactoryContract, token0.address, token1.address)
/* The below code is listening for a swap event on the Quickswap exchange. When a swap event is
detected, the code checks the price of the token pair on Quickswap and compares it to the price
of the token pair on Sushiswap. If the price on Quickswap is higher than the price on Sushiswap, the
code will execute a trade on Quickswap. If the price on Sushiswap is higher than the price on
Quickswap, the code will execute a trade on Uniswap. */
qPair.events.Swap({}, async () => {
console.log("qPair activated")
/*
*
* Do stuff here
*
*/
})
/* The below code is listening for an event on the Sushiswap contract. When the event is detected,
the code will check the price of the token pair and determine if there is an arbitrage
opportunity. If there is an arbitrage opportunity, the code will execute the trade. */
sPair.events.Swap({}, async () => {
console.log("sPair activated")
/*
*
* Do stuff here
*
*/
})
console.log("Waiting for swap event...")
}
And here is the code that doesn't work:
const main = async () => {
qPair1 = new cryptoPair(<same token details as before go here>)
sPair1 = new cryptoPair(<same token details as before go here>)
qPair1.pairContract.events.Swap({}, async () => {
// The code here activates once (after main() reaches the bottom) and never again
})
sPair1.pairContract.events.Swap({}, async () => {
// The code here activates once (after main() reaches the bottom) and never again
})
console.log("waiting for swap event")
} // Once the debugger reaches here, the two "async" console logs activate
The class has the same code as the "working" code but instead would just do this._pairContract = await getPairContract() and then return that variable using a getter function.
Here is the (nonworking) class code:
module.exports = class cryptoPair {
constructor(token0Address, token0Decimals, token1Address, token1Decimals, factory) {
this._token0Address = token0Address;
this._token0Decimals = token0Decimals;
this._token1Address = token1Address;
this._token1Decimals = token1Decimals;
this._factory = factory;
}
// Setter functions
set token0(web3Token) {
this._token0 = web3Token;
}
set token1(web3Token) {
this._token1 = web3Token;
}
set token0Contract(web3Contract) {
this._token0Contract = web3Contract;
}
set token1Contract(web3Contract) {
this._token1Contract = web3Contract;
}
// Getter functions
get token0Address() {
return this._token0Address;
}
get token1Address() {
return this._token1Address;
}
get factory() {
return this._factory;
}
get token0Contract() {
return this._token0Contract;
}
get token1Contract() {
return this._token1Contract;
}
get token0() {
return this._token0;
}
get pairContract() {
return this._pairContract;
}
// The following two functions are nearly identically defined in the "working code"
// But instead don't use the "this.variableName" syntax
async defineTokens(t0Address, t0Decimals, t1Address, t1Decimals) {
try {
this._token0Contract = new web3.eth.Contract(IERC20.abi, t0Address)
this._token1Contract = new web3.eth.Contract(IERC20.abi, t1Address)
const t0Symbol = await this._token0Contract.methods.symbol().call()
const t0Name = await this._token0Contract.methods.name().call()
this._token0 = new Token(
ChainId.POLYGON,
t0Address,
t0Decimals,
t0Symbol,
t0Name
)
const t1Symbol = await this._token1Contract.methods.symbol().call()
const t1Name = await this._token1Contract.methods.name().call()
this._token1 = new Token(
ChainId.POLYGON,
t1Address,
t1Decimals,
t1Symbol,
t1Name
)
} catch (err) {
// For some reason, I keep getting the error "hex data is odd-length" in the
// class but not when this same code is outside of a class
console.log("Token creation failed, retrying...")
this.defineTokens(this._token0Address, this._token0Decimals, this._token1Address, this._token1Decimals)
}
}
async definePairContract() {
this._pairAddress = await this._factory.methods.getPair(this._token0Address, this._token1Address).call();
this._pairContract = new web3.eth.Contract(IUniswapV2Pair.abi, this._pairAddress);
}
}
To reiterate, the "working code" runs the inner code of the async events.Swap() code whenever a swap is triggered, but the same code when implemented as a class does not work. Is this because of the use of classes? Or did I make a mistake somewhere? Thanks in advance!
I fixed the issue. Of course, the issue was outside of the code provided where I defined web3. The working way defined it as:
web3 = new Web3(`wss://polygon-mainnet.g.alchemy.com/v2/${process.env.ALCHEMY_API_KEY}`)
whereas the incorrect class was defining it as
provider = new HDWalletProvider({
privateKeys: [process.env.DEPLOYMENT_ACCOUNT_KEY],
providerOrUrl: `wss://polygon-mainnet.g.alchemy.com/v2/${process.env.ALCHEMY_API_KEY}`
})
web3 = new Web3(provider)

can't able to mock a variable while testing

I am trying testing on node js I want to mock a variable outside of a function that is going to be unit tested.
for example
const sample = [];
function uploadDoc {
sample.push('fileLocation')
}
function toSave(){
for (i=0;i<sample.length;i++)
**some process read and access doc
}
I am facing issue while unit testing the second function
I have tried rewire npm that is also not working
Programming likes this will work,You should call uploadDoc firstly.
const sample = [];
function uploadDoc {
sample.push('fileLocation')
}
function toSave(){
uploadDoc();
for (var i=0;i<sample.length;i++)
**some process read and access doc
}
Well, you face challenges to test both functions, then, what you need is to refactor the code. Because I think, your code is not testable.
I give you this long example, which contain both of your functions but testable.
Changes I made for refactor:
function uploadDoc now will output an array.
function toSave now will require 1 parameter, which is an array.
combine functions into class.
const sinon = require('sinon');
const { expect } = require('chai');
const Doc = {
/**
* #return array of file location.
*/
uploadDoc: () => {
const sample = [];
sample.push('fileLocation');
return sample;
},
/**
* #param array samples
* #return void
*/
toSave: (samples) => {
samples.forEach(() => {
// Some process read and access doc.
})
},
}
/**
* This is for example purposes.
* #return void.
*/
function integrationBothFunction () {
const samples = Doc.uploadDoc();
Doc.toSave(samples);
}
describe('Unit Test', function () {
it('uploadDoc fn', function () {
const result = Doc.uploadDoc();
// You expect the result to be an array.
expect(result).to.be.an('array');
});
it('toSave fn', function () {
const samples = [];
const spySamples = sinon.spy(samples, 'forEach');
// Call the function
Doc.toSave(samples);
// You expect: there is forEach called for samples.
expect(spySamples.calledOnce).to.equal(true);
// Do not forget to restore.
spySamples.restore();
});
it('integrationBothFunction fn', function () {
// This is just sample to check.
const testSample = ['x'];
// Now finally, you can stub uploadDoc.
// Where real uploadDoc function not get called.
const stubUploadDoc = sinon.stub(Doc, 'uploadDoc');
stubUploadDoc.returns(testSample);
// Spy on toSave fn.
const spyToSave = sinon.spy(Doc, 'toSave');
integrationBothFunction();
// You expect that toSave is processing output from uploadDoc.
expect(stubUploadDoc.calledOnce).to.equal(true);
expect(spyToSave.calledOnce).to.equal(true);
// Check argument toSave.
const { args } = spyToSave;
expect(args).to.have.lengthOf(1);
expect(args[0]).to.have.lengthOf(1);
expect(args[0][0]).to.include(testSample[0]);
// Restore spy and stub.
stubUploadDoc.restore();
spyToSave.restore();
});
});
I you run using mocha:
$ npx mocha stackoverflow.js
Unit Test
✓ uploadDoc fn
✓ toSave fn
✓ integrationBothFunction fn
3 passing (13ms)
$
Hope this helps. Good luck!

Call a generator function inside setInterval()

I am trying to call a generator function inside setInterval() method. The objective of this code is it will query a particular server for some data periodically, until it gets a non zero response. Upon getting the response it will call storeAddress() which is a generator function defined in the same file.
The below code is giving me an error like this:
SyntaxError: yield is a reserved word (248:6)
NOTE: I am using react-boilerplate to build my app. The above error is thrown by babel, as far as I can tell through searching internet.
I have tried const query = yeild call (setInterval, function(){magic code}, 10000). This does not give the error, but magic code never gets executed.
I have tried const query = setInterval(function* () {magic code}, 10000) with the same effect as above.
I have tried const query = setInterval(yield call(function(){magic code}, 10000) with same effect as above.
I have tried const query = yield call (setInterval, function(){magic code}, 10000) with same effect as above.
I have tried storeAddress(action.payload, balance).next() inside setInterval(). The control does flow inside storeAddress(), but that function also have generator calls inside, which never gets invoked. In fact nothing after the first generator call inside storeAddress() gets executed in this case.
function* callSaveNewAddress(action){
const selectedNetwork = yield select(selectNetworkId());
let count = 1;
let balance = 0;
const query = setInterval(function () {
getAddressBalance(action.payload, selectedNetwork).then(res =>
{return balance = res.data.mempool_balance});
if(balance > 0) {
yield call (storeAddress, action.payload, balance);
clearInterval(query);
} else if(count == 90) {
clearInterval(query);
console.log("Nothing received in 15 minutes");
}
}, 10000);
}
So how am I suppose to call storeAddress(), which is a generator function, inside a normal function like setInterval()?
const query= function * () {
const runner = yield call(setInterval, () => {
getAddressBalance(action.payload, selectedNetwork).then(res =>
{return balance = res.data.mempool_balance});
if(balance > 0) {
yield call (storeAddress, action.payload, balance);
clearInterval(query);
} else if(count == 90) {
clearInterval(query);
console.log("Nothing received in 15 minutes");
}
}, 1000);
}
try to use the setInterval within a call, passing through parameters the function you want to execute within it.

module.exports return value undefined

Little info, i have an arp.js file which takes a subnet address "192.168.2" and gets all strings returned from arp -a and stores in an array.
I can't figure out why my arpList function is returning an undefined value in my index.js file.
All the console.logs are returning the correct values in the arp.js page when called from the index.js, but the ipObj is coming up undefined. Even the console.log before i return of ipObj works.
Any help would be greatly appreciated.
var { spawn } = require('child_process');
const arpLs = spawn('arp', ['-a']);
var bufferData;
module.exports = {
arpList: function (subnet) {
arpLs.stdout.on('data', data => {
bufferData += data
})
arpLs.stderr.on('data', data => {
console.log('error: ' + data);
});
arpLs.on('exit', function (code) {
if (code != 0) {
console.log("Error exiting"); //if error occurs
}
console.log("exit start 1"); // checking internal processes at stages
var dataArray = bufferData.split(' ');
var ipArray = [];
for (i = 0; i < dataArray.length; i++) {
if (dataArray[i].includes(subnet)) {
ipArray.push(dataArray[i]);
console.log("loop working");
}
}
var ipObj = { "lanIps": ipArray };
console.log("Object is there: "+ipObj)
return ipObj; // this obj should be returned to the index.js call using
})
},
sayMyName: function () {
return "Hello";
}
}
//arpList(ipSubnet);
//INDEX.js
//the index page looks like this
//var arp = require('./arp.js);
//var ipSubnet = "192.168.2";
//var lanIps = arp.arpList(ipSubnet);
//console.log(lanIps);
I ended up adding a callback function to arpList - function (subnet, callback)
Then instead of returning the value pass it into the callback
Then on the index.js side instead of
var lanIps = arp.arpList(value)
i used
arp.arpList(value, function(res){lanIps = res}
return ipObj; // this obj should be returned to the index.js call using
It won't be returned. The reference say nothing about return value. Node-style callbacks rarely work like that because they are potentially asynchronous and returned value cannot be taken into account.
This a special case of this well-known problem. The process is asynchronous and is finished after arp.arpList(ipSubnet) call, there's nothing to assign to lanIps. This is a use case for promises. There are already third-party promisified counterparts like child-process-promise.
The problem can be also solved by moving to synchronous API. child_process functions have synchronous counterparts, including spawnSync.

I can't receive data from custom module in node.js

I wrote a module called accountManager.js
var sqlite3 = require('sqlite3');
var db = new sqlite3.Database("./users.db");
exports.userExists = function userExists(nickName) {
var stmt = 'SELECT * FROM users WHERE login="' + nickName + '"';
db.each(stmt,function(err,row) {
if(row) {
if(row.login==nickName) return true;
else return false;
}
});
}
In my main app.js file I've got
var accountManager = require('./lib/accountManager');
console.log(accountManager.userExists('user1'));
This app says 'undefined' in console... I checked that module is working fine, I guess it's problem with callback? Please, give me some help, I don't understand what is wrong with this code...
You need to understand how asynchronous functions and callbacks work.
Basically you cannot return anything inside the callback but need to invoke another callback which you pass to userExists.
var sqlite3 = require('sqlite3');
var db = new sqlite3.Database("./users.db");
exports.userExists = function userExists(nickName, cb) {
var stmt = 'SELECT * FROM users WHERE login="' + nickName + '"';
db.each(stmt,function(err,row) {
if(row) {
cb(row.login == nickName);
}
});
}
To use it:
accountManager.userExists('user1', function(found) {
console.log(found);
});
Besides that, your code has a gaping SQL injection hole and might not do what you intend to do. Here's a fixed version of the userExists function:
exports.userExists = function userExists(nickName, cb) {
var stmt = 'SELECT COUNT(*) AS cnt FROM users WHERE login = ?';
db.get(stmt, nickName, function(err, row) {
cb(row.cnt > 0);
});
};
Why is this better?
You do not interpolate the value in the SQL string (which is bad, you would have to escape stuff to avoid SQL injection). Passing it separately is much cleaner and better
You just want to know if a user exists. So retrieve the count (which will be exactly one row). If it's not zero the user exists.
Now the callback is always invoked. In the first example that is more closely based on your code it would only be invoked in case a user has been found - most likely not what you wanted.
You're returning a value from within the callback from db.each. However, this value is not returned by the outer function (userExists), which may return before the function passed to db.each is ever called.
You may want to provide a callback to the userExists function, like so:
exports.userExists = function (nickName, cb) {
var stmt = 'SELECT * FROM users WHERE login="' + nickName + '"';
var found=false;
db.each(stmt,function(err,row) {
if(row) {
if(row.login==nickName) {
found=true;
cb(true);
}
}
}, function () {
if (!found) {
cb(false);
}
});
}
Then, call it like:
var accountManager = require('./lib/accountManager');
accountManager.userExists('user1', function (found) {
console.log(found);
});

Resources