AutomationAnywhere + Javascript regular expression - javascript

I have an "Invalid character error" while using JS script to extract mails from text that I cannot handle for last 2 days.
I am getting text from web application by using Object cloning and passing it to variable which i will later pass to JS script.
And of course my JS script which I checked and it works:
var args = WScript.Arguments;
var pattern = \w+#\w+.\w;
var result = /pattern/.exec(args);
WScript.StdOut.WriteLine(result);

First and foremost lets break this down it modules and debug them.
.
First Module: Object cloning
Object Cloning is very good to build reliability and this reliability is acheived by careful selection of Properties and in your example you have selected Path,DOMXPath, HTML Tag
Its a good practice to identify the properties which are unique and therefore yield high accuracy and some of these properties depend on the context
For example in a login page some properties include:
Priority 1: Path, HTML ID, InnerText
Priority 2: DOMXPath, HTMLValue
You may chose to add properties that you think may be unique to your context
Does strResult give you the expected value ? If yes, lets proceed
Second Module: Run Script
Accepts 2 Parameters $strResult$ and $mail$
And of course my JS script which I checked and it works:
and you have confirmed the JS module also runs fine
If you have verified the results of the first 2 modules, I think there could be an Invalid character somewhere in the script, parameters, check the regular expressions used. Shouldn't the pattern be enclosed in string " " ??
=====================
EDIT:
I wanted to recreate the issue and give you the desired result but I do not know your intended input and output for Javascript. However to the best of my understanding of your javascript, I have compiled and executed this script in Automation Anywhere and works perfect.
JavaScript
var args = WScript.Arguments;
if (args.length > 0)
{
var val=0;
var str=args.item(0);
var ary = str.split(",");
//WScript.Echo(ary.length);
// for loop in case there are multiple parameters passed
for (var i=0; i < ary.length; i++)
{
//Takes the input passed as parameter
var input = (ary[i]);
// Uses the Match() Method to look for an email address in input string
var result = input.match(/\w+#\w+\.com/);
//returns the email address
}
WScript.StdOut.WriteLine(result);
}
OR
//Takes the input passed as parameter
var input = (ary[i]);
//Declares the pattern used
var pattern = /\w+#\w+\.com/
// Uses the Exec() Method to look for a match
var result = pattern.exec(input);
//returns the email address
Run Script
Input Parameter
Output Parameter

Related

Dynamically create a TW object in IBM BPM

I am using IBM BPM 8.6
I have an input string as follows:
"\"RECORD_CONTACT\":\"Maram\" , \"DRUG\":\"Panadol\"
In a script on server side, I want to dynamically create a business object like this:
tw.local.recordContact = Maram;
tw.local.drug = Panadol;
How can I dynamically create the business object?
There are a few problems with your request. The first is that you are not creating a business object, you are creating variables. In IBM BPM the variables have to be declared at design time or you will get an error, so invoking attempting to call something like -
tw.local.myVariable = 'Bob';
Will throw an exception if tw.local.myVariable has not been declared. Base on your other question you asked here (link), I'm going to assume you actually have an ANY variable declared called "return" so that
tw.local.return.myVariable = 'Bob'
will work. Given that I based on Sven's answer I think something like the following will work (you will need to validate)
var str = "\"RECORD_CONTACT\":\"Maram\" , \"DRUG\":\"Panadol\"";
var jsonStr = "{" + str.replace(/\\\"/g,'\"') + "}";
var tempValue = JSON.parse(jsonStr);
var keyArray = Object.keys(tempValue);
var valueArray = Object.values(tempValue);
for(var keyCount=0; keyCount<keyArray.length; keyCount++{
var evalString = "tw.local.return."+keyArray[keyCount]+"="+valueArray[keyCount];
eval(evalString);
}
I'll note that doing this is a very bad idea as it would be very brittle code and that using eval() in this manner opens you up to all sorts of possible exploits. It will also fail badly if the value for one of the keys is not a simple type.
-Andrew Paier
One should know what you are going to do with dynamically created Business Objects (BO) to answer you better. Like a very generic way would be - creating JSON object instead of BO.
But if you want to stick with BO then this is only possible when you know all the BO structure (schema) beforehand during design time.
var str = "\"RECORD_CONTACT\":\"Maram\" , \"DRUG\":\"Panadol\"";
vat objArray = str.split("reg ex to split each object string")
foreach (obj in objArray ){
if(obj.indexOf( "RECORD_CONTACT")!=-1)
tw.local.recordContact = new tw.object.RECORD_CONTACT();
//below goes code get value of each attribute of BPM from string
}
else if(obj.indexOf( "DRUG")!=-1){
//similar code to create BO DRUG
}
Don't forget to create BO before using those :)

node.js change in concatenation?

I'm trying to debug some code that another programmer has left for me to maintain. I've just attempted to upgrade from node.js 5 to node.js 8 and my database queries are for some requests coming back with key not found errors
We're using couchbase for the database and our document keys are "encrypted" for security. So we may have a key that starts like this "User_myemail#gmail.com" but we encrypt it using the following method:
function _GetScrambledKey(dbKey)
{
//select encryption key based on db key content
var eKeyIndex = CalculateEncryptionKeyIndex(dbKey, eKeys.length);
var sha = CalculateSHA512(dbKey + eKeyIndex);
return sha;
}
function CalculateEncryptionKeyIndex(str, max)
{
var hashBuf = CalculateSHA1(str);
var count = 0;
for (var i = 0; i < hashBuf.length; i++)
{
count += hashBuf[i];
count = count % max;
}
return count;
}
We then query couchbase for the document with
cb.get("ECB_"+encryptedKey, opts, callback);
In node5 this worked but in node8 we're getting some documents return fine and others return as missing. I outputted the "ECB_"+encryptedKey as an int array and the results have only confused me more. They are different on node5 to node8 but only by one character right in the middle of the array.
Outputting the encryptedKey as an int array on both versions shows this
188,106,14,227,211,70,94,97,63,130,78,246,155,65,6,148,62,215,47,230,211,109,35,99,21,60,178,74,195,13,233,253,187,142,213,213,104,58,168,60,225,148,25,101,155,91,122,77,2,99,102,235,26,71,157,99,6,47,162,152,58,181,21,175
Then outputting the concatenated string, in the same way, shows slightly different results
This is the node8 output
Node8 key: 69,67,66,95,65533,106,14,65533,65533,70,94,97,63,65533,78,65533,65533,65,6,65533,62,65533,47,65533,65533,109,35,99,21,60,65533,74,65533,13,65533,65533,65533,65533,65533,65533,104,58,65533,60,65533,25,101,65533,91,122,77,2,99,102,65533,26,71,65533,99,6,47,65533,65533,58,65533,21,65533
And this is the node5 output
Node5 key: 69,67,66,95,65533,106,14,65533,65533,70,94,97,63,65533,78,65533,65533,65,6,65533,62,65533,47,65533,65533,109,35,99,21,60,65533,74,65533,13,65533,65533,65533,65533,65533,65533,104,58,65533,60,65533,65533,25,101,65533,91,122,77,2,99,102,65533,26,71,65533,99,6,47,65533,65533,58,65533,21,65533
I had to run it through a diff tool to see the difference
Comparing that to the original pre-append array it looks like the 225 has just been dropped in node8. Is 225 significant? I can't understand how that would be possible otherwise unless it's a bug. Does anyone have any ideas?
Looks like this was a change in v8 5.5 https://github.com/nodejs/node/issues/21278
A lot of the issues you are facing, including the concatenation can be cleaned up using newer features from ES6 that are available in node 8.
In general, you should avoid doing string concatenations with the + operator and should use string literals instead. In your case, you should replace the "ECB_"+encryptedKey with `ECB_${encryptedKey}`.
Additionally, if you want to output the contents of the integers values from this concatenated string, then you are better off using .join, the spread operator (...) and the Buffer class from Node as follows:
let encKey = `ECB_${encryptedKey}`;
let tmpBuff = Buffer.from(encKey);
let buffArrVals = [...tmpBuff];
console.log(buffArrVals.join(','));
Also, if you can help it, you really should avoid using var inside of function blocks like it exists in your sample code. var performs something called variable hoisting and causes the variable to become available outside the scope it was declared, which is seldom intended. From node 6+ onward the recommendation is to use let or const for variable declarations to ensure they stay scoped to the block they are declared.

MS Word web add-in javascript search multiple strings at the same time

I have been able to run the Github project Word-Add-in-JS-Redact successfully. Now, I need to make a change in the code. Need help for that.
At present the code finds multiple occurrences of a single string in a Word Doc and highlights those. But, I need to search multiple strings (can be hard coded inside the js file as well) in the document with a single button click, and highlight those. For example, I want to find both strings 'this' and 'that' in the document at the same time, and highlight them.
The current code, which searches for a single string:
Word.run(function (context) {
//search string
var searchInput = "hello";
// Search the document.
var searchResults = context.document.body.search(searchInput, {matchWildCards: true});
// Load the search results and get the font property values.
context.load(searchResults, "");
// Synchronize the document state by executing the queued-up commands,
// and return a promise to indicate task completion.
return context.sync()
.then(function () {
var count = searchResults.items.length;
// // Queue a set of commands to change the font for each found item.
for (var i = 0; i < count; i++) {
searchResults.items[i].font.highlightColor = '#FFFF00'; //Yellow
}
return count;
})
.then(context.sync)
.then(reportWordsFound);
A couple of ways I have tried so far with no luck:
Ran context.document.body.search(searchInput, in a loop of the search strings, and tried to append the searchResults strings using + and push. This attempt gave an error saying, I cannot add multiple context results to a single object.
I tried to be creative with WildCards operators, but nothing was suitable for this. Many posts are talking about JS regex \(string1|string2/), but this seems to be invalid in Word context.
I could solve the problem at last, by creating a parent function, which calls the search function in a loop. My mistake was to create the loop inside the search function itself.
Here is the working code:
function searchStrings(){
searchString('hello world');
searchString('Goodbye');
}
RedactAddin.searchStrings = searchStrings;
function searchString(input) {
// Run a batch operation against the Word object model.
Word.run(function (context) {
//...... (same as the original) ...............

Why is the .text() function returning [object Object] in ngScenario for AngularJS e2e?

Update: A Solution below!
I'm fairly new to website development but I've been tasked with developing e2e (end-to-end) tests for a developing website that uses AngularJS. As a result I've been looking down the road of using AngularJS's karma-run ngScenario testing wrapper.
Anyway, just getting started I want to make sure that a simple hyperlink's text matches part of its href address. There isn't need to know the structure of this code snippet, but these are thumbnails for user profiles, and you can click the thumbnail object completely (the first 'a') or you can click a link displaying their name (the second 'a').
There dozens of these on a page.
Here is what a part of the page looks like loaded with a user "PurplePenguin".
<div class="thumbnail__section">
<a href="/profile/PurplePenguin">
<div class="thumbnail__bottom">
<div class="thumbnail__rating ng-binding"> </div>
<div class="thumbnail__info">
<div class="thumbnail__name">
<a class="ng-binding" href="/profile/PurplePenguin">PurplePenguin</a>
</div>
[...]
Essentially I want a test that will take the text of the second 'a' element and check it against the href attribute: "assert that href '/profile/PurplePenguin' equals '/profile/' + 'PurplePenguin'"
This is what I've made just wanting to test the first thumbnail's 'a', (in my time writing "PurplePengiun" is the first user every time so I could hard code it).
it('should have the performer\'s name match the link', function() {
// "eq(n)" gets the nth instance of the element;
// "> a:eq(0)" grabs its first child a
var nameElement = element('.thumbnail__name:eq(0) > a:eq(0)');
// These work and pass
expect(nameElement.text()).toBe('PurplePenguin');
expect(nameElement.attr('href')).toBe('/profile/PurplePenguin');
// This does not
var textString = nameElement.text(); // textString == "[object Object]"
expect(nameElement.attr('href')).toBe('/profile/' + textString);
This gets returned:
expect element '.thumbnail__name:eq(0) > a:eq(0)' get attr 'href' toEqual "/profile/[object Object]"
expected "/profile/[object Object]" but was "/profile/PurplePenguin"
So I've figured out how to find the particular element on the page I need, but trying to manipulate the text of a simple 'a' element only gives me [object Object].
Some things I've tried with my basic knowledge of JS:
nameElement.text().toString(), nameElement.text().value(), nameElement[0].text()
Trying things other than text()
nameElement.html() and nameElement.val()
They too return [object Object] when trying to use them as strings.
It seems that looking at the values and attributes of these elements only works when using the very specific API functions like .toBe or .toEqual, but I want to assert that a specifically formatted string is made.
Thank you for any help!
Solution
Thanks for that bit of insight Andyrooger, I had actually taken a stab at the query function before posting my question but gave up on it too quick. Your explanation gave me the idea to start looking deeper into the samples that have been posted in the official docs. I ended up taking a hint from a Adi Roiban's post to another Angular e2e writer's question talking about query, done() messages, and promises. This ended up leading me to my eventual solution.
So I've made myself a solution and in the spirit of cooperation made a set of examples for others to learn by. There are four examples, the first two are just getting the text and the href and comparing them against hard-coded values. The third one uses indexOf to do dirt-simple comparisons. The fourth one shows how you can make your own more specific pass/fail conditions (more than what Jasmine provides with its matchers).
Number 1: User name text vs hard coded value
it('should have the user\'s name be \'PurplePenguin\'', function() {
var textPromise = element('.thumbnail__name:eq(0) > a:eq(0)').query(function (nameElement, done) {
var text = nameElement.text(); // Can finally access this guy!
// The first param null indicates a nominal execution, the second param is a return of sorts
done(null, text);
});
// Passes
expect(textPromise).toBe('PurplePenguin')
});
Number 2: Profile href value vs hard coded value
it('should have the user\'s link be \'/profile/PurplePenguin\'', function() {
var textPromise = element('.thumbnail__name:eq(0) > a:eq(0)').query(function (nameElement, done) {
var href = nameElement.attr('href');
// The first param null indicates a nominal execution, the second param is a return of sorts
done(null, href);
});
// Passes
expect(textPromise).toBe('/profile/PurplePenguin')
});
Number 3: Simple string comparison
it('should have the user\'s name match the link', function() {
var textPromise = element('.thumbnail__name:eq(0) > a:eq(0)').query(function (nameElement, done) {
var text = nameElement.text();
var href = nameElement.attr('href');
// The first param null indicates a clean pass, the second param is a return of sorts
done(null, href.indexOf(text)); // indexOf returns -1 if text is _not_ a sub-string of href
});
expect(textPromise).toBeGreaterThan(-1);
// In the case of failure reports this in the console (if using Karma):
// expect element .thumbnail__name:eq(0) > a:eq(0) custom query toBeGreaterThan -1
// expected -1 but was -1
// In the runner.html page for the test simply reports this useless/misleading log:
// expected -1 but was -1
});
Number 4: More detailed string comparison doing it your own way plus a better error message
it('should have the user\'s name match the link', function() {
var nameStringPromise = element('.thumbnail__name:eq(0) > a:eq(0)').query(function (nameElement, done) {
var text = nameElement.text();
var href = nameElement.attr('href');
var message;
if (href.indexOf(text) == -1)
message = 'Did not find "' + text + '" in "' + href + '"';
done(message, href.indexOf(text));
});
expect(nameStringPromise);
// An expect() with no Jasmine matcher means that it only uses the done message to determine
// a pass or fail for the test. So I wrote that if my conditions weren't met it would print
// an informative message in the case of failure
// Example failure output with a broken url generator:
// Did not find "PurplePenguin" in "/profile/"
});
I'm struggling to find references to back this up or explain a little more nicely, other than these docs which don't have much info. Therefore this answer is mainly from memory of reading the relevant code.
When you write a test in ngScenario, you are not writing a series of immediate actions as you would do in a unit test. What you are actually doing queuing up a list of commands to execute when the test starts.
Methods that looks like normal jQuery functions, such as text() or attr() are actually part of ngScenario's DSL and return future objects (meaning they will at some point execute and have the result of the call you wanted.)
expect() already knows this so waits for the result before comparing to your expected value. The code underneath, in your example, is reading directly and immediately so will see the future object.
If you do need to read the element in this way I suggest looking at the query function which should allow it. On the other hand if you need to just check the formatting of the string you can use toMatch which has been implemented in ngScenario too.

Trying to reduce repetition of javascript using a variable

I am trying to reduce the repetition in my code but not having any luck. I reduced the code down to its simplest functionality to try and get it to work.
The idea is to take the last two letters of an id name, as those letters are the same as a previously declared variable and use it to refer to the old variable.
I used the alert to test whether I was getting the right output and the alert window pops up saying "E1". So I am not really sure why it wont work when I try and use it.
E1 = new Audio('audio/E1.ogg');
$('#noteE1').click(function() {
var fileName = this.id.slice(4);
//alert(fileName); used to test output
fileName.play();
$('#note' + fileName).addClass('active');
});
The code block works when I use the original variable E1 instead of fileName. I want to use fileName because I am hoping to have this function work for multiple elements on click, instead of having it repeated for each element.
How can I make this work? What am I missing?
Thanks.
fileName is still a string. JavaScript does not know that you want to use the variable with the same name. You are calling the play() method on a string, which of course does not exist (hence you get an error).
Suggestion:
Store your objects in a table:
var files = {
E1: new Audio('audio/E1.ogg')
};
$('#noteE1').click(function() {
var fileName = this.id.slice(4);
//alert(fileName); used to test output
files[fileName].play();
$('#note' + fileName).addClass('active');
});
Another suggestion:
Instead of using the ID to hold information about the file, consider using HTML5 data attributes:
<div id="#note" data-filename="E1">Something</div>
Then you can get the name with:
var filename = $('#note').data('filename');
This makes your code more flexible. You are not dependent on giving the elements an ID in a specific format.

Categories