Converting a JSON array from an ExecuteScript: Step-by-step guide

Exploring Possibilities

In my pursuit of automating web testing using Selenium and incorporating JavaScript functionality, I encountered an intriguing scenario. Within the string func1, resides a JS function that, when passed to ExecuteScript(func1), yields an array of objects structured as follows: {label:'start', time: 121}.

The objective now is to transform the outcome of ExecuteScript into a List<timings>

var result = jsExecutor.ExecuteScript(func1); 
var list = (ReadOnlyCollection<object>)result;
var timings = (List<Timing>)list;

An error surfaced:

 Cannot convert type 'System.Collections.ObjectModel.ReadOnlyCollection<object>' 
 to 'System.Collections.Generic.List<CoreConsoleApp.TestExecutions.Timing>' 

Behold, func1 in all its glory:

string func1= @"var t = window.performance.timing;
  var timings = [];
  timings.push({ label: 'navigationStart', time: t.navigationStart  });
  timings.push({ label: 'PageLoadTime', time: t.loadEventEnd - t.navigationStart  });

return timings;" // The outcome is an array of JS objects

Highlighted below is a snippet concerning the Selenium aspect

 public struct Timing
 {
   public string label;
   public int time;            
 }

 using (var driver = new FirefoxDriver())
 {
  ...
  var jsExecutor = (IJavaScriptExecutor)driver;
  var result = jsExecutor.ExecuteScript(func1); 
  var list = (ReadOnlyCollection<object>)result;
 }

Pondering Queries

According to the Selenium documentation, ExecuteScript endeavors to present a List for an array. Func1 should return an array composed of {label: string, time: number}, making it relatively straightforward to transition from

var list = (ReadOnlyCollection<object>)result
to
List<string,int> timings = (List<timings>)list;

  • How can I proficiently convert 'System.Collections.ObjectModel.ReadOnlyCollection' into a List?

Additional Insights

To initiate Firefox, employ var driver = new FirefoxDriver(), launch a designated URL via driver.Navigate().GoToUrl(url);, locate a specific button with

IWebElement button = driver.FindElement(By.Name("btnK"));
, submit the form through button.Submit();. Post submission, trigger JavaScript execution using ExecuteScript(func1) followed by displaying the outcome on the console.

All aforementioned steps operate smoothly. However, challenge arises when attempting to convert the JavaScript output into a list of C# objects.

Hence, a workaround ensues:

var result = jsExecutor.ExecuteScript(func1); 
var list = (ReadOnlyCollection<object>)result;

foreach (object item in list)
{   
    var timing = (Dictionary<string, object>)item;
    foreach(KeyValuePair<string, object> kvp in timing)
    {
       Console.WriteLine("Key = {0}, Value = {1}", kvp.Key, kvp.Value);
    }                    
 }

This method yields:

 Key = label, Value = navigationStart
 Key = time, Value = 1529720672670
 Key = label, Value = PageLoadTime
 Key = time, Value = 1194
 Key = label, Value = DOMContentLoadedTime
 Key = time, Value = 589
 Key = label, Value = ResponseTime

Answer №1

To extract the necessary data, you must transform the result into a designated List<Timings>.

  1. Access JSON.Net in the package at this location
  2. Convert the result (assuming it is a string) by following these steps:

    List<Timing> timings = JsonConvert.DeserializeObject<List<Timing>>(result);

If you need more guidance on serialization techniques, check out: https://www.newtonsoft.com/json/help/html/SerializingJSON.htm

Answer №2

Consider serializing your data before returning it.

string func2 = @"var t = window.performance.timing;
var timings = [];
timings.push({ label: 'navigationStart', time: t.navigationStart  });
timings.push({ label: 'PageLoadTime', time: t.loadEventEnd - t.navigationStart  });

return JSON.stringify(timings);" // result is string

To access the data in C#, you can use Json.NET

using Newtonsoft.Json.Linq;

string output = Convert.ToString(jsExecutor.ExecuteScript(func2));
Console.Write("result = " + output);
List<Timing> dataList = JToken.Parse(output).ToObject<List<Timing>>();
Console.Write("result = " + JToken.FromObject(dataList));

// Alternatively, you can access it using dynamic
dynamic dynamicDataList = JToken.Parse(jsExecutor.ExecuteScript(func2)); 
for (var j = 0; j < dynamicDataList.Count; j++) {
   Console.Write(dynamicDataList[j]);
}

Answer №3

The issue lies in the structure of

var result = jsExecutor.ExecuteScript(func1);
, which is not as expected.

The value of result resembles something like List<object>(). I demonstrated this using a program:

var dictionary1= new Dictionary<string, object>();

dictionary1.Add("label", (object)"PageloadTime");
dictionary1.Add("time", (object)"1087");    
var dictionary2= new Dictionary<string, object>()
{ 
    {"label", (object)"DOMContentLoadedTime"},
    {"time", (object)"494"}
};

var list = new List<object>(); // representing the structure of result
list.Add(dictionary1);
list.Add(dictionary2);  
list.Dump();

When you call list.Dump();, it displays as shown below:

https://i.sstatic.net/K3AEW.png

It is clear that there are multiple Dictionaries of type

Dictionary<string, object>();
within the structure. Therefore, I attempted to understand the nesting of objects by using two nested loops

Object result = jsExecutor.ExecuteScript(func1); // 

var resultCollection = (ReadOnlyCollection<object>)result;       
foreach (Dictionary<string, object> item in resultCollection)
{
   Console.WriteLine("{0} ", item.GetType()); 
   foreach (KeyValuePair<string, object> kvp in item)
   {
     Console.WriteLine("Keys: {0} Values: {1}", kvp.Key, kvp.Value);
   }
}

Then, I proceeded to create a structure resembling the 'result'

// create a structure similar to result
var list = new List<object>(); 
list.Add(dictionary1);
list.Add(dictionary2);  

var timings = new List<Timing>();

foreach (Dictionary<string, object> dict in list)
{       
    Console.WriteLine("Label = {0}  Value ={1} "
              , (string)dict["label"]
              , (string)dict["time"]);
    // create a timing object
    var t = new Timing();
    t.label = (string)dict["label"];
    t.time = (string)dict["time"];
    timings.Add(t);
}   

Due to potential invalid cast exceptions for (int)dict["time"], I decided to change the 'time' property from int to string.

Update

Following Steven Chong's suggestion, I modified the function func1 to return a string:

public static string jsGetTiming(){

    // func1 represents the javascript function being executed
    string func1= @"var t = window.performance.timing; 
    var PageLoadTime =  t.loadEventEnd - t.navigationStart;            
    var ResponseTime = t.responseEnd - t.requestStart;            

    var timings = 'navigationStart=' + t.navigationStart;
        timings += '|PageLoadTime=' + PageLoadTime;        
        timings += '|ResponseTime=' + ResponseTime;            
     return timings;";

   return func1;
} 

To run the string func1 as a function, use the following code snippet

 Object result = jsExecutor.ExecuteScript(MyClass.jsGetTiming());
 // the result is a string and appears like this
result = 
 navigationStart=1534377023791|PageLoadTime=943  
   |DOMContentLoadedTime=434|ResponseTime=337
   |Response=269|DomainLookup=0
   |LoadEvent=5|UnloadEvent=8
   |DOMContentLoadedEvent=17 

Similar questions

If you have not found the answer to your question or you are interested in this topic, then look at other similar questions below or use the search

Steps to Make Your Node.js Server Always Accessible to External Applications

I have been searching for a solution to this issue everywhere, but I seem to be unable to find a clear answer on how to execute this task. Recently, I created a basic server using node.js that retrieves two numbers from a website API and displays them on ...

Is it necessary to overlook Java Script when conducting load testing on my website?

We are in the process of developing a robust web application that needs to be able to handle a significant amount of traffic. I have been conducting load tests on a HP (Proliant DL 380) server with two 3.6GHz Xeon CPUs and 16GB of RAM. To perform these tes ...

I am struggling to make custom output for jQueryUI Autocomplete menu items function as intended

I am currently facing an issue with passing values from an object retrieved from a JSON string into a jQueryUI Autocomplete element. Specifically, I need to extract three different values from a 2-dimensional array format like this: [{1:a1, 2:b1,3:c1,4:d1 ...

How can we call a function in HTML from an external JavaScript file?

I am attempting to utilize a function that I have defined in my .js file within my HTML document. js/newsalerts.js function decodeHTML(html) { //https://stackoverflow.com/a/2989105/4650297 var tempDiv = document.createElement("DIV"); tempDiv. ...

The jCapSLide Jquery Plugin is experiencing compatibility issues in Chrome browser

While this JQuery plugin works perfectly in Internet Explorer and Firefox, it seems to be malfunctioning in Chrome. The plugin is not being recognized at all by Chrome, and the captions are appearing below the image instead of on top with a sliding effect. ...

A versatile console application framework equipped with reusable input and output functionalities

Throughout my coding journey, I have created numerous console applications. Sometimes it's for quick testing, other times for simple helper programs. Regardless of the reason, every time I feel like I am starting from scratch when it comes to implemen ...

Ways to eliminate an item in a JSON structure?

Allow me to elaborate. I received a JSON containing numerous objects: data = [{"id":"784","label":"blah","publisher":"me"},{"id":"785","label":"bleh","publisher":"you"},{"id":"786","label":"blih","publisher":"she"}]; For instance, I am looking to elim ...

Comparing WebElements to WebElement in Selenium: A Detailed Analysis

When working with Facebook, I am retrieving date elements and then looping through them using the following code snippet. public class select_facebook { public static void main(String[] args) throws Exception { WebDriver driver = new FirefoxDr ...

Searching for elements by their class name in Selenium may require using the `find_element

Having trouble with clicking the Log In button on my Facebook Page. Attempting to locate the button by class_name, but encountering an error. html: https://i.sstatic.net/gNBkw.png python: submit = browser.find_element_by_class_name("a8c37x1j ni8dbm ...

Is it possible to dynamically adjust div height using on resize event?

In my current setup, I have two separate divs on the left and right sides. The issue arises when the height of the left div exceeds the height of the right div. In such cases, the function adjusts the heights to be equal and hides any excess text in the le ...

Using Vue.js, separate the values that are separated by commas

I am looking to extract values from a string and store them in an array for use in displaying values in a dropdown format within Vuejs String str = "abc,123,676,uuu". Once I have iterated through the values <li v-for = "value i ...

When submitting a form in HTML, ensure that the input checkbox returns 'On' instead of 'True'

My MVC3 app is using Project Awesome from http://awesome.codeplex.com/, but I'm encountering a strange issue with checkboxes. Inside a Modal popup, I have the following simple Html code: <input type="checkbox" class="check-box" name="IsDeleted"> ...

Challenge encountered in posting a variable generated through ajax

Embarking on my first attempt at utilizing ajax has been quite challenging. Essentially, when an option is selected from the initial field, javascript and xml trigger a php script that generates the next dropdown menu based on information fetched from an S ...

What is the best way to transfer files (html, js, css, and resources) while utilizing socket.io?

I am currently in the process of developing a web application that involves the server updating the HTML content on the browser page at specific time intervals, essentially creating an HTML slideshow. My project directory structure is as follows: project ...

Utilizing i18n's useTranslation and Redux's connect Higher Order Components to export components efficiently

My application has been utilizing Redux for quite some time, with the component exports structured like this: export default connect(mapStateToProps, mapDispatchToProps)(MyComponent); Now, I am integrating an i18n translation library and would like to use ...

Updating Information Using JQuery

In my view, there is a partial view that displays details of open IT Tickets. Clicking on an open ticket loads the partial view with ticket details and comments using JQuery/Ajax. However, I'm facing an issue where if a new comment is added to a tick ...

Is there a way to verify if a user has selected the correct answer in a quiz program?

Here we have code segments in ajax, javascript, html, and an xml file. I'm looking to calculate the total score based on user input to determine if they selected the correct answers for a test. I've attempted to figure this out, but I'm str ...

A guide on determining if any item from an array is present in an object's array property and iterating through all objects in JavaScript

After searching for a solution to my specific case, I couldn't find one among similar questions. So, I apologize if this seems like a duplicate. I'm currently working on creating a filter for my website and have encountered an issue regarding ma ...

Use the Vue `this.$router.push` method inside a setTimeout function

I have a landing page '/' that users will see first when they visit our website. I want to display a loading wheel for 5 seconds before automatically redirecting them to the login page '/login'. My Landing.vue page in Vue and Bulma.io ...

Is it possible to access the Windows certificate store using JavaScript?

Is there a way to access the Windows certificate store using JavaScript? I'm looking to create a web application that can validate user logins by reading their certificates. ...