Store a variable in Intern funcational test - intern

How can you store a value from one element in an Intern functional test that can be used to find additional elements?
For example, I have the following test snippet:
var mainItem = "Menu 1";
var subItem = "Sub Menu 1";
var mainItemId = "";
return this.remote
.elementByXPath("//*[contains(text(),'" + mainItem + "')]/ancestor::*[#dojoattachpoint='focusNode']")
.getAttribute("id")
.then(function(id){ mainItemId = id; })
.clickElement()
.end()
.wait(500)
.then(function(){ console.log(mainItemId); })
.elementByXPath("//*[contains(text(),'" + subItem + "')][ancestor::*[#dijitpopupparent='" + mainItemId + "']]")
.clickElement()
.end()
Basically, when I run the test, the mainItemId value will log correctly, but the second elementByXPath will not be found. If I initialize mainItemId with the same value, the xpath works. Based on what I'm seeing, its as if mainItemId will store the value only within the .then() context.
Thanks.

All of the remote methods are non-blocking, and execute immediately when the test function is invoked. mainItemId is not set until after the 4th command is executed. If you need to perform a query that is conditional upon data retrieved from an earlier command, you need to do that within a callback:
var mainItem = "Menu 1";
var subItem = "Sub Menu 1";
var mainItemId = "";
var remote = this.remote;
return remote
.elementByXPath("//*[contains(text(),'" + mainItem + "')]/ancestor::*[#dojoattachpoint='focusNode']")
.getAttribute("id")
.then(function(id){ mainItemId = id; })
.clickElement()
.end()
.wait(500)
.then(function(){
return remote.elementByXPath("//*[contains(text(),'" + subItem + "')][ancestor::*[#dijitpopupparent='" + mainItemId + "']]")
.clickElement()
.end()
});

Related

Is there any way with suitescript 1.0 to run a server side function on a client script (like getFieldText)?

I was writing a client script for work and part of it involved getting getting the value of the cost category's text to display to the user. Unfortunately, that seems to only be a server side function. I've seen some posts about how to accomplish this in Suitescript 2.0, but for whatever reason, I can't seem to get Suitescript 2.0 scripts to work on Netsuite. Is there any way to run the getFieldText function from the client side script in 1.0?
I was able to use a separate Suitelet script to get the job done.
Code from the suitelet:
function getFTxt(request, response){
try{
var recordid = request.getParameter('rid');
var recordtype = request.getParameter('rt');
record = nlapiLoadRecord(recordtype, recordid);
var fieldName = request.getParameter('fn');
fieldText = record.getFieldText(fieldName);
response.write(fieldText);
}
catch(e){
var err = '';
if ( e instanceof nlobjError ){
err = 'System error: ' + e.getCode() + '\n' + e.getDetails();
}
else{
err = 'Unexpected error: ' + e.toString();
}
var errmsg = 'Error: ';
errmsg+= '\n' + err;
nlapiLogExecution( 'ERROR', 'Error is: ', errmsg);
response.write("");
}
}
Code from my original script:
function getFieldText(field,item){
var url = nlapiResolveURL('SUITELET', 'customscriptScriptIdGoesHere', 'customdeployDeployIdGoesHere') + '&rid=' + item.getId() + '&rt=' + item.getRecordType() + '&fn=' + field;
var response = nlapiRequestURL(url);
return response.getBody();
}
Then, whenever I wanted to get the field text for an item, I'd call that function from within the script.
be sure to replace the script and deployment id to that of the suitelet.

How to send values using labels of a field in Protractor

Can anyone please guide me on how can I send values using the labels of the field. I'm aware of the fact that one should not send values using labels as the labels changes but in my case it's not that case, i.e it's not gonna change.
I'm attaching the HTML Code screenshots of that label and the webpage screenshot as well. WebPage Screenshot and the HTML Code Screenshot.
The only code structure I can show is in this image.Code Structure
The codes which I have tried are as below,
The From Date and To Date is one set of code I tried. So, like first From and To Date variable is one way of implementation of code, second set is some other way of implementing the code and so on.
async selectDates(FromDate:string,ToDate:string){
console.log("$$$ From and To Date in selectDates function From: "+FromDate+" To: "+ToDate);
// var fromDate = "From Date";
// await browser.element(by.xpath("//label[. = '" + fromDate + "']/following-sibling::input"));
// await fromInput.sendKeys(FromDate);
// var toDate = "To Date";
// await browser.element(by.xpath("//label[. = '" + toDate + "']/following-sibling::input"));
// await toInput.sendKeys(ToDate);
// var TmpLabelName = "From Date";
// var TmpInput = await element(by.xpath("//label[contains(text(),'" + TmpLabelName + "')]/following-sibling::input"));
// await TmpInput.sendKeys(FromDate);
// var TmpLabelName2 = "To Date";
// var TmpInput2 = await element(by.xpath("//label[contains(text(),'" + TmpLabelName2 + "')]/following-sibling::input"));
// await TmpInput2.sendKeys(ToDate);
// var TmpLabelName = "From Date";
// var TmpInput = await element(by.xpath("//label[.,'" + TmpLabelName + "']/following-sibling::input"));
// await TmpInput.sendKeys(FromDate);
// var TmpLabelName2 = "To Date";
// var TmpInput2 = await element(by.xpath("//label[.,'" + TmpLabelName2 + "']/following-sibling::input"));
// await TmpInput2.sendKeys(ToDate);
// let FlabelName = "From Date";
// var Finput = await element(by.xpath("//label[. = '" + FlabelName + "']/following-sibling::input")).sendKeys(FromDate);
// let TlabelName = "To Date";
// var Tinput = await element(by.xpath("//label[. = '" + TlabelName + "']/following-sibling::input")).sendKeys(ToDate);
}
I have searched for many articles and other answers but neither of them gave the desired answer. can anyone please help me with this, It would be really helpful!!
Edits:
The Code structure (Sorry for identation issues)
function ele(label: string){
return element.all(by.css('td > label.fieldlabel')).filter((ele)=>{
return ele.getText().then((text: string) => {
return text === label;
});
}).get(0);
}
export class Reports extends ReportObjects {
async selectDates(FromDate:string,ToDate:string){
await browser.executeScript("arguments[0].value='" + FromDate + "';", ele('From Date'));
await browser.executeScript("arguments[0].value='" + ToDate + "';", ele('To Date'));
}
async generateReport(testDataRow:number){
let fromDate = excel.getColumnValue('FromDate',testDataRow).toString();
let toDate = excel.getColumnValue('ToDate',testDataRow).toString();
await this.selectDates(fromDate,toDate);
}
}
The Excel Screenshot From/To Date
PS: I cannot use ID because that is dynamic, it's changing for different scenarios
Even we not recommend to use XPATH, but in your case we need it.
cost ele = element(by.xpath('//label[text()="From Date"]/../../input'))
await ele.sendKeys(FromDate)
// if sendKeys() can't work, try as below
await browser.executeScript("arguments[0].value=arguments[1]", ele, FromDate);
Try below solution with java script executer
const FromDate= //your from date
function ele(label: string){
return element.all(by.css('td > label.feildlabel').filter((ele)=>{
return ele.getText().then((text: string) => {
return text === label;
});
}).get(0);
}
await browser.executeScript("arguments[0].value='" + FromDate + "';", ele('From Date'));
Refer https://www.protractortest.org/#/api?view=webdriver.WebDriver.prototype.executeScript

node's module function return value empty/undefined?

I'm trying to get the html encoded table row value, returned from the slqLite based logger. As I'm new to node modules I'm stuck at:
var sqlite3 = require('sqlite3').verbose();
var db = new sqlite3.Database(':memory:');
var html = '';
module.exports = {
readHtml: function() {
var html = ''; // optional but does not work here as well
db.serialize(function() {
db.each("SELECT rowid AS id, info FROM logger", function(err, row) {
html = html + '<tr><td>' + row.info + '<td><tr>'; << html is growing
console.log('Log: ' + row.info); << working
});
});
console.log(html); // html gets empty here!
return html;
}
}
So have no value returned from:
var sysLog = require('logger');
sysLog.init();
sysLog.write('test string1');
sysLog.write('test string2');
console.log(sysLog.readHtml());
It has to be very simple to be solved ...
node is 6.7
You problem is directly related to a very common issue when starting with JavaScript:
How do I return the response from an asynchronous call?
Which shows the simplest way to receive results of an asynchronous operation, such as db.each is using a callback.
function readHtml()
var html = ''
db.serialize(function() {
db.each(..., function(err, row) {
// this line executes sometime later
// after we already returned from readHtml()
});
});
// this line executes right after the call to db.serialize
// but before db.each calls the callback we give to it.
// At this point, html is '' because we still didn't read any rows
// (they are read asynchronously, sometime later)
return html;
}
readHtml(); // <-- this is always '' because rows are read at a later point
To solve this, you would need a function that will be called with a callback like this:
readHtml(function(html) { // <-- this callback gets called once all rows are read
console.log(html);
});
Your situation also has an additional complication that db.each calls its callback once for every row. By looking at the docs, you can see that db.each accepts an additional complete callback when all rows are read. You can use this callback to signalize reading is done and pass the html results.
Here's how you can define readHtml:
function readHtml(callback) { // pass in a callback to call once all rows are read and all html is accumulated
var html = '';
db.serialize(function() {
// read all the rows and accumulate html as before
db.each("SELECT rowid AS id, info FROM logger", function(err, row) {
html = html + '<tr><td>' + row.info + '<td><tr>';
}, function() {
callback(html); // use the second callback to signal you are done and pass the html back
});
});
}

How do I stop a table script from processing?

I am creating an insert script that does some business logic.
Basically, I want to check to see if a value in the inserted item exists in a table. But, it seems like if I find a problem Request.Send() doesn't stop execution and get an error.
I think there is an async issue here. I'm not 100% sure how to solve.
Is there a way to stop execution of the script?
if (item.memberType === 'Family' && item.primaryFamilyMember) {
table
.where({
memberNumber: item.primaryFamilyMember,
memberType: 'Family',
primaryFamilyMember: null })
.read({
success: function(results) {
if (results.length == 0) {
request.respond(statusCodes.BAD_REQUEST,
'Invalid Primary Family Member specified.');
console.error('Invalid Primary Family Member specified:' + item.primaryFamilyMember);
validInsert = false;
} else {
item.memberType = results[0].memberType;
item.memberLevel = results[0].memberLevel;
item.dateOfExpiry = results[0].dateOfExpiry;
}
}
});
}
if (validInsert) {
var today = new Date();
var prefix = today.getFullYear().toString().substr(2,2) + ('0' + (today.getMonth() + 1)).slice(-2);
table.includeTotalCount().where(function(prefix){
return this.memberNumber.substring(0, 4) === prefix;
}, prefix)
.take(0).read({
success: function (results) {
if (isNaN(results.totalCount)) {
results.totalCount = 0;
}
item.memberNumber = prefix + ('00' + (results.totalCount + 1)).slice(-3);
request.execute();
}
});
}
Yes, validInsert is declared at the top of the insert function.
I assume what's happening is the if(validInsert) runs before the read callback. But if so, i'm not sure why I'm getting "Error: Execute cannot be called after respond has been called." That implies the callback is running first.
Also, the record is being inserted when it shouldn't be even though the 400 error is sent back to the client.
This is an express app right? Should I just call response.end() after the error occurs?
Yes, there are definitely asyn issues in that code. To solve get rid of your validInsert flag and simply move the if (validInsert) section into the success callback (or make it a function called from the success callback). For example:
success: function(results) {
if (results.length == 0) {
request.respond(statusCodes.BAD_REQUEST,
'Invalid Primary Family Member specified.');
console.error('Invalid Primary Family Member specified:' + item.primaryFamilyMember);
} else {
item.memberType = results[0].memberType;
item.memberLevel = results[0].memberLevel;
item.dateOfExpiry = results[0].dateOfExpiry;
var today = new Date();
var prefix = today.getFullYear().toString().substr(2,2) + ('0' + (today.getMonth() + 1)).slice(-2);
...
//respond successfully
}
}

Return a value from phantomjs to nodejs

I'm using phantomjs using jquerygo library and am trying to this.
Visit a url
Click on a link and wait for it to load
Grab a particular tag and return it to nodejs for processing.
I realize that in phantomjs:
The execution is sandboxed, the web page has no access to the phantom object and it can't probe its own setting
But I should be able to return a simple string from the evaluate right?
But that is not working. My code is as follows:
var photogsScrapeCount = function(url, callback){
console.log("LOADED PHOTOGSSCRAPE Count");
url = decodeURIComponent(url);
//$.config.site = 'https://www.magnumphotos.com/';
$.config.addJQuery = false;
$.visit(url, function() {
$.waitForElement(".7n7np102",function() {
$.getPage(function(page) {
var imgCounterMinus = page.evaluate(function(){
$(".7n7np102 a").click(); // open the image enlarge
var temp = setTimeout(function(){
imgCounterMinus1 = $("span[id$='TotalPageCount_Lbl']").html();
imgCounterMinus1 = imgCounterMinus1.split(" ");
imgCounterMinus1 = imgCounterMinus1[2];
imgCounterMinus1 = parseInt(imgCounterMinus1);
console.log("imgCounterMinus1" + imgCounterMinus1);
return (imgCounterMinus1 - 3);
}, 4000);
return temp;
});
//console.log("After evaluate: " + imgCounterMinus)
});
});
});
};
Can this be achieved in any different way? The basic example from website is working so I am assuming that the setTimeout is giving me problems.
Any ideas or suggestions would be very helpful as I have very little experience in writing jquery, Js.
The docs say (emphasis mine):
For one, this library is not a complete API mirror of jQuery. Every API is asynchronous (due to its interaction with Phantom.js), so there are some differences.
There is also an example how page.evaluate() must be used. The result is not returned, but passed into a second callback. There is no way to return something from an asynchronous execution of a function except by using the callback. So the setTimeout syntax is also wrong.
$(".7n7np102 a").click(function(){
setTimeout(function(){
$.getPage(function(page) {
page.evaluate(function(){
var imgCounterMinus1 = $("span[id$='TotalPageCount_Lbl']").html();
imgCounterMinus1 = imgCounterMinus1.split(" ");
imgCounterMinus1 = imgCounterMinus1[2];
imgCounterMinus1 = parseInt(imgCounterMinus1);
console.log("imgCounterMinus1" + imgCounterMinus1);
return (imgCounterMinus1 - 3);
}, function(err, result){
console.log("After evaluate: " + result);
callback();
$.close();
});
});
}, 4000);
});

Resources