NightwatchJS > Storing response from "elements" command and performing further actions - node.js

I have a button with the same class name that appears on the page in a few instances. How do I store the response from elements(i.e Web Element JSON Objects) in array to perform further actions on them as clicking and asserting? I've been trying to do the following but it did not work:
browser.elements('css selector', 'elem', function(res) {
arr = res.value;
console.log(arr);
a = arr[1].ELEMENT;
console.log(a);
browser.elementIdClick(a);
It prints the index of the ELEMENT, but the elementIdClick command does not perform any actions nor throws any errors in response. Please help

It should work:
this.elementIdClick(a) or this.api.elementIdClick(a)
if not could you print console.log(browser) and console.log(this)
It might be helpful.

Related

*ngFor loop over mLab objects produce Error trying to diff'[object Object] even after declaring array

I have an array declared as carousels: any = [] in my TS file but I keep getting an error stating 'only arrays and iterables allowed' whenever I loop over it using *ngFor. The data inside this array is acquired from mLab.
The goal of my code is to update an object from mLab using its id which seems to work fine. But whenever I press the update, given the fact that the update even works, why do I still get the error?
I have tried to change carousels: any = [] to just carousels = [] but it doesn't seem to change anything.
This is my code.
api.js (backend) - this is the code that communicates with the database.
router.route('carousel/update/:_id).put(function(req, res) {
db.collection('home').updateOne({"_id": ObjectId(req.params._id)}, {$set: req.body}, (err, results) => {
if (err) throw err;
res.send(results)
console.log(req.params._id)
});
});
home.service.ts
return this.http.put<any[]>('./api/carousel/update/' + id, {'header': newheader, 'subheader': newsubheader})
}
component.ts
declaration:
carousels: any = [];
update function:
updateSlide(id: number){
this.HomeService.updateSlide(id, this.header, this.subheader).subscribe(slides => {this.carousels = slides})
}
Update works but I still get the Error: error trying to diff '[object object]'. only arrays and iterables are allowed
The .updateOne({}) doesn't return a list of objects, but an object with the information about the row updated.
You are returning that Object from the API and then setting it in the updateSlider() in your component, where you should be setting an array instead.
Try to log the results in the api or slides in the Subscription, and you should be able to see the issue.
After several readings and posts, I have found out that my mistake was tha I manually subscribed to the Observable inside my component file.
Manually updating looks like this:
.subscribe(slides => {this.carousels = slides})
It turns out that this has already been done automatically therefore I would not need to do it again manually. Refer to this post: Pipe Async - Error trying to diff '[object Object]'. Only arrays and iterables are allowed
This fixed the issue for me.

Read Only Form Filling - PDFTron

I'm using WebViewer [1] from PDFTron to fill Form Fields in a PDF on Web [2]. There's a way to make some fields in Read Only Mode, so the user will not be able to add text to textfield, check the checkboxes?
I found this page on the documentation [3] but it seems that I can only set document in read only mode, instead I want only custom fields in read only, users will be able to fill some fields and not others.
I found also this page [4] on doc to set fields to readonly but in my case on WebViewer it doesn't work, in my browser the viewerLoaded events never get called; I tried to put the code in another part of the code but nothing happens.
Are there some hints or some working code that you guys use?
Thanks, Alberto
[1] https://www.pdftron.com/webviewer
[2] https://www.pdftron.com/pdf-sdk/form-filler
[3] https://www.pdftron.com/documentation/web/guides/annotations/annotation-permissions?searchTerm=readon#readonly-mode
[4] https://www.pdftron.com/documentation/web/guides/advanced/forms#set-fields-to-readonly
I managed to make it work with a modified version of this code [1]. The final result is:
$(document).on('documentLoaded', function() {
var docViewer = myWebViewer.getInstance().docViewer;
var annotManager = docViewer.getAnnotationManager();
annotManager.on('annotationChanged', function(e, annotations, action) {
// if the annotation change occurs because of an import then
// these are fields from inside the document
if (action === 'add' && e.imported) {
annotations.forEach(function(annot) {
if(annot.fieldName == 'read_only_field_name'){
annot.fieldFlags.set('ReadOnly', true);
}
});
}
});
});
[1] https://www.pdftron.com/documentation/web/guides/advanced/forms#set-fields-to-readonly

Unable to Invoke Inserted Javascript Fragment

I am attempting to insert a Javascript fragment into a webpage and then invoke it using blue prism. The purpose of this is to analyse what elements are returned from a search to determine where to go next in the overall process flow.
I have tested the Javascript code on the intended website using the IE 11 developer console and it works without issue. The code is below in case it is useful.
function includes(stringToCheck, CharacterToSearchFor)
{
var found = new Boolean();
var splitString = stringToCheck.split("");
for (var index = 0; index < splitString.length; index++)
{
if(splitString[index] == CharacterToSearchFor)
{
return true;
}
}
return false;
}
function getPartners() //declare a function which can be called from BP. once called all code within the enclosing {} will be run
{
var searchResults = document.getElementsByClassName("findASolicitorListItem"); //search the web page for all elements with a specific tag and store them in a variable called searchResults.
if(searchResults.length == 0) // If the number
{
alert( "No Solicitors were found.");
}else if(searchResults.length == 1)
{
var innerSearchResults = searchResults[0].getElementsByTagName("span");
for(i = 0; i < innerSearchResults.length; i++)
{
var spanText = innerSearchResults[i].innerText.toString();
if((spanText != ""))
{
if(!includes(spanText, "|"))
{
alert("One Solicitor found. " + spanText);
}
}
}
}else if (searchResults.length > 1)
{
alert( "More than one solicitor was found. Manual Checking required.");
}
}
This is stored in a data item and is passed into the Navigate stage (Insert Javascript Fragment) parameter.
PrintScreen of Insert Javascript Fragment stage
When this stage is ran it successfully injects the Javascript functions into the webpage.
I then try and invoke this inserted javascript fragment
Printscreen of Invoke Javascript Function stage
When this stage runs I get the following error message raised by Blue Prism.
Internal : Failed to perform step 1 in Navigate Stage 'Analyse Result' on page 'Analyse Search Results' - Failed while invoking javascript method:Exception from HRESULT: 0x80020101-> at mshtml.HTMLWindow2Class.IHTMLWindow2_execScript(String code, String language)
at BluePrism.ApplicationManager.HTML.clsHTMLDocument.InvokeJavascriptMethod(String methodname, String jsonargs, Object& retval, String& sErr)
I have searched for this error code and found this answer which indicates there is a problem with the code however I can manually run this code just fine.
Does anyone have any experience with using these methods in BluePrism or have seen this error message before who can help me resolve?
I was actually never able to get Invoke Function working reliably with parameters, I always use Insert Fragment for everything, invoking included.
If you insert this function as a fragment...
function sayHello(name)
{
alert("Hello " + name + "!");
}
...to invoke it you just insert this as another fragment:
sayHello("World");
Tadaa!
As a side note, I am not sure which element in Application Modeler you are using for fragment insertion, but it seems like you are using the root (application) node. I had better experience with inserting the fragment to a dedicated HTML BODY element, for some reason the performance is much greater.
To invoke function by action "Invoke Javascript function", in Arguments field you should put arguments in JSON syntax. If there is no argument you put "[{}]".
On the above Marek's example the function should look:
function sayHello(name)
{
alert("Hello " + name.name + "!");
}
and arguments: "[{'name':'world'}]".

Element is not currently visible and so may not be interacted with node and selenium driver

I have the following code and I cannot get the driver to click the div. It keeps throwing the error
"Element is not currently visible and so may not be interacted"
when debugging you can clearly see that the element is visible. How can I ignore the warning or the error?
var webdriver = require('selenium-webdriver')
, By = webdriver.By
, until = webdriver.until;
var driver = new webdriver.Builder().forBrowser('firefox').build();
driver.get('http://www.vapeworld.com/');
driver.manage().timeouts().implicitlyWait(10, 10000);
var hrefs = driver.findElements(webdriver.By.tagName("a"));
hrefs.then(function (elements) {
elements.forEach(function (element) {
element.getAttribute('name').then(function (obj) {
if (obj == '1_name') {
console.log(obj);
element.click();
}
});
});
});
Your code is clicking an A tag with the name "1_name". I'm looking at the page right now and that element doesn't exist, hidden or otherwise.
You'd be better served by replacing the bulk of your code with a CSS selector, "a[name='1_name']" or "a[name='" + tagName + "']", that will find the element you want with a single find. You can then click on that element.
The issue you are running into is that the element you are trying to click is not visible, thus the error message. Selenium is designed to only interact with elements that the user can see, which would be visible elements. You will need to find the element you are looking for and figure out how to make it visible. It may be clicking another link on the page or scrolling a panel over, etc.
If you don't care about user scenarios and just want to click the element, visible or not, look into .executeScript().
Looked at the website and used the F12 tool (Chrome) to investigate the page:
var elements = [].slice.call(document.getElementsByTagName("a"));
var elementNames = elements.map(function (x) { return x.getAttribute("name"); });
var filledElementNames = elementNames.filter(function (x) { return x != null; });
console.log(filledElementNames);
The content of the website http://www.vapeworld.com is very dynamic. Depending on the situation you get one or more anchors with "x_name" and not always "1_name": the output of the script in Chrome was ["2_name"] and Edge returns ["1_name", "9_name", "10_name", "17_name", "2_name"]. So "you can clearly see that the element is visible" is not true in all situations. Also there were some driver bugs on this subject so it is worthwhile to update the driver if needed. See also the answers in this SO question explaining all the criteria the driver uses. If you want to ignore this error you can catch this exception:
try {
element.click();
} catch (Exception ex) {
console.log("Error!");
}
See this documentation page for more explanation.

Google Script: how to display GmailApp.search - mail data

I'm trying display starred mails in Logger.
function viewStarred() {
Logger.log( GmailApp.search('is:starred') );
}
but result in my Logger is this:
[GmailThread, GmailThread, GmailThread, GmailThread, .... GmailThread]
how can I display mail subjects? or content...
Here is my screen:
What you are seeing is behaviour as expected. If you see the documentation for GmailApp.search, you'll see that it returns an Array of GmailThread objects.
Logger.log cannot print out a GmailThread array object directly
So, you have to
a. Single out the GmailThread object you want to print
b. Print specific information about a GmailThread (subject, sender etc.)
See example below
var threads = GmailApp.search('is:starred');
for (var i in threads){
Logger.log(threads[i].getFirstMessageSubject());
}

Resources