Skip to content

Commit e26e56c

Browse files
nvborisenkoRenderMichael
authored andcommitted
[dotnet] [bidi] Make LocalValue types not nested (SeleniumHQ#15428)
Co-authored-by: Michael Render <[email protected]>
1 parent dd1ea0f commit e26e56c

File tree

7 files changed

+107
-70
lines changed

7 files changed

+107
-70
lines changed

dotnet/src/webdriver/BiDi/Communication/Json/BiDiJsonSerializerContext.cs

-2
Original file line numberDiff line numberDiff line change
@@ -140,8 +140,6 @@ namespace OpenQA.Selenium.BiDi.Communication.Json;
140140
[JsonSerializable(typeof(Modules.Network.FetchErrorEventArgs))]
141141
[JsonSerializable(typeof(Modules.Network.AuthRequiredEventArgs))]
142142

143-
[JsonSerializable(typeof(Modules.Script.Channel), TypeInfoPropertyName = "Script_Channel")]
144-
[JsonSerializable(typeof(Modules.Script.LocalValue.String), TypeInfoPropertyName = "Script_LocalValue_String")]
145143
[JsonSerializable(typeof(Modules.Script.Target.Realm), TypeInfoPropertyName = "Script_Target_Realm")]
146144
[JsonSerializable(typeof(Modules.Script.Target.Context), TypeInfoPropertyName = "Script_Target_Context")]
147145

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

+3-3
Original file line numberDiff line numberDiff line change
@@ -25,7 +25,7 @@ namespace OpenQA.Selenium.BiDi.Modules.Script;
2525
internal class AddPreloadScriptCommand(AddPreloadScriptCommandParameters @params)
2626
: Command<AddPreloadScriptCommandParameters>(@params, "script.addPreloadScript");
2727

28-
internal record AddPreloadScriptCommandParameters(string FunctionDeclaration, IEnumerable<LocalValue.Channel>? Arguments, IEnumerable<BrowsingContext.BrowsingContext>? Contexts, string? Sandbox) : CommandParameters;
28+
internal record AddPreloadScriptCommandParameters(string FunctionDeclaration, IEnumerable<ChannelLocalValue>? Arguments, IEnumerable<BrowsingContext.BrowsingContext>? Contexts, string? Sandbox) : CommandParameters;
2929

3030
public record AddPreloadScriptOptions : CommandOptions
3131
{
@@ -37,7 +37,7 @@ internal AddPreloadScriptOptions(BrowsingContextAddPreloadScriptOptions? options
3737
Sandbox = options?.Sandbox;
3838
}
3939

40-
public IEnumerable<LocalValue.Channel>? Arguments { get; set; }
40+
public IEnumerable<ChannelLocalValue>? Arguments { get; set; }
4141

4242
public IEnumerable<BrowsingContext.BrowsingContext>? Contexts { get; set; }
4343

@@ -46,7 +46,7 @@ internal AddPreloadScriptOptions(BrowsingContextAddPreloadScriptOptions? options
4646

4747
public record BrowsingContextAddPreloadScriptOptions
4848
{
49-
public IEnumerable<LocalValue.Channel>? Arguments { get; set; }
49+
public IEnumerable<ChannelLocalValue>? Arguments { get; set; }
5050

5151
public string? Sandbox { get; set; }
5252
}

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

+50-43
Original file line numberDiff line numberDiff line change
@@ -23,21 +23,23 @@
2323
namespace OpenQA.Selenium.BiDi.Modules.Script;
2424

2525
[JsonPolymorphic(TypeDiscriminatorPropertyName = "type")]
26-
[JsonDerivedType(typeof(Number), "number")]
27-
[JsonDerivedType(typeof(String), "string")]
28-
[JsonDerivedType(typeof(Null), "null")]
29-
[JsonDerivedType(typeof(Undefined), "undefined")]
30-
[JsonDerivedType(typeof(Channel), "channel")]
31-
[JsonDerivedType(typeof(Array), "array")]
32-
[JsonDerivedType(typeof(Date), "date")]
33-
[JsonDerivedType(typeof(Map), "map")]
34-
[JsonDerivedType(typeof(Object), "object")]
35-
[JsonDerivedType(typeof(RegExp), "regexp")]
36-
[JsonDerivedType(typeof(Set), "set")]
26+
[JsonDerivedType(typeof(NumberLocalValue), "number")]
27+
[JsonDerivedType(typeof(StringLocalValue), "string")]
28+
[JsonDerivedType(typeof(NullLocalValue), "null")]
29+
[JsonDerivedType(typeof(UndefinedLocalValue), "undefined")]
30+
[JsonDerivedType(typeof(BooleanLocalValue), "boolean")]
31+
[JsonDerivedType(typeof(BigIntLocalValue), "bigint")]
32+
[JsonDerivedType(typeof(ChannelLocalValue), "channel")]
33+
[JsonDerivedType(typeof(ArrayLocalValue), "array")]
34+
[JsonDerivedType(typeof(DateLocalValue), "date")]
35+
[JsonDerivedType(typeof(MapLocalValue), "map")]
36+
[JsonDerivedType(typeof(ObjectLocalValue), "object")]
37+
[JsonDerivedType(typeof(RegExpLocalValue), "regexp")]
38+
[JsonDerivedType(typeof(SetLocalValue), "set")]
3739
public abstract record LocalValue
3840
{
39-
public static implicit operator LocalValue(int value) { return new Number(value); }
40-
public static implicit operator LocalValue(string value) { return new String(value); }
41+
public static implicit operator LocalValue(int value) { return new NumberLocalValue(value); }
42+
public static implicit operator LocalValue(string? value) { return value is null ? new NullLocalValue() : new StringLocalValue(value); }
4143

4244
// TODO: Extend converting from types
4345
public static LocalValue ConvertFrom(object? value)
@@ -47,7 +49,7 @@ public static LocalValue ConvertFrom(object? value)
4749
case LocalValue:
4850
return (LocalValue)value;
4951
case null:
50-
return new Null();
52+
return new NullLocalValue();
5153
case int:
5254
return (int)value;
5355
case string:
@@ -65,52 +67,57 @@ public static LocalValue ConvertFrom(object? value)
6567
values.Add([property.Name, ConvertFrom(property.GetValue(value))]);
6668
}
6769

68-
return new Object(values);
70+
return new ObjectLocalValue(values);
6971
}
7072
}
7173
}
74+
}
7275

73-
public abstract record PrimitiveProtocolLocalValue : LocalValue;
76+
public abstract record PrimitiveProtocolLocalValue : LocalValue;
7477

75-
public record Number(double Value) : PrimitiveProtocolLocalValue
76-
{
77-
public static explicit operator Number(double n) => new Number(n);
78-
}
78+
public record NumberLocalValue(double Value) : PrimitiveProtocolLocalValue
79+
{
80+
public static explicit operator NumberLocalValue(double n) => new NumberLocalValue(n);
81+
}
7982

80-
public record String(string Value) : PrimitiveProtocolLocalValue;
83+
public record StringLocalValue(string Value) : PrimitiveProtocolLocalValue;
8184

82-
public record Null : PrimitiveProtocolLocalValue;
85+
public record NullLocalValue : PrimitiveProtocolLocalValue;
8386

84-
public record Undefined : PrimitiveProtocolLocalValue;
87+
public record UndefinedLocalValue : PrimitiveProtocolLocalValue;
8588

86-
public record Channel(Channel.ChannelProperties Value) : LocalValue
87-
{
88-
[JsonInclude]
89-
internal string type = "channel";
89+
public record BooleanLocalValue(bool Value) : PrimitiveProtocolLocalValue;
9090

91-
public record ChannelProperties(Script.Channel Channel)
92-
{
93-
public SerializationOptions? SerializationOptions { get; set; }
91+
public record BigIntLocalValue(string Value) : PrimitiveProtocolLocalValue;
9492

95-
public ResultOwnership? Ownership { get; set; }
96-
}
93+
public record ChannelLocalValue(ChannelLocalValue.ChannelProperties Value) : LocalValue
94+
{
95+
// TODO: Revise why we need it
96+
[JsonInclude]
97+
internal string type = "channel";
98+
99+
public record ChannelProperties(Channel Channel)
100+
{
101+
public SerializationOptions? SerializationOptions { get; set; }
102+
103+
public ResultOwnership? Ownership { get; set; }
97104
}
105+
}
98106

99-
public record Array(IEnumerable<LocalValue> Value) : LocalValue;
107+
public record ArrayLocalValue(IEnumerable<LocalValue> Value) : LocalValue;
100108

101-
public record Date(string Value) : LocalValue;
109+
public record DateLocalValue(string Value) : LocalValue;
102110

103-
public record Map(IEnumerable<IEnumerable<LocalValue>> Value) : LocalValue;
111+
public record MapLocalValue(IEnumerable<IEnumerable<LocalValue>> Value) : LocalValue;
104112

105-
public record Object(IEnumerable<IEnumerable<LocalValue>> Value) : LocalValue;
113+
public record ObjectLocalValue(IEnumerable<IEnumerable<LocalValue>> Value) : LocalValue;
106114

107-
public record RegExp(RegExp.RegExpValue Value) : LocalValue
115+
public record RegExpLocalValue(RegExpLocalValue.RegExpValue Value) : LocalValue
116+
{
117+
public record RegExpValue(string Pattern)
108118
{
109-
public record RegExpValue(string Pattern)
110-
{
111-
public string? Flags { get; set; }
112-
}
119+
public string? Flags { get; set; }
113120
}
114-
115-
public record Set(IEnumerable<LocalValue> Value) : LocalValue;
116121
}
122+
123+
public record SetLocalValue(IEnumerable<LocalValue> Value) : LocalValue;

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

+50-18
Original file line numberDiff line numberDiff line change
@@ -27,7 +27,7 @@ class CallFunctionLocalValueTest : BiDiTestFixture
2727
[Test]
2828
public void CanCallFunctionWithArgumentUndefined()
2929
{
30-
var arg = new LocalValue.Undefined();
30+
var arg = new UndefinedLocalValue();
3131
Assert.That(async () =>
3232
{
3333
await context.Script.CallFunctionAsync($$"""
@@ -43,7 +43,7 @@ await context.Script.CallFunctionAsync($$"""
4343
[Test]
4444
public void CanCallFunctionWithArgumentNull()
4545
{
46-
var arg = new LocalValue.Null();
46+
var arg = new NullLocalValue();
4747
Assert.That(async () =>
4848
{
4949
await context.Script.CallFunctionAsync($$"""
@@ -56,10 +56,42 @@ await context.Script.CallFunctionAsync($$"""
5656
}, Throws.Nothing);
5757
}
5858

59+
[Test]
60+
public void CanCallFunctionWithArgumentBoolean()
61+
{
62+
var arg = new BooleanLocalValue(true);
63+
Assert.That(async () =>
64+
{
65+
await context.Script.CallFunctionAsync($$"""
66+
(arg) => {
67+
if (arg !== true) {
68+
throw new Error("Assert failed: " + arg);
69+
}
70+
}
71+
""", false, new() { Arguments = [arg] });
72+
}, Throws.Nothing);
73+
}
74+
75+
[Test]
76+
public void CanCallFunctionWithArgumentBigInt()
77+
{
78+
var arg = new BigIntLocalValue("12345");
79+
Assert.That(async () =>
80+
{
81+
await context.Script.CallFunctionAsync($$"""
82+
(arg) => {
83+
if (arg !== 12345n) {
84+
throw new Error("Assert failed: " + arg);
85+
}
86+
}
87+
""", false, new() { Arguments = [arg] });
88+
}, Throws.Nothing);
89+
}
90+
5991
[Test]
6092
public void CanCallFunctionWithArgumentEmptyString()
6193
{
62-
var arg = new LocalValue.String(string.Empty);
94+
var arg = new StringLocalValue(string.Empty);
6395
Assert.That(async () =>
6496
{
6597
await context.Script.CallFunctionAsync($$"""
@@ -75,7 +107,7 @@ await context.Script.CallFunctionAsync($$"""
75107
[Test]
76108
public void CanCallFunctionWithArgumentNonEmptyString()
77109
{
78-
var arg = new LocalValue.String("whoa");
110+
var arg = new StringLocalValue("whoa");
79111
Assert.That(async () =>
80112
{
81113
await context.Script.CallFunctionAsync($$"""
@@ -93,7 +125,7 @@ public void CanCallFunctionWithArgumentRecentDate()
93125
{
94126
const string PinnedDateTimeString = "2025-03-09T00:30:33.083Z";
95127

96-
var arg = new LocalValue.Date(PinnedDateTimeString);
128+
var arg = new DateLocalValue(PinnedDateTimeString);
97129

98130
Assert.That(async () =>
99131
{
@@ -112,7 +144,7 @@ public void CanCallFunctionWithArgumentEpochDate()
112144
{
113145
const string EpochString = "1970-01-01T00:00:00.000Z";
114146

115-
var arg = new LocalValue.Date(EpochString);
147+
var arg = new DateLocalValue(EpochString);
116148

117149
Assert.That(async () =>
118150
{
@@ -129,7 +161,7 @@ await context.Script.CallFunctionAsync($$"""
129161
[Test]
130162
public void CanCallFunctionWithArgumentNumberFive()
131163
{
132-
var arg = new LocalValue.Number(5);
164+
var arg = new NumberLocalValue(5);
133165

134166
Assert.That(async () =>
135167
{
@@ -146,7 +178,7 @@ await context.Script.CallFunctionAsync($$"""
146178
[Test]
147179
public void CanCallFunctionWithArgumentNumberNegativeFive()
148180
{
149-
var arg = new LocalValue.Number(-5);
181+
var arg = new NumberLocalValue(-5);
150182

151183
Assert.That(async () =>
152184
{
@@ -163,7 +195,7 @@ await context.Script.CallFunctionAsync($$"""
163195
[Test]
164196
public void CanCallFunctionWithArgumentNumberZero()
165197
{
166-
var arg = new LocalValue.Number(0);
198+
var arg = new NumberLocalValue(0);
167199

168200
Assert.That(async () =>
169201
{
@@ -182,7 +214,7 @@ await context.Script.CallFunctionAsync($$"""
182214
[IgnoreBrowser(Selenium.Browser.Chrome, "Chromium can't handle -0 argument as a number: https://github.com/w3c/webdriver-bidi/issues/887")]
183215
public void CanCallFunctionWithArgumentNumberNegativeZero()
184216
{
185-
var arg = new LocalValue.Number(double.NegativeZero);
217+
var arg = new NumberLocalValue(double.NegativeZero);
186218

187219
Assert.That(async () =>
188220
{
@@ -199,7 +231,7 @@ await context.Script.CallFunctionAsync($$"""
199231
[Test]
200232
public void CanCallFunctionWithArgumentNumberPositiveInfinity()
201233
{
202-
var arg = new LocalValue.Number(double.PositiveInfinity);
234+
var arg = new NumberLocalValue(double.PositiveInfinity);
203235

204236
Assert.That(async () =>
205237
{
@@ -216,7 +248,7 @@ await context.Script.CallFunctionAsync($$"""
216248
[Test]
217249
public void CanCallFunctionWithArgumentNumberNegativeInfinity()
218250
{
219-
var arg = new LocalValue.Number(double.NegativeInfinity);
251+
var arg = new NumberLocalValue(double.NegativeInfinity);
220252

221253
Assert.That(async () =>
222254
{
@@ -233,7 +265,7 @@ await context.Script.CallFunctionAsync($$"""
233265
[Test]
234266
public void CanCallFunctionWithArgumentNumberNaN()
235267
{
236-
var arg = new LocalValue.Number(double.NaN);
268+
var arg = new NumberLocalValue(double.NaN);
237269
Assert.That(async () =>
238270
{
239271
await context.Script.CallFunctionAsync($$"""
@@ -249,7 +281,7 @@ await context.Script.CallFunctionAsync($$"""
249281
[Test]
250282
public void CanCallFunctionWithArgumentRegExp()
251283
{
252-
var arg = new LocalValue.RegExp(new LocalValue.RegExp.RegExpValue("foo*") { Flags = "g" });
284+
var arg = new RegExpLocalValue(new RegExpLocalValue.RegExpValue("foo*") { Flags = "g" });
253285

254286
Assert.That(async () =>
255287
{
@@ -266,7 +298,7 @@ await context.Script.CallFunctionAsync($$"""
266298
[Test]
267299
public void CanCallFunctionWithArgumentArray()
268300
{
269-
var arg = new LocalValue.Array([new LocalValue.String("hi")]);
301+
var arg = new ArrayLocalValue([new StringLocalValue("hi")]);
270302

271303
Assert.That(async () =>
272304
{
@@ -283,7 +315,7 @@ await context.Script.CallFunctionAsync($$"""
283315
[Test]
284316
public void CanCallFunctionWithArgumentObject()
285317
{
286-
var arg = new LocalValue.Object([[new LocalValue.String("objKey"), new LocalValue.String("objValue")]]);
318+
var arg = new ObjectLocalValue([[new StringLocalValue("objKey"), new StringLocalValue("objValue")]]);
287319

288320
Assert.That(async () =>
289321
{
@@ -300,7 +332,7 @@ await context.Script.CallFunctionAsync($$"""
300332
[Test]
301333
public void CanCallFunctionWithArgumentMap()
302334
{
303-
var arg = new LocalValue.Map([[new LocalValue.String("mapKey"), new LocalValue.String("mapValue")]]);
335+
var arg = new MapLocalValue([[new StringLocalValue("mapKey"), new StringLocalValue("mapValue")]]);
304336

305337
Assert.That(async () =>
306338
{
@@ -317,7 +349,7 @@ await context.Script.CallFunctionAsync($$"""
317349
[Test]
318350
public void CanCallFunctionWithArgumentSet()
319351
{
320-
var arg = new LocalValue.Set([new LocalValue.String("setKey")]);
352+
var arg = new SetLocalValue([new StringLocalValue("setKey")]);
321353

322354
Assert.That(async () =>
323355
{

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

+1-1
Original file line numberDiff line numberDiff line change
@@ -138,7 +138,7 @@ async function() {
138138
[Test]
139139
public async Task CanCallFunctionWithThisParameter()
140140
{
141-
var thisParameter = new LocalValue.Object([["some_property", 42]]);
141+
var thisParameter = new ObjectLocalValue([["some_property", 42]]);
142142

143143
var res = await context.Script.CallFunctionAsync<int>("""
144144
function(){return this.some_property}

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

+2-2
Original file line numberDiff line numberDiff line change
@@ -110,7 +110,7 @@ public async Task CanAddPreloadScriptWithArguments()
110110
{
111111
var preloadScript = await bidi.Script.AddPreloadScriptAsync("(channel) => channel('will_be_send', 'will_be_ignored')", new()
112112
{
113-
Arguments = [new LocalValue.Channel(new(new("channel_name")))]
113+
Arguments = [new ChannelLocalValue(new(new("channel_name")))]
114114
});
115115

116116
Assert.That(preloadScript, Is.Not.Null);
@@ -122,7 +122,7 @@ public async Task CanAddPreloadScriptWithChannelOptions()
122122
{
123123
var preloadScript = await bidi.Script.AddPreloadScriptAsync("(channel) => channel('will_be_send', 'will_be_ignored')", new()
124124
{
125-
Arguments = [new LocalValue.Channel(new(new("channel_name"))
125+
Arguments = [new ChannelLocalValue(new(new("channel_name"))
126126
{
127127
SerializationOptions = new()
128128
{

0 commit comments

Comments
 (0)