diff --git a/dotnet/src/webdriver/BiDi/BiDi.cs b/dotnet/src/webdriver/BiDi/BiDi.cs index f008d32a9394f..c94f411ca812f 100644 --- a/dotnet/src/webdriver/BiDi/BiDi.cs +++ b/dotnet/src/webdriver/BiDi/BiDi.cs @@ -62,7 +62,7 @@ public static async Task ConnectAsync(string url, Action bidi.Session); + bidi.Broker = new Broker(transport, bidi); return bidi; } diff --git a/dotnet/src/webdriver/BiDi/Broker.cs b/dotnet/src/webdriver/BiDi/Broker.cs index 6419709d315d9..e0b8d181e56d1 100644 --- a/dotnet/src/webdriver/BiDi/Broker.cs +++ b/dotnet/src/webdriver/BiDi/Broker.cs @@ -22,7 +22,6 @@ using System.Text.Json; using System.Text.Json.Serialization.Metadata; using System.Threading.Channels; -using OpenQA.Selenium.BiDi.Session; using OpenQA.Selenium.Internal.Logging; namespace OpenQA.Selenium.BiDi; @@ -39,7 +38,9 @@ internal sealed class Broker : IAsyncDisposable private readonly ITransport _transport; private readonly EventDispatcher _eventDispatcher; - private readonly IBiDi _bidi; + private readonly BiDi _bidi; + + private readonly ConcurrentDictionary _eventMetadata = new(); private readonly ConcurrentDictionary _pendingCommands = new(); @@ -57,21 +58,60 @@ internal sealed class Broker : IAsyncDisposable private readonly Task _processingTask; private readonly CancellationTokenSource _receiveMessagesCancellationTokenSource; - public Broker(ITransport transport, IBiDi bidi, Func sessionProvider) + public Broker(ITransport transport, BiDi bidi) { _transport = transport; _bidi = bidi; - _eventDispatcher = new EventDispatcher(sessionProvider); + _eventDispatcher = new EventDispatcher(); _receiveMessagesCancellationTokenSource = new CancellationTokenSource(); _receivingTask = Task.Run(() => ReceiveMessagesAsync(_receiveMessagesCancellationTokenSource.Token)); _processingTask = Task.Run(ProcessMessagesAsync); } - public Task SubscribeAsync(string eventName, EventHandler eventHandler, SubscriptionOptions? options, JsonTypeInfo jsonTypeInfo, CancellationToken cancellationToken) + public async Task SubscribeAsync(string eventName, Action action, Func factory, SubscriptionOptions? options, JsonTypeInfo jsonTypeInfo, CancellationToken cancellationToken) where TEventArgs : EventArgs { - return _eventDispatcher.SubscribeAsync(eventName, eventHandler, options, jsonTypeInfo, cancellationToken); + ValueTask InvokeAction(EventArgs args) { action((TEventArgs)args); return default; } + return await SubscribeAsync(eventName, InvokeAction, (bidi, ep) => factory(bidi, (TEventParams)ep), jsonTypeInfo, options, cancellationToken).ConfigureAwait(false); + } + + public async Task SubscribeAsync(string eventName, Func func, Func factory, SubscriptionOptions? options, JsonTypeInfo jsonTypeInfo, CancellationToken cancellationToken) + where TEventArgs : EventArgs + { + ValueTask InvokeFunc(EventArgs args) => new(func((TEventArgs)args)); + return await SubscribeAsync(eventName, InvokeFunc, (bidi, ep) => factory(bidi, (TEventParams)ep), jsonTypeInfo, options, cancellationToken).ConfigureAwait(false); + } + + private async Task SubscribeAsync(string eventName, Func handler, Func argsFactory, JsonTypeInfo jsonTypeInfo, SubscriptionOptions? options, CancellationToken cancellationToken) + { + var metadata = _eventMetadata.GetOrAdd(eventName, new EventMetadata(jsonTypeInfo, argsFactory)); + + if (metadata.JsonTypeInfo != jsonTypeInfo) + { + throw new ArgumentException($"Event '{eventName}' is already registered with different metadata.", nameof(eventName)); + } + + _eventDispatcher.AddHandler(eventName, handler); + + try + { + var subscribeResult = await _bidi.Session.SubscribeAsync([eventName], new() { Contexts = options?.Contexts, UserContexts = options?.UserContexts }, cancellationToken) + .ConfigureAwait(false); + + return new Subscription(subscribeResult.Subscription, this, eventName) { Handler = handler }; + } + catch + { + _eventDispatcher.RemoveHandler(eventName, handler); + throw; + } + } + + public async ValueTask UnsubscribeAsync(Subscription subscription, CancellationToken cancellationToken) + { + await _bidi.Session.UnsubscribeAsync([subscription.SubscriptionId], null, cancellationToken).ConfigureAwait(false); + _eventDispatcher.RemoveHandler(subscription.EventName, subscription.Handler); } public async Task ExecuteCommandAsync(TCommand command, CommandOptions? options, JsonTypeInfo jsonCommandTypeInfo, JsonTypeInfo jsonResultTypeInfo, CancellationToken cancellationToken) @@ -274,7 +314,7 @@ private void ProcessReceivedMessage(ReadOnlySpan data) case TypeEvent: if (method is null) throw new BiDiException($"The remote end responded with 'event' message type, but missed required 'method' property. Message content: {System.Text.Encoding.UTF8.GetString(data.ToArray())}"); - if (!_eventDispatcher.TryGetJsonTypeInfo(method, out var jsonTypeInfo)) + if (!_eventMetadata.TryGetValue(method, out var metadata)) { if (_logger.IsEnabled(LogEventLevel.Warn)) { @@ -284,10 +324,10 @@ private void ProcessReceivedMessage(ReadOnlySpan data) break; } - var eventArgs = JsonSerializer.Deserialize(ref paramsReader, jsonTypeInfo) as EventArgs + var eventParams = JsonSerializer.Deserialize(ref paramsReader, metadata.JsonTypeInfo) ?? throw new BiDiException("Remote end returned null event args in the 'params' property."); - eventArgs.BiDi = _bidi; + var eventArgs = metadata.CreateEventArgs(_bidi, eventParams); _eventDispatcher.EnqueueEvent(method, eventArgs); break; @@ -427,6 +467,11 @@ private void ReturnBuffer(PooledBufferWriter buffer) private readonly record struct CommandInfo(TaskCompletionSource TaskCompletionSource, JsonTypeInfo JsonResultTypeInfo); + private readonly record struct EventMetadata(JsonTypeInfo JsonTypeInfo, Func ArgsFactory) + { + public EventArgs CreateEventArgs(IBiDi bidi, object eventParams) => ArgsFactory(bidi, eventParams); + } + private sealed class PooledBufferWriter : IBufferWriter, IDisposable { private const int DefaultBufferSize = 1024 * 8; diff --git a/dotnet/src/webdriver/BiDi/BrowsingContext/BrowsingContext.cs b/dotnet/src/webdriver/BiDi/BrowsingContext/BrowsingContext.cs index 04abcb9e11f67..d007344b08b1d 100644 --- a/dotnet/src/webdriver/BiDi/BrowsingContext/BrowsingContext.cs +++ b/dotnet/src/webdriver/BiDi/BrowsingContext/BrowsingContext.cs @@ -123,7 +123,7 @@ public Task GetTreeAsync(ContextGetTreeOptions? options = null, C return BiDi.BrowsingContext.GetTreeAsync(ContextGetTreeOptions.WithContext(options, this), cancellationToken); } - public Task OnNavigationStartedAsync(Func handler, ContextSubscriptionOptions? options = null) + public Task OnNavigationStartedAsync(Func handler, ContextSubscriptionOptions? options = null) { if (handler is null) throw new ArgumentNullException(nameof(handler)); @@ -132,7 +132,7 @@ public Task OnNavigationStartedAsync(Func OnNavigationStartedAsync(Action handler, ContextSubscriptionOptions? options = null) + public Task OnNavigationStartedAsync(Action handler, ContextSubscriptionOptions? options = null) { if (handler is null) throw new ArgumentNullException(nameof(handler)); @@ -141,7 +141,7 @@ public Task OnNavigationStartedAsync(Action h ContextSubscriptionOptions.WithContext(options, this)); } - public Task OnFragmentNavigatedAsync(Func handler, ContextSubscriptionOptions? options = null) + public Task OnFragmentNavigatedAsync(Func handler, ContextSubscriptionOptions? options = null) { if (handler is null) throw new ArgumentNullException(nameof(handler)); @@ -150,7 +150,7 @@ public Task OnFragmentNavigatedAsync(Func OnFragmentNavigatedAsync(Action handler, ContextSubscriptionOptions? options = null) + public Task OnFragmentNavigatedAsync(Action handler, ContextSubscriptionOptions? options = null) { if (handler is null) throw new ArgumentNullException(nameof(handler)); @@ -177,7 +177,7 @@ public Task OnHistoryUpdatedAsync(Action ContextSubscriptionOptions.WithContext(options, this)); } - public Task OnDomContentLoadedAsync(Func handler, ContextSubscriptionOptions? options = null) + public Task OnDomContentLoadedAsync(Func handler, ContextSubscriptionOptions? options = null) { if (handler is null) throw new ArgumentNullException(nameof(handler)); @@ -186,7 +186,7 @@ public Task OnDomContentLoadedAsync(Func OnDomContentLoadedAsync(Action handler, ContextSubscriptionOptions? options = null) + public Task OnDomContentLoadedAsync(Action handler, ContextSubscriptionOptions? options = null) { if (handler is null) throw new ArgumentNullException(nameof(handler)); @@ -195,7 +195,7 @@ public Task OnDomContentLoadedAsync(Action ha ContextSubscriptionOptions.WithContext(options, this)); } - public Task OnLoadAsync(Action handler, ContextSubscriptionOptions? options = null) + public Task OnLoadAsync(Action handler, ContextSubscriptionOptions? options = null) { if (handler is null) throw new ArgumentNullException(nameof(handler)); @@ -204,7 +204,7 @@ public Task OnLoadAsync(Action handler, Conte ContextSubscriptionOptions.WithContext(options, this)); } - public Task OnLoadAsync(Func handler, ContextSubscriptionOptions? options = null) + public Task OnLoadAsync(Func handler, ContextSubscriptionOptions? options = null) { if (handler is null) throw new ArgumentNullException(nameof(handler)); @@ -249,7 +249,7 @@ public Task OnDownloadEndAsync(Func ha ContextSubscriptionOptions.WithContext(options, this)); } - public Task OnNavigationAbortedAsync(Action handler, ContextSubscriptionOptions? options = null) + public Task OnNavigationAbortedAsync(Action handler, ContextSubscriptionOptions? options = null) { if (handler is null) throw new ArgumentNullException(nameof(handler)); @@ -258,7 +258,7 @@ public Task OnNavigationAbortedAsync(Action h ContextSubscriptionOptions.WithContext(options, this)); } - public Task OnNavigationAbortedAsync(Func handler, ContextSubscriptionOptions? options = null) + public Task OnNavigationAbortedAsync(Func handler, ContextSubscriptionOptions? options = null) { if (handler is null) throw new ArgumentNullException(nameof(handler)); @@ -267,7 +267,7 @@ public Task OnNavigationAbortedAsync(Func OnNavigationFailedAsync(Action handler, ContextSubscriptionOptions? options = null) + public Task OnNavigationFailedAsync(Action handler, ContextSubscriptionOptions? options = null) { if (handler is null) throw new ArgumentNullException(nameof(handler)); @@ -276,7 +276,7 @@ public Task OnNavigationFailedAsync(Action ha ContextSubscriptionOptions.WithContext(options, this)); } - public Task OnNavigationFailedAsync(Func handler, ContextSubscriptionOptions? options = null) + public Task OnNavigationFailedAsync(Func handler, ContextSubscriptionOptions? options = null) { if (handler is null) throw new ArgumentNullException(nameof(handler)); @@ -285,7 +285,7 @@ public Task OnNavigationFailedAsync(Func OnNavigationCommittedAsync(Action handler, ContextSubscriptionOptions? options = null) + public Task OnNavigationCommittedAsync(Action handler, ContextSubscriptionOptions? options = null) { if (handler is null) throw new ArgumentNullException(nameof(handler)); @@ -294,7 +294,7 @@ public Task OnNavigationCommittedAsync(Action ContextSubscriptionOptions.WithContext(options, this)); } - public Task OnNavigationCommittedAsync(Func handler, ContextSubscriptionOptions? options = null) + public Task OnNavigationCommittedAsync(Func handler, ContextSubscriptionOptions? options = null) { if (handler is null) throw new ArgumentNullException(nameof(handler)); @@ -303,7 +303,7 @@ public Task OnNavigationCommittedAsync(Func handler) + private async Task HandleNavigationStartedAsync(NavigationStartedEventArgs e, Func handler) { if (Equals(e.Context)) { @@ -311,7 +311,7 @@ private async Task HandleNavigationStartedAsync(NavigationEventArgs e, Func handler) + private void HandleNavigationStarted(NavigationStartedEventArgs e, Action handler) { if (Equals(e.Context)) { @@ -319,7 +319,7 @@ private void HandleNavigationStarted(NavigationEventArgs e, Action handler) + private async Task HandleFragmentNavigatedAsync(FragmentNavigatedEventArgs e, Func handler) { if (Equals(e.Context)) { @@ -327,7 +327,7 @@ private async Task HandleFragmentNavigatedAsync(NavigationEventArgs e, Func handler) + private void HandleFragmentNavigated(FragmentNavigatedEventArgs e, Action handler) { if (Equals(e.Context)) { @@ -351,7 +351,7 @@ private void HandleHistoryUpdated(HistoryUpdatedEventArgs e, Action handler) + private async Task HandleDomContentLoadedAsync(DomContentLoadedEventArgs e, Func handler) { if (Equals(e.Context)) { @@ -359,7 +359,7 @@ private async Task HandleDomContentLoadedAsync(NavigationEventArgs e, Func handler) + private void HandleDomContentLoaded(DomContentLoadedEventArgs e, Action handler) { if (Equals(e.Context)) { @@ -367,7 +367,7 @@ private void HandleDomContentLoaded(NavigationEventArgs e, Action handler) + private void HandleLoad(LoadEventArgs e, Action handler) { if (Equals(e.Context)) { @@ -375,7 +375,7 @@ private void HandleLoad(NavigationEventArgs e, Action handl } } - private async Task HandleLoadAsync(NavigationEventArgs e, Func handler) + private async Task HandleLoadAsync(LoadEventArgs e, Func handler) { if (Equals(e.Context)) { @@ -415,7 +415,7 @@ private async Task HandleDownloadEndAsync(DownloadEndEventArgs e, Func handler) + private void HandleNavigationAborted(NavigationAbortedEventArgs e, Action handler) { if (Equals(e.Context)) { @@ -423,7 +423,7 @@ private void HandleNavigationAborted(NavigationEventArgs e, Action handler) + private async Task HandleNavigationAbortedAsync(NavigationAbortedEventArgs e, Func handler) { if (Equals(e.Context)) { @@ -431,7 +431,7 @@ private async Task HandleNavigationAbortedAsync(NavigationEventArgs e, Func handler) + private void HandleNavigationFailed(NavigationFailedEventArgs e, Action handler) { if (Equals(e.Context)) { @@ -439,7 +439,7 @@ private void HandleNavigationFailed(NavigationEventArgs e, Action handler) + private async Task HandleNavigationFailedAsync(NavigationFailedEventArgs e, Func handler) { if (Equals(e.Context)) { @@ -447,7 +447,7 @@ private async Task HandleNavigationFailedAsync(NavigationEventArgs e, Func handler) + private void HandleNavigationCommitted(NavigationCommittedEventArgs e, Action handler) { if (Equals(e.Context)) { @@ -455,7 +455,7 @@ private void HandleNavigationCommitted(NavigationEventArgs e, Action handler) + private async Task HandleNavigationCommittedAsync(NavigationCommittedEventArgs e, Func handler) { if (Equals(e.Context)) { diff --git a/dotnet/src/webdriver/BiDi/BrowsingContext/BrowsingContextInputModule.cs b/dotnet/src/webdriver/BiDi/BrowsingContext/BrowsingContextInputModule.cs index 7a10aa1c2f22c..d57553a02d284 100644 --- a/dotnet/src/webdriver/BiDi/BrowsingContext/BrowsingContextInputModule.cs +++ b/dotnet/src/webdriver/BiDi/BrowsingContext/BrowsingContextInputModule.cs @@ -38,7 +38,7 @@ public Task SetFilesAsync(Script.ISharedReference element, IEnum return inputModule.SetFilesAsync(context, element, files, options, cancellationToken); } - public Task OnFileDialogOpenedAsync(Func handler, ContextSubscriptionOptions? options = null, CancellationToken cancellationToken = default) + public Task OnFileDialogOpenedAsync(Func handler, ContextSubscriptionOptions? options = null, CancellationToken cancellationToken = default) { if (handler is null) throw new ArgumentNullException(nameof(handler)); @@ -48,7 +48,7 @@ public Task OnFileDialogOpenedAsync(Func OnFileDialogOpenedAsync(Action handler, ContextSubscriptionOptions? options = null, CancellationToken cancellationToken = default) + public Task OnFileDialogOpenedAsync(Action handler, ContextSubscriptionOptions? options = null, CancellationToken cancellationToken = default) { if (handler is null) throw new ArgumentNullException(nameof(handler)); @@ -58,7 +58,7 @@ public Task OnFileDialogOpenedAsync(Action ha cancellationToken); } - private async Task HandleFileDialogOpenedAsync(FileDialogEventArgs e, Func handler) + private async Task HandleFileDialogOpenedAsync(FileDialogOpenedEventArgs e, Func handler) { if (context.Equals(e.Context)) { @@ -66,7 +66,7 @@ private async Task HandleFileDialogOpenedAsync(FileDialogEventArgs e, Func handler) + private void HandleFileDialogOpened(FileDialogOpenedEventArgs e, Action handler) { if (context.Equals(e.Context)) { diff --git a/dotnet/src/webdriver/BiDi/BrowsingContext/BrowsingContextLogModule.cs b/dotnet/src/webdriver/BiDi/BrowsingContext/BrowsingContextLogModule.cs index 20699843ecb92..9e29d351125e8 100644 --- a/dotnet/src/webdriver/BiDi/BrowsingContext/BrowsingContextLogModule.cs +++ b/dotnet/src/webdriver/BiDi/BrowsingContext/BrowsingContextLogModule.cs @@ -23,7 +23,7 @@ namespace OpenQA.Selenium.BiDi.BrowsingContext; public sealed class BrowsingContextLogModule(BrowsingContext context, ILogModule logModule) : IBrowsingContextLogModule { - public Task OnEntryAddedAsync(Func handler, ContextSubscriptionOptions? options = null, CancellationToken cancellationToken = default) + public Task OnEntryAddedAsync(Func handler, ContextSubscriptionOptions? options = null, CancellationToken cancellationToken = default) { if (handler is null) throw new ArgumentNullException(nameof(handler)); @@ -33,7 +33,7 @@ public Task OnEntryAddedAsync(Func handle cancellationToken); } - public Task OnEntryAddedAsync(Action handler, ContextSubscriptionOptions? options = null, CancellationToken cancellationToken = default) + public Task OnEntryAddedAsync(Action handler, ContextSubscriptionOptions? options = null, CancellationToken cancellationToken = default) { if (handler is null) throw new ArgumentNullException(nameof(handler)); @@ -43,7 +43,7 @@ public Task OnEntryAddedAsync(Action handler, C cancellationToken); } - private async Task HandleEntryAddedAsync(LogEntryEventArgs e, Func handler) + private async Task HandleEntryAddedAsync(EntryAddedEventArgs e, Func handler) { if (context.Equals(e.Source.Context)) { @@ -51,7 +51,7 @@ private async Task HandleEntryAddedAsync(LogEntryEventArgs e, Func handler) + private void HandleEntryAdded(EntryAddedEventArgs e, Action handler) { if (context.Equals(e.Source.Context)) { diff --git a/dotnet/src/webdriver/BiDi/BrowsingContext/BrowsingContextModule.cs b/dotnet/src/webdriver/BiDi/BrowsingContext/BrowsingContextModule.cs index 08b5bc39cbcdf..0c0de20c5dc78 100644 --- a/dotnet/src/webdriver/BiDi/BrowsingContext/BrowsingContextModule.cs +++ b/dotnet/src/webdriver/BiDi/BrowsingContext/BrowsingContextModule.cs @@ -111,146 +111,179 @@ public async Task HandleUserPromptAsync(BrowsingContext return await ExecuteCommandAsync(new HandleUserPromptCommand(@params), options, _jsonContext.HandleUserPromptCommand, _jsonContext.HandleUserPromptResult, cancellationToken).ConfigureAwait(false); } - public async Task OnNavigationStartedAsync(Func handler, SubscriptionOptions? options = null, CancellationToken cancellationToken = default) + public async Task OnNavigationStartedAsync(Func handler, SubscriptionOptions? options = null, CancellationToken cancellationToken = default) { - return await SubscribeAsync("browsingContext.navigationStarted", handler, options, _jsonContext.NavigationEventArgs, cancellationToken).ConfigureAwait(false); + return await SubscribeAsync("browsingContext.navigationStarted", handler, CreateNavigationStartedEventArgs, options, _jsonContext.NavigationInfo, cancellationToken).ConfigureAwait(false); } - public async Task OnNavigationStartedAsync(Action handler, SubscriptionOptions? options = null, CancellationToken cancellationToken = default) + public async Task OnNavigationStartedAsync(Action handler, SubscriptionOptions? options = null, CancellationToken cancellationToken = default) { - return await SubscribeAsync("browsingContext.navigationStarted", handler, options, _jsonContext.NavigationEventArgs, cancellationToken).ConfigureAwait(false); + return await SubscribeAsync("browsingContext.navigationStarted", handler, CreateNavigationStartedEventArgs, options, _jsonContext.NavigationInfo, cancellationToken).ConfigureAwait(false); } - public async Task OnFragmentNavigatedAsync(Func handler, SubscriptionOptions? options = null, CancellationToken cancellationToken = default) + public async Task OnFragmentNavigatedAsync(Func handler, SubscriptionOptions? options = null, CancellationToken cancellationToken = default) { - return await SubscribeAsync("browsingContext.fragmentNavigated", handler, options, _jsonContext.NavigationEventArgs, cancellationToken).ConfigureAwait(false); + return await SubscribeAsync("browsingContext.fragmentNavigated", handler, CreateFragmentNavigatedEventArgs, options, _jsonContext.NavigationInfo, cancellationToken).ConfigureAwait(false); } - public async Task OnFragmentNavigatedAsync(Action handler, SubscriptionOptions? options = null, CancellationToken cancellationToken = default) + public async Task OnFragmentNavigatedAsync(Action handler, SubscriptionOptions? options = null, CancellationToken cancellationToken = default) { - return await SubscribeAsync("browsingContext.fragmentNavigated", handler, options, _jsonContext.NavigationEventArgs, cancellationToken).ConfigureAwait(false); + return await SubscribeAsync("browsingContext.fragmentNavigated", handler, CreateFragmentNavigatedEventArgs, options, _jsonContext.NavigationInfo, cancellationToken).ConfigureAwait(false); } public async Task OnHistoryUpdatedAsync(Func handler, SubscriptionOptions? options = null, CancellationToken cancellationToken = default) { - return await SubscribeAsync("browsingContext.historyUpdated", handler, options, _jsonContext.HistoryUpdatedEventArgs, cancellationToken).ConfigureAwait(false); + return await SubscribeAsync("browsingContext.historyUpdated", handler, CreateHistoryUpdatedEventArgs, options, _jsonContext.HistoryUpdatedParameters, cancellationToken).ConfigureAwait(false); } public async Task OnHistoryUpdatedAsync(Action handler, SubscriptionOptions? options = null, CancellationToken cancellationToken = default) { - return await SubscribeAsync("browsingContext.historyUpdated", handler, options, _jsonContext.HistoryUpdatedEventArgs, cancellationToken).ConfigureAwait(false); + return await SubscribeAsync("browsingContext.historyUpdated", handler, CreateHistoryUpdatedEventArgs, options, _jsonContext.HistoryUpdatedParameters, cancellationToken).ConfigureAwait(false); } - public async Task OnDomContentLoadedAsync(Func handler, SubscriptionOptions? options = null, CancellationToken cancellationToken = default) + public async Task OnDomContentLoadedAsync(Func handler, SubscriptionOptions? options = null, CancellationToken cancellationToken = default) { - return await SubscribeAsync("browsingContext.domContentLoaded", handler, options, _jsonContext.NavigationEventArgs, cancellationToken).ConfigureAwait(false); + return await SubscribeAsync("browsingContext.domContentLoaded", handler, CreateDomContentLoadedEventArgs, options, _jsonContext.NavigationInfo, cancellationToken).ConfigureAwait(false); } - public async Task OnDomContentLoadedAsync(Action handler, SubscriptionOptions? options = null, CancellationToken cancellationToken = default) + public async Task OnDomContentLoadedAsync(Action handler, SubscriptionOptions? options = null, CancellationToken cancellationToken = default) { - return await SubscribeAsync("browsingContext.domContentLoaded", handler, options, _jsonContext.NavigationEventArgs, cancellationToken).ConfigureAwait(false); + return await SubscribeAsync("browsingContext.domContentLoaded", handler, CreateDomContentLoadedEventArgs, options, _jsonContext.NavigationInfo, cancellationToken).ConfigureAwait(false); } - public async Task OnLoadAsync(Func handler, SubscriptionOptions? options = null, CancellationToken cancellationToken = default) + public async Task OnLoadAsync(Func handler, SubscriptionOptions? options = null, CancellationToken cancellationToken = default) { - return await SubscribeAsync("browsingContext.load", handler, options, _jsonContext.NavigationEventArgs, cancellationToken).ConfigureAwait(false); + return await SubscribeAsync("browsingContext.load", handler, CreateLoadEventArgs, options, _jsonContext.NavigationInfo, cancellationToken).ConfigureAwait(false); } - public async Task OnLoadAsync(Action handler, SubscriptionOptions? options = null, CancellationToken cancellationToken = default) + public async Task OnLoadAsync(Action handler, SubscriptionOptions? options = null, CancellationToken cancellationToken = default) { - return await SubscribeAsync("browsingContext.load", handler, options, _jsonContext.NavigationEventArgs, cancellationToken).ConfigureAwait(false); + return await SubscribeAsync("browsingContext.load", handler, CreateLoadEventArgs, options, _jsonContext.NavigationInfo, cancellationToken).ConfigureAwait(false); } public async Task OnDownloadWillBeginAsync(Func handler, SubscriptionOptions? options = null, CancellationToken cancellationToken = default) { - return await SubscribeAsync("browsingContext.downloadWillBegin", handler, options, _jsonContext.DownloadWillBeginEventArgs, cancellationToken).ConfigureAwait(false); + return await SubscribeAsync("browsingContext.downloadWillBegin", handler, CreateDownloadWillBeginEventArgs, options, _jsonContext.DownloadWillBeginParams, cancellationToken).ConfigureAwait(false); } public async Task OnDownloadWillBeginAsync(Action handler, SubscriptionOptions? options = null, CancellationToken cancellationToken = default) { - return await SubscribeAsync("browsingContext.downloadWillBegin", handler, options, _jsonContext.DownloadWillBeginEventArgs, cancellationToken).ConfigureAwait(false); + return await SubscribeAsync("browsingContext.downloadWillBegin", handler, CreateDownloadWillBeginEventArgs, options, _jsonContext.DownloadWillBeginParams, cancellationToken).ConfigureAwait(false); } public async Task OnDownloadEndAsync(Func handler, SubscriptionOptions? options = null, CancellationToken cancellationToken = default) { - return await SubscribeAsync("browsingContext.downloadEnd", handler, options, _jsonContext.DownloadEndEventArgs, cancellationToken).ConfigureAwait(false); + return await SubscribeAsync("browsingContext.downloadEnd", handler, CreateDownloadEndEventArgs, options, _jsonContext.DownloadEndParams, cancellationToken).ConfigureAwait(false); } public async Task OnDownloadEndAsync(Action handler, SubscriptionOptions? options = null, CancellationToken cancellationToken = default) { - return await SubscribeAsync("browsingContext.downloadEnd", handler, options, _jsonContext.DownloadEndEventArgs, cancellationToken).ConfigureAwait(false); + return await SubscribeAsync("browsingContext.downloadEnd", handler, CreateDownloadEndEventArgs, options, _jsonContext.DownloadEndParams, cancellationToken).ConfigureAwait(false); } - public async Task OnNavigationAbortedAsync(Func handler, SubscriptionOptions? options = null, CancellationToken cancellationToken = default) + public async Task OnNavigationAbortedAsync(Func handler, SubscriptionOptions? options = null, CancellationToken cancellationToken = default) { - return await SubscribeAsync("browsingContext.navigationAborted", handler, options, _jsonContext.NavigationEventArgs, cancellationToken).ConfigureAwait(false); + return await SubscribeAsync("browsingContext.navigationAborted", handler, CreateNavigationAbortedEventArgs, options, _jsonContext.NavigationInfo, cancellationToken).ConfigureAwait(false); } - public async Task OnNavigationAbortedAsync(Action handler, SubscriptionOptions? options = null, CancellationToken cancellationToken = default) + public async Task OnNavigationAbortedAsync(Action handler, SubscriptionOptions? options = null, CancellationToken cancellationToken = default) { - return await SubscribeAsync("browsingContext.navigationAborted", handler, options, _jsonContext.NavigationEventArgs, cancellationToken).ConfigureAwait(false); + return await SubscribeAsync("browsingContext.navigationAborted", handler, CreateNavigationAbortedEventArgs, options, _jsonContext.NavigationInfo, cancellationToken).ConfigureAwait(false); } - public async Task OnNavigationFailedAsync(Func handler, SubscriptionOptions? options = null, CancellationToken cancellationToken = default) + public async Task OnNavigationFailedAsync(Func handler, SubscriptionOptions? options = null, CancellationToken cancellationToken = default) { - return await SubscribeAsync("browsingContext.navigationFailed", handler, options, _jsonContext.NavigationEventArgs, cancellationToken).ConfigureAwait(false); + return await SubscribeAsync("browsingContext.navigationFailed", handler, CreateNavigationFailedEventArgs, options, _jsonContext.NavigationInfo, cancellationToken).ConfigureAwait(false); } - public async Task OnNavigationFailedAsync(Action handler, SubscriptionOptions? options = null, CancellationToken cancellationToken = default) + public async Task OnNavigationFailedAsync(Action handler, SubscriptionOptions? options = null, CancellationToken cancellationToken = default) { - return await SubscribeAsync("browsingContext.navigationFailed", handler, options, _jsonContext.NavigationEventArgs, cancellationToken).ConfigureAwait(false); + return await SubscribeAsync("browsingContext.navigationFailed", handler, CreateNavigationFailedEventArgs, options, _jsonContext.NavigationInfo, cancellationToken).ConfigureAwait(false); } - public async Task OnNavigationCommittedAsync(Func handler, SubscriptionOptions? options = null, CancellationToken cancellationToken = default) + public async Task OnNavigationCommittedAsync(Func handler, SubscriptionOptions? options = null, CancellationToken cancellationToken = default) { - return await SubscribeAsync("browsingContext.navigationCommitted", handler, options, _jsonContext.NavigationEventArgs, cancellationToken).ConfigureAwait(false); + return await SubscribeAsync("browsingContext.navigationCommitted", handler, CreateNavigationCommittedEventArgs, options, _jsonContext.NavigationInfo, cancellationToken).ConfigureAwait(false); } - public async Task OnNavigationCommittedAsync(Action handler, SubscriptionOptions? options = null, CancellationToken cancellationToken = default) + public async Task OnNavigationCommittedAsync(Action handler, SubscriptionOptions? options = null, CancellationToken cancellationToken = default) { - return await SubscribeAsync("browsingContext.navigationCommitted", handler, options, _jsonContext.NavigationEventArgs, cancellationToken).ConfigureAwait(false); + return await SubscribeAsync("browsingContext.navigationCommitted", handler, CreateNavigationCommittedEventArgs, options, _jsonContext.NavigationInfo, cancellationToken).ConfigureAwait(false); } - public async Task OnContextCreatedAsync(Func handler, SubscriptionOptions? options = null, CancellationToken cancellationToken = default) + public async Task OnContextCreatedAsync(Func handler, SubscriptionOptions? options = null, CancellationToken cancellationToken = default) { - return await SubscribeAsync("browsingContext.contextCreated", handler, options, _jsonContext.BrowsingContextEventArgs, cancellationToken).ConfigureAwait(false); + return await SubscribeAsync("browsingContext.contextCreated", handler, CreateContextCreatedEventArgs, options, _jsonContext.Info, cancellationToken).ConfigureAwait(false); } - public async Task OnContextCreatedAsync(Action handler, SubscriptionOptions? options = null, CancellationToken cancellationToken = default) + public async Task OnContextCreatedAsync(Action handler, SubscriptionOptions? options = null, CancellationToken cancellationToken = default) { - return await SubscribeAsync("browsingContext.contextCreated", handler, options, _jsonContext.BrowsingContextEventArgs, cancellationToken).ConfigureAwait(false); + return await SubscribeAsync("browsingContext.contextCreated", handler, CreateContextCreatedEventArgs, options, _jsonContext.Info, cancellationToken).ConfigureAwait(false); } - public async Task OnContextDestroyedAsync(Func handler, SubscriptionOptions? options = null, CancellationToken cancellationToken = default) + public async Task OnContextDestroyedAsync(Func handler, SubscriptionOptions? options = null, CancellationToken cancellationToken = default) { - return await SubscribeAsync("browsingContext.contextDestroyed", handler, options, _jsonContext.BrowsingContextEventArgs, cancellationToken).ConfigureAwait(false); + return await SubscribeAsync("browsingContext.contextDestroyed", handler, CreateContextDestroyedEventArgs, options, _jsonContext.Info, cancellationToken).ConfigureAwait(false); } - public async Task OnContextDestroyedAsync(Action handler, SubscriptionOptions? options = null, CancellationToken cancellationToken = default) + public async Task OnContextDestroyedAsync(Action handler, SubscriptionOptions? options = null, CancellationToken cancellationToken = default) { - return await SubscribeAsync("browsingContext.contextDestroyed", handler, options, _jsonContext.BrowsingContextEventArgs, cancellationToken).ConfigureAwait(false); + return await SubscribeAsync("browsingContext.contextDestroyed", handler, CreateContextDestroyedEventArgs, options, _jsonContext.Info, cancellationToken).ConfigureAwait(false); } public async Task OnUserPromptOpenedAsync(Func handler, SubscriptionOptions? options = null, CancellationToken cancellationToken = default) { - return await SubscribeAsync("browsingContext.userPromptOpened", handler, options, _jsonContext.UserPromptOpenedEventArgs, cancellationToken).ConfigureAwait(false); + return await SubscribeAsync("browsingContext.userPromptOpened", handler, CreateUserPromptOpenedEventArgs, options, _jsonContext.UserPromptOpenedParameters, cancellationToken).ConfigureAwait(false); } public async Task OnUserPromptOpenedAsync(Action handler, SubscriptionOptions? options = null, CancellationToken cancellationToken = default) { - return await SubscribeAsync("browsingContext.userPromptOpened", handler, options, _jsonContext.UserPromptOpenedEventArgs, cancellationToken).ConfigureAwait(false); + return await SubscribeAsync("browsingContext.userPromptOpened", handler, CreateUserPromptOpenedEventArgs, options, _jsonContext.UserPromptOpenedParameters, cancellationToken).ConfigureAwait(false); } public async Task OnUserPromptClosedAsync(Func handler, SubscriptionOptions? options = null, CancellationToken cancellationToken = default) { - return await SubscribeAsync("browsingContext.userPromptClosed", handler, options, _jsonContext.UserPromptClosedEventArgs, cancellationToken).ConfigureAwait(false); + return await SubscribeAsync("browsingContext.userPromptClosed", handler, CreateUserPromptClosedEventArgs, options, _jsonContext.UserPromptClosedParameters, cancellationToken).ConfigureAwait(false); } public async Task OnUserPromptClosedAsync(Action handler, SubscriptionOptions? options = null, CancellationToken cancellationToken = default) { - return await SubscribeAsync("browsingContext.userPromptClosed", handler, options, _jsonContext.UserPromptClosedEventArgs, cancellationToken).ConfigureAwait(false); + return await SubscribeAsync("browsingContext.userPromptClosed", handler, CreateUserPromptClosedEventArgs, options, _jsonContext.UserPromptClosedParameters, cancellationToken).ConfigureAwait(false); } + private static NavigationStartedEventArgs CreateNavigationStartedEventArgs(IBiDi bidi, NavigationInfo p) => new(bidi, p.Context, p.Navigation, p.Timestamp, p.Url, p.UserContext); + + private static FragmentNavigatedEventArgs CreateFragmentNavigatedEventArgs(IBiDi bidi, NavigationInfo p) => new(bidi, p.Context, p.Navigation, p.Timestamp, p.Url, p.UserContext); + + private static DomContentLoadedEventArgs CreateDomContentLoadedEventArgs(IBiDi bidi, NavigationInfo p) => new(bidi, p.Context, p.Navigation, p.Timestamp, p.Url, p.UserContext); + + private static LoadEventArgs CreateLoadEventArgs(IBiDi bidi, NavigationInfo p) => new(bidi, p.Context, p.Navigation, p.Timestamp, p.Url, p.UserContext); + + private static NavigationAbortedEventArgs CreateNavigationAbortedEventArgs(IBiDi bidi, NavigationInfo p) => new(bidi, p.Context, p.Navigation, p.Timestamp, p.Url, p.UserContext); + + private static NavigationFailedEventArgs CreateNavigationFailedEventArgs(IBiDi bidi, NavigationInfo p) => new(bidi, p.Context, p.Navigation, p.Timestamp, p.Url, p.UserContext); + + private static NavigationCommittedEventArgs CreateNavigationCommittedEventArgs(IBiDi bidi, NavigationInfo p) => new(bidi, p.Context, p.Navigation, p.Timestamp, p.Url, p.UserContext); + + private static HistoryUpdatedEventArgs CreateHistoryUpdatedEventArgs(IBiDi bidi, HistoryUpdatedParameters p) => new(bidi, p.Context, p.Timestamp, p.Url, p.UserContext); + + private static DownloadWillBeginEventArgs CreateDownloadWillBeginEventArgs(IBiDi bidi, DownloadWillBeginParams p) => new(bidi, p.SuggestedFilename, p.Context, p.Navigation, p.Timestamp, p.Url); + + private static DownloadEndEventArgs CreateDownloadEndEventArgs(IBiDi bidi, DownloadEndParams p) => p switch + { + DownloadCanceledParams c => new DownloadCanceledEventArgs(bidi, c.Context, c.Navigation, c.Timestamp, c.Url), + DownloadCompleteParams c => new DownloadCompleteEventArgs(bidi, c.Filepath, c.Context, c.Navigation, c.Timestamp, c.Url), + _ => throw new BiDiException($"Unknown {nameof(DownloadEndParams)} type: {p.GetType()}") + }; + + private static ContextCreatedEventArgs CreateContextCreatedEventArgs(IBiDi bidi, Info p) => new(bidi, p.Children, p.ClientWindow, p.Context, p.OriginalOpener, p.Url, p.UserContext, p.Parent); + + private static ContextDestroyedEventArgs CreateContextDestroyedEventArgs(IBiDi bidi, Info p) => new(bidi, p.Children, p.ClientWindow, p.Context, p.OriginalOpener, p.Url, p.UserContext, p.Parent); + + private static UserPromptOpenedEventArgs CreateUserPromptOpenedEventArgs(IBiDi bidi, UserPromptOpenedParameters p) => new(bidi, p.Context, p.Handler, p.Message, p.Type, p.UserContext, p.DefaultValue); + + private static UserPromptClosedEventArgs CreateUserPromptClosedEventArgs(IBiDi bidi, UserPromptClosedParameters p) => new(bidi, p.Context, p.Accepted, p.Type, p.UserContext, p.UserText); + protected override void Initialize(IBiDi bidi, JsonSerializerOptions jsonSerializerOptions) { jsonSerializerOptions.Converters.Add(new BrowsingContextConverter(bidi)); @@ -287,14 +320,13 @@ protected override void Initialize(IBiDi bidi, JsonSerializerOptions jsonSeriali [JsonSerializable(typeof(TraverseHistoryCommand))] [JsonSerializable(typeof(TraverseHistoryResult))] -[JsonSerializable(typeof(BrowsingContextEventArgs))] -[JsonSerializable(typeof(DownloadWillBeginEventArgs))] -[JsonSerializable(typeof(DownloadEndEventArgs))] -[JsonSerializable(typeof(DownloadCanceledEventArgs))] -[JsonSerializable(typeof(DownloadCompleteEventArgs))] -[JsonSerializable(typeof(HistoryUpdatedEventArgs))] -[JsonSerializable(typeof(NavigationEventArgs))] -[JsonSerializable(typeof(UserPromptOpenedEventArgs))] -[JsonSerializable(typeof(UserPromptClosedEventArgs))] +[JsonSerializable(typeof(DownloadWillBeginParams))] +[JsonSerializable(typeof(DownloadEndParams))] +[JsonSerializable(typeof(DownloadCanceledParams))] +[JsonSerializable(typeof(DownloadCompleteParams))] +[JsonSerializable(typeof(HistoryUpdatedParameters))] +[JsonSerializable(typeof(NavigationInfo))] +[JsonSerializable(typeof(UserPromptClosedParameters))] +[JsonSerializable(typeof(UserPromptOpenedParameters))] internal partial class BrowsingContextJsonSerializerContext : JsonSerializerContext; diff --git a/dotnet/src/webdriver/BiDi/BrowsingContext/ContextCreatedEventArgs.cs b/dotnet/src/webdriver/BiDi/BrowsingContext/ContextCreatedEventArgs.cs new file mode 100644 index 0000000000000..f44ff21f6009b --- /dev/null +++ b/dotnet/src/webdriver/BiDi/BrowsingContext/ContextCreatedEventArgs.cs @@ -0,0 +1,30 @@ +// +// Licensed to the Software Freedom Conservancy (SFC) under one +// or more contributor license agreements. See the NOTICE file +// distributed with this work for additional information +// regarding copyright ownership. The SFC licenses this file +// to you under the Apache License, Version 2.0 (the +// "License"); you may not use this file except in compliance +// with the License. You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, +// software distributed under the License is distributed on an +// "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY +// KIND, either express or implied. See the License for the +// specific language governing permissions and limitations +// under the License. +// + +namespace OpenQA.Selenium.BiDi.BrowsingContext; + +public sealed record ContextCreatedEventArgs( + IBiDi BiDi, + IReadOnlyList? Children, + Browser.ClientWindow ClientWindow, + BrowsingContext Context, + BrowsingContext? OriginalOpener, + string Url, + Browser.UserContext UserContext, + BrowsingContext? Parent) : EventArgs(BiDi); diff --git a/dotnet/src/webdriver/BiDi/BrowsingContext/ContextDestroyedEventArgs.cs b/dotnet/src/webdriver/BiDi/BrowsingContext/ContextDestroyedEventArgs.cs new file mode 100644 index 0000000000000..225786a76e6a3 --- /dev/null +++ b/dotnet/src/webdriver/BiDi/BrowsingContext/ContextDestroyedEventArgs.cs @@ -0,0 +1,28 @@ +// +// Licensed to the Software Freedom Conservancy (SFC) under one +// or more contributor license agreements. See the NOTICE file +// distributed with this work for additional information +// regarding copyright ownership. The SFC licenses this file +// to you under the Apache License, Version 2.0 (the +// "License"); you may not use this file except in compliance +// with the License. You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, +// software distributed under the License is distributed on an +// "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY +// KIND, either express or implied. See the License for the +// specific language governing permissions and limitations +// under the License. +// + +namespace OpenQA.Selenium.BiDi.BrowsingContext; + +public sealed record ContextDestroyedEventArgs(IBiDi BiDi, IReadOnlyList? Children, + Browser.ClientWindow ClientWindow, + BrowsingContext Context, + BrowsingContext? OriginalOpener, + string Url, + Browser.UserContext UserContext, + BrowsingContext? Parent) : EventArgs(BiDi); diff --git a/dotnet/src/webdriver/BiDi/BrowsingContext/BrowsingContextEventArgs.cs b/dotnet/src/webdriver/BiDi/BrowsingContext/DomContentLoadedEventArgs.cs similarity index 71% rename from dotnet/src/webdriver/BiDi/BrowsingContext/BrowsingContextEventArgs.cs rename to dotnet/src/webdriver/BiDi/BrowsingContext/DomContentLoadedEventArgs.cs index 3aadd108cd52e..ff08994cdbeac 100644 --- a/dotnet/src/webdriver/BiDi/BrowsingContext/BrowsingContextEventArgs.cs +++ b/dotnet/src/webdriver/BiDi/BrowsingContext/DomContentLoadedEventArgs.cs @@ -1,4 +1,4 @@ -// +// // Licensed to the Software Freedom Conservancy (SFC) under one // or more contributor license agreements. See the NOTICE file // distributed with this work for additional information @@ -19,5 +19,5 @@ namespace OpenQA.Selenium.BiDi.BrowsingContext; -public sealed record BrowsingContextEventArgs(IReadOnlyList? Children, Browser.ClientWindow ClientWindow, BrowsingContext Context, BrowsingContext? OriginalOpener, string Url, Browser.UserContext UserContext, BrowsingContext? Parent) - : EventArgs; +public sealed record DomContentLoadedEventArgs(IBiDi BiDi, BrowsingContext Context, Navigation? Navigation, DateTimeOffset Timestamp, string Url, Browser.UserContext? UserContext) + : NavigationEventArgs(BiDi, Context, Navigation, Timestamp, Url, UserContext); diff --git a/dotnet/src/webdriver/BiDi/BrowsingContext/DownloadEndEventArgs.cs b/dotnet/src/webdriver/BiDi/BrowsingContext/DownloadEndEventArgs.cs index 7c081ece08f46..9b69b2b9e95fc 100644 --- a/dotnet/src/webdriver/BiDi/BrowsingContext/DownloadEndEventArgs.cs +++ b/dotnet/src/webdriver/BiDi/BrowsingContext/DownloadEndEventArgs.cs @@ -17,21 +17,71 @@ // under the License. // +using System.Text.Json; using System.Text.Json.Serialization; -using OpenQA.Selenium.BiDi.Json.Converters.Polymorphic; +using OpenQA.Selenium.BiDi.Json; namespace OpenQA.Selenium.BiDi.BrowsingContext; +public abstract record DownloadEndEventArgs( + IBiDi BiDi, + BrowsingContext Context) + : EventArgs(BiDi); + +public sealed record DownloadCanceledEventArgs( + IBiDi BiDi, + BrowsingContext Context, + Navigation? Navigation, + DateTimeOffset Timestamp, + string Url) + : DownloadEndEventArgs(BiDi, Context), IBaseNavigationInfo; + +public sealed record DownloadCompleteEventArgs( + IBiDi BiDi, + string? Filepath, + BrowsingContext Context, + Navigation? Navigation, + DateTimeOffset Timestamp, + string Url) + : DownloadEndEventArgs(BiDi, Context), IBaseNavigationInfo; + // https://github.com/dotnet/runtime/issues/72604 //[JsonPolymorphic(TypeDiscriminatorPropertyName = "status")] -//[JsonDerivedType(typeof(DownloadCanceledEventArgs), "canceled")] -//[JsonDerivedType(typeof(DownloadCompleteEventArgs), "complete")] -[JsonConverter(typeof(DownloadEndEventArgsConverter))] -public abstract record DownloadEndEventArgs(BrowsingContext Context) - : EventArgs; +//[JsonDerivedType(typeof(DownloadCanceledParams), "canceled")] +//[JsonDerivedType(typeof(DownloadCompleteParams), "complete")] +[JsonConverter(typeof(DownloadEndParamsConverter))] +internal abstract record DownloadEndParams(BrowsingContext Context); -public sealed record DownloadCanceledEventArgs(BrowsingContext Context, Navigation? Navigation, DateTimeOffset Timestamp, string Url) - : DownloadEndEventArgs(Context), IBaseNavigationInfo; +internal sealed record DownloadCanceledParams( + BrowsingContext Context, + Navigation? Navigation, + DateTimeOffset Timestamp, + string Url) + : DownloadEndParams(Context), IBaseNavigationInfo; + +internal sealed record DownloadCompleteParams( + string? Filepath, + BrowsingContext Context, + Navigation? Navigation, + DateTimeOffset Timestamp, + string Url) + : DownloadEndParams(Context), IBaseNavigationInfo; + +// https://github.com/dotnet/runtime/issues/72604 +internal class DownloadEndParamsConverter : JsonConverter +{ + public override DownloadEndParams? Read(ref Utf8JsonReader reader, Type typeToConvert, JsonSerializerOptions options) + { + return reader.GetDiscriminator("status") switch + { + "canceled" => JsonSerializer.Deserialize(ref reader, options.GetTypeInfo()), + "complete" => JsonSerializer.Deserialize(ref reader, options.GetTypeInfo()), + _ => null, + }; + } -public sealed record DownloadCompleteEventArgs(string? Filepath, BrowsingContext Context, Navigation? Navigation, DateTimeOffset Timestamp, string Url) - : DownloadEndEventArgs(Context), IBaseNavigationInfo; + public override void Write(Utf8JsonWriter writer, DownloadEndParams value, JsonSerializerOptions options) + { + throw new NotImplementedException(); + } +} diff --git a/dotnet/src/webdriver/BiDi/BrowsingContext/DownloadWillBeginEventArgs.cs b/dotnet/src/webdriver/BiDi/BrowsingContext/DownloadWillBeginEventArgs.cs index c9535227fda02..6b0f9ffccc4fe 100644 --- a/dotnet/src/webdriver/BiDi/BrowsingContext/DownloadWillBeginEventArgs.cs +++ b/dotnet/src/webdriver/BiDi/BrowsingContext/DownloadWillBeginEventArgs.cs @@ -19,5 +19,19 @@ namespace OpenQA.Selenium.BiDi.BrowsingContext; -public sealed record DownloadWillBeginEventArgs(string SuggestedFilename, BrowsingContext Context, Navigation? Navigation, DateTimeOffset Timestamp, string Url) - : EventArgs, IBaseNavigationInfo; +public sealed record DownloadWillBeginEventArgs( + IBiDi BiDi, + string SuggestedFilename, + BrowsingContext Context, + Navigation? Navigation, + DateTimeOffset Timestamp, + string Url) + : EventArgs(BiDi), IBaseNavigationInfo; + +internal sealed record DownloadWillBeginParams( + string SuggestedFilename, + BrowsingContext Context, + Navigation? Navigation, + DateTimeOffset Timestamp, + string Url) + : IBaseNavigationInfo; diff --git a/dotnet/src/webdriver/BiDi/BrowsingContext/FragmentNavigatedEventArgs.cs b/dotnet/src/webdriver/BiDi/BrowsingContext/FragmentNavigatedEventArgs.cs new file mode 100644 index 0000000000000..8297ad76d82ae --- /dev/null +++ b/dotnet/src/webdriver/BiDi/BrowsingContext/FragmentNavigatedEventArgs.cs @@ -0,0 +1,23 @@ +// +// Licensed to the Software Freedom Conservancy (SFC) under one +// or more contributor license agreements. See the NOTICE file +// distributed with this work for additional information +// regarding copyright ownership. The SFC licenses this file +// to you under the Apache License, Version 2.0 (the +// "License"); you may not use this file except in compliance +// with the License. You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, +// software distributed under the License is distributed on an +// "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY +// KIND, either express or implied. See the License for the +// specific language governing permissions and limitations +// under the License. +// + +namespace OpenQA.Selenium.BiDi.BrowsingContext; + +public sealed record FragmentNavigatedEventArgs(IBiDi BiDi, BrowsingContext Context, Navigation? Navigation, DateTimeOffset Timestamp, string Url, Browser.UserContext? UserContext) + : NavigationEventArgs(BiDi, Context, Navigation, Timestamp, Url, UserContext); diff --git a/dotnet/src/webdriver/BiDi/BrowsingContext/GetTreeCommand.cs b/dotnet/src/webdriver/BiDi/BrowsingContext/GetTreeCommand.cs index b2ffc683e83db..c05cad1c33099 100644 --- a/dotnet/src/webdriver/BiDi/BrowsingContext/GetTreeCommand.cs +++ b/dotnet/src/webdriver/BiDi/BrowsingContext/GetTreeCommand.cs @@ -43,4 +43,4 @@ public sealed record ContextGetTreeOptions : CommandOptions }; } -public sealed record GetTreeResult(IReadOnlyList Contexts) : EmptyResult; +public sealed record GetTreeResult(IReadOnlyList Contexts) : EmptyResult; diff --git a/dotnet/src/webdriver/BiDi/BrowsingContext/HistoryUpdatedEventArgs.cs b/dotnet/src/webdriver/BiDi/BrowsingContext/HistoryUpdatedEventArgs.cs index 445f0a6c36dc7..d78a7dffed133 100644 --- a/dotnet/src/webdriver/BiDi/BrowsingContext/HistoryUpdatedEventArgs.cs +++ b/dotnet/src/webdriver/BiDi/BrowsingContext/HistoryUpdatedEventArgs.cs @@ -19,5 +19,16 @@ namespace OpenQA.Selenium.BiDi.BrowsingContext; -public sealed record HistoryUpdatedEventArgs(BrowsingContext Context, DateTimeOffset Timestamp, string Url, Browser.UserContext? UserContext) - : EventArgs; +public sealed record HistoryUpdatedEventArgs( + IBiDi BiDi, + BrowsingContext Context, + DateTimeOffset Timestamp, + string Url, + Browser.UserContext? UserContext) + : EventArgs(BiDi); + +internal sealed record HistoryUpdatedParameters( + BrowsingContext Context, + DateTimeOffset Timestamp, + string Url, + Browser.UserContext? UserContext); diff --git a/dotnet/src/webdriver/BiDi/BrowsingContext/IBrowsingContextInputModule.cs b/dotnet/src/webdriver/BiDi/BrowsingContext/IBrowsingContextInputModule.cs index ac76063ca471c..4c1af45ade035 100644 --- a/dotnet/src/webdriver/BiDi/BrowsingContext/IBrowsingContextInputModule.cs +++ b/dotnet/src/webdriver/BiDi/BrowsingContext/IBrowsingContextInputModule.cs @@ -23,8 +23,8 @@ namespace OpenQA.Selenium.BiDi.BrowsingContext; public interface IBrowsingContextInputModule { - Task OnFileDialogOpenedAsync(Func handler, ContextSubscriptionOptions? options = null, CancellationToken cancellationToken = default); - Task OnFileDialogOpenedAsync(Action handler, ContextSubscriptionOptions? options = null, CancellationToken cancellationToken = default); + Task OnFileDialogOpenedAsync(Func handler, ContextSubscriptionOptions? options = null, CancellationToken cancellationToken = default); + Task OnFileDialogOpenedAsync(Action handler, ContextSubscriptionOptions? options = null, CancellationToken cancellationToken = default); Task PerformActionsAsync(IEnumerable actions, PerformActionsOptions? options = null, CancellationToken cancellationToken = default); Task ReleaseActionsAsync(ReleaseActionsOptions? options = null, CancellationToken cancellationToken = default); Task SetFilesAsync(Script.ISharedReference element, IEnumerable files, SetFilesOptions? options = null, CancellationToken cancellationToken = default); diff --git a/dotnet/src/webdriver/BiDi/BrowsingContext/IBrowsingContextLogModule.cs b/dotnet/src/webdriver/BiDi/BrowsingContext/IBrowsingContextLogModule.cs index 74d5c0f22d90e..300228a57543a 100644 --- a/dotnet/src/webdriver/BiDi/BrowsingContext/IBrowsingContextLogModule.cs +++ b/dotnet/src/webdriver/BiDi/BrowsingContext/IBrowsingContextLogModule.cs @@ -23,6 +23,6 @@ namespace OpenQA.Selenium.BiDi.BrowsingContext; public interface IBrowsingContextLogModule { - Task OnEntryAddedAsync(Func handler, ContextSubscriptionOptions? options = null, CancellationToken cancellationToken = default); - Task OnEntryAddedAsync(Action handler, ContextSubscriptionOptions? options = null, CancellationToken cancellationToken = default); + Task OnEntryAddedAsync(Func handler, ContextSubscriptionOptions? options = null, CancellationToken cancellationToken = default); + Task OnEntryAddedAsync(Action handler, ContextSubscriptionOptions? options = null, CancellationToken cancellationToken = default); } diff --git a/dotnet/src/webdriver/BiDi/BrowsingContext/IBrowsingContextModule.cs b/dotnet/src/webdriver/BiDi/BrowsingContext/IBrowsingContextModule.cs index bd99fb34474b1..a4f853aacd49c 100644 --- a/dotnet/src/webdriver/BiDi/BrowsingContext/IBrowsingContextModule.cs +++ b/dotnet/src/webdriver/BiDi/BrowsingContext/IBrowsingContextModule.cs @@ -29,30 +29,30 @@ public interface IBrowsingContextModule Task HandleUserPromptAsync(BrowsingContext context, HandleUserPromptOptions? options = null, CancellationToken cancellationToken = default); Task LocateNodesAsync(BrowsingContext context, Locator locator, LocateNodesOptions? options = null, CancellationToken cancellationToken = default); Task NavigateAsync(BrowsingContext context, string url, NavigateOptions? options = null, CancellationToken cancellationToken = default); - Task OnContextCreatedAsync(Func handler, SubscriptionOptions? options = null, CancellationToken cancellationToken = default); - Task OnContextCreatedAsync(Action handler, SubscriptionOptions? options = null, CancellationToken cancellationToken = default); - Task OnContextDestroyedAsync(Func handler, SubscriptionOptions? options = null, CancellationToken cancellationToken = default); - Task OnContextDestroyedAsync(Action handler, SubscriptionOptions? options = null, CancellationToken cancellationToken = default); - Task OnDomContentLoadedAsync(Func handler, SubscriptionOptions? options = null, CancellationToken cancellationToken = default); - Task OnDomContentLoadedAsync(Action handler, SubscriptionOptions? options = null, CancellationToken cancellationToken = default); + Task OnContextCreatedAsync(Func handler, SubscriptionOptions? options = null, CancellationToken cancellationToken = default); + Task OnContextCreatedAsync(Action handler, SubscriptionOptions? options = null, CancellationToken cancellationToken = default); + Task OnContextDestroyedAsync(Func handler, SubscriptionOptions? options = null, CancellationToken cancellationToken = default); + Task OnContextDestroyedAsync(Action handler, SubscriptionOptions? options = null, CancellationToken cancellationToken = default); + Task OnDomContentLoadedAsync(Func handler, SubscriptionOptions? options = null, CancellationToken cancellationToken = default); + Task OnDomContentLoadedAsync(Action handler, SubscriptionOptions? options = null, CancellationToken cancellationToken = default); Task OnDownloadEndAsync(Func handler, SubscriptionOptions? options = null, CancellationToken cancellationToken = default); Task OnDownloadEndAsync(Action handler, SubscriptionOptions? options = null, CancellationToken cancellationToken = default); Task OnDownloadWillBeginAsync(Func handler, SubscriptionOptions? options = null, CancellationToken cancellationToken = default); Task OnDownloadWillBeginAsync(Action handler, SubscriptionOptions? options = null, CancellationToken cancellationToken = default); - Task OnFragmentNavigatedAsync(Func handler, SubscriptionOptions? options = null, CancellationToken cancellationToken = default); - Task OnFragmentNavigatedAsync(Action handler, SubscriptionOptions? options = null, CancellationToken cancellationToken = default); + Task OnFragmentNavigatedAsync(Func handler, SubscriptionOptions? options = null, CancellationToken cancellationToken = default); + Task OnFragmentNavigatedAsync(Action handler, SubscriptionOptions? options = null, CancellationToken cancellationToken = default); Task OnHistoryUpdatedAsync(Func handler, SubscriptionOptions? options = null, CancellationToken cancellationToken = default); Task OnHistoryUpdatedAsync(Action handler, SubscriptionOptions? options = null, CancellationToken cancellationToken = default); - Task OnLoadAsync(Func handler, SubscriptionOptions? options = null, CancellationToken cancellationToken = default); - Task OnLoadAsync(Action handler, SubscriptionOptions? options = null, CancellationToken cancellationToken = default); - Task OnNavigationAbortedAsync(Func handler, SubscriptionOptions? options = null, CancellationToken cancellationToken = default); - Task OnNavigationAbortedAsync(Action handler, SubscriptionOptions? options = null, CancellationToken cancellationToken = default); - Task OnNavigationCommittedAsync(Func handler, SubscriptionOptions? options = null, CancellationToken cancellationToken = default); - Task OnNavigationCommittedAsync(Action handler, SubscriptionOptions? options = null, CancellationToken cancellationToken = default); - Task OnNavigationFailedAsync(Func handler, SubscriptionOptions? options = null, CancellationToken cancellationToken = default); - Task OnNavigationFailedAsync(Action handler, SubscriptionOptions? options = null, CancellationToken cancellationToken = default); - Task OnNavigationStartedAsync(Func handler, SubscriptionOptions? options = null, CancellationToken cancellationToken = default); - Task OnNavigationStartedAsync(Action handler, SubscriptionOptions? options = null, CancellationToken cancellationToken = default); + Task OnLoadAsync(Func handler, SubscriptionOptions? options = null, CancellationToken cancellationToken = default); + Task OnLoadAsync(Action handler, SubscriptionOptions? options = null, CancellationToken cancellationToken = default); + Task OnNavigationAbortedAsync(Func handler, SubscriptionOptions? options = null, CancellationToken cancellationToken = default); + Task OnNavigationAbortedAsync(Action handler, SubscriptionOptions? options = null, CancellationToken cancellationToken = default); + Task OnNavigationCommittedAsync(Func handler, SubscriptionOptions? options = null, CancellationToken cancellationToken = default); + Task OnNavigationCommittedAsync(Action handler, SubscriptionOptions? options = null, CancellationToken cancellationToken = default); + Task OnNavigationFailedAsync(Func handler, SubscriptionOptions? options = null, CancellationToken cancellationToken = default); + Task OnNavigationFailedAsync(Action handler, SubscriptionOptions? options = null, CancellationToken cancellationToken = default); + Task OnNavigationStartedAsync(Func handler, SubscriptionOptions? options = null, CancellationToken cancellationToken = default); + Task OnNavigationStartedAsync(Action handler, SubscriptionOptions? options = null, CancellationToken cancellationToken = default); Task OnUserPromptClosedAsync(Func handler, SubscriptionOptions? options = null, CancellationToken cancellationToken = default); Task OnUserPromptClosedAsync(Action handler, SubscriptionOptions? options = null, CancellationToken cancellationToken = default); Task OnUserPromptOpenedAsync(Func handler, SubscriptionOptions? options = null, CancellationToken cancellationToken = default); diff --git a/dotnet/src/webdriver/BiDi/BrowsingContext/BrowsingContextInfo.cs b/dotnet/src/webdriver/BiDi/BrowsingContext/Info.cs similarity index 72% rename from dotnet/src/webdriver/BiDi/BrowsingContext/BrowsingContextInfo.cs rename to dotnet/src/webdriver/BiDi/BrowsingContext/Info.cs index 1742af0c337fe..de1289c9d79cc 100644 --- a/dotnet/src/webdriver/BiDi/BrowsingContext/BrowsingContextInfo.cs +++ b/dotnet/src/webdriver/BiDi/BrowsingContext/Info.cs @@ -1,4 +1,4 @@ -// +// // Licensed to the Software Freedom Conservancy (SFC) under one // or more contributor license agreements. See the NOTICE file // distributed with this work for additional information @@ -19,4 +19,11 @@ namespace OpenQA.Selenium.BiDi.BrowsingContext; -public sealed record BrowsingContextInfo(IReadOnlyList? Children, Browser.ClientWindow ClientWindow, BrowsingContext Context, BrowsingContext? OriginalOpener, string Url, Browser.UserContext UserContext, BrowsingContext? Parent); +public sealed record Info( + IReadOnlyList? Children, + Browser.ClientWindow ClientWindow, + BrowsingContext Context, + BrowsingContext? OriginalOpener, + string Url, + Browser.UserContext UserContext, + BrowsingContext? Parent); diff --git a/dotnet/src/webdriver/BiDi/BrowsingContext/LoadEventArgs.cs b/dotnet/src/webdriver/BiDi/BrowsingContext/LoadEventArgs.cs new file mode 100644 index 0000000000000..ff9a799090780 --- /dev/null +++ b/dotnet/src/webdriver/BiDi/BrowsingContext/LoadEventArgs.cs @@ -0,0 +1,23 @@ +// +// Licensed to the Software Freedom Conservancy (SFC) under one +// or more contributor license agreements. See the NOTICE file +// distributed with this work for additional information +// regarding copyright ownership. The SFC licenses this file +// to you under the Apache License, Version 2.0 (the +// "License"); you may not use this file except in compliance +// with the License. You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, +// software distributed under the License is distributed on an +// "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY +// KIND, either express or implied. See the License for the +// specific language governing permissions and limitations +// under the License. +// + +namespace OpenQA.Selenium.BiDi.BrowsingContext; + +public sealed record LoadEventArgs(IBiDi BiDi, BrowsingContext Context, Navigation? Navigation, DateTimeOffset Timestamp, string Url, Browser.UserContext? UserContext) + : NavigationEventArgs(BiDi, Context, Navigation, Timestamp, Url, UserContext); diff --git a/dotnet/src/webdriver/BiDi/BrowsingContext/NavigationAbortedEventArgs.cs b/dotnet/src/webdriver/BiDi/BrowsingContext/NavigationAbortedEventArgs.cs new file mode 100644 index 0000000000000..4ecd7d3392b1d --- /dev/null +++ b/dotnet/src/webdriver/BiDi/BrowsingContext/NavigationAbortedEventArgs.cs @@ -0,0 +1,23 @@ +// +// Licensed to the Software Freedom Conservancy (SFC) under one +// or more contributor license agreements. See the NOTICE file +// distributed with this work for additional information +// regarding copyright ownership. The SFC licenses this file +// to you under the Apache License, Version 2.0 (the +// "License"); you may not use this file except in compliance +// with the License. You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, +// software distributed under the License is distributed on an +// "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY +// KIND, either express or implied. See the License for the +// specific language governing permissions and limitations +// under the License. +// + +namespace OpenQA.Selenium.BiDi.BrowsingContext; + +public sealed record NavigationAbortedEventArgs(IBiDi BiDi, BrowsingContext Context, Navigation? Navigation, DateTimeOffset Timestamp, string Url, Browser.UserContext? UserContext) + : NavigationEventArgs(BiDi, Context, Navigation, Timestamp, Url, UserContext); diff --git a/dotnet/src/webdriver/BiDi/BrowsingContext/NavigationCommittedEventArgs.cs b/dotnet/src/webdriver/BiDi/BrowsingContext/NavigationCommittedEventArgs.cs new file mode 100644 index 0000000000000..b15241d58de79 --- /dev/null +++ b/dotnet/src/webdriver/BiDi/BrowsingContext/NavigationCommittedEventArgs.cs @@ -0,0 +1,23 @@ +// +// Licensed to the Software Freedom Conservancy (SFC) under one +// or more contributor license agreements. See the NOTICE file +// distributed with this work for additional information +// regarding copyright ownership. The SFC licenses this file +// to you under the Apache License, Version 2.0 (the +// "License"); you may not use this file except in compliance +// with the License. You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, +// software distributed under the License is distributed on an +// "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY +// KIND, either express or implied. See the License for the +// specific language governing permissions and limitations +// under the License. +// + +namespace OpenQA.Selenium.BiDi.BrowsingContext; + +public sealed record NavigationCommittedEventArgs(IBiDi BiDi, BrowsingContext Context, Navigation? Navigation, DateTimeOffset Timestamp, string Url, Browser.UserContext? UserContext) + : NavigationEventArgs(BiDi, Context, Navigation, Timestamp, Url, UserContext); diff --git a/dotnet/src/webdriver/BiDi/BrowsingContext/NavigationEventArgs.cs b/dotnet/src/webdriver/BiDi/BrowsingContext/NavigationEventArgs.cs index c7e0570c93a78..6d7aa19394cd0 100644 --- a/dotnet/src/webdriver/BiDi/BrowsingContext/NavigationEventArgs.cs +++ b/dotnet/src/webdriver/BiDi/BrowsingContext/NavigationEventArgs.cs @@ -19,5 +19,5 @@ namespace OpenQA.Selenium.BiDi.BrowsingContext; -public sealed record NavigationEventArgs(BrowsingContext Context, Navigation? Navigation, DateTimeOffset Timestamp, string Url, Browser.UserContext? UserContext) - : EventArgs, IBaseNavigationInfo; +public record NavigationEventArgs(IBiDi BiDi, BrowsingContext Context, Navigation? Navigation, DateTimeOffset Timestamp, string Url, Browser.UserContext? UserContext) + : EventArgs(BiDi), IBaseNavigationInfo; diff --git a/dotnet/src/webdriver/BiDi/BrowsingContext/NavigationFailedEventArgs.cs b/dotnet/src/webdriver/BiDi/BrowsingContext/NavigationFailedEventArgs.cs new file mode 100644 index 0000000000000..d831ad55183f6 --- /dev/null +++ b/dotnet/src/webdriver/BiDi/BrowsingContext/NavigationFailedEventArgs.cs @@ -0,0 +1,23 @@ +// +// Licensed to the Software Freedom Conservancy (SFC) under one +// or more contributor license agreements. See the NOTICE file +// distributed with this work for additional information +// regarding copyright ownership. The SFC licenses this file +// to you under the Apache License, Version 2.0 (the +// "License"); you may not use this file except in compliance +// with the License. You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, +// software distributed under the License is distributed on an +// "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY +// KIND, either express or implied. See the License for the +// specific language governing permissions and limitations +// under the License. +// + +namespace OpenQA.Selenium.BiDi.BrowsingContext; + +public sealed record NavigationFailedEventArgs(IBiDi BiDi, BrowsingContext Context, Navigation? Navigation, DateTimeOffset Timestamp, string Url, Browser.UserContext? UserContext) + : NavigationEventArgs(BiDi, Context, Navigation, Timestamp, Url, UserContext); diff --git a/dotnet/src/webdriver/BiDi/BrowsingContext/NavigationInfo.cs b/dotnet/src/webdriver/BiDi/BrowsingContext/NavigationInfo.cs index ffc58577a6cd9..961ddcd083ed0 100644 --- a/dotnet/src/webdriver/BiDi/BrowsingContext/NavigationInfo.cs +++ b/dotnet/src/webdriver/BiDi/BrowsingContext/NavigationInfo.cs @@ -19,5 +19,10 @@ namespace OpenQA.Selenium.BiDi.BrowsingContext; -public sealed record NavigationInfo(BrowsingContext Context, Navigation? Navigation, DateTimeOffset Timestamp, string Url, Browser.UserContext? UserContext) +public sealed record NavigationInfo( + BrowsingContext Context, + Navigation? Navigation, + DateTimeOffset Timestamp, + string Url, + Browser.UserContext? UserContext) : IBaseNavigationInfo; diff --git a/dotnet/src/webdriver/BiDi/BrowsingContext/NavigationStartedEventArgs.cs b/dotnet/src/webdriver/BiDi/BrowsingContext/NavigationStartedEventArgs.cs new file mode 100644 index 0000000000000..2300008f233bd --- /dev/null +++ b/dotnet/src/webdriver/BiDi/BrowsingContext/NavigationStartedEventArgs.cs @@ -0,0 +1,23 @@ +// +// Licensed to the Software Freedom Conservancy (SFC) under one +// or more contributor license agreements. See the NOTICE file +// distributed with this work for additional information +// regarding copyright ownership. The SFC licenses this file +// to you under the Apache License, Version 2.0 (the +// "License"); you may not use this file except in compliance +// with the License. You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, +// software distributed under the License is distributed on an +// "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY +// KIND, either express or implied. See the License for the +// specific language governing permissions and limitations +// under the License. +// + +namespace OpenQA.Selenium.BiDi.BrowsingContext; + +public sealed record NavigationStartedEventArgs(IBiDi BiDi, BrowsingContext Context, Navigation? Navigation, DateTimeOffset Timestamp, string Url, Browser.UserContext? UserContext) + : NavigationEventArgs(BiDi, Context, Navigation, Timestamp, Url, UserContext); diff --git a/dotnet/src/webdriver/BiDi/BrowsingContext/UserPromptClosedEventArgs.cs b/dotnet/src/webdriver/BiDi/BrowsingContext/UserPromptClosedEventArgs.cs index 90c6badb78461..40b12fe9b69a2 100644 --- a/dotnet/src/webdriver/BiDi/BrowsingContext/UserPromptClosedEventArgs.cs +++ b/dotnet/src/webdriver/BiDi/BrowsingContext/UserPromptClosedEventArgs.cs @@ -19,5 +19,18 @@ namespace OpenQA.Selenium.BiDi.BrowsingContext; -public sealed record UserPromptClosedEventArgs(BrowsingContext Context, bool Accepted, UserPromptType Type, Browser.UserContext? UserContext, string? UserText) - : EventArgs; +public sealed record UserPromptClosedEventArgs( + IBiDi BiDi, + BrowsingContext Context, + bool Accepted, + UserPromptType Type, + Browser.UserContext? UserContext, + string? UserText) + : EventArgs(BiDi); + +internal sealed record UserPromptClosedParameters( + BrowsingContext Context, + bool Accepted, + UserPromptType Type, + Browser.UserContext? UserContext, + string? UserText); diff --git a/dotnet/src/webdriver/BiDi/BrowsingContext/UserPromptOpenedEventArgs.cs b/dotnet/src/webdriver/BiDi/BrowsingContext/UserPromptOpenedEventArgs.cs index 08bea97f9fdd4..2dea8436242a6 100644 --- a/dotnet/src/webdriver/BiDi/BrowsingContext/UserPromptOpenedEventArgs.cs +++ b/dotnet/src/webdriver/BiDi/BrowsingContext/UserPromptOpenedEventArgs.cs @@ -17,19 +17,22 @@ // under the License. // -using System.Text.Json.Serialization; -using OpenQA.Selenium.BiDi.Json.Converters; - namespace OpenQA.Selenium.BiDi.BrowsingContext; -public sealed record UserPromptOpenedEventArgs(BrowsingContext Context, Session.UserPromptHandlerType Handler, string Message, UserPromptType Type, Browser.UserContext? UserContext, string? DefaultValue) - : EventArgs; +public sealed record UserPromptOpenedEventArgs( + IBiDi BiDi, + BrowsingContext Context, + Session.UserPromptHandlerType Handler, + string Message, + UserPromptType Type, + Browser.UserContext? UserContext, + string? DefaultValue) + : EventArgs(BiDi); -[JsonConverter(typeof(CamelCaseEnumConverter))] -public enum UserPromptType -{ - Alert, - Confirm, - Prompt, - BeforeUnload -} +internal sealed record UserPromptOpenedParameters( + BrowsingContext Context, + Session.UserPromptHandlerType Handler, + string Message, + UserPromptType Type, + Browser.UserContext? UserContext, + string? DefaultValue); diff --git a/dotnet/src/webdriver/BiDi/Input/FileDialogEventArgs.cs b/dotnet/src/webdriver/BiDi/BrowsingContext/UserPromptType.cs similarity index 70% rename from dotnet/src/webdriver/BiDi/Input/FileDialogEventArgs.cs rename to dotnet/src/webdriver/BiDi/BrowsingContext/UserPromptType.cs index b048251b54e8b..410256fa51d73 100644 --- a/dotnet/src/webdriver/BiDi/Input/FileDialogEventArgs.cs +++ b/dotnet/src/webdriver/BiDi/BrowsingContext/UserPromptType.cs @@ -1,4 +1,4 @@ -// +// // Licensed to the Software Freedom Conservancy (SFC) under one // or more contributor license agreements. See the NOTICE file // distributed with this work for additional information @@ -17,7 +17,16 @@ // under the License. // -namespace OpenQA.Selenium.BiDi.Input; +using System.Text.Json.Serialization; +using OpenQA.Selenium.BiDi.Json.Converters; -public sealed record FileDialogEventArgs(BrowsingContext.BrowsingContext Context, Browser.UserContext? UserContext, bool Multiple, Script.SharedReference? Element) - : EventArgs; +namespace OpenQA.Selenium.BiDi.BrowsingContext; + +[JsonConverter(typeof(CamelCaseEnumConverter))] +public enum UserPromptType +{ + Alert, + Confirm, + Prompt, + BeforeUnload +} diff --git a/dotnet/src/webdriver/BiDi/EventArgs.cs b/dotnet/src/webdriver/BiDi/EventArgs.cs index 691b62ad32250..9b78d23ef06e2 100644 --- a/dotnet/src/webdriver/BiDi/EventArgs.cs +++ b/dotnet/src/webdriver/BiDi/EventArgs.cs @@ -17,18 +17,6 @@ // under the License. // -using System.Text.Json.Serialization; - namespace OpenQA.Selenium.BiDi; -public abstract record EventArgs -{ - private IBiDi? _bidi; - - [JsonIgnore] - public IBiDi BiDi - { - get => _bidi ?? throw new InvalidOperationException($"{nameof(BiDi)} instance has not been hydrated."); - internal set => _bidi = value; - } -} +public abstract record EventArgs(IBiDi BiDi); diff --git a/dotnet/src/webdriver/BiDi/EventDispatcher.cs b/dotnet/src/webdriver/BiDi/EventDispatcher.cs index 16753b106ff18..c70f1c8d9ff37 100644 --- a/dotnet/src/webdriver/BiDi/EventDispatcher.cs +++ b/dotnet/src/webdriver/BiDi/EventDispatcher.cs @@ -18,10 +18,7 @@ // using System.Collections.Concurrent; -using System.Diagnostics.CodeAnalysis; -using System.Text.Json.Serialization.Metadata; using System.Threading.Channels; -using OpenQA.Selenium.BiDi.Session; using OpenQA.Selenium.Internal.Logging; namespace OpenQA.Selenium.BiDi; @@ -30,9 +27,7 @@ internal sealed class EventDispatcher : IAsyncDisposable { private readonly ILogger _logger = Internal.Logging.Log.GetLogger(); - private readonly Func _sessionProvider; - - private readonly ConcurrentDictionary _eventRegistrations = new(); + private readonly ConcurrentDictionary _handlerRegistrations = new(); private readonly ConcurrentDictionary _runningHandlers = new(); @@ -44,36 +39,28 @@ internal sealed class EventDispatcher : IAsyncDisposable private readonly Task _eventEmitterTask; - public EventDispatcher(Func sessionProvider) + public EventDispatcher() { - _sessionProvider = sessionProvider; _eventEmitterTask = Task.Run(ProcessEventsAwaiterAsync); } - public async Task SubscribeAsync(string eventName, EventHandler eventHandler, SubscriptionOptions? options, JsonTypeInfo jsonTypeInfo, CancellationToken cancellationToken) - where TEventArgs : EventArgs + public void AddHandler(string eventName, Func handler) { - var registration = _eventRegistrations.GetOrAdd(eventName, _ => new EventRegistration(jsonTypeInfo)); - - var subscribeResult = await _sessionProvider().SubscribeAsync([eventName], new() { Contexts = options?.Contexts, UserContexts = options?.UserContexts }, cancellationToken).ConfigureAwait(false); - - registration.AddHandler(eventHandler); - - return new Subscription(subscribeResult.Subscription, this, eventHandler); + var registration = _handlerRegistrations.GetOrAdd(eventName, _ => new HandlerRegistration()); + registration.AddHandler(handler); } - public async ValueTask UnsubscribeAsync(Subscription subscription, CancellationToken cancellationToken) + public void RemoveHandler(string eventName, Func handler) { - if (_eventRegistrations.TryGetValue(subscription.EventHandler.EventName, out var registration)) + if (_handlerRegistrations.TryGetValue(eventName, out var registration)) { - await _sessionProvider().UnsubscribeAsync([subscription.SubscriptionId], null, cancellationToken).ConfigureAwait(false); - registration.RemoveHandler(subscription.EventHandler); + registration.RemoveHandler(handler); } } - public void EnqueueEvent(string method, EventArgs eventArgs) + public void EnqueueEvent(string eventName, EventArgs eventArgs) { - _pendingEvents.Writer.TryWrite(new PendingEvent(method, eventArgs)); + _pendingEvents.Writer.TryWrite(new PendingEvent(eventName, eventArgs)); } private async Task ProcessEventsAwaiterAsync() @@ -83,7 +70,7 @@ private async Task ProcessEventsAwaiterAsync() { while (reader.TryRead(out var result)) { - if (_eventRegistrations.TryGetValue(result.Method, out var registration)) + if (_handlerRegistrations.TryGetValue(result.EventName, out var registration)) { foreach (var handler in registration.GetHandlers()) // copy-on-write array, safe to iterate { @@ -100,11 +87,11 @@ private async Task ProcessEventsAwaiterAsync() } } - private async Task InvokeHandlerAsync(EventHandler handler, EventArgs eventArgs) + private async Task InvokeHandlerAsync(Func handler, EventArgs eventArgs) { try { - await handler.InvokeAsync(eventArgs).ConfigureAwait(false); + await handler(eventArgs).ConfigureAwait(false); } catch (Exception ex) { @@ -126,35 +113,21 @@ public async ValueTask DisposeAsync() GC.SuppressFinalize(this); } - public bool TryGetJsonTypeInfo(string eventName, [NotNullWhen(true)] out JsonTypeInfo? jsonTypeInfo) - { - if (_eventRegistrations.TryGetValue(eventName, out var registration)) - { - jsonTypeInfo = registration.TypeInfo; - return true; - } - - jsonTypeInfo = null; - return false; - } + private readonly record struct PendingEvent(string EventName, EventArgs EventArgs); - private readonly record struct PendingEvent(string Method, EventArgs EventArgs); - - private sealed class EventRegistration(JsonTypeInfo typeInfo) + private sealed class HandlerRegistration { private readonly object _lock = new(); - private volatile EventHandler[] _handlers = []; - - public JsonTypeInfo TypeInfo { get; } = typeInfo; + private volatile Func[] _handlers = []; - public EventHandler[] GetHandlers() => _handlers; + public Func[] GetHandlers() => _handlers; - public void AddHandler(EventHandler handler) + public void AddHandler(Func handler) { lock (_lock) _handlers = [.. _handlers, handler]; } - public void RemoveHandler(EventHandler handler) + public void RemoveHandler(Func handler) { lock (_lock) _handlers = Array.FindAll(_handlers, h => h != handler); } diff --git a/dotnet/src/webdriver/BiDi/EventHandler.cs b/dotnet/src/webdriver/BiDi/EventHandler.cs deleted file mode 100644 index ac19fce9e951b..0000000000000 --- a/dotnet/src/webdriver/BiDi/EventHandler.cs +++ /dev/null @@ -1,51 +0,0 @@ -// -// Licensed to the Software Freedom Conservancy (SFC) under one -// or more contributor license agreements. See the NOTICE file -// distributed with this work for additional information -// regarding copyright ownership. The SFC licenses this file -// to you under the Apache License, Version 2.0 (the -// "License"); you may not use this file except in compliance -// with the License. You may obtain a copy of the License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, -// software distributed under the License is distributed on an -// "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY -// KIND, either express or implied. See the License for the -// specific language governing permissions and limitations -// under the License. -// - -namespace OpenQA.Selenium.BiDi; - -internal abstract class EventHandler(string eventName) -{ - public string EventName { get; } = eventName; - - public abstract ValueTask InvokeAsync(EventArgs args); -} - -internal class AsyncEventHandler(string eventName, Func func) - : EventHandler(eventName) where TEventArgs : EventArgs -{ - private readonly Func _func = func ?? throw new ArgumentNullException(nameof(func), "Async event handler function cannot be null."); - - public override async ValueTask InvokeAsync(EventArgs args) - { - await _func((TEventArgs)args).ConfigureAwait(false); - } -} - -internal class SyncEventHandler(string eventName, Action action) - : EventHandler(eventName) where TEventArgs : EventArgs -{ - private readonly Action _action = action ?? throw new ArgumentNullException(nameof(action), "Sync event handler action cannot be null."); - - public override ValueTask InvokeAsync(EventArgs args) - { - _action((TEventArgs)args); - - return default; - } -} diff --git a/dotnet/src/webdriver/BiDi/Input/FileDialogOpenedEventArgs.cs b/dotnet/src/webdriver/BiDi/Input/FileDialogOpenedEventArgs.cs new file mode 100644 index 0000000000000..3e3c88218bbb2 --- /dev/null +++ b/dotnet/src/webdriver/BiDi/Input/FileDialogOpenedEventArgs.cs @@ -0,0 +1,34 @@ +// +// Licensed to the Software Freedom Conservancy (SFC) under one +// or more contributor license agreements. See the NOTICE file +// distributed with this work for additional information +// regarding copyright ownership. The SFC licenses this file +// to you under the Apache License, Version 2.0 (the +// "License"); you may not use this file except in compliance +// with the License. You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, +// software distributed under the License is distributed on an +// "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY +// KIND, either express or implied. See the License for the +// specific language governing permissions and limitations +// under the License. +// + +namespace OpenQA.Selenium.BiDi.Input; + +public sealed record FileDialogOpenedEventArgs( + IBiDi BiDi, + BrowsingContext.BrowsingContext Context, + Browser.UserContext? UserContext, + bool Multiple, + Script.SharedReference? Element) + : EventArgs(BiDi); + +internal sealed record FileDialogInfo( + BrowsingContext.BrowsingContext Context, + Browser.UserContext? UserContext, + bool Multiple, + Script.SharedReference? Element); diff --git a/dotnet/src/webdriver/BiDi/Input/IInputModule.cs b/dotnet/src/webdriver/BiDi/Input/IInputModule.cs index 5730b806133ee..942e808f26b4d 100644 --- a/dotnet/src/webdriver/BiDi/Input/IInputModule.cs +++ b/dotnet/src/webdriver/BiDi/Input/IInputModule.cs @@ -21,8 +21,8 @@ namespace OpenQA.Selenium.BiDi.Input; public interface IInputModule { - Task OnFileDialogOpenedAsync(Func handler, SubscriptionOptions? options = null, CancellationToken cancellationToken = default); - Task OnFileDialogOpenedAsync(Action handler, SubscriptionOptions? options = null, CancellationToken cancellationToken = default); + Task OnFileDialogOpenedAsync(Func handler, SubscriptionOptions? options = null, CancellationToken cancellationToken = default); + Task OnFileDialogOpenedAsync(Action handler, SubscriptionOptions? options = null, CancellationToken cancellationToken = default); Task PerformActionsAsync(BrowsingContext.BrowsingContext context, IEnumerable actions, PerformActionsOptions? options = null, CancellationToken cancellationToken = default); Task ReleaseActionsAsync(BrowsingContext.BrowsingContext context, ReleaseActionsOptions? options = null, CancellationToken cancellationToken = default); Task SetFilesAsync(BrowsingContext.BrowsingContext context, Script.ISharedReference element, IEnumerable files, SetFilesOptions? options = null, CancellationToken cancellationToken = default); diff --git a/dotnet/src/webdriver/BiDi/Input/InputModule.cs b/dotnet/src/webdriver/BiDi/Input/InputModule.cs index 3e94189a1e191..a48bddef9fccf 100644 --- a/dotnet/src/webdriver/BiDi/Input/InputModule.cs +++ b/dotnet/src/webdriver/BiDi/Input/InputModule.cs @@ -48,14 +48,19 @@ public async Task SetFilesAsync(BrowsingContext.BrowsingContext return await ExecuteCommandAsync(new SetFilesCommand(@params), options, _jsonContext.SetFilesCommand, _jsonContext.SetFilesResult, cancellationToken).ConfigureAwait(false); } - public async Task OnFileDialogOpenedAsync(Func handler, SubscriptionOptions? options = null, CancellationToken cancellationToken = default) + public async Task OnFileDialogOpenedAsync(Func handler, SubscriptionOptions? options = null, CancellationToken cancellationToken = default) { - return await SubscribeAsync("input.fileDialogOpened", handler, options, _jsonContext.FileDialogEventArgs, cancellationToken).ConfigureAwait(false); + return await SubscribeAsync("input.fileDialogOpened", handler, CreateFileDialogOpenedEventArgs, options, _jsonContext.FileDialogInfo, cancellationToken).ConfigureAwait(false); } - public async Task OnFileDialogOpenedAsync(Action handler, SubscriptionOptions? options = null, CancellationToken cancellationToken = default) + public async Task OnFileDialogOpenedAsync(Action handler, SubscriptionOptions? options = null, CancellationToken cancellationToken = default) { - return await SubscribeAsync("input.fileDialogOpened", handler, options, _jsonContext.FileDialogEventArgs, cancellationToken).ConfigureAwait(false); + return await SubscribeAsync("input.fileDialogOpened", handler, CreateFileDialogOpenedEventArgs, options, _jsonContext.FileDialogInfo, cancellationToken).ConfigureAwait(false); + } + + private static FileDialogOpenedEventArgs CreateFileDialogOpenedEventArgs(IBiDi bidi, FileDialogInfo p) + { + return new FileDialogOpenedEventArgs(bidi, p.Context, p.UserContext, p.Multiple, p.Element); } protected override void Initialize(IBiDi bidi, JsonSerializerOptions jsonSerializerOptions) @@ -74,6 +79,7 @@ protected override void Initialize(IBiDi bidi, JsonSerializerOptions jsonSeriali [JsonSerializable(typeof(ReleaseActionsResult))] [JsonSerializable(typeof(SetFilesCommand))] [JsonSerializable(typeof(SetFilesResult))] -[JsonSerializable(typeof(FileDialogEventArgs))] + +[JsonSerializable(typeof(FileDialogInfo))] internal partial class InputJsonSerializerContext : JsonSerializerContext; diff --git a/dotnet/src/webdriver/BiDi/Json/Converters/Polymorphic/DownloadEndEventArgsConverter.cs b/dotnet/src/webdriver/BiDi/Json/Converters/Polymorphic/DownloadEndEventArgsConverter.cs deleted file mode 100644 index c4f4869d98b0f..0000000000000 --- a/dotnet/src/webdriver/BiDi/Json/Converters/Polymorphic/DownloadEndEventArgsConverter.cs +++ /dev/null @@ -1,43 +0,0 @@ -// -// Licensed to the Software Freedom Conservancy (SFC) under one -// or more contributor license agreements. See the NOTICE file -// distributed with this work for additional information -// regarding copyright ownership. The SFC licenses this file -// to you under the Apache License, Version 2.0 (the -// "License"); you may not use this file except in compliance -// with the License. You may obtain a copy of the License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, -// software distributed under the License is distributed on an -// "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY -// KIND, either express or implied. See the License for the -// specific language governing permissions and limitations -// under the License. -// - -using System.Text.Json; -using System.Text.Json.Serialization; -using OpenQA.Selenium.BiDi.BrowsingContext; - -namespace OpenQA.Selenium.BiDi.Json.Converters.Polymorphic; - -// https://github.com/dotnet/runtime/issues/72604 -internal class DownloadEndEventArgsConverter : JsonConverter -{ - public override DownloadEndEventArgs? Read(ref Utf8JsonReader reader, Type typeToConvert, JsonSerializerOptions options) - { - return reader.GetDiscriminator("status") switch - { - "canceled" => JsonSerializer.Deserialize(ref reader, options.GetTypeInfo()), - "complete" => JsonSerializer.Deserialize(ref reader, options.GetTypeInfo()), - _ => null, - }; - } - - public override void Write(Utf8JsonWriter writer, DownloadEndEventArgs value, JsonSerializerOptions options) - { - throw new NotImplementedException(); - } -} diff --git a/dotnet/src/webdriver/BiDi/Json/Converters/Polymorphic/EvaluateResultConverter.cs b/dotnet/src/webdriver/BiDi/Json/Converters/Polymorphic/EvaluateResultConverter.cs deleted file mode 100644 index 04c98dcbe0c58..0000000000000 --- a/dotnet/src/webdriver/BiDi/Json/Converters/Polymorphic/EvaluateResultConverter.cs +++ /dev/null @@ -1,43 +0,0 @@ -// -// Licensed to the Software Freedom Conservancy (SFC) under one -// or more contributor license agreements. See the NOTICE file -// distributed with this work for additional information -// regarding copyright ownership. The SFC licenses this file -// to you under the Apache License, Version 2.0 (the -// "License"); you may not use this file except in compliance -// with the License. You may obtain a copy of the License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, -// software distributed under the License is distributed on an -// "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY -// KIND, either express or implied. See the License for the -// specific language governing permissions and limitations -// under the License. -// - -using System.Text.Json; -using System.Text.Json.Serialization; -using OpenQA.Selenium.BiDi.Script; - -namespace OpenQA.Selenium.BiDi.Json.Converters.Polymorphic; - -// https://github.com/dotnet/runtime/issues/72604 -internal class EvaluateResultConverter : JsonConverter -{ - public override EvaluateResult? Read(ref Utf8JsonReader reader, Type typeToConvert, JsonSerializerOptions options) - { - return reader.GetDiscriminator("type") switch - { - "success" => JsonSerializer.Deserialize(ref reader, options.GetTypeInfo()), - "exception" => JsonSerializer.Deserialize(ref reader, options.GetTypeInfo()), - _ => null, - }; - } - - public override void Write(Utf8JsonWriter writer, EvaluateResult value, JsonSerializerOptions options) - { - throw new NotImplementedException(); - } -} diff --git a/dotnet/src/webdriver/BiDi/Json/Converters/Polymorphic/LogEntryEventArgsConverter.cs b/dotnet/src/webdriver/BiDi/Json/Converters/Polymorphic/LogEntryEventArgsConverter.cs deleted file mode 100644 index e60ec6764d725..0000000000000 --- a/dotnet/src/webdriver/BiDi/Json/Converters/Polymorphic/LogEntryEventArgsConverter.cs +++ /dev/null @@ -1,43 +0,0 @@ -// -// Licensed to the Software Freedom Conservancy (SFC) under one -// or more contributor license agreements. See the NOTICE file -// distributed with this work for additional information -// regarding copyright ownership. The SFC licenses this file -// to you under the Apache License, Version 2.0 (the -// "License"); you may not use this file except in compliance -// with the License. You may obtain a copy of the License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, -// software distributed under the License is distributed on an -// "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY -// KIND, either express or implied. See the License for the -// specific language governing permissions and limitations -// under the License. -// - -using System.Text.Json; -using System.Text.Json.Serialization; -using OpenQA.Selenium.BiDi.Log; - -namespace OpenQA.Selenium.BiDi.Json.Converters.Polymorphic; - -// https://github.com/dotnet/runtime/issues/72604 -internal class LogEntryEventArgsConverter : JsonConverter -{ - public override LogEntryEventArgs? Read(ref Utf8JsonReader reader, Type typeToConvert, JsonSerializerOptions options) - { - return reader.GetDiscriminator("type") switch - { - "console" => JsonSerializer.Deserialize(ref reader, options.GetTypeInfo()), - "javascript" => JsonSerializer.Deserialize(ref reader, options.GetTypeInfo()), - _ => JsonSerializer.Deserialize(ref reader, options.GetTypeInfo()), - }; - } - - public override void Write(Utf8JsonWriter writer, LogEntryEventArgs value, JsonSerializerOptions options) - { - throw new NotImplementedException(); - } -} diff --git a/dotnet/src/webdriver/BiDi/Json/Converters/Polymorphic/RealmInfoConverter.cs b/dotnet/src/webdriver/BiDi/Json/Converters/Polymorphic/RealmInfoConverter.cs deleted file mode 100644 index 56ee96c261e9b..0000000000000 --- a/dotnet/src/webdriver/BiDi/Json/Converters/Polymorphic/RealmInfoConverter.cs +++ /dev/null @@ -1,49 +0,0 @@ -// -// Licensed to the Software Freedom Conservancy (SFC) under one -// or more contributor license agreements. See the NOTICE file -// distributed with this work for additional information -// regarding copyright ownership. The SFC licenses this file -// to you under the Apache License, Version 2.0 (the -// "License"); you may not use this file except in compliance -// with the License. You may obtain a copy of the License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, -// software distributed under the License is distributed on an -// "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY -// KIND, either express or implied. See the License for the -// specific language governing permissions and limitations -// under the License. -// - -using System.Text.Json; -using System.Text.Json.Serialization; -using OpenQA.Selenium.BiDi.Script; - -namespace OpenQA.Selenium.BiDi.Json.Converters.Polymorphic; - -// https://github.com/dotnet/runtime/issues/72604 -internal class RealmInfoConverter : JsonConverter -{ - public override RealmInfo? Read(ref Utf8JsonReader reader, Type typeToConvert, JsonSerializerOptions options) - { - return reader.GetDiscriminator("type") switch - { - "window" => JsonSerializer.Deserialize(ref reader, options.GetTypeInfo()), - "dedicated-worker" => JsonSerializer.Deserialize(ref reader, options.GetTypeInfo()), - "shared-worker" => JsonSerializer.Deserialize(ref reader, options.GetTypeInfo()), - "service-worker" => JsonSerializer.Deserialize(ref reader, options.GetTypeInfo()), - "worker" => JsonSerializer.Deserialize(ref reader, options.GetTypeInfo()), - "paint-worklet" => JsonSerializer.Deserialize(ref reader, options.GetTypeInfo()), - "audio-worklet" => JsonSerializer.Deserialize(ref reader, options.GetTypeInfo()), - "worklet" => JsonSerializer.Deserialize(ref reader, options.GetTypeInfo()), - _ => null, - }; - } - - public override void Write(Utf8JsonWriter writer, RealmInfo value, JsonSerializerOptions options) - { - throw new NotImplementedException(); - } -} diff --git a/dotnet/src/webdriver/BiDi/Json/Converters/Polymorphic/RealmInfoEventArgsConverter.cs b/dotnet/src/webdriver/BiDi/Json/Converters/Polymorphic/RealmInfoEventArgsConverter.cs deleted file mode 100644 index d8306a0cfde62..0000000000000 --- a/dotnet/src/webdriver/BiDi/Json/Converters/Polymorphic/RealmInfoEventArgsConverter.cs +++ /dev/null @@ -1,49 +0,0 @@ -// -// Licensed to the Software Freedom Conservancy (SFC) under one -// or more contributor license agreements. See the NOTICE file -// distributed with this work for additional information -// regarding copyright ownership. The SFC licenses this file -// to you under the Apache License, Version 2.0 (the -// "License"); you may not use this file except in compliance -// with the License. You may obtain a copy of the License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, -// software distributed under the License is distributed on an -// "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY -// KIND, either express or implied. See the License for the -// specific language governing permissions and limitations -// under the License. -// - -using System.Text.Json; -using System.Text.Json.Serialization; -using OpenQA.Selenium.BiDi.Script; - -namespace OpenQA.Selenium.BiDi.Json.Converters.Polymorphic; - -// https://github.com/dotnet/runtime/issues/72604 -internal class RealmInfoEventArgsConverter : JsonConverter -{ - public override RealmInfoEventArgs? Read(ref Utf8JsonReader reader, Type typeToConvert, JsonSerializerOptions options) - { - return reader.GetDiscriminator("type") switch - { - "window" => JsonSerializer.Deserialize(ref reader, options.GetTypeInfo()), - "dedicated-worker" => JsonSerializer.Deserialize(ref reader, options.GetTypeInfo()), - "shared-worker" => JsonSerializer.Deserialize(ref reader, options.GetTypeInfo()), - "service-worker" => JsonSerializer.Deserialize(ref reader, options.GetTypeInfo()), - "worker" => JsonSerializer.Deserialize(ref reader, options.GetTypeInfo()), - "paint-worklet" => JsonSerializer.Deserialize(ref reader, options.GetTypeInfo()), - "audio-worklet" => JsonSerializer.Deserialize(ref reader, options.GetTypeInfo()), - "worklet" => JsonSerializer.Deserialize(ref reader, options.GetTypeInfo()), - _ => null, - }; - } - - public override void Write(Utf8JsonWriter writer, RealmInfoEventArgs value, JsonSerializerOptions options) - { - throw new NotImplementedException(); - } -} diff --git a/dotnet/src/webdriver/BiDi/Json/Converters/Polymorphic/RemoteValueConverter.cs b/dotnet/src/webdriver/BiDi/Json/Converters/Polymorphic/RemoteValueConverter.cs deleted file mode 100644 index e50e96048cc2f..0000000000000 --- a/dotnet/src/webdriver/BiDi/Json/Converters/Polymorphic/RemoteValueConverter.cs +++ /dev/null @@ -1,72 +0,0 @@ -// -// Licensed to the Software Freedom Conservancy (SFC) under one -// or more contributor license agreements. See the NOTICE file -// distributed with this work for additional information -// regarding copyright ownership. The SFC licenses this file -// to you under the Apache License, Version 2.0 (the -// "License"); you may not use this file except in compliance -// with the License. You may obtain a copy of the License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, -// software distributed under the License is distributed on an -// "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY -// KIND, either express or implied. See the License for the -// specific language governing permissions and limitations -// under the License. -// - -using System.Text.Json; -using System.Text.Json.Serialization; -using OpenQA.Selenium.BiDi.Script; - -namespace OpenQA.Selenium.BiDi.Json.Converters.Polymorphic; - -// https://github.com/dotnet/runtime/issues/72604 -internal class RemoteValueConverter : JsonConverter -{ - public override RemoteValue? Read(ref Utf8JsonReader reader, Type typeToConvert, JsonSerializerOptions options) - { - if (reader.TokenType == JsonTokenType.String) - { - return new StringRemoteValue(reader.GetString()!); - } - - return reader.GetDiscriminator("type") switch - { - "number" => JsonSerializer.Deserialize(ref reader, options.GetTypeInfo()), - "boolean" => JsonSerializer.Deserialize(ref reader, options.GetTypeInfo()), - "bigint" => JsonSerializer.Deserialize(ref reader, options.GetTypeInfo()), - "string" => JsonSerializer.Deserialize(ref reader, options.GetTypeInfo()), - "null" => JsonSerializer.Deserialize(ref reader, options.GetTypeInfo()), - "undefined" => JsonSerializer.Deserialize(ref reader, options.GetTypeInfo()), - "symbol" => JsonSerializer.Deserialize(ref reader, options.GetTypeInfo()), - "array" => JsonSerializer.Deserialize(ref reader, options.GetTypeInfo()), - "object" => JsonSerializer.Deserialize(ref reader, options.GetTypeInfo()), - "function" => JsonSerializer.Deserialize(ref reader, options.GetTypeInfo()), - "regexp" => JsonSerializer.Deserialize(ref reader, options.GetTypeInfo()), - "date" => JsonSerializer.Deserialize(ref reader, options.GetTypeInfo()), - "map" => JsonSerializer.Deserialize(ref reader, options.GetTypeInfo()), - "set" => JsonSerializer.Deserialize(ref reader, options.GetTypeInfo()), - "weakmap" => JsonSerializer.Deserialize(ref reader, options.GetTypeInfo()), - "weakset" => JsonSerializer.Deserialize(ref reader, options.GetTypeInfo()), - "generator" => JsonSerializer.Deserialize(ref reader, options.GetTypeInfo()), - "error" => JsonSerializer.Deserialize(ref reader, options.GetTypeInfo()), - "proxy" => JsonSerializer.Deserialize(ref reader, options.GetTypeInfo()), - "promise" => JsonSerializer.Deserialize(ref reader, options.GetTypeInfo()), - "typedarray" => JsonSerializer.Deserialize(ref reader, options.GetTypeInfo()), - "arraybuffer" => JsonSerializer.Deserialize(ref reader, options.GetTypeInfo()), - "nodelist" => JsonSerializer.Deserialize(ref reader, options.GetTypeInfo()), - "htmlcollection" => JsonSerializer.Deserialize(ref reader, options.GetTypeInfo()), - "node" => JsonSerializer.Deserialize(ref reader, options.GetTypeInfo()), - "window" => JsonSerializer.Deserialize(ref reader, options.GetTypeInfo()), - _ => null, - }; - } - - public override void Write(Utf8JsonWriter writer, RemoteValue value, JsonSerializerOptions options) - { - throw new NotImplementedException(); - } -} diff --git a/dotnet/src/webdriver/BiDi/Log/EntryAddedEventArgs.cs b/dotnet/src/webdriver/BiDi/Log/EntryAddedEventArgs.cs new file mode 100644 index 0000000000000..afe8ef6a43d68 --- /dev/null +++ b/dotnet/src/webdriver/BiDi/Log/EntryAddedEventArgs.cs @@ -0,0 +1,131 @@ +// +// Licensed to the Software Freedom Conservancy (SFC) under one +// or more contributor license agreements. See the NOTICE file +// distributed with this work for additional information +// regarding copyright ownership. The SFC licenses this file +// to you under the Apache License, Version 2.0 (the +// "License"); you may not use this file except in compliance +// with the License. You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, +// software distributed under the License is distributed on an +// "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY +// KIND, either express or implied. See the License for the +// specific language governing permissions and limitations +// under the License. +// + +using System.Text.Json; +using System.Text.Json.Serialization; +using OpenQA.Selenium.BiDi.Json; +using OpenQA.Selenium.BiDi.Json.Converters; + +namespace OpenQA.Selenium.BiDi.Log; + +public abstract record EntryAddedEventArgs( + IBiDi BiDi, + Level Level, + Script.Source Source, + string? Text, + DateTimeOffset Timestamp) + : EventArgs(BiDi) +{ + public Script.StackTrace? StackTrace { get; init; } +} + +public sealed record GenericEntryAddedEventArgs( + IBiDi BiDi, + string Type, + Level Level, + Script.Source Source, + string? Text, + DateTimeOffset Timestamp) + : EntryAddedEventArgs(BiDi, Level, Source, Text, Timestamp); + +public sealed record ConsoleEntryAddedEventArgs( + IBiDi BiDi, + Level Level, + Script.Source Source, + string? Text, + DateTimeOffset Timestamp, + string Method, + IReadOnlyList Args) + : EntryAddedEventArgs(BiDi, Level, Source, Text, Timestamp); + +public sealed record JavascriptEntryAddedEventArgs( + IBiDi BiDi, + Level Level, + Script.Source Source, + string? Text, + DateTimeOffset Timestamp) + : EntryAddedEventArgs(BiDi, Level, Source, Text, Timestamp); + +[JsonConverter(typeof(CamelCaseEnumConverter))] +public enum Level +{ + Debug, + Info, + Warn, + Error +} + +// https://github.com/dotnet/runtime/issues/72604 +//[JsonPolymorphic(TypeDiscriminatorPropertyName = "type")] +//[JsonDerivedType(typeof(GenericLogEntry))] +//[JsonDerivedType(typeof(ConsoleLogEntry), "console")] +//[JsonDerivedType(typeof(JavascriptLogEntry), "javascript")] +[JsonConverter(typeof(LogEntryConverter))] +internal abstract record LogEntry( + Level Level, + Script.Source Source, + string? Text, + DateTimeOffset Timestamp) +{ + public Script.StackTrace? StackTrace { get; init; } +} + +internal sealed record GenericLogEntry( + string Type, + Level Level, + Script.Source Source, + string? Text, + DateTimeOffset Timestamp) + : LogEntry(Level, Source, Text, Timestamp); + +internal sealed record ConsoleLogEntry( + Level Level, + Script.Source Source, + string? Text, + DateTimeOffset Timestamp, + string Method, + IReadOnlyList Args) + : LogEntry(Level, Source, Text, Timestamp); + +internal sealed record JavascriptLogEntry( + Level Level, + Script.Source Source, + string? Text, + DateTimeOffset Timestamp) + : LogEntry(Level, Source, Text, Timestamp); + + +// https://github.com/dotnet/runtime/issues/72604 +internal class LogEntryConverter : JsonConverter +{ + public override LogEntry? Read(ref Utf8JsonReader reader, Type typeToConvert, JsonSerializerOptions options) + { + return reader.GetDiscriminator("type") switch + { + "console" => JsonSerializer.Deserialize(ref reader, options.GetTypeInfo()), + "javascript" => JsonSerializer.Deserialize(ref reader, options.GetTypeInfo()), + _ => JsonSerializer.Deserialize(ref reader, options.GetTypeInfo()), + }; + } + + public override void Write(Utf8JsonWriter writer, LogEntry value, JsonSerializerOptions options) + { + throw new NotImplementedException(); + } +} diff --git a/dotnet/src/webdriver/BiDi/Log/ILogModule.cs b/dotnet/src/webdriver/BiDi/Log/ILogModule.cs index 8accd921ccf56..7cc72781e490c 100644 --- a/dotnet/src/webdriver/BiDi/Log/ILogModule.cs +++ b/dotnet/src/webdriver/BiDi/Log/ILogModule.cs @@ -21,6 +21,6 @@ namespace OpenQA.Selenium.BiDi.Log; public interface ILogModule { - Task OnEntryAddedAsync(Func handler, SubscriptionOptions? options = null, CancellationToken cancellationToken = default); - Task OnEntryAddedAsync(Action handler, SubscriptionOptions? options = null, CancellationToken cancellationToken = default); + Task OnEntryAddedAsync(Func handler, SubscriptionOptions? options = null, CancellationToken cancellationToken = default); + Task OnEntryAddedAsync(Action handler, SubscriptionOptions? options = null, CancellationToken cancellationToken = default); } diff --git a/dotnet/src/webdriver/BiDi/Log/LogEntryEventArgs.cs b/dotnet/src/webdriver/BiDi/Log/LogEntryEventArgs.cs deleted file mode 100644 index 1f0d6c4e9aa62..0000000000000 --- a/dotnet/src/webdriver/BiDi/Log/LogEntryEventArgs.cs +++ /dev/null @@ -1,54 +0,0 @@ -// -// Licensed to the Software Freedom Conservancy (SFC) under one -// or more contributor license agreements. See the NOTICE file -// distributed with this work for additional information -// regarding copyright ownership. The SFC licenses this file -// to you under the Apache License, Version 2.0 (the -// "License"); you may not use this file except in compliance -// with the License. You may obtain a copy of the License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, -// software distributed under the License is distributed on an -// "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY -// KIND, either express or implied. See the License for the -// specific language governing permissions and limitations -// under the License. -// - -using System.Text.Json.Serialization; -using OpenQA.Selenium.BiDi.Json.Converters; -using OpenQA.Selenium.BiDi.Json.Converters.Polymorphic; - -namespace OpenQA.Selenium.BiDi.Log; - -// https://github.com/dotnet/runtime/issues/72604 -//[JsonPolymorphic(TypeDiscriminatorPropertyName = "type")] -//[JsonDerivedType(typeof(GenericLogEntryEventArgs))] -//[JsonDerivedType(typeof(ConsoleLogEntryEventArgs), "console")] -//[JsonDerivedType(typeof(JavascriptLogEntryEventArgs), "javascript")] -[JsonConverter(typeof(LogEntryEventArgsConverter))] -public abstract record LogEntryEventArgs(Level Level, Script.Source Source, string? Text, DateTimeOffset Timestamp) - : EventArgs -{ - public Script.StackTrace? StackTrace { get; init; } -} - -public sealed record GenericLogEntryEventArgs(string Type, Level Level, Script.Source Source, string? Text, DateTimeOffset Timestamp) - : LogEntryEventArgs(Level, Source, Text, Timestamp); - -public sealed record ConsoleLogEntryEventArgs(Level Level, Script.Source Source, string? Text, DateTimeOffset Timestamp, string Method, IReadOnlyList Args) - : LogEntryEventArgs(Level, Source, Text, Timestamp); - -public sealed record JavascriptLogEntryEventArgs(Level Level, Script.Source Source, string? Text, DateTimeOffset Timestamp) - : LogEntryEventArgs(Level, Source, Text, Timestamp); - -[JsonConverter(typeof(CamelCaseEnumConverter))] -public enum Level -{ - Debug, - Info, - Warn, - Error -} diff --git a/dotnet/src/webdriver/BiDi/Log/LogModule.cs b/dotnet/src/webdriver/BiDi/Log/LogModule.cs index 66cb735dce597..da84cd4edcf82 100644 --- a/dotnet/src/webdriver/BiDi/Log/LogModule.cs +++ b/dotnet/src/webdriver/BiDi/Log/LogModule.cs @@ -27,16 +27,24 @@ public sealed class LogModule : Module, ILogModule { private LogJsonSerializerContext _jsonContext = null!; - public async Task OnEntryAddedAsync(Func handler, SubscriptionOptions? options = null, CancellationToken cancellationToken = default) + public async Task OnEntryAddedAsync(Func handler, SubscriptionOptions? options = null, CancellationToken cancellationToken = default) { - return await SubscribeAsync("log.entryAdded", handler, options, _jsonContext.LogEntryEventArgs, cancellationToken).ConfigureAwait(false); + return await SubscribeAsync("log.entryAdded", handler, CreateEntryAddedEventArgs, options, _jsonContext.LogEntry, cancellationToken).ConfigureAwait(false); } - public async Task OnEntryAddedAsync(Action handler, SubscriptionOptions? options = null, CancellationToken cancellationToken = default) + public async Task OnEntryAddedAsync(Action handler, SubscriptionOptions? options = null, CancellationToken cancellationToken = default) { - return await SubscribeAsync("log.entryAdded", handler, options, _jsonContext.LogEntryEventArgs, cancellationToken).ConfigureAwait(false); + return await SubscribeAsync("log.entryAdded", handler, CreateEntryAddedEventArgs, options, _jsonContext.LogEntry, cancellationToken).ConfigureAwait(false); } + private static EntryAddedEventArgs CreateEntryAddedEventArgs(IBiDi bidi, LogEntry p) => p switch + { + ConsoleLogEntry c => new ConsoleEntryAddedEventArgs(bidi, c.Level, c.Source, c.Text, c.Timestamp, c.Method, c.Args) { StackTrace = c.StackTrace }, + JavascriptLogEntry j => new JavascriptEntryAddedEventArgs(bidi, j.Level, j.Source, j.Text, j.Timestamp) { StackTrace = j.StackTrace }, + GenericLogEntry g => new GenericEntryAddedEventArgs(bidi, g.Type, g.Level, g.Source, g.Text, g.Timestamp) { StackTrace = g.StackTrace }, + _ => throw new BiDiException($"Unknown {nameof(LogEntry)} type: {p.GetType()}") + }; + protected override void Initialize(IBiDi bidi, JsonSerializerOptions jsonSerializerOptions) { jsonSerializerOptions.Converters.Add(new BrowsingContextConverter(bidi)); @@ -78,12 +86,10 @@ protected override void Initialize(IBiDi bidi, JsonSerializerOptions jsonSeriali [JsonSerializable(typeof(Script.WindowProxyRemoteValue))] #endregion -[JsonSerializable(typeof(LogEntryEventArgs))] - -#region https://github.com/dotnet/runtime/issues/72604 -[JsonSerializable(typeof(GenericLogEntryEventArgs))] -[JsonSerializable(typeof(ConsoleLogEntryEventArgs))] -[JsonSerializable(typeof(JavascriptLogEntryEventArgs))] -#endregion +[JsonSerializable(typeof(LogEntry))] +// https://github.com/dotnet/runtime/issues/72604 +[JsonSerializable(typeof(GenericLogEntry))] +[JsonSerializable(typeof(ConsoleLogEntry))] +[JsonSerializable(typeof(JavascriptLogEntry))] internal partial class LogJsonSerializerContext : JsonSerializerContext; diff --git a/dotnet/src/webdriver/BiDi/Module.cs b/dotnet/src/webdriver/BiDi/Module.cs index bb94bdb901cd7..7eadf7bd42a70 100644 --- a/dotnet/src/webdriver/BiDi/Module.cs +++ b/dotnet/src/webdriver/BiDi/Module.cs @@ -33,18 +33,16 @@ protected Task ExecuteCommandAsync(TCommand command, return Broker.ExecuteCommandAsync(command, options, jsonCommandTypeInfo, jsonResultTypeInfo, cancellationToken); } - protected Task SubscribeAsync(string eventName, Action action, SubscriptionOptions? options, JsonTypeInfo jsonTypeInfo, CancellationToken cancellationToken) + protected Task SubscribeAsync(string name, Action action, Func factory, SubscriptionOptions? options, JsonTypeInfo jsonTypeInfo, CancellationToken cancellationToken) where TEventArgs : EventArgs { - var eventHandler = new SyncEventHandler(eventName, action); - return Broker.SubscribeAsync(eventName, eventHandler, options, jsonTypeInfo, cancellationToken); + return Broker.SubscribeAsync(name, action, factory, options, jsonTypeInfo, cancellationToken); } - protected Task SubscribeAsync(string eventName, Func func, SubscriptionOptions? options, JsonTypeInfo jsonTypeInfo, CancellationToken cancellationToken) + protected Task SubscribeAsync(string name, Func func, Func factory, SubscriptionOptions? options, JsonTypeInfo jsonTypeInfo, CancellationToken cancellationToken) where TEventArgs : EventArgs { - var eventHandler = new AsyncEventHandler(eventName, func); - return Broker.SubscribeAsync(eventName, eventHandler, options, jsonTypeInfo, cancellationToken); + return Broker.SubscribeAsync(name, func, factory, options, jsonTypeInfo, cancellationToken); } protected abstract void Initialize(IBiDi bidi, JsonSerializerOptions jsonSerializerOptions); diff --git a/dotnet/src/webdriver/BiDi/Network/AuthRequiredEventArgs.cs b/dotnet/src/webdriver/BiDi/Network/AuthRequiredEventArgs.cs index 0e035a903bb9b..7e26c9b4a4823 100644 --- a/dotnet/src/webdriver/BiDi/Network/AuthRequiredEventArgs.cs +++ b/dotnet/src/webdriver/BiDi/Network/AuthRequiredEventArgs.cs @@ -19,5 +19,27 @@ namespace OpenQA.Selenium.BiDi.Network; -public record AuthRequiredEventArgs(BrowsingContext.BrowsingContext? Context, bool IsBlocked, BrowsingContext.Navigation? Navigation, long RedirectCount, RequestData Request, DateTimeOffset Timestamp, ResponseData Response, IReadOnlyList? Intercepts) : - BaseParametersEventArgs(Context, IsBlocked, Navigation, RedirectCount, Request, Timestamp, Intercepts); +public record AuthRequiredEventArgs( + IBiDi BiDi, + BrowsingContext.BrowsingContext? Context, + bool IsBlocked, + BrowsingContext.Navigation? Navigation, + long RedirectCount, + RequestData Request, + DateTimeOffset Timestamp, + Browser.UserContext? UserContext, + IReadOnlyList? Intercepts, + ResponseData Response) + : EventArgs(BiDi); + +internal record AuthRequiredParameters( + BrowsingContext.BrowsingContext? Context, + bool IsBlocked, + BrowsingContext.Navigation? Navigation, + long RedirectCount, + RequestData Request, + DateTimeOffset Timestamp, + ResponseData Response, + Browser.UserContext? UserContext, + IReadOnlyList? Intercepts) + : BaseParameters(Context, IsBlocked, Navigation, RedirectCount, Request, Timestamp, UserContext, Intercepts); diff --git a/dotnet/src/webdriver/BiDi/Network/BaseParametersEventArgs.cs b/dotnet/src/webdriver/BiDi/Network/BaseParameters.cs similarity index 69% rename from dotnet/src/webdriver/BiDi/Network/BaseParametersEventArgs.cs rename to dotnet/src/webdriver/BiDi/Network/BaseParameters.cs index bfbbd60070638..34712058a97ef 100644 --- a/dotnet/src/webdriver/BiDi/Network/BaseParametersEventArgs.cs +++ b/dotnet/src/webdriver/BiDi/Network/BaseParameters.cs @@ -1,4 +1,4 @@ -// +// // Licensed to the Software Freedom Conservancy (SFC) under one // or more contributor license agreements. See the NOTICE file // distributed with this work for additional information @@ -19,5 +19,12 @@ namespace OpenQA.Selenium.BiDi.Network; -public abstract record BaseParametersEventArgs(BrowsingContext.BrowsingContext? Context, bool IsBlocked, BrowsingContext.Navigation? Navigation, long RedirectCount, RequestData Request, DateTimeOffset Timestamp, IReadOnlyList? Intercepts) - : EventArgs; +internal abstract record BaseParameters( + BrowsingContext.BrowsingContext? Context, + bool IsBlocked, + BrowsingContext.Navigation? Navigation, + long RedirectCount, + RequestData Request, + DateTimeOffset Timestamp, + Browser.UserContext? UserContext, + IReadOnlyList? Intercepts); diff --git a/dotnet/src/webdriver/BiDi/Network/BeforeRequestSentEventArgs.cs b/dotnet/src/webdriver/BiDi/Network/BeforeRequestSentEventArgs.cs index a96491f52bf58..693eedd3b0318 100644 --- a/dotnet/src/webdriver/BiDi/Network/BeforeRequestSentEventArgs.cs +++ b/dotnet/src/webdriver/BiDi/Network/BeforeRequestSentEventArgs.cs @@ -21,5 +21,26 @@ namespace OpenQA.Selenium.BiDi.Network; -public record BeforeRequestSentEventArgs(BrowsingContext.BrowsingContext? Context, bool IsBlocked, Navigation? Navigation, long RedirectCount, RequestData Request, DateTimeOffset Timestamp, Initiator Initiator, IReadOnlyList? Intercepts) - : BaseParametersEventArgs(Context, IsBlocked, Navigation, RedirectCount, Request, Timestamp, Intercepts); +public record BeforeRequestSentEventArgs( + IBiDi BiDi, + BrowsingContext.BrowsingContext? Context, + bool IsBlocked, + Navigation? Navigation, + long RedirectCount, + RequestData Request, + DateTimeOffset Timestamp, + Initiator Initiator, + Browser.UserContext? UserContext, + IReadOnlyList? Intercepts) : EventArgs(BiDi); + +internal record BeforeRequestSentParameters( + BrowsingContext.BrowsingContext? Context, + bool IsBlocked, + Navigation? Navigation, + long RedirectCount, + RequestData Request, + DateTimeOffset Timestamp, + Initiator Initiator, + Browser.UserContext? UserContext, + IReadOnlyList? Intercepts) + : BaseParameters(Context, IsBlocked, Navigation, RedirectCount, Request, Timestamp, UserContext, Intercepts); diff --git a/dotnet/src/webdriver/BiDi/Network/FetchErrorEventArgs.cs b/dotnet/src/webdriver/BiDi/Network/FetchErrorEventArgs.cs index e86489a6f3165..fc255124fa205 100644 --- a/dotnet/src/webdriver/BiDi/Network/FetchErrorEventArgs.cs +++ b/dotnet/src/webdriver/BiDi/Network/FetchErrorEventArgs.cs @@ -21,5 +21,27 @@ namespace OpenQA.Selenium.BiDi.Network; -public sealed record FetchErrorEventArgs(BrowsingContext.BrowsingContext? Context, bool IsBlocked, Navigation? Navigation, long RedirectCount, RequestData Request, DateTimeOffset Timestamp, string ErrorText, IReadOnlyList? Intercepts) - : BaseParametersEventArgs(Context, IsBlocked, Navigation, RedirectCount, Request, Timestamp, Intercepts); +public sealed record FetchErrorEventArgs( + IBiDi BiDi, + BrowsingContext.BrowsingContext? Context, + bool IsBlocked, + Navigation? Navigation, + long RedirectCount, + RequestData Request, + DateTimeOffset Timestamp, + string ErrorText, + Browser.UserContext? UserContext, + IReadOnlyList? Intercepts) + : EventArgs(BiDi); + +internal sealed record FetchErrorParameters( + BrowsingContext.BrowsingContext? Context, + bool IsBlocked, + Navigation? Navigation, + long RedirectCount, + RequestData Request, + DateTimeOffset Timestamp, + string ErrorText, + Browser.UserContext? UserContext, + IReadOnlyList? Intercepts) + : BaseParameters(Context, IsBlocked, Navigation, RedirectCount, Request, Timestamp, UserContext, Intercepts); diff --git a/dotnet/src/webdriver/BiDi/Network/NetworkModule.cs b/dotnet/src/webdriver/BiDi/Network/NetworkModule.cs index d9f7745dbb3b8..4779a69771a8c 100644 --- a/dotnet/src/webdriver/BiDi/Network/NetworkModule.cs +++ b/dotnet/src/webdriver/BiDi/Network/NetworkModule.cs @@ -123,54 +123,69 @@ public async Task ContinueWithAuthAsync(Request request, public async Task OnBeforeRequestSentAsync(Func handler, SubscriptionOptions? options = null, CancellationToken cancellationToken = default) { - return await SubscribeAsync("network.beforeRequestSent", handler, options, _jsonContext.BeforeRequestSentEventArgs, cancellationToken).ConfigureAwait(false); + return await SubscribeAsync("network.beforeRequestSent", handler, CreateBeforeRequestSentEventArgs, options, _jsonContext.BeforeRequestSentParameters, cancellationToken).ConfigureAwait(false); } public async Task OnBeforeRequestSentAsync(Action handler, SubscriptionOptions? options = null, CancellationToken cancellationToken = default) { - return await SubscribeAsync("network.beforeRequestSent", handler, options, _jsonContext.BeforeRequestSentEventArgs, cancellationToken).ConfigureAwait(false); + return await SubscribeAsync("network.beforeRequestSent", handler, CreateBeforeRequestSentEventArgs, options, _jsonContext.BeforeRequestSentParameters, cancellationToken).ConfigureAwait(false); } public async Task OnResponseStartedAsync(Func handler, SubscriptionOptions? options = null, CancellationToken cancellationToken = default) { - return await SubscribeAsync("network.responseStarted", handler, options, _jsonContext.ResponseStartedEventArgs, cancellationToken).ConfigureAwait(false); + return await SubscribeAsync("network.responseStarted", handler, CreateResponseStartedEventArgs, options, _jsonContext.ResponseStartedParameters, cancellationToken).ConfigureAwait(false); } public async Task OnResponseStartedAsync(Action handler, SubscriptionOptions? options = null, CancellationToken cancellationToken = default) { - return await SubscribeAsync("network.responseStarted", handler, options, _jsonContext.ResponseStartedEventArgs, cancellationToken).ConfigureAwait(false); + return await SubscribeAsync("network.responseStarted", handler, CreateResponseStartedEventArgs, options, _jsonContext.ResponseStartedParameters, cancellationToken).ConfigureAwait(false); } public async Task OnResponseCompletedAsync(Func handler, SubscriptionOptions? options = null, CancellationToken cancellationToken = default) { - return await SubscribeAsync("network.responseCompleted", handler, options, _jsonContext.ResponseCompletedEventArgs, cancellationToken).ConfigureAwait(false); + return await SubscribeAsync("network.responseCompleted", handler, CreateResponseCompletedEventArgs, options, _jsonContext.ResponseCompletedParameters, cancellationToken).ConfigureAwait(false); } public async Task OnResponseCompletedAsync(Action handler, SubscriptionOptions? options = null, CancellationToken cancellationToken = default) { - return await SubscribeAsync("network.responseCompleted", handler, options, _jsonContext.ResponseCompletedEventArgs, cancellationToken).ConfigureAwait(false); + return await SubscribeAsync("network.responseCompleted", handler, CreateResponseCompletedEventArgs, options, _jsonContext.ResponseCompletedParameters, cancellationToken).ConfigureAwait(false); } public async Task OnFetchErrorAsync(Func handler, SubscriptionOptions? options = null, CancellationToken cancellationToken = default) { - return await SubscribeAsync("network.fetchError", handler, options, _jsonContext.FetchErrorEventArgs, cancellationToken).ConfigureAwait(false); + return await SubscribeAsync("network.fetchError", handler, CreateFetchErrorEventArgs, options, _jsonContext.FetchErrorParameters, cancellationToken).ConfigureAwait(false); } public async Task OnFetchErrorAsync(Action handler, SubscriptionOptions? options = null, CancellationToken cancellationToken = default) { - return await SubscribeAsync("network.fetchError", handler, options, _jsonContext.FetchErrorEventArgs, cancellationToken).ConfigureAwait(false); + return await SubscribeAsync("network.fetchError", handler, CreateFetchErrorEventArgs, options, _jsonContext.FetchErrorParameters, cancellationToken).ConfigureAwait(false); } public async Task OnAuthRequiredAsync(Func handler, SubscriptionOptions? options = null, CancellationToken cancellationToken = default) { - return await SubscribeAsync("network.authRequired", handler, options, _jsonContext.AuthRequiredEventArgs, cancellationToken).ConfigureAwait(false); + return await SubscribeAsync("network.authRequired", handler, CreateAuthRequiredEventArgs, options, _jsonContext.AuthRequiredParameters, cancellationToken).ConfigureAwait(false); } public async Task OnAuthRequiredAsync(Action handler, SubscriptionOptions? options = null, CancellationToken cancellationToken = default) { - return await SubscribeAsync("network.authRequired", handler, options, _jsonContext.AuthRequiredEventArgs, cancellationToken).ConfigureAwait(false); + return await SubscribeAsync("network.authRequired", handler, CreateAuthRequiredEventArgs, options, _jsonContext.AuthRequiredParameters, cancellationToken).ConfigureAwait(false); } + private static BeforeRequestSentEventArgs CreateBeforeRequestSentEventArgs(IBiDi bidi, BeforeRequestSentParameters p) + => new(bidi, p.Context, p.IsBlocked, p.Navigation, p.RedirectCount, p.Request, p.Timestamp, p.Initiator, p.UserContext, p.Intercepts); + + private static ResponseStartedEventArgs CreateResponseStartedEventArgs(IBiDi bidi, ResponseStartedParameters p) + => new(bidi, p.Context, p.IsBlocked, p.Navigation, p.RedirectCount, p.Request, p.Timestamp, p.Response, p.UserContext, p.Intercepts); + + private static ResponseCompletedEventArgs CreateResponseCompletedEventArgs(IBiDi bidi, ResponseCompletedParameters p) + => new(bidi, p.Context, p.IsBlocked, p.Navigation, p.RedirectCount, p.Request, p.Timestamp, p.Response, p.UserContext, p.Intercepts); + + private static FetchErrorEventArgs CreateFetchErrorEventArgs(IBiDi bidi, FetchErrorParameters p) + => new(bidi, p.Context, p.IsBlocked, p.Navigation, p.RedirectCount, p.Request, p.Timestamp, p.ErrorText, p.UserContext, p.Intercepts); + + private static AuthRequiredEventArgs CreateAuthRequiredEventArgs(IBiDi bidi, AuthRequiredParameters p) + => new(bidi, p.Context, p.IsBlocked, p.Navigation, p.RedirectCount, p.Request, p.Timestamp, p.UserContext, p.Intercepts, p.Response); + protected override void Initialize(IBiDi bidi, JsonSerializerOptions jsonSerializerOptions) { jsonSerializerOptions.Converters.Add(new BrowsingContextConverter(bidi)); @@ -207,10 +222,10 @@ protected override void Initialize(IBiDi bidi, JsonSerializerOptions jsonSeriali [JsonSerializable(typeof(SetExtraHeadersCommand))] [JsonSerializable(typeof(SetExtraHeadersResult))] -[JsonSerializable(typeof(BeforeRequestSentEventArgs))] -[JsonSerializable(typeof(ResponseStartedEventArgs))] -[JsonSerializable(typeof(ResponseCompletedEventArgs))] -[JsonSerializable(typeof(FetchErrorEventArgs))] -[JsonSerializable(typeof(AuthRequiredEventArgs))] +[JsonSerializable(typeof(BeforeRequestSentParameters))] +[JsonSerializable(typeof(ResponseStartedParameters))] +[JsonSerializable(typeof(ResponseCompletedParameters))] +[JsonSerializable(typeof(FetchErrorParameters))] +[JsonSerializable(typeof(AuthRequiredParameters))] internal partial class NetworkJsonSerializerContext : JsonSerializerContext; diff --git a/dotnet/src/webdriver/BiDi/Network/ResponseCompletedEventArgs.cs b/dotnet/src/webdriver/BiDi/Network/ResponseCompletedEventArgs.cs index e087063c1c965..78fc1d46a3cde 100644 --- a/dotnet/src/webdriver/BiDi/Network/ResponseCompletedEventArgs.cs +++ b/dotnet/src/webdriver/BiDi/Network/ResponseCompletedEventArgs.cs @@ -22,6 +22,7 @@ namespace OpenQA.Selenium.BiDi.Network; public sealed record ResponseCompletedEventArgs( + IBiDi BiDi, BrowsingContext.BrowsingContext? Context, bool IsBlocked, Navigation? Navigation, @@ -29,5 +30,18 @@ public sealed record ResponseCompletedEventArgs( RequestData Request, DateTimeOffset Timestamp, ResponseData Response, + Browser.UserContext? UserContext, IReadOnlyList? Intercepts) - : BaseParametersEventArgs(Context, IsBlocked, Navigation, RedirectCount, Request, Timestamp, Intercepts); + : EventArgs(BiDi); + +internal sealed record ResponseCompletedParameters( + BrowsingContext.BrowsingContext? Context, + bool IsBlocked, + Navigation? Navigation, + long RedirectCount, + RequestData Request, + DateTimeOffset Timestamp, + Browser.UserContext? UserContext, + IReadOnlyList? Intercepts, + ResponseData Response) + : BaseParameters(Context, IsBlocked, Navigation, RedirectCount, Request, Timestamp, UserContext, Intercepts); diff --git a/dotnet/src/webdriver/BiDi/Network/ResponseStartedEventArgs.cs b/dotnet/src/webdriver/BiDi/Network/ResponseStartedEventArgs.cs index 55088b2abf6f1..a6f81db8fc1ee 100644 --- a/dotnet/src/webdriver/BiDi/Network/ResponseStartedEventArgs.cs +++ b/dotnet/src/webdriver/BiDi/Network/ResponseStartedEventArgs.cs @@ -22,6 +22,7 @@ namespace OpenQA.Selenium.BiDi.Network; public record ResponseStartedEventArgs( + IBiDi BiDi, BrowsingContext.BrowsingContext? Context, bool IsBlocked, Navigation? Navigation, @@ -29,5 +30,18 @@ public record ResponseStartedEventArgs( RequestData Request, DateTimeOffset Timestamp, ResponseData Response, + Browser.UserContext? UserContext, IReadOnlyList? Intercepts) - : BaseParametersEventArgs(Context, IsBlocked, Navigation, RedirectCount, Request, Timestamp, Intercepts); + : EventArgs(BiDi); + +internal record ResponseStartedParameters( + BrowsingContext.BrowsingContext? Context, + bool IsBlocked, + Navigation? Navigation, + long RedirectCount, + RequestData Request, + DateTimeOffset Timestamp, + ResponseData Response, + Browser.UserContext? UserContext, + IReadOnlyList? Intercepts) + : BaseParameters(Context, IsBlocked, Navigation, RedirectCount, Request, Timestamp, UserContext, Intercepts); diff --git a/dotnet/src/webdriver/BiDi/Script/EvaluateCommand.cs b/dotnet/src/webdriver/BiDi/Script/EvaluateCommand.cs index f719c9c553ef7..0f7488eae03df 100644 --- a/dotnet/src/webdriver/BiDi/Script/EvaluateCommand.cs +++ b/dotnet/src/webdriver/BiDi/Script/EvaluateCommand.cs @@ -17,16 +17,22 @@ // under the License. // -using System.Diagnostics.CodeAnalysis; +using System.Text.Json; using System.Text.Json.Serialization; -using OpenQA.Selenium.BiDi.Json.Converters.Polymorphic; +using OpenQA.Selenium.BiDi.Json; namespace OpenQA.Selenium.BiDi.Script; internal sealed class EvaluateCommand(EvaluateParameters @params) : Command(@params, "script.evaluate"); -internal sealed record EvaluateParameters([StringSyntax(StringSyntaxConstants.JavaScript)] string Expression, Target Target, bool AwaitPromise, ResultOwnership? ResultOwnership, SerializationOptions? SerializationOptions, bool? UserActivation) : Parameters; +internal sealed record EvaluateParameters( + string Expression, + Target Target, + bool AwaitPromise, + ResultOwnership? ResultOwnership, + SerializationOptions? SerializationOptions, + bool? UserActivation) : Parameters; public sealed record EvaluateOptions : CommandOptions { @@ -51,15 +57,43 @@ public RemoteValue AsSuccessResult() return success.Result; } - throw new InvalidCastException($"Expected the result to be {nameof(EvaluateResultSuccess)}, but received {this}"); + throw new InvalidCastException($"Expected the result to be {nameof(EvaluateResultSuccess)}, but got {this}"); } } -public sealed record EvaluateResultSuccess(RemoteValue Result, Realm Realm) : EvaluateResult +public sealed record EvaluateResultSuccess( + RemoteValue Result, + Realm Realm) : EvaluateResult { - public static implicit operator RemoteValue(EvaluateResultSuccess success) => success.Result; + public static implicit operator RemoteValue(EvaluateResultSuccess success) + => success.Result; } -public sealed record EvaluateResultException(ExceptionDetails ExceptionDetails, Realm Realm) : EvaluateResult; +public sealed record EvaluateResultException( + ExceptionDetails ExceptionDetails, + Realm Realm) : EvaluateResult; -public sealed record ExceptionDetails(long ColumnNumber, long LineNumber, StackTrace StackTrace, string Text); +public sealed record ExceptionDetails( + long ColumnNumber, + long LineNumber, + StackTrace StackTrace, + string Text); + +// https://github.com/dotnet/runtime/issues/72604 +internal class EvaluateResultConverter : JsonConverter +{ + public override EvaluateResult? Read(ref Utf8JsonReader reader, Type typeToConvert, JsonSerializerOptions options) + { + return reader.GetDiscriminator("type") switch + { + "success" => JsonSerializer.Deserialize(ref reader, options.GetTypeInfo()), + "exception" => JsonSerializer.Deserialize(ref reader, options.GetTypeInfo()), + _ => null, + }; + } + + public override void Write(Utf8JsonWriter writer, EvaluateResult value, JsonSerializerOptions options) + { + throw new NotImplementedException(); + } +} diff --git a/dotnet/src/webdriver/BiDi/Script/IScriptModule.cs b/dotnet/src/webdriver/BiDi/Script/IScriptModule.cs index 1a473a619fd37..d3775a43217ec 100644 --- a/dotnet/src/webdriver/BiDi/Script/IScriptModule.cs +++ b/dotnet/src/webdriver/BiDi/Script/IScriptModule.cs @@ -32,8 +32,8 @@ public interface IScriptModule Task GetRealmsAsync(GetRealmsOptions? options = null, CancellationToken cancellationToken = default); Task OnMessageAsync(Func handler, SubscriptionOptions? options = null, CancellationToken cancellationToken = default); Task OnMessageAsync(Action handler, SubscriptionOptions? options = null, CancellationToken cancellationToken = default); - Task OnRealmCreatedAsync(Func handler, SubscriptionOptions? options = null, CancellationToken cancellationToken = default); - Task OnRealmCreatedAsync(Action handler, SubscriptionOptions? options = null, CancellationToken cancellationToken = default); + Task OnRealmCreatedAsync(Func handler, SubscriptionOptions? options = null, CancellationToken cancellationToken = default); + Task OnRealmCreatedAsync(Action handler, SubscriptionOptions? options = null, CancellationToken cancellationToken = default); Task OnRealmDestroyedAsync(Func handler, SubscriptionOptions? options = null, CancellationToken cancellationToken = default); Task OnRealmDestroyedAsync(Action handler, SubscriptionOptions? options = null, CancellationToken cancellationToken = default); Task RemovePreloadScriptAsync(PreloadScript script, RemovePreloadScriptOptions? options = null, CancellationToken cancellationToken = default); diff --git a/dotnet/src/webdriver/BiDi/Script/MessageEventArgs.cs b/dotnet/src/webdriver/BiDi/Script/MessageEventArgs.cs index fd49c6c677f1a..96c72723f991b 100644 --- a/dotnet/src/webdriver/BiDi/Script/MessageEventArgs.cs +++ b/dotnet/src/webdriver/BiDi/Script/MessageEventArgs.cs @@ -19,4 +19,13 @@ namespace OpenQA.Selenium.BiDi.Script; -public sealed record MessageEventArgs(Channel Channel, RemoteValue Data, Source Source) : EventArgs; +public sealed record MessageEventArgs( + IBiDi BiDi, + Channel Channel, + RemoteValue Data, + Source Source) : EventArgs(BiDi); + +internal sealed record MessageParameters( + Channel Channel, + RemoteValue Data, + Source Source); diff --git a/dotnet/src/webdriver/BiDi/Script/RealmDestroyedEventArgs.cs b/dotnet/src/webdriver/BiDi/Script/RealmDestroyedEventArgs.cs index 5d840a7be6d97..707ebcb77d152 100644 --- a/dotnet/src/webdriver/BiDi/Script/RealmDestroyedEventArgs.cs +++ b/dotnet/src/webdriver/BiDi/Script/RealmDestroyedEventArgs.cs @@ -19,4 +19,8 @@ namespace OpenQA.Selenium.BiDi.Script; -public sealed record RealmDestroyedEventArgs(Realm Realm) : EventArgs; +public sealed record RealmDestroyedEventArgs( + IBiDi BiDi, + Realm Realm) : EventArgs(BiDi); + +internal sealed record RealmDestroyedParameters(Realm Realm); diff --git a/dotnet/src/webdriver/BiDi/Script/RealmInfo.cs b/dotnet/src/webdriver/BiDi/Script/RealmInfo.cs index 448e6e70c0e25..2081b841669ca 100644 --- a/dotnet/src/webdriver/BiDi/Script/RealmInfo.cs +++ b/dotnet/src/webdriver/BiDi/Script/RealmInfo.cs @@ -17,8 +17,9 @@ // under the License. // +using System.Text.Json; using System.Text.Json.Serialization; -using OpenQA.Selenium.BiDi.Json.Converters.Polymorphic; +using OpenQA.Selenium.BiDi.Json; namespace OpenQA.Selenium.BiDi.Script; @@ -33,25 +34,72 @@ namespace OpenQA.Selenium.BiDi.Script; //[JsonDerivedType(typeof(AudioWorkletRealmInfo), "audio-worklet")] //[JsonDerivedType(typeof(WorkletRealmInfo), "worklet")] [JsonConverter(typeof(RealmInfoConverter))] -public abstract record RealmInfo(Realm Realm, string Origin); +public abstract record RealmInfo( + Realm Realm, + string Origin); -public sealed record WindowRealmInfo(Realm Realm, string Origin, BrowsingContext.BrowsingContext Context) : RealmInfo(Realm, Origin) +public sealed record WindowRealmInfo( + Realm Realm, + string Origin, + BrowsingContext.BrowsingContext Context) : RealmInfo(Realm, Origin) { public Browser.UserContext? UserContext { get; init; } public string? Sandbox { get; init; } } -public sealed record DedicatedWorkerRealmInfo(Realm Realm, string Origin, IReadOnlyList Owners) : RealmInfo(Realm, Origin); +public sealed record DedicatedWorkerRealmInfo( + Realm Realm, + string Origin, + IReadOnlyList Owners) : RealmInfo(Realm, Origin); -public sealed record SharedWorkerRealmInfo(Realm Realm, string Origin) : RealmInfo(Realm, Origin); +public sealed record SharedWorkerRealmInfo( + Realm Realm, + string Origin) : RealmInfo(Realm, Origin); -public sealed record ServiceWorkerRealmInfo(Realm Realm, string Origin) : RealmInfo(Realm, Origin); +public sealed record ServiceWorkerRealmInfo( + Realm Realm, + string Origin) : RealmInfo(Realm, Origin); -public sealed record WorkerRealmInfo(Realm Realm, string Origin) : RealmInfo(Realm, Origin); +public sealed record WorkerRealmInfo( + Realm Realm, + string Origin) : RealmInfo(Realm, Origin); -public sealed record PaintWorkletRealmInfo(Realm Realm, string Origin) : RealmInfo(Realm, Origin); +public sealed record PaintWorkletRealmInfo( + Realm Realm, + string Origin) : RealmInfo(Realm, Origin); -public sealed record AudioWorkletRealmInfo(Realm Realm, string Origin) : RealmInfo(Realm, Origin); +public sealed record AudioWorkletRealmInfo( + Realm Realm, + string Origin) : RealmInfo(Realm, Origin); -public sealed record WorkletRealmInfo(Realm Realm, string Origin) : RealmInfo(Realm, Origin); +public sealed record WorkletRealmInfo( + Realm Realm, + string Origin) : RealmInfo(Realm, Origin); + +// https://github.com/dotnet/runtime/issues/72604 +internal class RealmInfoConverter : JsonConverter +{ + public override RealmInfo? Read(ref Utf8JsonReader reader, Type typeToConvert, JsonSerializerOptions options) + { + var type = reader.GetDiscriminator("type"); + + return type switch + { + "window" => JsonSerializer.Deserialize(ref reader, options.GetTypeInfo()), + "dedicated-worker" => JsonSerializer.Deserialize(ref reader, options.GetTypeInfo()), + "shared-worker" => JsonSerializer.Deserialize(ref reader, options.GetTypeInfo()), + "service-worker" => JsonSerializer.Deserialize(ref reader, options.GetTypeInfo()), + "worker" => JsonSerializer.Deserialize(ref reader, options.GetTypeInfo()), + "paint-worklet" => JsonSerializer.Deserialize(ref reader, options.GetTypeInfo()), + "audio-worklet" => JsonSerializer.Deserialize(ref reader, options.GetTypeInfo()), + "worklet" => JsonSerializer.Deserialize(ref reader, options.GetTypeInfo()), + _ => throw new BiDiException($"Unknown realm type '{type}'") + }; + } + + public override void Write(Utf8JsonWriter writer, RealmInfo value, JsonSerializerOptions options) + { + throw new NotImplementedException(); + } +} diff --git a/dotnet/src/webdriver/BiDi/Script/RealmInfoEventArgs.cs b/dotnet/src/webdriver/BiDi/Script/RealmInfoEventArgs.cs index 80ebdbfd02add..0d8663d020ad2 100644 --- a/dotnet/src/webdriver/BiDi/Script/RealmInfoEventArgs.cs +++ b/dotnet/src/webdriver/BiDi/Script/RealmInfoEventArgs.cs @@ -17,36 +17,53 @@ // under the License. // -using System.Text.Json.Serialization; -using OpenQA.Selenium.BiDi.Json.Converters.Polymorphic; - namespace OpenQA.Selenium.BiDi.Script; -// https://github.com/dotnet/runtime/issues/72604 -// [JsonPolymorphic(TypeDiscriminatorPropertyName = "type")] -// [JsonDerivedType(typeof(WindowRealmInfoEventArgs), "window")] -// [JsonDerivedType(typeof(DedicatedWorkerRealmInfoEventArgs), "dedicated-worker")] -// [JsonDerivedType(typeof(SharedWorkerRealmInfoEventArgs), "shared-worker")] -// [JsonDerivedType(typeof(ServiceWorkerRealmInfoEventArgs), "service-worker")] -// [JsonDerivedType(typeof(WorkerRealmInfoEventArgs), "worker")] -// [JsonDerivedType(typeof(PaintWorkletRealmInfoEventArgs), "paint-worklet")] -// [JsonDerivedType(typeof(AudioWorkletRealmInfoEventArgs), "audio-worklet")] -// [JsonDerivedType(typeof(WorkletRealmInfoEventArgs), "worklet")] -[JsonConverter(typeof(RealmInfoEventArgsConverter))] -public abstract record RealmInfoEventArgs(Realm Realm, string Origin) : EventArgs; +public abstract record RealmCreatedEventArgs( + IBiDi BiDi, + Realm Realm, + string Origin) : EventArgs(BiDi); -public sealed record WindowRealmInfoEventArgs(Realm Realm, string Origin, BrowsingContext.BrowsingContext Context, Browser.UserContext? UserContext, string? Sandbox) : RealmInfoEventArgs(Realm, Origin); +public sealed record WindowRealmCreatedEventArgs( + IBiDi BiDi, + Realm Realm, + string Origin, + BrowsingContext.BrowsingContext Context, + Browser.UserContext? UserContext, + string? Sandbox) : RealmCreatedEventArgs(BiDi, Realm, Origin); -public sealed record DedicatedWorkerRealmInfoEventArgs(Realm Realm, string Origin, IReadOnlyList Owners) : RealmInfoEventArgs(Realm, Origin); +public sealed record DedicatedWorkerRealmCreatedEventArgs( + IBiDi BiDi, + Realm Realm, + string Origin, + IReadOnlyList Owners) : RealmCreatedEventArgs(BiDi, Realm, Origin); -public sealed record SharedWorkerRealmInfoEventArgs(Realm Realm, string Origin) : RealmInfoEventArgs(Realm, Origin); +public sealed record SharedWorkerRealmCreatedEventArgs( + IBiDi BiDi, + Realm Realm, + string Origin) : RealmCreatedEventArgs(BiDi, Realm, Origin); -public sealed record ServiceWorkerRealmInfoEventArgs(Realm Realm, string Origin) : RealmInfoEventArgs(Realm, Origin); +public sealed record ServiceWorkerRealmCreatedEventArgs( + IBiDi BiDi, + Realm Realm, + string Origin) : RealmCreatedEventArgs(BiDi, Realm, Origin); -public sealed record WorkerRealmInfoEventArgs(Realm Realm, string Origin) : RealmInfoEventArgs(Realm, Origin); +public sealed record WorkerRealmCreatedEventArgs( + IBiDi BiDi, + Realm Realm, + string Origin) : RealmCreatedEventArgs(BiDi, Realm, Origin); -public sealed record PaintWorkletRealmInfoEventArgs(Realm Realm, string Origin) : RealmInfoEventArgs(Realm, Origin); +public sealed record PaintWorkletRealmCreatedEventArgs( + IBiDi BiDi, + Realm Realm, + string Origin) : RealmCreatedEventArgs(BiDi, Realm, Origin); -public sealed record AudioWorkletRealmInfoEventArgs(Realm Realm, string Origin) : RealmInfoEventArgs(Realm, Origin); +public sealed record AudioWorkletRealmCreatedEventArgs( + IBiDi BiDi, + Realm Realm, + string Origin) : RealmCreatedEventArgs(BiDi, Realm, Origin); -public sealed record WorkletRealmInfoEventArgs(Realm Realm, string Origin) : RealmInfoEventArgs(Realm, Origin); +public sealed record WorkletRealmCreatedEventArgs( + IBiDi BiDi, + Realm Realm, + string Origin) : RealmCreatedEventArgs(BiDi, Realm, Origin); diff --git a/dotnet/src/webdriver/BiDi/Script/RemoteValue.cs b/dotnet/src/webdriver/BiDi/Script/RemoteValue.cs index a567009a5895a..530fcc7839904 100644 --- a/dotnet/src/webdriver/BiDi/Script/RemoteValue.cs +++ b/dotnet/src/webdriver/BiDi/Script/RemoteValue.cs @@ -17,9 +17,10 @@ // under the License. // +using System.Text.Json; using System.Text.Json.Serialization; +using OpenQA.Selenium.BiDi.Json; using OpenQA.Selenium.BiDi.Json.Converters; -using OpenQA.Selenium.BiDi.Json.Converters.Polymorphic; namespace OpenQA.Selenium.BiDi.Script; @@ -354,3 +355,52 @@ public enum Mode Open, Closed } + + +// https://github.com/dotnet/runtime/issues/72604 +internal class RemoteValueConverter : JsonConverter +{ + public override RemoteValue? Read(ref Utf8JsonReader reader, Type typeToConvert, JsonSerializerOptions options) + { + if (reader.TokenType == JsonTokenType.String) + { + return new StringRemoteValue(reader.GetString()!); + } + + return reader.GetDiscriminator("type") switch + { + "number" => JsonSerializer.Deserialize(ref reader, options.GetTypeInfo()), + "boolean" => JsonSerializer.Deserialize(ref reader, options.GetTypeInfo()), + "bigint" => JsonSerializer.Deserialize(ref reader, options.GetTypeInfo()), + "string" => JsonSerializer.Deserialize(ref reader, options.GetTypeInfo()), + "null" => JsonSerializer.Deserialize(ref reader, options.GetTypeInfo()), + "undefined" => JsonSerializer.Deserialize(ref reader, options.GetTypeInfo()), + "symbol" => JsonSerializer.Deserialize(ref reader, options.GetTypeInfo()), + "array" => JsonSerializer.Deserialize(ref reader, options.GetTypeInfo()), + "object" => JsonSerializer.Deserialize(ref reader, options.GetTypeInfo()), + "function" => JsonSerializer.Deserialize(ref reader, options.GetTypeInfo()), + "regexp" => JsonSerializer.Deserialize(ref reader, options.GetTypeInfo()), + "date" => JsonSerializer.Deserialize(ref reader, options.GetTypeInfo()), + "map" => JsonSerializer.Deserialize(ref reader, options.GetTypeInfo()), + "set" => JsonSerializer.Deserialize(ref reader, options.GetTypeInfo()), + "weakmap" => JsonSerializer.Deserialize(ref reader, options.GetTypeInfo()), + "weakset" => JsonSerializer.Deserialize(ref reader, options.GetTypeInfo()), + "generator" => JsonSerializer.Deserialize(ref reader, options.GetTypeInfo()), + "error" => JsonSerializer.Deserialize(ref reader, options.GetTypeInfo()), + "proxy" => JsonSerializer.Deserialize(ref reader, options.GetTypeInfo()), + "promise" => JsonSerializer.Deserialize(ref reader, options.GetTypeInfo()), + "typedarray" => JsonSerializer.Deserialize(ref reader, options.GetTypeInfo()), + "arraybuffer" => JsonSerializer.Deserialize(ref reader, options.GetTypeInfo()), + "nodelist" => JsonSerializer.Deserialize(ref reader, options.GetTypeInfo()), + "htmlcollection" => JsonSerializer.Deserialize(ref reader, options.GetTypeInfo()), + "node" => JsonSerializer.Deserialize(ref reader, options.GetTypeInfo()), + "window" => JsonSerializer.Deserialize(ref reader, options.GetTypeInfo()), + _ => null, + }; + } + + public override void Write(Utf8JsonWriter writer, RemoteValue value, JsonSerializerOptions options) + { + throw new NotImplementedException(); + } +} diff --git a/dotnet/src/webdriver/BiDi/Script/ScriptModule.cs b/dotnet/src/webdriver/BiDi/Script/ScriptModule.cs index 07be9238d2568..0e10bf8a212f1 100644 --- a/dotnet/src/webdriver/BiDi/Script/ScriptModule.cs +++ b/dotnet/src/webdriver/BiDi/Script/ScriptModule.cs @@ -86,34 +86,53 @@ public async Task RemovePreloadScriptAsync(PreloadScr public async Task OnMessageAsync(Func handler, SubscriptionOptions? options = null, CancellationToken cancellationToken = default) { - return await SubscribeAsync("script.message", handler, options, _jsonContext.MessageEventArgs, cancellationToken).ConfigureAwait(false); + return await SubscribeAsync("script.message", handler, CreateMessageEventArgs, options, _jsonContext.MessageParameters, cancellationToken).ConfigureAwait(false); } public async Task OnMessageAsync(Action handler, SubscriptionOptions? options = null, CancellationToken cancellationToken = default) { - return await SubscribeAsync("script.message", handler, options, _jsonContext.MessageEventArgs, cancellationToken).ConfigureAwait(false); + return await SubscribeAsync("script.message", handler, CreateMessageEventArgs, options, _jsonContext.MessageParameters, cancellationToken).ConfigureAwait(false); } - public async Task OnRealmCreatedAsync(Func handler, SubscriptionOptions? options = null, CancellationToken cancellationToken = default) + public async Task OnRealmCreatedAsync(Func handler, SubscriptionOptions? options = null, CancellationToken cancellationToken = default) { - return await SubscribeAsync("script.realmCreated", handler, options, _jsonContext.RealmInfoEventArgs, cancellationToken).ConfigureAwait(false); + return await SubscribeAsync("script.realmCreated", handler, CreateRealmCreatedEventArgs, options, _jsonContext.RealmInfo, cancellationToken).ConfigureAwait(false); } - public async Task OnRealmCreatedAsync(Action handler, SubscriptionOptions? options = null, CancellationToken cancellationToken = default) + public async Task OnRealmCreatedAsync(Action handler, SubscriptionOptions? options = null, CancellationToken cancellationToken = default) { - return await SubscribeAsync("script.realmCreated", handler, options, _jsonContext.RealmInfoEventArgs, cancellationToken).ConfigureAwait(false); + return await SubscribeAsync("script.realmCreated", handler, CreateRealmCreatedEventArgs, options, _jsonContext.RealmInfo, cancellationToken).ConfigureAwait(false); } public async Task OnRealmDestroyedAsync(Func handler, SubscriptionOptions? options = null, CancellationToken cancellationToken = default) { - return await SubscribeAsync("script.realmDestroyed", handler, options, _jsonContext.RealmDestroyedEventArgs, cancellationToken).ConfigureAwait(false); + return await SubscribeAsync("script.realmDestroyed", handler, CreateRealmDestroyedEventArgs, options, _jsonContext.RealmDestroyedParameters, cancellationToken).ConfigureAwait(false); } public async Task OnRealmDestroyedAsync(Action handler, SubscriptionOptions? options = null, CancellationToken cancellationToken = default) { - return await SubscribeAsync("script.realmDestroyed", handler, options, _jsonContext.RealmDestroyedEventArgs, cancellationToken).ConfigureAwait(false); + return await SubscribeAsync("script.realmDestroyed", handler, CreateRealmDestroyedEventArgs, options, _jsonContext.RealmDestroyedParameters, cancellationToken).ConfigureAwait(false); } + private static MessageEventArgs CreateMessageEventArgs(IBiDi bidi, MessageParameters p) + => new(bidi, p.Channel, p.Data, p.Source); + + private static RealmDestroyedEventArgs CreateRealmDestroyedEventArgs(IBiDi bidi, RealmDestroyedParameters p) + => new(bidi, p.Realm); + + private static RealmCreatedEventArgs CreateRealmCreatedEventArgs(IBiDi bidi, RealmInfo p) => p switch + { + WindowRealmInfo w => new WindowRealmCreatedEventArgs(bidi, w.Realm, w.Origin, w.Context, w.UserContext, w.Sandbox), + DedicatedWorkerRealmInfo d => new DedicatedWorkerRealmCreatedEventArgs(bidi, d.Realm, d.Origin, d.Owners), + SharedWorkerRealmInfo s => new SharedWorkerRealmCreatedEventArgs(bidi, s.Realm, s.Origin), + ServiceWorkerRealmInfo s => new ServiceWorkerRealmCreatedEventArgs(bidi, s.Realm, s.Origin), + WorkerRealmInfo w => new WorkerRealmCreatedEventArgs(bidi, w.Realm, w.Origin), + PaintWorkletRealmInfo p2 => new PaintWorkletRealmCreatedEventArgs(bidi, p2.Realm, p2.Origin), + AudioWorkletRealmInfo a => new AudioWorkletRealmCreatedEventArgs(bidi, a.Realm, a.Origin), + WorkletRealmInfo w => new WorkletRealmCreatedEventArgs(bidi, w.Realm, w.Origin), + _ => throw new BiDiException($"Unknown {nameof(RealmInfo)} type: {p.GetType()}") + }; + protected override void Initialize(IBiDi bidi, JsonSerializerOptions jsonSerializerOptions) { jsonSerializerOptions.Converters.Add(new BrowsingContextConverter(bidi)); @@ -181,18 +200,7 @@ protected override void Initialize(IBiDi bidi, JsonSerializerOptions jsonSeriali [JsonSerializable(typeof(RemovePreloadScriptCommand))] [JsonSerializable(typeof(RemovePreloadScriptResult))] -[JsonSerializable(typeof(MessageEventArgs))] -[JsonSerializable(typeof(RealmInfoEventArgs))] -[JsonSerializable(typeof(RealmDestroyedEventArgs))] -#region https://github.com/dotnet/runtime/issues/72604 -[JsonSerializable(typeof(WindowRealmInfoEventArgs))] -[JsonSerializable(typeof(DedicatedWorkerRealmInfoEventArgs))] -[JsonSerializable(typeof(SharedWorkerRealmInfoEventArgs))] -[JsonSerializable(typeof(ServiceWorkerRealmInfoEventArgs))] -[JsonSerializable(typeof(WorkerRealmInfoEventArgs))] -[JsonSerializable(typeof(PaintWorkletRealmInfoEventArgs))] -[JsonSerializable(typeof(AudioWorkletRealmInfoEventArgs))] -[JsonSerializable(typeof(WorkletRealmInfoEventArgs))] -#endregion +[JsonSerializable(typeof(MessageParameters))] +[JsonSerializable(typeof(RealmDestroyedParameters))] internal partial class ScriptJsonSerializerContext : JsonSerializerContext; diff --git a/dotnet/src/webdriver/BiDi/Speculation/PrefetchStatusUpdatedEventArgs.cs b/dotnet/src/webdriver/BiDi/Speculation/PrefetchStatusUpdatedEventArgs.cs index b586738bec080..d47e8307a6408 100644 --- a/dotnet/src/webdriver/BiDi/Speculation/PrefetchStatusUpdatedEventArgs.cs +++ b/dotnet/src/webdriver/BiDi/Speculation/PrefetchStatusUpdatedEventArgs.cs @@ -19,5 +19,14 @@ namespace OpenQA.Selenium.BiDi.Speculation; -public sealed record PrefetchStatusUpdatedEventArgs(BrowsingContext.BrowsingContext Context, string Url, PreloadingStatus Status) - : EventArgs; +public sealed record PrefetchStatusUpdatedEventArgs( + IBiDi BiDi, + BrowsingContext.BrowsingContext Context, + string Url, + PreloadingStatus Status) + : EventArgs(BiDi); + +internal sealed record PrefetchStatusUpdatedParameters( + BrowsingContext.BrowsingContext Context, + string Url, + PreloadingStatus Status); diff --git a/dotnet/src/webdriver/BiDi/Speculation/SpeculationModule.cs b/dotnet/src/webdriver/BiDi/Speculation/SpeculationModule.cs index 2564aa1afb0dd..f202158d95ade 100644 --- a/dotnet/src/webdriver/BiDi/Speculation/SpeculationModule.cs +++ b/dotnet/src/webdriver/BiDi/Speculation/SpeculationModule.cs @@ -29,14 +29,17 @@ public sealed class SpeculationModule : Module, ISpeculationModule public async Task OnPrefetchStatusUpdatedAsync(Func handler, SubscriptionOptions? options = null, CancellationToken cancellationToken = default) { - return await SubscribeAsync("speculation.prefetchStatusUpdated", handler, options, _jsonContext.PrefetchStatusUpdatedEventArgs, cancellationToken).ConfigureAwait(false); + return await SubscribeAsync("speculation.prefetchStatusUpdated", handler, CreatePrefetchStatusUpdatedEventArgs, options, _jsonContext.PrefetchStatusUpdatedParameters, cancellationToken).ConfigureAwait(false); } public async Task OnPrefetchStatusUpdatedAsync(Action handler, SubscriptionOptions? options = null, CancellationToken cancellationToken = default) { - return await SubscribeAsync("speculation.prefetchStatusUpdated", handler, options, _jsonContext.PrefetchStatusUpdatedEventArgs, cancellationToken).ConfigureAwait(false); + return await SubscribeAsync("speculation.prefetchStatusUpdated", handler, CreatePrefetchStatusUpdatedEventArgs, options, _jsonContext.PrefetchStatusUpdatedParameters, cancellationToken).ConfigureAwait(false); } + private static PrefetchStatusUpdatedEventArgs CreatePrefetchStatusUpdatedEventArgs(IBiDi bidi, PrefetchStatusUpdatedParameters p) + => new(bidi, p.Context, p.Url, p.Status); + protected override void Initialize(IBiDi bidi, JsonSerializerOptions jsonSerializerOptions) { jsonSerializerOptions.Converters.Add(new BrowsingContextConverter(bidi)); @@ -45,5 +48,5 @@ protected override void Initialize(IBiDi bidi, JsonSerializerOptions jsonSeriali } } -[JsonSerializable(typeof(PrefetchStatusUpdatedEventArgs))] +[JsonSerializable(typeof(PrefetchStatusUpdatedParameters))] internal partial class SpeculationJsonSerializerContext : JsonSerializerContext; diff --git a/dotnet/src/webdriver/BiDi/Subscription.cs b/dotnet/src/webdriver/BiDi/Subscription.cs index 319e346b9cdc0..57d302b54afd4 100644 --- a/dotnet/src/webdriver/BiDi/Subscription.cs +++ b/dotnet/src/webdriver/BiDi/Subscription.cs @@ -21,22 +21,24 @@ namespace OpenQA.Selenium.BiDi; public class Subscription : IAsyncDisposable { - private readonly EventDispatcher _eventDispatcher; + private readonly Broker _broker; - internal Subscription(Session.Subscription subscription, EventDispatcher eventDispatcher, EventHandler eventHandler) + internal Subscription(Session.Subscription subscription, Broker broker, string eventName) { SubscriptionId = subscription; - _eventDispatcher = eventDispatcher; - EventHandler = eventHandler; + _broker = broker; + EventName = eventName; } internal Session.Subscription SubscriptionId { get; } - internal EventHandler EventHandler { get; } + internal string EventName { get; } + + internal Func Handler { get; init; } = null!; public async ValueTask UnsubscribeAsync(CancellationToken cancellationToken = default) { - await _eventDispatcher.UnsubscribeAsync(this, cancellationToken).ConfigureAwait(false); + await _broker.UnsubscribeAsync(this, cancellationToken).ConfigureAwait(false); } public async ValueTask DisposeAsync() diff --git a/dotnet/test/webdriver/BiDi/Input/InputEventsTests.cs b/dotnet/test/webdriver/BiDi/Input/InputEventsTests.cs index 6effe2a99c82e..222b0d5007628 100644 --- a/dotnet/test/webdriver/BiDi/Input/InputEventsTests.cs +++ b/dotnet/test/webdriver/BiDi/Input/InputEventsTests.cs @@ -28,7 +28,7 @@ internal class InputEventsTests : BiDiTestFixture [Test] public async Task CanListenToFileDialogOpenedEvent() { - TaskCompletionSource tcs = new(); + TaskCompletionSource tcs = new(); await using var subscription = await context.Input.OnFileDialogOpenedAsync(tcs.SetResult); diff --git a/dotnet/test/webdriver/BiDi/Log/LogTests.cs b/dotnet/test/webdriver/BiDi/Log/LogTests.cs index d03cfd252c7a7..d723008ee99c8 100644 --- a/dotnet/test/webdriver/BiDi/Log/LogTests.cs +++ b/dotnet/test/webdriver/BiDi/Log/LogTests.cs @@ -27,7 +27,7 @@ internal class LogTests : BiDiTestFixture [Test] public async Task CanListenToConsoleLog() { - TaskCompletionSource tcs = new(); + TaskCompletionSource tcs = new(); await using var subscription = await context.Log.OnEntryAddedAsync(tcs.SetResult); @@ -42,9 +42,9 @@ public async Task CanListenToConsoleLog() Assert.That(logEntry.Source.Realm, Is.Not.Null); Assert.That(logEntry.Text, Is.EqualTo("Hello, world!")); Assert.That(logEntry.Level, Is.EqualTo(Level.Info)); - Assert.That(logEntry, Is.AssignableFrom()); + Assert.That(logEntry, Is.AssignableFrom()); - var consoleLogEntry = logEntry as ConsoleLogEntryEventArgs; + var consoleLogEntry = logEntry as ConsoleEntryAddedEventArgs; Assert.That(consoleLogEntry.Method, Is.EqualTo("log")); @@ -56,7 +56,7 @@ public async Task CanListenToConsoleLog() [Test] public async Task CanListenToJavascriptLog() { - TaskCompletionSource tcs = new(); + TaskCompletionSource tcs = new(); await using var subscription = await context.Log.OnEntryAddedAsync(tcs.SetResult); @@ -71,13 +71,13 @@ public async Task CanListenToJavascriptLog() Assert.That(logEntry.Source.Realm, Is.Not.Null); Assert.That(logEntry.Text, Is.EqualTo("Error: Not working")); Assert.That(logEntry.Level, Is.EqualTo(Level.Error)); - Assert.That(logEntry, Is.AssignableFrom()); + Assert.That(logEntry, Is.AssignableFrom()); } [Test] public async Task CanRetrieveStacktrace() { - TaskCompletionSource tcs = new(); + TaskCompletionSource tcs = new(); await using var subscription = await bidi.Log.OnEntryAddedAsync(tcs.SetResult); diff --git a/dotnet/test/webdriver/BiDi/Script/ScriptCommandsTests.cs b/dotnet/test/webdriver/BiDi/Script/ScriptCommandsTests.cs index 1123c4615f982..315eb879cfb94 100644 --- a/dotnet/test/webdriver/BiDi/Script/ScriptCommandsTests.cs +++ b/dotnet/test/webdriver/BiDi/Script/ScriptCommandsTests.cs @@ -92,7 +92,7 @@ public async Task CanAddPreloadScript() Assert.That(preloadScript, Is.Not.Null); - TaskCompletionSource tcs = new(); + TaskCompletionSource tcs = new(); await context.Log.OnEntryAddedAsync(tcs.SetResult); diff --git a/dotnet/test/webdriver/BiDi/Script/ScriptEventsTests.cs b/dotnet/test/webdriver/BiDi/Script/ScriptEventsTests.cs index f52d6aaf3f342..3520b4182a4fc 100644 --- a/dotnet/test/webdriver/BiDi/Script/ScriptEventsTests.cs +++ b/dotnet/test/webdriver/BiDi/Script/ScriptEventsTests.cs @@ -49,7 +49,7 @@ public async Task CanListenToChannelMessage() [Test] public async Task CanListenToRealmCreatedEvent() { - TaskCompletionSource tcs = new(); + TaskCompletionSource tcs = new(); await bidi.Script.OnRealmCreatedAsync(tcs.SetResult); @@ -58,7 +58,7 @@ public async Task CanListenToRealmCreatedEvent() var realmInfo = await tcs.Task.WaitAsync(TimeSpan.FromSeconds(5)); Assert.That(realmInfo, Is.Not.Null); - Assert.That(realmInfo, Is.AssignableFrom()); + Assert.That(realmInfo, Is.AssignableFrom()); Assert.That(realmInfo.Realm, Is.Not.Null); }