how to execute Js Script in Selenium Webdriver C# - c#

This line code returns number of elements.
document.getElementsByClassName("entry entryWriteable");-> returns 70 elements
I want to implement a loop so that, Below line of code will execute for all the element.
document.getElementsByClassName("entry entryWriteable")[i].value;
Can any one help me how to impliment in C# selenium ?

In order to execute JS in selenium on C# you should use the next code:
((IJavaScriptExecutor) Driver).ExecuteScript("your code"));
So you can execute any JS code you want.
The ExecuteScript returns object so probably you can typify it.

Like Denis said, but if you need a return value of all values in entire element array, then try:
using OpenQa.Selenium.Webdriver.Extensions
driver.ExecuteJavascript<string>(`
var els = document.getElementsByClassName("entry entryWriteable");
string returnAllElementTexts = "";
for(var i = 0; i < els.length; i++) {
returnAllElementTexts += els[i] + "|";
}
return returnAllElementText;`);
This will return a pipe-delimited string of all values. Split on pipe from C#. Is that what you wanted? All text values from array of elements?

Related

Selenium webdriver System Invalid Cast Exception

To collect some test data for a neural net in C# I want to use Selenium to scrape some dynamically generated data WSJ. There is an example implementation on the Selenium site that seems to do exactly what I need Finding all the input elements to the every label on a page. The example searches on TagName, I search on ClassName, but other than that, I think it's identical.
Yet, when I run this code, creating an IList with IWebElements works, but the following IJavaScriptExecutor throws an Invalid Cast exception:
Unable to cast object of type
System.Collections.ObjectModel.ReadOnlyCollection 1[System.Object]
to type
System.Collections.Generic.IList 1[OpenQA.Selenium.IWebElement]
Here's a bit of the code, this is for "text", I do the same for "num":
// Find elements by class name
IList<IWebElement> labels = driver.FindElements(By.ClassName("text"));
// get all input elements for every class label
IList<IWebElement> labVals = (IList<IWebElement>)((IJavaScriptExecutor)driver).ExecuteScript(
"var labels = arguments[0], labVals = []; for (var i=0; i < labels.length; i++){" +
"labVals.push(document.getElementById(labels[i].getAttribute('for'))); } return labVals;", labels);
I have looked at this question Selenium Web Driver C# InvalidCastException which may point to the same problem, but I don't see how the answers provided can help me.
An option could be to break up the IJavaScriptExecutor statement into "discrete" code with a work around, but I would not know how to do that.
Once I have the text labels and data values both in a List structure, I should be able to find the numbers I need.
This is not using javascript, but it will work.
I would use a CssSelector method that receives throught parameters which column/row you need, and then you would be calling this method with loop to get all info from the page.
Checking the css of the page this is what I get from the first column/row
table.mdcTable > tbody > tr:nth-of-type(3) > td:nth-of-type(1)
So, the number "3" is related to the first row, and "1" is the first column. So we can make a method to return the exact element you want:
public IWebElement test(int line, int row)
{
return driver.FindElement(By.CssSelector(string.Format("table.mdcTable > tbody > tr:nth-of-type({}) > td:nth-of-type({})", line + 2, row)));
}
Calling this method will return the element that has the text, so all you need to do is use 'element.Text' to the the value of the 'cell', or make the method return the text directly.
public String test(int line, int row)
{
return driver.FindElement(By.CssSelector(string.Format("table.mdcTable > tbody > tr:nth-of-type({}) > td:nth-of-type({})", line + 2, row))).Text;
}
The only problem would be with the columns "Latest", because they do not only contain the numbers, but a bar. You would have to create a method to take care only of these column.
This would end up with something like this:
try
{
int line = 1;
int column = 1;
while(column <= 7)
valueOfTheCell = test(line, column);
getLatestGreen(line); //string.Format("tbody > tr:nth-of-type({0}) > td:nth-of-type(9) > span.text", line)
getLatestRed(line); //string.Format("tbody > tr:nth-of-type({0}) > td:nth-of-type(8) > span.text > b", line)
}
catch (NoSuchElementException)
{
//Exception will be thrown when the code reaches the end of the list
}
I won't say this is optimal, but it is an option.
If you want to do this way I can help you with any question or problem about how to use the selector.
The cast error occurs because the IJavascriptExecutor outputs the general System.Object class MSDN which I then try to cast to an IWebElement. This may work in some cases, but in this case it does not. Changing the receiving IList to IList<Object> solves the cast exception. With this the code runs, and then I found out with the debugger that all the data is captured with the first part of the code in the Labels list. The IJavaScriptExecutor returns null items only. So the second step is not required in my case.

How can I pass a javascript multidimensional array to c#?

I need to pass a js multidimensional array (the dimensions are not known at compile time) to my code-behind in c#, I have done this in the next way:
var AdjustItems = ""; //My string variable to store the array separated with '|' and '-'
for (var i = 0; i < adjusts.length; i++) { //adjusts is my js array
AdjustItems += adjusts[i].Motive + '|' + adjusts[i].Amount.toFixed(2).toString() + '-';
}
if (AdjustItems != "") {
AdjustItems = AdjustItems.substring(0, AdjustItems.length - 1);
}
g('arrAdjust').value = AdjustItems; //arrAdjust is my hidden input.
Is there another way to do this where I can get the array, like an array and not like a string in c#?
Is there another way to do this where I can get the array, like an
array and not like a string in c#?
The only way to communicate between the client and server is with strings. Therefore, you must use a library like JSON to pass complex variables between the client and server.
You can use javascript's built-in JSON library to turn your array into a string. This would change your example to the following:
g('arrAdjust').value = JSON.stringify(adjusts);
Then, use a C# JSON parsing library to convert it to an array on the server side. This stackoverflow question may help you with C# and parsing the JSON.

send a String array as parameter to a function

I have a function in a class called Function, like below:
public int SearchedRecords(String [] recs)
{
int counter = 0;
String pat = "-----";
String[] records = recs;
foreach (String line in records)
{
if (line.Contains(pat) == true)
{
counter++;
}
}
return counter;
}
And I am calling this method from my main class this way:
String [] file = File.ReadAllLines("C:/Users.../results.txt");
int counter = Function.SearchedRecords( []file);
But I get an error saying:
;expected
What is wrong?
Another question: The function above is counting from a file all the lines with the pattern ----- in them (even if with more dashes, or if the line has some chars before or after the dashes). Am I right?
It's something like the patterns in Java so maybe there is an other way.
Can you enlighten me?
Remove the [] from your parameter.
e.g.
int counter = Function.SearchedRecords(file);
And yes, your assumption about the behavior of the Contains method is correct - you'll match any line containing five consecutive dashes, regardless of what characters are before or after them.
If you want to parse for exactly five dashes, with nothing before or after them I suggest looking into the RegEx class (regular expressions).
Change
int counter = Function.SearchedRecords( []file);
to
int counter = Function.SearchedRecords(file);
and yes, this will work, for that string.
However Contains is case sensitive, if you were matching on a name, or another string with alphabetic characters, the case would have to be identical to match e.g. line.Contains("Binary Worrier") will not match a string "Hello binary worrier".
Also, reading the entire file into memory is fine if you know that the file will always be small, this method gets less efficient the larger the file.
Better to always use something like System.IO.StreamReader or System.IO.File.ReadLines (available in .Net 4 and later), these allow you to consume the file one line at a time. e.g.
using (var reader = new System.IO.StreamReader("MyFile.txt"))
{
while(!reader.EndOfStream)
{
string line = reader.ReadLine();
if (line.Contains(pattern))
counter++;
}
}
Change it to
int counter = Function.SearchedRecords(file);
Remove '[]' from a method call. Yes, your function seems to count what you want.
First of all you need to create an instance of function class and then run the function. Hope following code helps
Function fb = new Function();
int counter = fb.SearchedRecords(file);
Right now, you are using SearchRecords as an static function of a static class which doesn't require instantiation.
You can do this in a shorter way using LINQ:
int counter = file.Count(line => line.Contains("-----"));

turn javascript array into c# array

Hey. I have this javascript file that I'm getting off the web and it consists of basically several large javascript arrays. Since I'm a .net developer I'd like for this array to be accessible through c# so I'm wondering if there are any codeplex contributions or any other methods that I could use to turn the javascript array into a c# array that I could work with from my c# code.
like:
var roomarray = new Array(194);
var modulearray = new Array(2055);
var progarray = new Array(160);
var staffarray = new Array(3040);
var studsetarray = new Array(3221);
function PopulateFilter(strZoneOrDept, cbxFilter) {
var deptarray = new Array(111);
for (var i=0; i<deptarray.length; i++) {
deptarray[i] = new Array(1);
}
deptarray[0] [0] = "a/MPG - Master of Public Governance";
deptarray[0] [1] = "a/MPG - Master of Public Governance";
deptarray[1] [0] = "a/MBA_Flex MBA 1";
deptarray[1] [1] = "a/MBA_Flex MBA 1";
deptarray[2] [0] = "a/MBA_Flex MBA 2";
deptarray[2] [1] = "a/MBA_Flex MBA 2";
deptarray[3] [0] = "a/cand.oecon";
deptarray[3] [1] = "a/cand.oecon";
and so forth
This is what I'm thinking after overlooking the suggestions:
Retrieve the javascript file in my c# code by making an httprequest for it
paste it together with some code i made myself
from c# call an execute on a javascript function selfmade function that will turn the javascript array into json (with help from json.org/json2.js), and output it to a new file
retrieve the new file in c# parsing the json with the DataContractJsonSerializer resulting hopefully resulting in a c# array
does it sound doable to you guys?
I'm not in front of a computer with c# right now so I'm not able to fully try this.
What you're going to need to do #Jakob is the following:
Write a parser that will download the file and store it in memory.
For each section that you want to "parse" into a c# array (for example zonearray), you need to setup bounds to begin searching and end searching the file. Example: We know that zonearray starts building the array the two lines after zonearray[i] = new Array(1); and ends on zonearray.sort().
So with these bounds we can then zip through each line between and parse a C# array. This is simple enough I think that you can figure out. You'll need to keep track of sub-index as well remember.
Repeat this 2-3 for each array you want to parse (zonearray, roomarray..etc).
If you can't quite figure out how to code the bounds or how to parse the line and dump them into arrays, I might be able to write something tomorrow (even though it's a holiday here in Canada).
EDIT: It should be noted that you can't use some JSON parser for this; you have to write your own. It's not really that difficult to do, you just need to break it into small steps (first figure out how to zip through each line and find the right "bounds").
HTH
EDIT: I just spent ~20 minutes writing this up for you. It should parse the file and load each array into a List<string[]>. I've heavily commented it so you can see what's going on. If you have any questions, don't hesitate to ask. Cheers!
private class SearchBound
{
public string ArrayName { get; set; }
public int SubArrayLength { get; set; }
public string StartBound { get; set; }
public int StartOffset { get; set; }
public string EndBound { get; set; }
}
public static void Main(string[] args)
{
//
// NOTE: I used FireFox to determine the encoding that was used.
//
List<string> lines = new List<string>();
// Step 1 - Download the file and dump all the lines of the file to the list.
var request = WebRequest.Create("http://skema.ku.dk/life1011/js/filter.js");
using (var response = request.GetResponse())
using(var stream = response.GetResponseStream())
using(var reader = new StreamReader(stream, Encoding.GetEncoding("ISO-8859-1")))
{
string line = null;
while ((line = reader.ReadLine()) != null)
{
lines.Add(line.Trim());
}
Console.WriteLine("Download Complete.");
}
var deptArrayBounds = new SearchBound
{
ArrayName = "deptarray", // The name of the JS array.
SubArrayLength = 2, // In the JS, the sub array is defined as "new Array(X)" and should always be X+1 here.
StartBound = "deptarray[i] = new Array(1);",// The line that should *start* searching for the array values.
StartOffset = 1, // The StartBound + some number line to start searching the array values.
// For example: the next line might be a '}' so we'd want to skip that line.
EndBound = "deptarray.sort();" // The line to stop searching.
};
var zoneArrayBounds = new SearchBound
{
ArrayName = "zonearray",
SubArrayLength = 2,
StartBound = "zonearray[i] = new Array(1);",
StartOffset = 1,
EndBound = "zonearray.sort();"
};
var staffArrayBounds = new SearchBound
{
ArrayName = "staffarray",
SubArrayLength = 3,
StartBound = "staffarray[i] = new Array(2);",
StartOffset = 1,
EndBound = "staffarray.sort();"
};
List<string[]> deptArray = GetArrayValues(lines, deptArrayBounds);
List<string[]> zoneArray = GetArrayValues(lines, zoneArrayBounds);
List<string[]> staffArray = GetArrayValues(lines, staffArrayBounds);
// ... and so on ...
// You can then use deptArray, zoneArray etc where you want...
Console.WriteLine("Depts: " + deptArray.Count);
Console.WriteLine("Zones: " + zoneArray.Count);
Console.WriteLine("Staff: " + staffArray.Count);
Console.ReadKey();
}
private static List<string[]> GetArrayValues(List<string> lines, SearchBound bound)
{
List<string[]> values = new List<string[]>();
// Get the enumerator for the lines.
var enumerator = lines.GetEnumerator();
string line = null;
// Step 1 - Find the starting bound line.
while (enumerator.MoveNext() && (line = enumerator.Current) != bound.StartBound)
{
// Continue looping until we've found the start bound.
}
// Step 2 - Skip to the right offset (maybe skip a line that has a '}' ).
for (int i = 0; i <= bound.StartOffset; i++)
{
enumerator.MoveNext();
}
// Step 3 - Read each line of the array.
while ((line = enumerator.Current) != bound.EndBound)
{
string[] subArray = new string[bound.SubArrayLength];
// Read each sub-array value.
for (int i = 0; i < bound.SubArrayLength; i++)
{
// Matches everything that is between an equal sign then the value
// wrapped in quotes ending with a semi-colon.
var m = Regex.Matches(line, "^(.* = \")(.*)(\";)$");
// Get the matched value.
subArray[i] = m[0].Groups[2].Value;
// Move to the next sub-item if not the last sub-item.
if (i < bound.SubArrayLength - 1)
{
enumerator.MoveNext();
line = enumerator.Current;
}
}
// Add the sub-array to the list of values.
values.Add(subArray);
// Move to the next line.
if (!enumerator.MoveNext())
{
break;
}
}
return values;
}
If I understand your question right, you are asking whether you can execute JavaScript code from C#, and then pass the result (which in your example would be a JavaScript Array object) into C# code.
The answer is: Of course it’s theoretically possible, but you would need to have an actual JavaScript interpreter to execute the JavaScript. You’ll have to find one or write your own, but given that JavaScript is a full-blown programming language, and writing interpreters for such a large and full-featured programming language is quite an undertaking, I suspect that you won’t find a complete ready-made solution, nor will you be able to write one unless your dedication exceeds that of all other die-hard C#-and-JavaScript fans worldwide.
However, with a bit of trickery, you might be able to coerce an existing JavaScript interpreter to do what you want. For obvious reasons, all browsers have such an interpreter, including Internet Explorer, which you can access using the WinForms WebBrowser control. Thus, you could try the following:
Have your C# code generate an HTML file containing the JavaScript you downloaded plus some JavaScript that turns it into JSON (you appear to have already found something that does this) and outputs it in the browser.
Open that HTML file in the WebBrowser control, have it execute the JavaScript, and then read the contents of the website back, now that it contains the result of the executed JavaScript.
Turn the JSON into a C# array using DataContractJsonSerializer as you suggested.
This is a pretty roundabout way to do it, but it is the best I can think of.
I have to wonder, though, why you are retrieving a JavaScript file from the web in the first place. What generates this JavaScript file? Whatever generates it, surely could generate some properly readable stuff instead (e.g. an XML file)? If it is not generated but written by humans, then why is it written in JavaScript instead of XML, CSV, or some other data format? Hopefully with these thoughts you might be able to find a solution that doesn’t require JavaScript trickery like the above.
Easiest solution is to just execute the Javascript function that makes the array. Include there a function that makes it an JSON (http://www.json.org/js.html). After that make a XMLHttpRequest (AJAX) to the server and from there extract the JSON to a custom class.
If I may use jQuery, here's an example of the needed Javascript:
var myJSONText = JSON.stringify(deptarray);
(function($){
$.ajax({
type: "POST",
url: "some.aspx",
data: myJSONText,
success: function(msg){
alert( "Data Saved: " + msg );
}
});
})(jQuery);
Only now need some code to rip the JSON string to an C# Array.
EDIT:
After looking around a bit, I found Json.NET: http://json.codeplex.com/
There are also a lot of the same questions on Stackoverflow that ask the same.

Display array values from web service method

I'm new to web services and im actually trying to learn how to develop one in C#.
I have the following method in my web service which actually displays an array of int when i test it.
[WebMethod]
public int[] FindID(string str1,string str2)
{
Customer obj = new Customer();
obj.FindMatch(str1,str2);
return obj.customer_id;
}
Now in my web application in which i have a button, the code is as below:
Dim obj As localhost.Service = New localhost.Service
Dim str1 As String = Session("str1")
Dim str2 As String = Session("str2")
Response.Write(obj.FindID(str1, str2))
The problem is that only the first value from the array is being displayed. Can anyone please help me to solve this problem?
You could also use String.Join() http://msdn.microsoft.com/en-us/library/57a79xd0.aspx which takes a delimiter and an array of strings, and returns a single string containing the original strings inside the array, delimited by your delimiter.
This can be achieved very simply:
Console.WriteLine(", ", string.Join(obj.FindID(str1, str2)));
Console.Write displays only a single value such an integer, a float number or a string. It will never walk through an array to display each value.
Instead, you can call a Console.Write on each entry in your array.
foreach (int value in obj.FindID(str1, str2))
{
Console.WriteLine(value.ToString());
}
Note that calling Console.Write is resource expensive. If you need to display values of a very long array, maybe you will achieve better results by using StringBuilder class, then calling Console.Write once.
StringBuilder stringBuilder = new StringBuilder();
foreach (int value in obj.FindID(str1, str2))
{
stringBuilder.AppendLine(value.ToString());
}
// Call this once.
Console.Write(stringBuilder.ToString());

Categories

Resources