Skip to content

Commit ae2d622

Browse files
committed
[dotnet] Align Scipt.LocalValue.Map with spec
1 parent 80feb18 commit ae2d622

File tree

4 files changed

+142
-2
lines changed

4 files changed

+142
-2
lines changed

dotnet/src/webdriver/BiDi/Communication/Broker.cs

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -64,6 +64,7 @@ internal Broker(BiDi bidi, ITransport transport)
6464
PropertyNameCaseInsensitive = true,
6565
PropertyNamingPolicy = JsonNamingPolicy.CamelCase,
6666
DefaultIgnoreCondition = JsonIgnoreCondition.WhenWritingNull,
67+
NumberHandling = JsonNumberHandling.AllowNamedFloatingPointLiterals,
6768
Converters =
6869
{
6970
new BrowsingContextConverter(_bidi),

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

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -103,7 +103,7 @@ public record Array(IEnumerable<LocalValue> Value) : LocalValue;
103103

104104
public record Date(string Value) : LocalValue;
105105

106-
public record Map(IDictionary<string, LocalValue> Value) : LocalValue; // seems to implement IDictionary
106+
public record Map(IEnumerable<IEnumerable<LocalValue>> Value) : LocalValue;
107107

108108
public record Object(IEnumerable<IEnumerable<LocalValue>> Value) : LocalValue;
109109

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

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -158,7 +158,7 @@ public record Map : RemoteValue
158158

159159
public InternalId? InternalId { get; set; }
160160

161-
public IDictionary<string, RemoteValue>? Value { get; set; }
161+
public IReadOnlyList<IReadOnlyList<RemoteValue>>? Value { get; set; }
162162
}
163163

164164
public record Set : RemoteValue

dotnet/test/common/BiDi/Script/CallFunctionParameterTest.cs

Lines changed: 139 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -19,6 +19,9 @@
1919

2020
using NUnit.Framework;
2121
using OpenQA.Selenium.BiDi.Modules.Script;
22+
using System;
23+
using System.Collections.Generic;
24+
using System.Globalization;
2225
using System.Threading.Tasks;
2326

2427
namespace OpenQA.Selenium.BiDi.Script;
@@ -219,4 +222,140 @@ public async Task CanCallFunctionInARealm()
219222
Assert.That(res1, Is.EqualTo(3));
220223
Assert.That(res2, Is.EqualTo(5));
221224
}
225+
226+
[Test]
227+
[TestCaseSource(nameof(RoundtripOptions))]
228+
public async Task CanCallFunctionAndRoundtrip_Five(LocalValue local, RemoteValue returned, string javaScriptAssert)
229+
{
230+
var response = await context.Script.CallFunctionAsync($$"""
231+
(arg) => {
232+
if ({{javaScriptAssert}}) {
233+
return arg;
234+
}
235+
236+
throw new Error("Assert failed: " + arg);
237+
}
238+
""", false, new() { Arguments = [local] });
239+
240+
if (response.Result is RemoteValue.Array arrayResponse && returned is RemoteValue.Array expectedArray)
241+
{
242+
Assert.That(arrayResponse.Value, Is.EqualTo(expectedArray.Value));
243+
}
244+
else if (response.Result is RemoteValue.Object objectResponse && returned is RemoteValue.Object expectedObject)
245+
{
246+
Assert.That(objectResponse.Value, Is.EqualTo(expectedObject.Value));
247+
}
248+
else if (response.Result is RemoteValue.Map mapResponse && returned is RemoteValue.Map expectedMap)
249+
{
250+
Assert.That(mapResponse.Value, Is.EqualTo(expectedMap.Value));
251+
}
252+
else if (response.Result is RemoteValue.Date dateResponse && returned is RemoteValue.Date expectedDate)
253+
{
254+
var actualDate = DateTime.SpecifyKind(DateTime.Parse(dateResponse.Value, CultureInfo.InvariantCulture), DateTimeKind.Utc);
255+
Assert.That(actualDate.Kind, Is.EqualTo(DateTimeKind.Utc));
256+
Assert.That(actualDate, Is.EqualTo(DateTime.Parse(expectedDate.Value)).Within(TimeSpan.FromMilliseconds(1)));
257+
}
258+
else
259+
{
260+
Assert.That(response.Result, Is.EqualTo(returned));
261+
}
262+
}
263+
private const string PinnedDateTimeString = "2025-03-09T00:30:33.083Z";
264+
private static IEnumerable<TestCaseData> RoundtripOptions()
265+
{
266+
267+
yield return new TestCaseData(new LocalValue.Null(), new RemoteValue.Null(), "arg === null")
268+
{
269+
TestName = nameof(CanCallFunctionAndRoundtrip_Five) + "(Null)"
270+
};
271+
yield return new TestCaseData(new LocalValue.Undefined(), new RemoteValue.Undefined(), "typeof arg === 'undefined'")
272+
{
273+
TestName = nameof(CanCallFunctionAndRoundtrip_Five) + "(Undefined)",
274+
};
275+
//yield return new TestCaseData(new LocalValue.Boolean(true), new RemoteValue.Boolean(true), "typeof arg === true")
276+
//{
277+
// TestName = nameof(CanCallFunctionAndRoundtrip_Five) + "(true)",
278+
//};
279+
//yield return new TestCaseData(new LocalValue.Boolean(false), new RemoteValue.Boolean(false), "typeof arg === false")
280+
//{
281+
// TestName = nameof(CanCallFunctionAndRoundtrip_Five) + "(false)",
282+
//};
283+
yield return new TestCaseData(new LocalValue.String("whoa"), new RemoteValue.String("whoa"), "arg === 'whoa'")
284+
{
285+
TestName = nameof(CanCallFunctionAndRoundtrip_Five) + "(String('whoa'))",
286+
};
287+
yield return new TestCaseData(new LocalValue.String(string.Empty), new RemoteValue.String(string.Empty), "arg === ''")
288+
{
289+
TestName = nameof(CanCallFunctionAndRoundtrip_Five) + "(String(''))",
290+
};
291+
yield return new TestCaseData(new LocalValue.Date(PinnedDateTimeString), new RemoteValue.Date(PinnedDateTimeString), $"arg.toISOString() === '{PinnedDateTimeString}'")
292+
{
293+
TestName = nameof(CanCallFunctionAndRoundtrip_Five) + "(Date)",
294+
};
295+
yield return new TestCaseData(new LocalValue.Number(5), new RemoteValue.Number(5), "arg === 5")
296+
{
297+
TestName = nameof(CanCallFunctionAndRoundtrip_Five) + "(Number(5))",
298+
};
299+
yield return new TestCaseData(new LocalValue.Number(0), new RemoteValue.Number(0), "arg === 0")
300+
{
301+
TestName = nameof(CanCallFunctionAndRoundtrip_Five) + "(Number(0))",
302+
};
303+
yield return new TestCaseData(new LocalValue.Number(-5), new RemoteValue.Number(-5), "arg === -5")
304+
{
305+
TestName = nameof(CanCallFunctionAndRoundtrip_Five) + "(Number(-5))",
306+
};
307+
yield return new TestCaseData(new LocalValue.Number(double.PositiveInfinity), new RemoteValue.Number(double.PositiveInfinity), "arg === Number.POSITIVE_INFINITY")
308+
{
309+
TestName = nameof(CanCallFunctionAndRoundtrip_Five) + "(Number(Infinity))",
310+
};
311+
yield return new TestCaseData(new LocalValue.Number(double.NegativeInfinity), new RemoteValue.Number(double.NegativeInfinity), "arg === Number.NEGATIVE_INFINITY")
312+
{
313+
TestName = nameof(CanCallFunctionAndRoundtrip_Five) + "(Number(-Infinity))",
314+
};
315+
yield return new TestCaseData(new LocalValue.Number(double.NegativeZero), new RemoteValue.Number(double.NegativeZero), "arg === -0")
316+
{
317+
TestName = nameof(CanCallFunctionAndRoundtrip_Five) + "(Number(-0))",
318+
};
319+
yield return new TestCaseData(
320+
new LocalValue.RegExp(new LocalValue.RegExp.RegExpValue("foo*") { Flags = "g" }),
321+
new RemoteValue.RegExp(new RemoteValue.RegExp.RegExpValue("foo*") { Flags = "g" }),
322+
"arg.test('foo') && arg.source === 'foo*' && arg.global"
323+
)
324+
{
325+
TestName = nameof(CanCallFunctionAndRoundtrip_Five) + "(RegExp(/foo/g))",
326+
};
327+
yield return new TestCaseData(
328+
329+
new LocalValue.Array([new LocalValue.String("hi")]),
330+
new RemoteValue.Array { Value = [new RemoteValue.String("hi")] },
331+
"arg.length === 1 && arg[0] === 'hi'"
332+
)
333+
{
334+
TestName = nameof(CanCallFunctionAndRoundtrip_Five) + "(Array(['hi']))",
335+
};
336+
yield return new TestCaseData
337+
(
338+
new LocalValue.Object([[new LocalValue.String("key"), new LocalValue.String("value")]]),
339+
new RemoteValue.Object
340+
{
341+
Value = [[new RemoteValue.String("key"), new RemoteValue.String("value")]]
342+
},
343+
"arg.key === 'value' && Object.keys(arg).length === 1"
344+
)
345+
{
346+
TestName = nameof(CanCallFunctionAndRoundtrip_Five) + "(Object({key: 'value'}))",
347+
};
348+
yield return new TestCaseData
349+
(
350+
new LocalValue.Map([[new LocalValue.String("key"), new LocalValue.String("value")]]),
351+
new RemoteValue.Map
352+
{
353+
Value = [[new RemoteValue.String("key"), new RemoteValue.String("value")]]
354+
},
355+
"arg.get('key') === 'value' && arg.size === 1"
356+
)
357+
{
358+
TestName = nameof(CanCallFunctionAndRoundtrip_Five) + "(Map({'key': 'value'}))",
359+
};
360+
}
222361
}

0 commit comments

Comments
 (0)