【问题标题】:How to convert a json array from ExecuteScript如何从 ExecuteScript 转换 json 数组
【发布时间】:2018-12-02 12:01:47
【问题描述】:

范围

我想使用 Selenium 进行自动化 Web 测试并执行 JavaScript。字符串func1 包含我的js 函数,它被传递给ExecuteScript(func1),它返回一个对象数组,看起来像{label:'start', time: 121}

我想将ExecuteScript 的结果转换成List<timings>

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

我收到了错误

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

这是 func1

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;" // result is an array of js-objects

下面的代码是硒部分的sn-p

 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;
 }

问题

selenium 文档声明 ExecuteScript attempts to return a List 用于数组。 Func1 应该返回数组 {label: string, time: number} 它应该很容易将结果 var list = (ReadOnlyCollection&lt;object&gt;)result 转换为 List&lt;string,int&gt; timings = (List&lt;timings&gt;)list;

  • 如何将“System.Collections.ObjectModel.ReadOnlyCollection”转换为 List?

更多信息

启动火狐var driver = new FirefoxDriver()打开一个URLdriver.Navigate().GoToUrl(url);找到某个按钮IWebElement button = driver.FindElement(By.Name("btnK"));提交表单button.Submit();提交后执行JavaScriptExecuteScript(func1)并将结果写入控制台

以上所有工作。但我无法将 JavaScript 转换为 c# 对象列表。

所以我的解决方法是这样的

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);
    }                    
 }

这就出来了:

 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

【问题讨论】:

    标签: javascript c# selenium .net-core


    【解决方案1】:

    问题在于var result = jsExecutor.ExecuteScript(func1); 的结构与预期不同。

    result 看起来类似于 List&lt;object&gt;() 我创建了这个 程序:

    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>(); // this is the structure of result
    list.Add(dictionary1);
    list.Add(dictionary2);  
    list.Dump();
    

    如果你打电话给list.Dump();,它看起来像这样:

    如您所见,该结构包含 n 个这种类型的字典 Dictionary&lt;string, object&gt;(); 因此我尝试了两个嵌套循环以更好地理解对象的嵌套

    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);
       }
    }
    

    最后

    // 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);
    }   
    

    由于有时我得到(int)dict["time"] 的无效转换异常,我将属性时间从 int 更改为 string。

    更新

    正如 Steven Chong 建议的那样,我将函数 func1 更改为返回一个字符串:

    public static string jsGetTiming(){
    
        // func1 is the javascript function that will get 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;
    } 
    

    要将字符串func1作为函数执行,您可以这样调用它

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

    【讨论】:

      【解决方案2】:

      在返回之前尝试序列化您的数据。

      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 JSON.stringify(timings);" // result is string
      

      并使用 Json.NET 在 c# 中访问您的数据

      using Newtonsoft.Json.Linq;
      
      string result = Convert.ToString(jsExecutor.ExecuteScript(func1));
      Console.Write("result = " + result);
      List<Timing> list = JToken.Parse(result).ToObject<List<Timing>>();
      Console.Write("result = " + JToken.FromObject(list));
      
      // or access using dynamic
      dynamic dynamicList = JToken.Parse(jsExecutor.ExecuteScript(func1)); 
      for (var i = 0; i < dynamicList.Count; i++) {
         Console.Write(dynamicList[i]);
      }
      

      【讨论】:

      • 这可能是我要走的路线。但我的意图是了解发生了什么。感谢您的帮助 +1。
      【解决方案3】:

      您需要将result 反序列化为所需的List&lt;Timings&gt;

      1. here引用包JSON.Net
      2. 反序列化result(假设是string)如下:

        List&lt;Timing&gt; timings = JsonConvert.DeserializeObject&lt;List&lt;Timing&gt;&gt;(result);

      以下是关于序列化的一些基本帮助: https://www.newtonsoft.com/json/help/html/SerializingJSON.htm

      【讨论】:

      • 谢谢。正如你所说的反序列化result 它需要是string 类型。上面不是这种情况:Error CS1503 Argument 1: cannot convert from 'object' to 'string'。我会尽快添加更多信息。
      猜你喜欢
      • 2023-03-16
      • 2020-04-11
      • 1970-01-01
      • 2020-12-10
      • 1970-01-01
      • 2021-01-16
      • 1970-01-01
      • 2013-05-03
      • 2021-09-15
      相关资源
      最近更新 更多