Skip to content

Commit cfa8d3e

Browse files
authored
Merge branch 'trunk' into alert_tests
2 parents 670fc6f + f457f15 commit cfa8d3e

File tree

14 files changed

+642
-344
lines changed

14 files changed

+642
-344
lines changed

dotnet/src/webdriver/BiDi/Modules/BrowsingContext/BrowsingContextScriptModule.cs

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -44,7 +44,7 @@ public async Task<IReadOnlyList<RealmInfo>> GetRealmsAsync(GetRealmsOptions? opt
4444
return await scriptModule.GetRealmsAsync(options).ConfigureAwait(false);
4545
}
4646

47-
public Task<EvaluateResultSuccess> EvaluateAsync(string expression, bool awaitPromise, EvaluateOptions? options = null, ContextTargetOptions? targetOptions = null)
47+
public Task<EvaluateResult> EvaluateAsync(string expression, bool awaitPromise, EvaluateOptions? options = null, ContextTargetOptions? targetOptions = null)
4848
{
4949
var contextTarget = new ContextTarget(context);
5050

@@ -60,10 +60,10 @@ public Task<EvaluateResultSuccess> EvaluateAsync(string expression, bool awaitPr
6060
{
6161
var result = await EvaluateAsync(expression, awaitPromise, options, targetOptions).ConfigureAwait(false);
6262

63-
return result.Result.ConvertTo<TResult>();
63+
return result.AsSuccessResult().ConvertTo<TResult>();
6464
}
6565

66-
public Task<EvaluateResultSuccess> CallFunctionAsync(string functionDeclaration, bool awaitPromise, CallFunctionOptions? options = null, ContextTargetOptions? targetOptions = null)
66+
public Task<EvaluateResult> CallFunctionAsync(string functionDeclaration, bool awaitPromise, CallFunctionOptions? options = null, ContextTargetOptions? targetOptions = null)
6767
{
6868
var contextTarget = new ContextTarget(context);
6969

@@ -79,6 +79,6 @@ public Task<EvaluateResultSuccess> CallFunctionAsync(string functionDeclaration,
7979
{
8080
var result = await CallFunctionAsync(functionDeclaration, awaitPromise, options, targetOptions).ConfigureAwait(false);
8181

82-
return result.Result.ConvertTo<TResult>();
82+
return result.AsSuccessResult().ConvertTo<TResult>();
8383
}
8484
}

dotnet/src/webdriver/BiDi/Modules/Script/EvaluateCommand.cs

Lines changed: 13 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -18,6 +18,7 @@
1818
// </copyright>
1919

2020
using OpenQA.Selenium.BiDi.Communication;
21+
using System;
2122

2223
namespace OpenQA.Selenium.BiDi.Modules.Script;
2324

@@ -39,7 +40,18 @@ public record EvaluateOptions : CommandOptions
3940
//[JsonPolymorphic(TypeDiscriminatorPropertyName = "type")]
4041
//[JsonDerivedType(typeof(EvaluateResultSuccess), "success")]
4142
//[JsonDerivedType(typeof(EvaluateResultException), "exception")]
42-
public abstract record EvaluateResult : EmptyResult;
43+
public abstract record EvaluateResult : EmptyResult
44+
{
45+
public RemoteValue AsSuccessResult()
46+
{
47+
if (this is EvaluateResultSuccess success)
48+
{
49+
return success.Result;
50+
}
51+
52+
throw new InvalidCastException($"Expected the result to be {nameof(EvaluateResultSuccess)}, but received {this}");
53+
}
54+
}
4355

4456
public record EvaluateResultSuccess(RemoteValue Result, Realm Realm) : EvaluateResult
4557
{

dotnet/src/webdriver/BiDi/Modules/Script/LocalValue.cs

Lines changed: 198 additions & 59 deletions
Original file line numberDiff line numberDiff line change
@@ -18,10 +18,12 @@
1818
// </copyright>
1919

2020
using System;
21+
using System.Collections;
2122
using System.Collections.Generic;
2223
using System.Linq;
2324
using System.Numerics;
2425
using System.Text.Json.Serialization;
26+
using System.Text.RegularExpressions;
2527

2628
namespace OpenQA.Selenium.BiDi.Modules.Script;
2729

@@ -41,10 +43,11 @@ namespace OpenQA.Selenium.BiDi.Modules.Script;
4143
[JsonDerivedType(typeof(SetLocalValue), "set")]
4244
public abstract record LocalValue
4345
{
44-
public static implicit operator LocalValue(bool? value) { return value is bool b ? new BooleanLocalValue(b) : new NullLocalValue(); }
45-
public static implicit operator LocalValue(int? value) { return value is int i ? new NumberLocalValue(i) : new NullLocalValue(); }
46-
public static implicit operator LocalValue(double? value) { return value is double d ? new NumberLocalValue(d) : new NullLocalValue(); }
47-
public static implicit operator LocalValue(string? value) { return value is null ? new NullLocalValue() : new StringLocalValue(value); }
46+
public static implicit operator LocalValue(bool? value) { return ConvertFrom(value); }
47+
public static implicit operator LocalValue(int? value) { return ConvertFrom(value); }
48+
public static implicit operator LocalValue(double? value) { return ConvertFrom(value); }
49+
public static implicit operator LocalValue(string? value) { return ConvertFrom(value); }
50+
public static implicit operator LocalValue(DateTimeOffset? value) { return ConvertFrom(value); }
4851

4952
// TODO: Extend converting from types
5053
public static LocalValue ConvertFrom(object? value)
@@ -58,86 +61,222 @@ public static LocalValue ConvertFrom(object? value)
5861
return new NullLocalValue();
5962

6063
case bool b:
61-
return new BooleanLocalValue(b);
64+
return ConvertFrom(b);
6265

6366
case int i:
64-
return new NumberLocalValue(i);
67+
return ConvertFrom(i);
6568

6669
case double d:
67-
return new NumberLocalValue(d);
70+
return ConvertFrom(d);
6871

6972
case long l:
70-
return new NumberLocalValue(l);
73+
return ConvertFrom(l);
7174

72-
case DateTime dt:
73-
return new DateLocalValue(dt.ToString("o"));
75+
case DateTimeOffset dt:
76+
return ConvertFrom(dt);
7477

7578
case BigInteger bigInt:
76-
return new BigIntLocalValue(bigInt.ToString());
79+
return ConvertFrom(bigInt);
7780

7881
case string str:
79-
return new StringLocalValue(str);
82+
return ConvertFrom(str);
8083

81-
case IDictionary<string, string?> dictionary:
84+
case Regex regex:
85+
return ConvertFrom(regex);
86+
87+
case { } when value.GetType().GetInterfaces()
88+
.Any(i => i.IsGenericType && i.GetGenericTypeDefinition() == typeof(ISet<>)):
8289
{
83-
var bidiObject = new List<List<LocalValue>>(dictionary.Count);
84-
foreach (var item in dictionary)
85-
{
86-
bidiObject.Add([new StringLocalValue(item.Key), ConvertFrom(item.Value)]);
87-
}
90+
IEnumerable set = (IEnumerable)value;
8891

89-
return new ObjectLocalValue(bidiObject);
90-
}
92+
List<LocalValue> setValues = [];
9193

92-
case IDictionary<string, object?> dictionary:
93-
{
94-
var bidiObject = new List<List<LocalValue>>(dictionary.Count);
95-
foreach (var item in dictionary)
94+
foreach (var obj in set)
9695
{
97-
bidiObject.Add([new StringLocalValue(item.Key), ConvertFrom(item.Value)]);
96+
setValues.Add(ConvertFrom(obj));
9897
}
9998

100-
return new ObjectLocalValue(bidiObject);
99+
return new SetLocalValue(setValues);
101100
}
102101

103-
case IDictionary<int, object?> dictionary:
104-
{
105-
var bidiObject = new List<List<LocalValue>>(dictionary.Count);
106-
foreach (var item in dictionary)
107-
{
108-
bidiObject.Add([ConvertFrom(item.Key), ConvertFrom(item.Value)]);
109-
}
102+
case IDictionary dictionary:
103+
return ConvertFrom(dictionary);
110104

111-
return new MapLocalValue(bidiObject);
112-
}
105+
case IEnumerable enumerable:
106+
return ConvertFrom(enumerable);
113107

114-
case IEnumerable<object?> list:
115-
return new ArrayLocalValue(list.Select(ConvertFrom).ToList());
108+
default:
109+
return ReflectionBasedConvertFrom(value);
110+
}
111+
}
116112

117-
case object:
118-
{
119-
const System.Reflection.BindingFlags Flags = System.Reflection.BindingFlags.Public | System.Reflection.BindingFlags.Instance;
113+
public static LocalValue ConvertFrom(bool? value)
114+
{
115+
if (value is bool b)
116+
{
117+
return new BooleanLocalValue(b);
118+
}
120119

121-
var properties = value.GetType().GetProperties(Flags);
120+
return new NullLocalValue();
121+
}
122122

123-
var values = new List<List<LocalValue>>(properties.Length);
124-
foreach (var property in properties)
125-
{
126-
object? propertyValue;
127-
try
128-
{
129-
propertyValue = property.GetValue(value);
130-
}
131-
catch (Exception ex)
132-
{
133-
throw new BiDiException($"Could not retrieve property {property.Name} from {property.DeclaringType}", ex);
134-
}
135-
values.Add([property.Name, ConvertFrom(propertyValue)]);
136-
}
123+
public static LocalValue ConvertFrom(int? value)
124+
{
125+
if (value is int b)
126+
{
127+
return new NumberLocalValue(b);
128+
}
137129

138-
return new ObjectLocalValue(values);
139-
}
130+
return new NullLocalValue();
131+
}
132+
133+
public static LocalValue ConvertFrom(double? value)
134+
{
135+
if (value is double b)
136+
{
137+
return new NumberLocalValue(b);
138+
}
139+
140+
return new NullLocalValue();
141+
}
142+
143+
public static LocalValue ConvertFrom(long? value)
144+
{
145+
if (value is long b)
146+
{
147+
return new NumberLocalValue(b);
148+
}
149+
150+
return new NullLocalValue();
151+
}
152+
153+
public static LocalValue ConvertFrom(string? value)
154+
{
155+
if (value is not null)
156+
{
157+
return new StringLocalValue(value);
158+
}
159+
160+
return new NullLocalValue();
161+
}
162+
163+
/// <summary>
164+
/// Converts a .NET Regex into a BiDi Regex
165+
/// </summary>
166+
/// <param name="regex">A .NET Regex.</param>
167+
/// <returns>A BiDi Regex.</returns>
168+
/// <remarks>
169+
/// Note that the .NET regular expression engine does not work the same as the JavaScript engine.
170+
/// To minimize the differences between the two engines, it is recommended to enabled the <see cref="RegexOptions.ECMAScript"/> option.
171+
/// </remarks>
172+
public static LocalValue ConvertFrom(Regex? regex)
173+
{
174+
if (regex is null)
175+
{
176+
return new NullLocalValue();
140177
}
178+
179+
string? flags = RegExpValue.GetRegExpFlags(regex.Options);
180+
181+
return new RegExpLocalValue(new RegExpValue(regex.ToString()) { Flags = flags });
182+
}
183+
184+
public static LocalValue ConvertFrom(DateTimeOffset? value)
185+
{
186+
if (value is null)
187+
{
188+
return new NullLocalValue();
189+
}
190+
191+
return new DateLocalValue(value.Value.ToString("o"));
192+
}
193+
194+
public static LocalValue ConvertFrom(BigInteger? value)
195+
{
196+
if (value is not null)
197+
{
198+
return new BigIntLocalValue(value.Value.ToString());
199+
}
200+
201+
return new NullLocalValue();
202+
}
203+
204+
public static LocalValue ConvertFrom(IEnumerable? value)
205+
{
206+
if (value is null)
207+
{
208+
return new NullLocalValue();
209+
}
210+
211+
List<LocalValue> list = [];
212+
213+
foreach (var element in value)
214+
{
215+
list.Add(ConvertFrom(element));
216+
}
217+
218+
return new ArrayLocalValue(list);
219+
}
220+
221+
public static LocalValue ConvertFrom(IDictionary? value)
222+
{
223+
if (value is null)
224+
{
225+
return new NullLocalValue();
226+
}
227+
228+
var bidiObject = new List<List<LocalValue>>(value.Count);
229+
230+
foreach (var key in value.Keys)
231+
{
232+
bidiObject.Add([ConvertFrom(key), ConvertFrom(value[key])]);
233+
}
234+
235+
return new MapLocalValue(bidiObject);
236+
}
237+
238+
public static LocalValue ConvertFrom<T>(ISet<T?>? value)
239+
{
240+
if (value is null)
241+
{
242+
return new NullLocalValue();
243+
}
244+
245+
LocalValue[] convertedValues = [.. value.Select(x => ConvertFrom(x))];
246+
247+
return new SetLocalValue(convertedValues);
248+
}
249+
250+
private static LocalValue ReflectionBasedConvertFrom(object? value)
251+
{
252+
if (value is null)
253+
{
254+
return new NullLocalValue();
255+
}
256+
257+
const System.Reflection.BindingFlags Flags = System.Reflection.BindingFlags.Public | System.Reflection.BindingFlags.Instance;
258+
259+
System.Reflection.PropertyInfo[] properties = value.GetType().GetProperties(Flags);
260+
261+
var values = new List<List<LocalValue>>(properties.Length);
262+
263+
foreach (System.Reflection.PropertyInfo? property in properties)
264+
{
265+
object? propertyValue;
266+
267+
try
268+
{
269+
propertyValue = property.GetValue(value);
270+
}
271+
catch (Exception ex)
272+
{
273+
throw new BiDiException($"Could not retrieve property {property.Name} from {property.DeclaringType}", ex);
274+
}
275+
276+
values.Add([property.Name, ConvertFrom(propertyValue)]);
277+
}
278+
279+
return new ObjectLocalValue(values);
141280
}
142281
}
143282

@@ -160,9 +299,9 @@ public record BigIntLocalValue(string Value) : PrimitiveProtocolLocalValue;
160299

161300
public record ChannelLocalValue(ChannelProperties Value) : LocalValue
162301
{
163-
// TODO: Revise why we need it
302+
// AddPreloadScript takes arguments typed as ChannelLocalValue but still requires "type":"channel"
164303
[JsonInclude]
165-
internal string type = "channel";
304+
internal string Type => "channel";
166305
}
167306

168307
public record ArrayLocalValue(IEnumerable<LocalValue> Value) : LocalValue;

0 commit comments

Comments
 (0)