How to manipulate URL while executing Test cafe scripts - javascript

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.

Related

Generate logs for web application in Javascript

I have a use case in which I would like to generate logs for my JS web application, which could be stored as a file on the client-side (stored on the user's machine).
Therefore, I want to know that what approach can I follow for generating logs in JS?
If you mean you want to do this from browser-hosted JavaScript code, I'm afraid you can't. Browser-based JavaScript code can't write to arbitrary files on the user's computer. It would be a massive security problem.
You could keep a "log" in web storage, but note that web storage has size limits so you wouldn't want to let it grow too huge.
Here's a barebones logging function that adds to a log in local storage:
function log(...msgs) {
// Get the current log's text, or "" if there isn't any yet
let text = localStorage.getItem("log") || "";
// Add this "line" of log data
text += msgs.join(" ") + "\r\n";
// Write it back to local storage
localStorage.setItem("log", text);
}
Obviously you can then build on that in a bunch of different ways (log levels, date/time logging, etc.).
You can use local storage to simulate file :
Create id for each line of your "file" and store the number of the last line
function logIntoStorage (pMsg) {
if (!pMsg) pMsg = "pMsg is not here !";
if ((typeof pMsg) != "string") pMsg = "pMsg is Not a string:"+(typeof pMsg);
let logNb = "logNb";
let padLong = 7;
let strLg = "0";
let lg = 0;
let maxSize = 50; // max nb of lines in the log
// Reading log num line
strLg = localStorage.getItem(logNb);
if(!strLg) { //logNb not stored yet
lg = 0;
strLg = "0";
localStorage.setItem(logNb, lg.toString(10)); // store the number of cur line
} else { // Read logNb from storage
strLg = localStorage.getItem(logNb);
lg = parseInt(strLg,10);
}
if (lg >= maxSize) {
lg = maxSize; // size limit nb lines.
pMsg = "LIMIT SIZE REACHED";
}
// log msg into localStorage at logLine:0000####
let s = ("0000000000000000"+strLg).substr(-padLong); // padding zeros
localStorage.setItem("logLine:"+s, pMsg);
if (lg >= maxSize) return;
lg++; // point to the next line
localStorage.setItem(logNb, lg.toString(10));
}
In modern Chrome you can actually "stream" data to the user's disk, after they give permission, thanks to the File System Access API.
To do so, you have to request for a file to save to, calling showSaveFilePicker().
Once you get the user's approval you'll receive a handle from where you'll be able to get a WriteableStream.
Once you are done writing, you just have to .close() the writer.
onclick = async () => {
if( !("showSaveFilePicker" in self) ) {
throw new Error( "unsupported browser" );
}
const handle = await showSaveFilePicker();
const filestream = await handle.createWritable();
const writer = await filestream.getWriter();
// here we have a WritableStream, with direct access to the user's disk
// we can write to it as we wish
writer.write( "hello" );
writer.write( " world" );
// when we're done writing
await writer.ready;
writer.close();
};
Live example.

Saving text from an element on a web page using javascript

Let's say there's some text inside a particular element on a web page that I want to save. Using Javascript, how could I save that text/append it to a file "myfile.txt" on my hard drive? The element dynamically changes over time so whenever it updates i'd like it to append the new text to the file.
I've been doing some research on web scraping, and it just seems too over the top/complicated for this task.
I've written a Node.js program that fetches a webpage url every X seconds, and compare the previous and new value of a specific html element. It will only save changes to a specific output file.
Note that the previous value record will be deleted after each run of this program, meaning that the first time you run this program it will always save the extracted text ( Because there's nothing to compare to )
This program uses node-fetch and jsdom npm packages.
fs is a build in package for Node.js.
If you are new to Node.js, you can follow this to install in your computer.
const fetch = require('node-fetch');
const jsdom = require('jsdom');
const fs = require('fs');
// Local previous extracted text variable to compare and determine changes
let prevExtractedText;
// The webpage URL to fetch from
const url = 'https://en.wikipedia.org/wiki/Node.js';
// Setting your file's output path
const outputFilepath = 'myfile.txt';
// Setting timeout every 5 seconds
const timeout = 5000;
const handleOnError = (err) => {
console.error(`! An error occurred: ${err.message}`);
process.exit(1);
}
const handleFetchAndSaveFile = async () => {
let html;
try {
console.log(`* Fetching ${url}...`);
const resp = await fetch(url);
console.log('* Converting response into html text...');
html = await resp.text();
} catch (err) {
handleOnError(err);
}
// Convert into DOM in Node.js enviroment
const dom = new jsdom.JSDOM(html);
// Example with element of id "footer-places-privacy"
const extractedText = dom.window.document.getElementById("footer-places-privacy").textContent;
console.log(`* Comparing previous extracted text (${prevExtractedText}) and current extracted text (${extractedText})`);
if (prevExtractedText !== extractedText) {
// Update prevExtractedText
prevExtractedText = extractedText;
console.log(`* Updating ${outputFilepath}...`);
try {
// Writing new extracted text into a file
await fs.appendFileSync(outputFilepath, extractedText);
console.log(`* ${outputFilepath} has been updated and saved.`);
} catch (err) {
handleOnError(err);
}
}
console.log('--------------------------------------------------')
}
console.log(`* Polling ${url} every ${timeout}ms`);
setInterval(handleFetchAndSaveFile, timeout);
Working demo: https://codesandbox.io/s/nodejs-webpage-polling-jqf6v?fontsize=14&hidenavigation=1&theme=dark

For Loop in Protractor is not working properly

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

Store output of shell command in sqlite

If I execute a certain shell command in node js, the output is on the console. Is there a way I can save it in a variable so it can be POST to Sqlite database.
const shell = require('shelljs');
shell.exec('arp -a');
In this scenario, I want to store the IP address of a specific MAC/Physical address into the database. How can this be done?
Any help would be much appreciated. Thank you
You need to get the output of the command you're passing to exec. To do that, just call stdout, like this:
const shell = require('shelljs');
const stdout = shell.exec('arp -a').stdout;
Then just parse that output to get your ipaddress:
const entries = stdout.split('\r\n');
// entries sample
[ '',
'Interface: 10.17.60.53 --- 0xd',
' Internet Address Physical Address Type',
' 10.11.10.52 6c-4b-90-1d-97-b8 dynamic ',
' 10.10.11.254 xx-yy-53-2e-98-44 dynamic ']
Then you can filter your wanted address with some more manipulation.
EDIT:
To get the ip address, you could do:
let ipAddr = null;
for (let i = 0; i < entries.length; i++) {
if (entries[i].indexOf('6c-4b-90-1d-97-b8') > -1) {
ipAddr = entries[i].match(/\b\d{1,3}\.\d{1,3}\.\d{1,3}\.\d{1,3}\b/)[0];
break;
}
}
console.log(ipAddr); // '10.11.10.52'
I'm merely copy pasting from the docs. You should research more.
You need to add a listener to stdout
var child = exec('arp -a', {async:true});
child.stdout.on('data', function(data) {
/* ... do something with data ... */
});
Or adding the callback directly when calling exec
exec('some_long_running_process', function(code, stdout, stderr) {
console.log('Exit code:', code);
console.log('Program output:', stdout);
console.log('Program stderr:', stderr);
});
You can access the result of the command run using shell.exec with the .output property. Try the code below.
var shell = require('shelljs');
var result = shell.exec('arp -a').output;
If you don't want the result in the console, you can specify the silent option.
var result = shell.exec('arp -a', {silent: true}).output;
Now, you can use regular expressions to extract ip and mac address from the result.
I am getting the result of the command like below:
? (xxx.xxx.xxx.xxx) at xx:xx:xx:xx:xx:xx [ether] on eth0
? (yyy.yyy.yyy.yyy) at yy:yy:yy:yy:yy:yy [ether] on eth0
You can use the following code to extract ip and mac.
var res = result.split("\n").map(function(item){
return item.match(/\((\d+\.\d+\.\d+\.\d+)\) at (..:..:..:..:..:..)/);
});
console.log(res[0][1]); //IP of first interface
console.log(res[0][2]); //MAC of first interface
console.log(res[1][1]); //IP of second interface
console.log(res[1][2]); //MAC of second interface
NOTE
I was not able to find the .output property in the documentation but trying the shell.exec function in the node console revealed it.
The .stdout property or the exec function mentioned in other answers doesn't work for me. They are giving undefined errors.

Verify PKCS#7 (PEM) signature / unpack data in node.js

I get a PKCS#7 crypto package from a 3rd party system.
The package is not compressed and not encrypted, PEM-encoded, signed with X.509 certificate.
I also have a PEM cert file from the provider.
The data inside is XML
I need to do the following in Node.JS:
extract the data
verify the signature
A sample package (no sensitive info, data refers to our qa system) http://pastebin.com/7ay7F99e
OK, finally got it.
First of all, PKCS messages are complex structures binary-encoded using ASN1.
Second, they can be serialized to binary files (DER encoding) or text PEM files using Base64 encoding.
Third, PKCS#7 format specifies several package types from which my is called Signed Data. These formats are distinguished by OBJECT IDENTIFIER value in the beginning of the ASN1 object (1st element of the wrapper sequence) — you can go to http://lapo.it/asn1js/ and paste the package text for the fully parsed structure.
Next, we need to parse the package (Base64 -> ASN1 -> some object representation). Unfortunately, there's no npm package for that. I found quite a good project forge that is not published to npm registry (though npm-compatible). It parsed PEM format but the resulting tree is quite an unpleasant thing to traverse. Based on their Encrypted Data and Enveloped Data implementations I created partial implementation of Signed Data in my own fork. UPD: my pull request was later merged to the forge project.
Now finally we have the whole thing parsed.
At that point I found a great (and probably the only on the whole web) explanative article on signed PKCS#7 verification: http://qistoph.blogspot.com/2012/01/manual-verify-pkcs7-signed-data-with.html
I was able to extract and successfully decode the signature from the file, but the hash inside was different from the data's hash. God bless Chris who explained what actually happens.
The data signing process is 2-step:
original content's hash is calculated
a set of "Authorized Attributes" is constructed including: type of the data singed, signing time and data hash
Then the set from step 2 is signed using the signer's private key.
Due to PKCS#7 specifics this set of attributes is stored inside of the context-specific constructed type (class=0x80, type=0) but should be signed and validated as normal SET (class=0, type=17).
As Chris mentions (https://stackoverflow.com/a/16154756/108533) this only verifies that the attributes in the package are valid. We should also validate the actual data hash against the digest attribute.
So finally here's a code doing validation (cert.pem is a certificate file that the provider sent me, package is a PEM-encoded message I got from them over HTTP POST):
var fs = require('fs');
var crypto = require('crypto');
var forge = require('forge');
var pkcs7 = forge.pkcs7;
var asn1 = forge.asn1;
var oids = forge.pki.oids;
var folder = '/a/path/to/files/';
var pkg = fs.readFileSync(folder + 'package').toString();
var cert = fs.readFileSync(folder + 'cert.pem').toString();
var res = true;
try {
var msg = pkcs7.messageFromPem(pkg);
var attrs = msg.rawCapture.authenticatedAttributes;
var set = asn1.create(asn1.Class.UNIVERSAL, asn1.Type.SET, true, attrs);
var buf = Buffer.from(asn1.toDer(set).data, 'binary');
var sig = msg.rawCapture.signature;
var v = crypto.createVerify('RSA-SHA1');
v.update(buf);
if (!v.verify(cert, sig)) {
console.log('Wrong authorized attributes!');
res = false;
}
var h = crypto.createHash('SHA1');
var data = msg.rawCapture.content.value[0].value[0].value;
h.update(data);
var attrDigest = null;
for (var i = 0, l = attrs.length; i < l; ++i) {
if (asn1.derToOid(attrs[i].value[0].value) === oids.messageDigest) {
attrDigest = attrs[i].value[1].value[0].value;
}
}
var dataDigest = h.digest();
if (dataDigest !== attrDigest) {
console.log('Wrong content digest');
res = false;
}
}
catch (_e) {
console.dir(_e);
res = false;
}
if (res) {
console.log("It's OK");
}
Your answer is a big step in the right direction. You are however missing out an essential part of the validation!
You should verify the hash of the data against the digest contained in the signed attributes. Otherwise it would be possible for someone to replace the content with malicious data. Try for example validating the following 'package' with your code (and have a look at the content): http://pastebin.com/kaZ2XQQc
I'm not much of a NodeJS developer (this is actually my first try :p), but here's a suggestion to help you get started.
var fs = require('fs');
var crypto = require('crypto');
var pkcs7 = require('./js/pkcs7'); // forge from my own fork
var asn1 = require('./js/asn1');
var folder = '';
var pkg = fs.readFileSync(folder + 'package').toString();
var cert = fs.readFileSync(folder + 'cert.pem').toString();
try {
var msg = pkcs7.messageFromPem(pkg);
var attrs = msg.rawCapture.authenticatedAttributes; // got the list of auth attrs
var set = asn1.create(asn1.Class.UNIVERSAL, asn1.Type.SET, true, attrs); // packed them inside of the SET object
var buf = new Buffer(asn1.toDer(set).data, 'binary'); // DO NOT forget 'binary', otherwise it tries to interpret bytes as UTF-8 chars
var sig = msg.rawCapture.signature;
var shasum = crypto.createHash('sha1'); // better be based on msg.rawCapture.digestAlgorithms
shasum.update(msg.rawCapture.content.value[0].value[0].value);
for(var n in attrs) {
var attrib = attrs[n].value;
var attrib_type = attrib[0].value;
var attrib_value = attrib[1].value[0].value;
if(attrib_type == "\x2a\x86\x48\x86\xf7\x0d\x01\x09\x04") { // better would be to use the OID (1.2.840.113549.1.9.4)
if(shasum.digest('binary') == attrib_value) {
console.log('hash matches');
var v = crypto.createVerify('RSA-SHA1');
v.update(buf);
console.log(v.verify(cert, sig)); // -> should type true
} else {
console.log('hash mismatch');
}
}
}
}
catch (_e) {
console.dir(_e);
}
based on inspiration form this answer, I've implemented a sample for signing and verifying pdf files using node-signpdf and node-forge.

Categories