diff --git a/Lombiq.Tests.UI/Constants/DirectoryPaths.cs b/Lombiq.Tests.UI/Constants/DirectoryPaths.cs index f73b6db7e..d7b3b426b 100644 --- a/Lombiq.Tests.UI/Constants/DirectoryPaths.cs +++ b/Lombiq.Tests.UI/Constants/DirectoryPaths.cs @@ -1,6 +1,5 @@ using System; using System.IO; -using System.Linq; namespace Lombiq.Tests.UI.Constants; @@ -10,8 +9,14 @@ public static class DirectoryPaths public const string Temp = nameof(Temp); public const string Screenshots = nameof(Screenshots); + public static string GetTempDirectoryPath(params string[] subDirectoryNames) => + Path.Combine( + Path.Combine(Environment.CurrentDirectory, Temp), + Path.Combine(subDirectoryNames)); + public static string GetTempSubDirectoryPath(string contextId, params string[] subDirectoryNames) => - Path.Combine(new[] { Environment.CurrentDirectory, Temp, contextId }.Concat(subDirectoryNames).ToArray()); + GetTempDirectoryPath( + Path.Combine(contextId, Path.Combine(subDirectoryNames))); public static string GetScreenshotsDirectoryPath(string contextId) => GetTempSubDirectoryPath(contextId, Screenshots); diff --git a/Lombiq.Tests.UI/Docs/FakeVideoCaptureSource.md b/Lombiq.Tests.UI/Docs/FakeVideoCaptureSource.md new file mode 100644 index 000000000..7aa8d7f4a --- /dev/null +++ b/Lombiq.Tests.UI/Docs/FakeVideoCaptureSource.md @@ -0,0 +1,71 @@ +# Fake video capture source + +## Preparing video file + +You can use video files as a fake video capture source in Chrome browser of format `y4m` or `mjpeg`. + +If you have a video file in e.g., `mp4` format, use your preferred video tool to convert it to one of the formats mentioned above. If you don't have a preferred tool, simply use `ffmpeg`. + +_Suggestion: use `mjpeg`, it will result in a smaller file size._ + +```bash +# Convert mp4 to y4m. +ffmpeg -y -i test.mp4 -pix_fmt yuv420p test.y4m + +# Convert with resize to 480p. +ffmpeg -y -i test.mp4 -filter:v scale=480:-1 -pix_fmt yuv420p test.y4m + +# Convert mp4 to mjpeg. +ffmpeg -y -i test.mp4 test.mjpeg + +# Convert with resize to 480p. +ffmpeg -y -i test.mp4 -filter:v scale=480:-1 test.mjpeg + +``` + +### Configuring test + +Add the prepared video file to your `csproj` project as an `EmbeddedResource`, and then configure the test method as shown below. + +```csharp +using Lombiq.Tests.UI.Attributes; +using Lombiq.Tests.UI.Constants; +using Lombiq.Tests.UI.Extensions; +using Lombiq.Tests.UI.Models; +using Lombiq.Tests.UI.Services; +using OpenQA.Selenium; +using Shouldly; +using System.Linq; +using System.Threading.Tasks; +using Xunit; +using Xunit.Abstractions; + +namespace Lombiq.Tests.UI.Samples.Tests; + +public class BasicTests : UITestBase +{ + public BasicTests(ITestOutputHelper testOutputHelper) + : base(testOutputHelper) + { + } + + [Theory, Chrome] + public Task TestMethod(Browser browser) => + ExecuteTestAfterSetupAsync( + async context => + { + // ... + }, + browser, + configuration => + // Here we set the fake video source configuration. + configuration.BrowserConfiguration.FakeVideoSource = new FakeBrowserVideoSource + { + StreamProvider = () => + // Load video file content from resources. + typeof(BasicTests).Assembly.GetManifestResourceStream(typeof(BasicTests), "BasicTest.mjpeg"), + // Set the video format. + Format = FakeBrowserVideoSourceFileFormat.MJpeg, + }); +} +``` diff --git a/Lombiq.Tests.UI/Extensions/FakeBrowserVideoSourceExtensions.cs b/Lombiq.Tests.UI/Extensions/FakeBrowserVideoSourceExtensions.cs new file mode 100644 index 000000000..829a16195 --- /dev/null +++ b/Lombiq.Tests.UI/Extensions/FakeBrowserVideoSourceExtensions.cs @@ -0,0 +1,30 @@ +using Lombiq.Tests.UI.Constants; +using Lombiq.Tests.UI.Models; +using System; +using System.IO; + +namespace Lombiq.Tests.UI.Extensions; + +public static class FakeBrowserVideoSourceExtensions +{ + public static string SaveVideoToTempFolder(this FakeBrowserVideoSource source) + { + using var fakeCameraSource = source.StreamProvider(); + var fakeCameraSourcePath = Path.ChangeExtension( + DirectoryPaths.GetTempDirectoryPath(Guid.NewGuid().ToString()), + GetExtension(source.Format)); + using var fakeCameraSourceFile = new FileStream(fakeCameraSourcePath, FileMode.CreateNew, FileAccess.Write); + + fakeCameraSource.CopyTo(fakeCameraSourceFile); + + return fakeCameraSourcePath; + } + + private static string GetExtension(FakeBrowserVideoSourceFileFormat format) => + format switch + { + FakeBrowserVideoSourceFileFormat.MJpeg => "mjpeg", + FakeBrowserVideoSourceFileFormat.Y4m => "y4m", + _ => throw new ArgumentOutOfRangeException(nameof(format)), + }; +} diff --git a/Lombiq.Tests.UI/Models/FakeBrowserVideoSource.cs b/Lombiq.Tests.UI/Models/FakeBrowserVideoSource.cs new file mode 100644 index 000000000..9a869029f --- /dev/null +++ b/Lombiq.Tests.UI/Models/FakeBrowserVideoSource.cs @@ -0,0 +1,19 @@ +using System; +using System.IO; + +namespace Lombiq.Tests.UI.Models; + +public class FakeBrowserVideoSource +{ + /// + /// Gets or sets a callback that will be used to obtain the video content and will be saved and used + /// as a fake video capture file for the Chrome browser. The consumer will dispose of the returned + /// after the callback is called. + /// + public Func StreamProvider { get; set; } + + /// + /// Gets or sets the video format of the provided stream. + /// + public FakeBrowserVideoSourceFileFormat Format { get; set; } = FakeBrowserVideoSourceFileFormat.MJpeg; +} diff --git a/Lombiq.Tests.UI/Models/FakeBrowserVideoSourceFileFormat.cs b/Lombiq.Tests.UI/Models/FakeBrowserVideoSourceFileFormat.cs new file mode 100644 index 000000000..39c2c7745 --- /dev/null +++ b/Lombiq.Tests.UI/Models/FakeBrowserVideoSourceFileFormat.cs @@ -0,0 +1,7 @@ +namespace Lombiq.Tests.UI.Models; + +public enum FakeBrowserVideoSourceFileFormat +{ + MJpeg, + Y4m, +} diff --git a/Lombiq.Tests.UI/Services/BrowserConfiguration.cs b/Lombiq.Tests.UI/Services/BrowserConfiguration.cs index 78fcf0adc..6a058e1aa 100644 --- a/Lombiq.Tests.UI/Services/BrowserConfiguration.cs +++ b/Lombiq.Tests.UI/Services/BrowserConfiguration.cs @@ -1,4 +1,5 @@ using Lombiq.Tests.UI.Constants; +using Lombiq.Tests.UI.Models; using SixLabors.ImageSharp; using System; using System.Globalization; @@ -37,4 +38,9 @@ public class BrowserConfiguration /// cref="CommonDisplayResolutions.Standard"/> when the setup is loaded. /// public Size DefaultBrowserSize { get; set; } = CommonDisplayResolutions.Standard; + + /// + /// Gets or sets the fake camera video source information. See: . + /// + public FakeBrowserVideoSource FakeVideoSource { get; set; } } diff --git a/Lombiq.Tests.UI/Services/WebDriverFactory.cs b/Lombiq.Tests.UI/Services/WebDriverFactory.cs index 7a4e7bc3f..29de4ae23 100644 --- a/Lombiq.Tests.UI/Services/WebDriverFactory.cs +++ b/Lombiq.Tests.UI/Services/WebDriverFactory.cs @@ -1,3 +1,4 @@ +using Lombiq.Tests.UI.Extensions; using OpenQA.Selenium; using OpenQA.Selenium.Chrome; using OpenQA.Selenium.Chromium; @@ -136,6 +137,15 @@ private static TDriverOptions SetCommonChromiumOptions( // Disabling smooth scrolling to avoid large waiting time when taking full-page screenshots. options.AddArgument("disable-smooth-scrolling"); + if (configuration.FakeVideoSource is not null) + { + var fakeCameraSourceFilePath = configuration.FakeVideoSource.SaveVideoToTempFolder(); + + options.AddArgument("use-fake-device-for-media-stream"); + options.AddArgument("use-fake-ui-for-media-stream"); + options.AddArgument($"use-file-for-fake-video-capture={fakeCameraSourceFilePath}"); + } + if (configuration.Headless) options.AddArgument("headless"); return options; diff --git a/Readme.md b/Readme.md index 58012e86a..baedb4487 100644 --- a/Readme.md +++ b/Readme.md @@ -24,6 +24,7 @@ Highlights: - Ready to use GitHub Actions workflows for CI builds and support for test grouping and error annotations in [Lombiq GitHub Actions](https://github.com/features/actions). This feature is automatically enabled if a GitHub environment is detected. - Support for [TeamCity test metadata reporting](https://www.jetbrains.com/help/teamcity/reporting-test-metadata.html) so you can see the important details and metrics of a test at a glance in a TeamCity CI/CD server. - Visual verification testing: You can make the test fail if the look of the app changes. Demo video [here](https://www.youtube.com/watch?v=a-1zKjxTKkk). +- Using video files as a fake video capture source in Chrome browser. Docs [here](Lombiq.Tests.UI/Docs/FakeVideoCaptureSource.md). See a demo video of the project [here](https://www.youtube.com/watch?v=mEUg6-pad-E). Also, see our [Testing Toolbox](https://github.com/Lombiq/Testing-Toolbox) for similar features for lower-level tests.