For Loop in Protractor is not working properly - javascript

I am working on Protractor for testing the Angular JS application. I have written a code to read the data from excel sheet.My scenario is like I have a end to end flow that should execute.The code will take the URL,UserName and Password from the excel sheet and will execute the entire flow. Than again it will iterate the other value. But its not going into the loop.
My code is:
var Excel = require('exceljs');
var XLSX = require('xlsx');
var os = require('os');
var TEMP_DIR = os.tmpdir();
var wrkbook = new Excel.Workbook();
//---------------------Duration as Days------------------------------------------
describe('Open the clinicare website by logging into the site', function () {
it('IP Medication Simple flows for Patient Keerthi for Days,Weeks and Months', function () {
console.log("hello6");
browser.driver.manage().window().maximize();
var wb = XLSX.readFile('E:\\LAM WAH EE_Testing Enviornment\\IP_Medication_Flow\\Patients_Entry.xlsx');
var ws = wb.Sheets.Sheet1;
var json = XLSX.utils.sheet_to_json(wb.Sheets.Sheet1);
console.log("json", json);
//var json = XLSX.utils.sheet_to_json(wb.Sheets.Sheet1);
//console.log("json", json);
for(var a = 0; a < json.length ; a++){
console.log("Test_URL", json[a].Test_URL);
console.log("User_Name", json[a].User_Name);
console.log("Password", json[a].Password);
browser.get(json[a].Test_URL);
console.log("hello10");
//Perform Login:UserName
element(by.model('accessCode')).sendKeys(json[a].User_Name);
browser.sleep(6000);
// browser.driver.sleep(6000);
//Perform Login:Password
element(by.model('password')).sendKeys(json[a].Password);
browser.sleep(6000);
//Hospital Name
element(by.cssContainingText('option', 'HLWE')).click();
browser.sleep(6000);
//Perform Login:LoginButton
element(by.css('.btn.btn-primary.pull-right')).click();
browser.sleep(6000);
//Clicking on Admitted Tab
element(by.xpath("//span[contains(text(),' Admitted(25)')]")).click();
browser.sleep(6000);
// browser.driver.sleep(6000);
//Clicking on First Admitted Patient
element(by.cssContainingText('span.clearfloat', '35690')).element(by.xpath('//*[#id="searchPatientImgAdmittedF"]')).click();
jasmine.DEFAULT_TIMEOUT_INTERVAL = 600000;
// browser.sleep(600);
//Clicking anywhere to proceed
element(by.xpath('/html/body/div[3]/div[1]/div[16]/div[1]/div/table[4]/tbody/tr[2]/td/div/div/div[3]/table/tbody/tr[1]/td[3]')).click();
jasmine.DEFAULT_TIMEOUT_INTERVAL = 10000;
browser.sleep(800);
Anyone's help is appreciated. Thanks in advance.

Alright initially confused with the 'exceljs' node module. It is not used in your test. I think the major problem here is that the file does not exist.
readFile and ENOENT
The first thing of the readFile is an alias for readFileSync which calls readSync which calls (probably) read_binary which offloads to node's fs.readFileSync. More than likely the fs.readFileSync is throwing the ENOENT because the path does not exist.
Looking at your path, you might need a backslash before your spaces.
var wb = XLSX.readFile('E:\\LAM\ WAH\ EE_Testing Enviornment\\IP_Medication_Flow\\Patients_Entry.xlsx');
It could be a good practice to get the file path with path.resolve prior to calling the read file method.
var path = require('path');
var patientEntryFilePath = path.resolve('E:\\LAM\ WAH\ EE_Testing Enviornment\\IP_Medication_Flow\\Patients_Entry.xlsx');
console.log(patientEntryFilePath);
var wb = XLSX.readFile(patientEntryFilePath);
Additional comments and thoughts about the original code snippet
Some additional comments about the code snippet from the original question. Maybe considerations for future cleanup.
Think about using a beforeAll or beforeEach for setting your browser driver window size and reading in a file. Reading in the file once is potentially a time and resource saver.
describe('Open the clinicare website by logging into the site', function () {
var json = null;
beforeAll(() => {
browser.driver.manage().window().maximize();
var wb = XLSX.readFile('E:\\LAM\ WAH\ EE_Testing Enviornment\\IP_Medication_Flow\\Patients_Entry.xlsx');
var ws = wb.Sheets.Sheet1;
json = XLSX.utils.sheet_to_json(wb.Sheets.Sheet1);
});
it('IP Medication Simple flows for Patient Keerthi for Days,Weeks and Months', function () {
console.log("json", json);
...
Looking at your test that it is a login and it appears to have the same flow, you really only need to test this once. The for loop is acceptable since the json file is resolved and each line is executed in the control flow that Protractor uses.
Avoid using xpath. It is better to find elements by css or id or partial path. In the developer adds an additional div in the list of div's will break your test, making your test more fragile and require more upkeep.

This because Protractor API execute Async, but the For loop execute Sync. Get detail explain from here, which is same issue as yours.
To fix your issue, we can use javascript closure.
for(var a = 0; a < json.length ; a++) {
(function(a){
console.log("Test_URL", json[a].Test_URL);
console.log("User_Name", json[a].User_Name);
console.log("Password", json[a].Password);
browser.get(json[a].Test_URL);
console.log("hello10");
//Perform Login:UserName
element(by.model('accessCode')).sendKeys(json[a].User_Name);
browser.sleep(6000);
// browser.driver.sleep(6000);
//Perform Login:Password
element(by.model('password')).sendKeys(json[a].Password);
browser.sleep(6000);
...
})(a)
}

Related

How to manipulate URL while executing Test cafe scripts

I tried executing my TestCafe scripts using command prompt. While executing, test cafe starts execution by taking local IP, port number and session ID along side the URL. I want my scripts to execute directly on the URL without the local host IP, port and other details. Refer attached screenshot when I executed my scripts on Test Cafe.
Screenshot of test cafe script with local host IP, port
Attached is the code for test case which was executed on Test Cafe.
import { Selector } from 'testcafe';
import { Crypto } from 'testcafe';
var faker = require('faker');
function randomString(size) {
return crt
.randomBytes(size)
.toString('hex')
.slice(0, size)
};
function numberGen(len) { //Function to Generate random number;
length of number = value specified in 'len'
// var genNum= Math.floor(Math.pow(10, len)*Math.random()).toString()
var text = "";
var charset = "0123456789";
for( var i=0; i < len; i++ ) {
text += charset.charAt(Math.floor(Math.random() * charset.length));}
return text;
};
const dataSet = require('./dataIUT.json');
const crt = require('crypto')
var randomBankAccName = faker.random.alphaNumeric(6)+"Bank";
var AccountNumber = numberGen(9)
var AccountName = "AccName_"+faker.random.alphaNumeric(4)
fixture `CreateBankAccount`
.page `https://dev-assure-claims.dxc-rmcl.com/riskmasterux/#/login?
clientId=3f28130450c00018`
.beforeEach(t => t.resizeWindow(1200, 1100));
dataSet.forEach(data => {
test('CreateBankAccount', async t => {
//==================Login Code With JSON Starts================================
await t
.maximizeWindow()
.typeText(Selector('#username'), data.Username)
.pressKey('tab')
.typeText(Selector('#login-password'), data.Password)
.pressKey('enter')
.click(Selector('[ng-model="dsnSelected"]'))
.click(Selector('[role="option"]').find('span').withText(data.DSN))
.click(Selector('[ng-model="zoneSelected"]'))
.click(Selector('[role="option"]').find('a').withText('Claims'))
.click(Selector('#loginbox').find('button').withText('Continue'))
.wait(1000)
//==================Login Code With JSON Ends================================
//==================Code to Create Bank Account Starts ================================
.click(Selector('#menuBar').find('a').withText('Funds').nth(0))
.click(Selector('#menu_FundsRoot').find('a').withText('Bank Account'))
.switchToIframe(Selector('[id^="bankaccount"]'))
.wait(1000)
//var BankAccount = "BA_"+randomString(4).toUpperCase()
//await t
.click(Selector('#lookup_banklastname'))
.typeText(Selector('#lookup_banklastname'), randomBankAccName).setTestSpeed(0.6).pressKey('tab')
//.click(Selector('#accountnumber'))
.typeText(Selector('#accountnumber'), AccountNumber).setTestSpeed(0.6)
.pressKey('tab')
.click(Selector('#accountname')).typeText(Selector('#accountname'), AccountName).setTestSpeed(0.6)
.pressKey("tab")
.click(Selector('#Save').find('i').withText('save'))
//==================Code to Create Bank Account Endss==================================
//========================Click to RHS Child's Add button Starts=========================
const ele1 = Selector('[class="row main_menu right-panel-bg-hover"]').find('i').withText('add').with({ visibilityCheck: true }) // RHS Menu is available
await t.expect(ele1.exists).ok('', { timeout: 20000 })
.click(ele1)
//========================Click to RHS Child's Add button Ends=========================
//==========================Logout Code Starts==========================================
.switchToMainWindow()
.click(Selector('#morebtn').find('i').withText('more_vert'))
.click(Selector('#menu_othersMenu').find('a').withText('exit_to_appLogout'))
.click(Selector('#btnRoll').find('i').withText('done'));
//===========================Logout Code Ends========================================
});});
What issues is having the tests "run" on localhost causing you? What exactly are you trying to solve for?
What you're seeing is TestCafe communicating with the local TestCafe server. Looking at the docs, it isn't possible to have TestCafe communicate with a device that isn't your current machine, so I don't think what you want to achieve is possible.

Uploading and processing multiple files in node.js API

I'm new to nodejs and lets say i have to upload several text files in this kind of format to a nodejs endpoint (they could stack to a total of 200mb):
AU Olsen, BI
Lund, NW
Ellingsen, G
Hartvigsen, G
PY 2012
ER
AU Ming, X
Hajid, H
PY 2012
ER
What i want to do is to read those files and generate an array of objects that will be returned in the response, something like this:
publications = [{"author":["Olsen, BI", "Lund, NW", "Ellingsen, G", "Hartvigsen, G"],"publicationYear": "2012"},{"author":["Ming, X", "Hajid, H"],"publicationYear":"2012}]
At the moment i try to read all the files that were uploaded in the folder line by line so i can add to the publications variable latter on,the problem is that the publications variable always end up returning empty, looks like anything i do inside the IFS doesn't do anything, its probably an assynchronous callback problem but i have no idea how to fix it.
const multer = require ('multer');
const lineReader = require('line-reader');
var fs = require('fs');
const upload = multer({dest: 'uploads/'})
const app = express();
app.use(express.static('public'));
app.post('/uploadAndProcess', upload.array('publications'),(req,res) => {
var publications = [{}]
fs.readdir('./uploads', (err, dir)=>{
for(var i=0; i<dir.length; i++){
fileName = dir[i];
lineReader.eachLine('./uploads/'+fileName, function(line) {
if(line.includes('ER')) {
//do something and add to publications variable
}
if(line.includes('PY')) {
//do something and add to publications variable
}
});
}
})
return res.json({pub: publications});
});
app.listen(3001, () => console.log('App is listening...'));
Any thoughts? Thank you!
EDIT: Tried with sync readdir and still didnt work :(
app.post('/uploadAndProcess', upload.array('publications'),(req,res) => {
var publications = [{}]
var files = fs.readdirSync('./uploads');
for(var file in files) {
lineReader.eachLine('./uploads/'+files[file], function(line) {
if(line.includes('ER')) {
publications.push({'test':'test'})
}
});
};
return res.json({pub: publications});
});
I think you are on the right track with the async callback idea. I imagine the response is being sent out before the callback from fs.readdir is complete since fs.readdir is async and file reading is generally an expensive operation. Try using the fs.readdirSync function to process these synchronously and see if it works! Here's a link to the Node documentation to get you started.

Is there a way to share and edit global variables between two javascript node runs?

The main function file main.js has:
var nLastPingTime = 0,
nLastPingNumber = 0;
module.exports = {
compareData: function(nPingTime, nLastPingNumber){
nLastPingTime = nPingTime;
nLastPingNumber = nLastPingNumber;
}
};
Now two other files dataGenOne.js and dataGenTwo.js look something like this:
const mainDataHolder = require('./main.js');
//Gets data from some API's here
mainDataHolder.compareData(nPingTime, nLastPingNumber);
Then to start we run:
node dataGenOne.js
and
node dataGenTwo.js
The problem is that the main.js file doesn't share nLastPingTime and nLastPingNumber mutually between both sets of data.
For example when looking at nLastPingNumber, its the number from dataGenOne.js specifically and not from dataGenTwo.js at all (or vise versa).
I believe this is because they are running on two separate threads.
Is there anyway to achieve what I'm trying to do? The alternative could be to connect database or write to a file but if possible I would rather not do that.
To achieve what you are attempting to do, have two node processes communicate, you are going to have create process, lets call it spawn, that spawns both of the processes (let's call them p1 & p2) and then handles communication between p1 & p2.
So spawn would be a very simple process that would just wire the events for p1 & p2 and then forward those events to the other process. I don't have a working example of this but if you take a look here you should be able to piece that together pretty quickly.
Adam H pointed me in the right direct. The correct way to do this is in fact child_processes.
Below are the code changes:
The main function file main.js now has:
var cp = require('child_process');
var childDataOne = cp.fork('./dataGenOne.js', [process.argv[2]], { silent: true });
var childDataTwo = cp.fork('./dataGenTwo.js', [process.argv[3]], { silent: true });
childDataOne.stdout.on('data', function(data) {
console.log('parent: ' + data);
compareData(data);
//Here is where the output goes
});
childDataTwo.stdout.on('data', function(data) {
console.log('parent: ' + data);
compareData(data);
//Here is where the output goes
});
Now two other files dataGenOne.js and dataGenTwo.js changed to something like this:
process.stdin.resume();
var passingString = nPingTime + "," + nLastPingNumber;
process.stdout.write(passingString);
To start running we only have to do:
node main.js param1 param2
Instead of running dataGenOne.js and dataGenTwo.js individually.
This correctly allows the child processes to pass data back to the parent process. main.js is listening with stdout.on and the two dataGen child processes are passing the data with stdout.write.
So to avoid the complexity of storing these variables somewhere, merge the processes, but reorganize your code to make it easier to navigate.
main.js (the compare function?) - remove the variables from the top but make sure the compare function returns the latest ping values along with the comparison data i.e.
return {
data,
lastPingTime,
lastPingNumber
}
move the api stuff into separate files so you can do this
var dataSetOne = require('./dataOne');
var dataSetTwo = require('./dataTwo');
var datasets = [dataSetOne, DataSetTwo];
// initialize the values
var lastPingTime = 0;
var lastPingNumber = 0;
// loop through the datasets
for (var i = 0, len = datasets.length; i < len; i++) {
let currentDataSet = datasets[i];
const results = comparePrices(lastPingTime, lastPingumber, aAsks, aBids);
// update the ping info here
lastPingTime = results.lastPingTime;
lastPingNumber = results.lastPingNumber;
}
And if you have a lot of datasets, make an 'index.js' file that does all those requires and just returns the datasets array.
Hope that helps!

NodeJS stream parse and write json line to line upon Promise result

I have a large json file that looks like that:
[
{"name": "item1"},
{"name": "item2"},
{"name": "item3"}
]
I want to stream this file (pretty easy so far), for each line run a asynchronous function (that returns a promise) upon the resolve/reject call edit this line.
The result of the input file could be:
[
{"name": "item1", "response": 200},
{"name": "item2", "response": 404},
{"name": "item3"} // not processed yet
]
I do not wish to create another file, I want to edit on the fly the SAME FILE (if possible!).
Thanks :)
I don't really answer the question, but don't think it can be answered in a satisfactory way anyway, so here are my 2 cents.
I assume that you know how to stream line by line, and run the function, and that the only problem you have is editing the file that you are reading from.
Consequences of inserting
It is not possible to natively insert data into any file (which is what you want to do by changing the JSON live). A file can only grow up at its end.
So inserting 10 bytes of data at the beginning of a 1GB file means that you need to write 1GB to the disk (to move all the data 10 bytes further).
Your filesystem does not understand JSON, and just sees that you are inserting bytes in the middle of a big file so this is going to be very slow.
So, yes it is possible to do.
Write a wrapper over the file API in NodeJS with an insert() method.
Then write some more code to be able to know where to insert bytes into a JSON file without loading the whole file and not producing invalid JSON at the end.
Now I would not recommend it :)
=> Read this question: Is it possible to prepend data to an file without rewriting?
Why do it then?
I assume that want to either
Be able to kill your process at any time, and easily resume work by reading the file again.
Retry partially treated files to fill only the missing bits.
First solution: Use a database
Abstracting the work that needs to be done to live edit files at random places is the sole purpose of existence of databases.
They all exist only to abstract the magic that is behind UPDATE mytable SET name = 'a_longer_name_that_the_name_that_was_there_before' where name = 'short_name'.
Have a look at LevelUP/Down, sqlite, etc...
They will abstract all the magic that needs to be done in your JSON file!
Second solution: Use multiple files
When you stream your file, write two new files!
One that contain current position in the input file and lines that need to be retried
The other one the expected result.
You will also be able to kill your process at any time and restart
According to this answer writing to the same file while reading is not reliable. As a commenter there says, better to write to a temporary file, and then delete the original and rename the temp file over it.
To create a stream of lines you can use byline. Then for each line, apply some operation and pipe it out to the output file.
Something like this:
var fs = require('fs');
var stream = require('stream');
var util = require('util');
var LineStream = require('byline').LineStream;
function Modify(options) {
stream.Transform.call(this, options);
}
util.inherits(Modify, stream.Transform);
Modify.prototype._transform = function(chunk, encoding, done) {
var self = this;
setTimeout(function() {
// your modifications here, note that the exact regex depends on
// your json format and is probably the most brittle part of this
var modifiedChunk = chunk.toString();
if (modifiedChunk.search('response:[^,}]+') === -1) {
modifiedChunk = modifiedChunk
.replace('}', ', response: ' + new Date().getTime() + '}') + '\n';
}
self.push(modifiedChunk);
done();
}, Math.random() * 2000 + 1000); // to simulate an async modification
};
var inPath = './data.json';
var outPath = './out.txt';
fs.createReadStream(inPath)
.pipe(new LineStream())
.pipe(new Modify())
.pipe(fs.createWriteStream(outPath))
.on('close', function() {
// replace input with output
fs.unlink(inPath, function() {
fs.rename(outPath, inPath);
});
});
Note that the above results in only one async operation happening at a time. You could also save the modifications to an array and once all of them are done write the lines from the array to a file, like this:
var fs = require('fs');
var stream = require('stream');
var LineStream = require('byline').LineStream;
var modifiedLines = [];
var modifiedCount = 0;
var inPath = './data.json';
var allModified = new Promise(function(resolve, reject) {
fs.createReadStream(inPath).pipe(new LineStream()).on('data', function(chunk) {
modifiedLines.length++;
var index = modifiedLines.length - 1;
setTimeout(function() {
// your modifications here
var modifiedChunk = chunk.toString();
if (modifiedChunk.search('response:[^,}]+') === -1) {
modifiedChunk = modifiedChunk
.replace('}', ', response: ' + new Date().getTime() + '}');
}
modifiedLines[index] = modifiedChunk;
modifiedCount++;
if (modifiedCount === modifiedLines.length) {
resolve();
}
}, Math.random() * 2000 + 1000);
});
}).then(function() {
fs.writeFile(inPath, modifiedLines.join('\n'));
}).catch(function(reason) {
console.error(reason);
});
If instead of lines you wish to stream chunks of valid json which would be a more robust approach, take a look at JSONStream.
As mentioned in the comment, the file you have is not proper JSON, although is valid in Javascript. In order to generate proper JSON, JSON.stringify() could be used. I think it would make life difficult for others to parse nonstandard JSON as well, therefore I would recommend furnishing a new output file instead of keeping the original one.
However, it is still possible to parse the original file as JSON. This is possible via eval('(' + procline + ')');, however it is not secure to take external data into node.js like this.
const fs = require('fs');
const readline = require('readline');
const fr = fs.createReadStream('file1');
const rl = readline.createInterface({
input: fr
});
rl.on('line', function (line) {
if (line.match(new RegExp("\{name"))) {
var procline = "";
if (line.trim().split('').pop() === ','){
procline = line.trim().substring(0,line.trim().length-1);
}
else{
procline = line.trim();
}
var lineObj = eval('(' + procline + ')');
lineObj.response = 200;
console.log(JSON.stringify(lineObj));
}
});
The output would be like this:
{"name":"item1","response":200}
{"name":"item2","response":200}
{"name":"item3","response":200}
Which is line-delimited JSON (LDJSON) and could be useful for streaming stuff, without the need for leading and trailing [, ], or ,. There is an ldjson-stream package for it as well.

Nodejs/Javascript Getting Process Memory of any process

I am looking for a way of getting the process memory of any process running.
I am doing a web application. I have a server (through Nodejs), my file app.js, and an agent sending information to app.js through the server.
I would like to find a way to get the process memory of any process (in order to then sending this information to the agent) ?
Do you have any idea how I can do this ? I have searched on google but I haven't found my answer :/
Thank you
PS : I need a windows compatible solution :)
Windows
For windows, use tasklist instead of ps
In the example below, i use the ps unix program, so it's not windows compatible.
Here, the %MEM is the 4st element of each finalProcess iterations.
On Windows the %MEM is the 5th element.
var myFunction = function(processList) {
// here, your code
};
var parseProcess = function(err, process, stderr) {
var process = (process.split("\n")),
finalProcess = [];
// 1st line is a tab descriptor
// if Windows, i should start to 2
for (var i = 1; i < process.length; i++) {
finalProcess.push(cleanArray(process[i].split(" ")));
}
console.log(finalProcess);
// callback to another function
myFunction(finalProcess);
};
var getProcessList = function() {
var exec = require('child_process').exec;
exec('ps aux', parseProcess.bind(this));
}
// thx http://stackoverflow.com/questions/281264/remove-empty-elements-from-an-array-in-javascript
function cleanArray(actual){
var newArray = new Array();
for(var i = 0; i<actual.length; i++){
if (actual[i]){
newArray.push(actual[i]);
}
}
return newArray;
}
getProcessList();

Categories