diff --git a/dotnet/src/webdriver/BiDi/BrowsingContext/BrowsingContext.cs b/dotnet/src/webdriver/BiDi/BrowsingContext/BrowsingContext.cs index 43b5e942502df..91884f457565e 100644 --- a/dotnet/src/webdriver/BiDi/BrowsingContext/BrowsingContext.cs +++ b/dotnet/src/webdriver/BiDi/BrowsingContext/BrowsingContext.cs @@ -105,6 +105,11 @@ public Task PrintAsync(PrintOptions? options = null, CancellationTo return BiDi.BrowsingContext.PrintAsync(this, options, cancellationToken); } + public Task StartScreencastAsync(StartScreencastOptions? options = null, CancellationToken cancellationToken = default) + { + return BiDi.BrowsingContext.StartScreencastAsync(this, options, cancellationToken); + } + public Task HandleUserPromptAsync(HandleUserPromptOptions? options = null, CancellationToken cancellationToken = default) { return BiDi.BrowsingContext.HandleUserPromptAsync(this, options, cancellationToken); diff --git a/dotnet/src/webdriver/BiDi/BrowsingContext/BrowsingContextModule.cs b/dotnet/src/webdriver/BiDi/BrowsingContext/BrowsingContextModule.cs index 3d053294fc559..bc52b605fe678 100644 --- a/dotnet/src/webdriver/BiDi/BrowsingContext/BrowsingContextModule.cs +++ b/dotnet/src/webdriver/BiDi/BrowsingContext/BrowsingContextModule.cs @@ -108,6 +108,20 @@ public async Task HandleUserPromptAsync(BrowsingContext return await ExecuteAsync("browsingContext.handleUserPrompt", @params, Default.HandleUserPromptParameters, Default.HandleUserPromptResult, options, cancellationToken).ConfigureAwait(false); } + public async Task StartScreencastAsync(BrowsingContext context, StartScreencastOptions? options = null, CancellationToken cancellationToken = default) + { + var @params = new StartScreencastParameters(context, options?.MimeType, options?.Video, options?.Audio); + + return await ExecuteAsync("browsingContext.startScreencast", @params, Default.StartScreencastParameters, Default.StartScreencastResult, options, cancellationToken).ConfigureAwait(false); + } + + public async Task StopScreencastAsync(Screencast screencast, StopScreencastOptions? options = null, CancellationToken cancellationToken = default) + { + var @params = new StopScreencastParameters(screencast); + + return await ExecuteAsync("browsingContext.stopScreencast", @params, Default.StopScreencastParameters, Default.StopScreencastResult, options, cancellationToken).ConfigureAwait(false); + } + public IEventSource NavigationStarted => _navigationStarted ?? Interlocked.CompareExchange(ref _navigationStarted, CreateEventSource(BrowsingContextEvent.NavigationStarted), null) ?? _navigationStarted; private IEventSource? _navigationStarted; @@ -173,6 +187,10 @@ public async Task HandleUserPromptAsync(BrowsingContext [JsonSerializable(typeof(ReloadResult))] [JsonSerializable(typeof(SetViewportParameters))] [JsonSerializable(typeof(SetViewportResult))] +[JsonSerializable(typeof(StartScreencastParameters))] +[JsonSerializable(typeof(StartScreencastResult))] +[JsonSerializable(typeof(StopScreencastParameters))] +[JsonSerializable(typeof(StopScreencastResult))] [JsonSerializable(typeof(TraverseHistoryParameters))] [JsonSerializable(typeof(TraverseHistoryResult))] diff --git a/dotnet/src/webdriver/BiDi/BrowsingContext/IBrowsingContextModule.cs b/dotnet/src/webdriver/BiDi/BrowsingContext/IBrowsingContextModule.cs index 696191fb1f595..63a41449c60d8 100644 --- a/dotnet/src/webdriver/BiDi/BrowsingContext/IBrowsingContextModule.cs +++ b/dotnet/src/webdriver/BiDi/BrowsingContext/IBrowsingContextModule.cs @@ -46,5 +46,7 @@ public interface IBrowsingContextModule Task PrintAsync(BrowsingContext context, PrintOptions? options = null, CancellationToken cancellationToken = default); Task ReloadAsync(BrowsingContext context, ReloadOptions? options = null, CancellationToken cancellationToken = default); Task SetViewportAsync(SetViewportOptions? options = null, CancellationToken cancellationToken = default); + Task StartScreencastAsync(BrowsingContext context, StartScreencastOptions? options = null, CancellationToken cancellationToken = default); + Task StopScreencastAsync(Screencast screencast, StopScreencastOptions? options = null, CancellationToken cancellationToken = default); Task TraverseHistoryAsync(BrowsingContext context, int delta, TraverseHistoryOptions? options = null, CancellationToken cancellationToken = default); } diff --git a/dotnet/src/webdriver/BiDi/BrowsingContext/Screencast.cs b/dotnet/src/webdriver/BiDi/BrowsingContext/Screencast.cs new file mode 100644 index 0000000000000..3803e996f0442 --- /dev/null +++ b/dotnet/src/webdriver/BiDi/BrowsingContext/Screencast.cs @@ -0,0 +1,68 @@ +// +// 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.Diagnostics.CodeAnalysis; +using System.Text; +using System.Text.Json.Serialization; +using OpenQA.Selenium.BiDi.Json.Converters; + +namespace OpenQA.Selenium.BiDi.BrowsingContext; + +[JsonConverter(typeof(Converter))] +public sealed record Screencast : IIdentifiable +{ + public Screencast(IBiDi bidi, string id) + { + ArgumentNullException.ThrowIfNull(bidi); + BiDi = bidi; + Id = id; + } + + public string Id { get; } + + [JsonIgnore] + public IBiDi BiDi { get; } + + public Task StopAsync(StopScreencastOptions? options = null, CancellationToken cancellationToken = default) + { + return BiDi.BrowsingContext.StopScreencastAsync(this, options, cancellationToken); + } + + public bool Equals(Screencast? other) + { + return other is not null && string.Equals(Id, other.Id, StringComparison.Ordinal); + } + + public override int GetHashCode() + { + return StringComparer.Ordinal.GetHashCode(Id); + } + + [SuppressMessage("CodeQuality", "IDE0051", Justification = "Used by compiler-generated ToString()")] + private bool PrintMembers(StringBuilder builder) + { + builder.Append($"Id = {Id}"); + return true; + } + + public sealed class Converter : IdentifiableConverter + { + protected override Screencast Create(IBiDi bidi, string id) => new(bidi, id); + } +} diff --git a/dotnet/src/webdriver/BiDi/BrowsingContext/StartScreencast.cs b/dotnet/src/webdriver/BiDi/BrowsingContext/StartScreencast.cs new file mode 100644 index 0000000000000..32698e41dcb4d --- /dev/null +++ b/dotnet/src/webdriver/BiDi/BrowsingContext/StartScreencast.cs @@ -0,0 +1,42 @@ +// +// 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; + +internal sealed record StartScreencastParameters(BrowsingContext Context, string? MimeType, MediaTrackConstraints? Video, bool? Audio) : Parameters; + +public sealed record StartScreencastOptions : CommandOptions +{ + public string? MimeType { get; init; } + + public MediaTrackConstraints? Video { get; init; } + + public bool? Audio { get; init; } +} + +public record struct MediaTrackConstraints +{ + public long? Width { get; init; } + + public long? Height { get; init; } + + public long? FrameRate { get; init; } +} + +public sealed record StartScreencastResult(Screencast Screencast, string Path) : EmptyResult; diff --git a/dotnet/src/webdriver/BiDi/BrowsingContext/StopScreencast.cs b/dotnet/src/webdriver/BiDi/BrowsingContext/StopScreencast.cs new file mode 100644 index 0000000000000..22f3d156d432d --- /dev/null +++ b/dotnet/src/webdriver/BiDi/BrowsingContext/StopScreencast.cs @@ -0,0 +1,26 @@ +// +// 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; + +internal sealed record StopScreencastParameters(Screencast Screencast) : Parameters; + +public sealed record StopScreencastOptions : CommandOptions; + +public sealed record StopScreencastResult(string Path, string? Error) : EmptyResult; diff --git a/dotnet/test/webdriver/BiDi/BrowsingContext/BrowsingContextTests.cs b/dotnet/test/webdriver/BiDi/BrowsingContext/BrowsingContextTests.cs index d97a81973ec8c..20475d9fb31e0 100644 --- a/dotnet/test/webdriver/BiDi/BrowsingContext/BrowsingContextTests.cs +++ b/dotnet/test/webdriver/BiDi/BrowsingContext/BrowsingContextTests.cs @@ -17,6 +17,7 @@ // under the License. // +using System.IO; using OpenQA.Selenium.BiDi.BrowsingContext; namespace OpenQA.Selenium.Tests.BiDi.BrowsingContext; @@ -341,4 +342,33 @@ public async Task CanPrintPage() Assert.That(pdf, Is.Not.Null); Assert.That(pdf.Data.Length, Is.Not.Zero); } + + [Test] + [IgnoreBrowser(Infrastructure.Browser.Chrome, "Not supported yet?")] + [IgnoreBrowser(Infrastructure.Browser.Edge, "Not supported yet?")] + [IgnoreBrowser(Infrastructure.Browser.Firefox, "Not supported yet?")] + public async Task CanStartAndStopScreencast() + { + StartScreencastResult startScreencastResult = null; + + try + { + startScreencastResult = await context.StartScreencastAsync(); + + Assert.That(startScreencastResult.Screencast, Is.Not.Null); + Assert.That(startScreencastResult.Path, Is.Not.Empty); + + var stopScreencastResult = await startScreencastResult.Screencast.StopAsync(); + + Assert.That(stopScreencastResult.Path, Is.EqualTo(startScreencastResult.Path)); + Assert.That(stopScreencastResult.Error, Is.Null); + } + finally + { + if (Path.Exists(startScreencastResult?.Path)) + { + File.Delete(startScreencastResult.Path); + } + } + } }