Compare commits

...

12 Commits

Author SHA1 Message Date
Florian Rappl
1ac371b3da Merge pull request #962 from softworkz/submit_testupd
Collection of test fixes
2025-12-09 15:23:33 +01:00
softworkz
95e02e2655 Introduce common base class for tests 2025-12-07 11:56:32 +01:00
softworkz
153625ba51 Introduce IntegrationFactAttribute 2025-12-07 11:56:26 +01:00
softworkz
c97f914e7a Introduce TimeSpan extensions 2025-12-07 11:20:43 +01:00
softworkz
2b2b26e13b GetSetUserAgent 2025-12-06 21:08:47 +01:00
softworkz
9bb2adca78 Use 3s timeout for GetUserAgentAsync and updat test 2025-12-06 20:53:15 +01:00
softworkz
88d2daacb1 WebContentsTests: Experiment!
Re-enable some tests for CI as experiment
2025-12-06 20:35:51 +01:00
softworkz
c90f003519 GetSetZoomLevel: Don't use shared window
Because we need a visible window and the main window
visibility must not be mutated by tests
2025-12-06 20:11:27 +01:00
softworkz
daa9f399e9 ScreenTests: Remove invalid constraints
Negative values for cursor position are not invalid
2025-12-06 20:09:05 +01:00
softworkz
6246b44d68 ReadyToShow_event_fires: Destroy window 2025-12-06 20:08:01 +01:00
softworkz
347c1ef0e4 Show_hide_visibility_roundtrip: Don't use shared window 2025-12-06 20:06:34 +01:00
softworkz
7c8eeef225 GetPrintersAsync: Increase timeout 2025-12-06 20:04:23 +01:00
31 changed files with 654 additions and 431 deletions

View File

@@ -31,7 +31,7 @@ namespace ElectronNET.API
CamelCase,
}
private const int InvocationTimeout = 1000;
private static readonly TimeSpan InvocationTimeout = 1000.ms();
private readonly string objectName;
private readonly ConcurrentDictionary<string, Invocator> invocators;
@@ -120,7 +120,7 @@ namespace ElectronNET.API
return this.InvokeAsyncWithTimeout<T>(InvocationTimeout, arg, callerName);
}
protected Task<T> InvokeAsyncWithTimeout<T>(int invocationTimeout, object arg = null, [CallerMemberName] string callerName = null)
protected Task<T> InvokeAsyncWithTimeout<T>(TimeSpan invocationTimeout, object arg = null, [CallerMemberName] string callerName = null)
{
Debug.Assert(callerName != null, nameof(callerName) + " != null");
@@ -245,7 +245,7 @@ namespace ElectronNET.API
private readonly Task<T> tcsTask;
private TaskCompletionSource<T> tcs;
public Invocator(ApiBase apiBase, string callerName, int timeoutMs, object arg = null)
public Invocator(ApiBase apiBase, string callerName, TimeSpan timeout, object arg = null)
{
this.tcs = new TaskCompletionSource<T>(TaskCreationOptions.RunContinuationsAsynchronously);
this.tcsTask = this.tcs.Task;
@@ -306,7 +306,7 @@ namespace ElectronNET.API
_ = apiBase.Id >= 0 ? BridgeConnector.Socket.Emit(messageName, apiBase.Id) : BridgeConnector.Socket.Emit(messageName);
}
System.Threading.Tasks.Task.Delay(timeoutMs).ContinueWith(_ =>
System.Threading.Tasks.Task.Delay(timeout).ContinueWith(_ =>
{
if (this.tcs != null)
{
@@ -314,7 +314,7 @@ namespace ElectronNET.API
{
if (this.tcs != null)
{
var ex = new TimeoutException($"No response after {timeoutMs:D}ms trying to retrieve value {apiBase.objectName}.{callerName}()");
var ex = new TimeoutException($"No response after {timeout:D}ms trying to retrieve value {apiBase.objectName}.{callerName}()");
this.tcs.TrySetException(ex);
this.tcs = null;
}

View File

@@ -1,6 +1,7 @@
using ElectronNET.API.Entities;
using System;
using System.Threading.Tasks;
using ElectronNET.API.Entities;
using ElectronNET.Common;
// ReSharper disable InconsistentNaming
@@ -173,7 +174,7 @@ public class WebContents : ApiBase
/// Get system printers.
/// </summary>
/// <returns>printers</returns>
public Task<PrinterInfo[]> GetPrintersAsync() => this.InvokeAsyncWithTimeout<PrinterInfo[]>(5_000);
public Task<PrinterInfo[]> GetPrintersAsync() => this.InvokeAsyncWithTimeout<PrinterInfo[]>(8.seconds());
/// <summary>
/// Prints window's web page.
@@ -388,7 +389,7 @@ public class WebContents : ApiBase
/// Returns string - The user agent for this web page.
/// </summary>
/// <returns></returns>
public Task<string> GetUserAgentAsync() => InvokeAsync<string>();
public Task<string> GetUserAgentAsync() => InvokeAsyncWithTimeout<string>(3.seconds());
/// <summary>
/// Overrides the user agent for this web page.

View File

@@ -0,0 +1,74 @@
// <copyright file="TimeSpanExtensions.cs" company="Emby LLC">
// Copyright © Emby LLC. All rights reserved.
// </copyright>
namespace ElectronNET.Common
{
using System;
using System.Diagnostics.CodeAnalysis;
/// <summary>
/// The TimeSpanExtensions class.
/// </summary>
[SuppressMessage("StyleCop.CSharp.NamingRules", "SA1300:Element should begin with upper-case letter", Justification = "OK")]
[SuppressMessage("StyleCop.CSharp.DocumentationRules", "SA1600:Elements should be documented", Justification = "OK")]
[SuppressMessage("ReSharper", "StyleCop.SA1300", Justification = "OK")]
[SuppressMessage("ReSharper", "InconsistentNaming", Justification = "OK")]
internal static class TimeSpanExtensions
{
public static TimeSpan ms(this int value)
{
return TimeSpan.FromMilliseconds(value);
}
public static TimeSpan ms(this long value)
{
return TimeSpan.FromMilliseconds(value);
}
public static TimeSpan seconds(this int value)
{
return TimeSpan.FromSeconds(value);
}
public static TimeSpan minutes(this int value)
{
return TimeSpan.FromMinutes(value);
}
public static TimeSpan hours(this int value)
{
return TimeSpan.FromHours(value);
}
public static TimeSpan days(this int value)
{
return TimeSpan.FromDays(value);
}
public static TimeSpan ms(this double value)
{
return TimeSpan.FromMilliseconds(value);
}
public static TimeSpan seconds(this double value)
{
return TimeSpan.FromSeconds(value);
}
public static TimeSpan minutes(this double value)
{
return TimeSpan.FromMinutes(value);
}
public static TimeSpan hours(this double value)
{
return TimeSpan.FromHours(value);
}
public static TimeSpan days(this double value)
{
return TimeSpan.FromDays(value);
}
}
}

View File

@@ -35,5 +35,6 @@
<ItemGroup>
<InternalsVisibleTo Include="ElectronNET.AspNet" />
<InternalsVisibleTo Include="ElectronNET.Core.AspNet" />
<InternalsVisibleTo Include="ElectronNET.IntegrationTests" />
</ItemGroup>
</Project>

View File

@@ -76,7 +76,7 @@
{
try
{
await Task.Delay(10).ConfigureAwait(false);
await Task.Delay(10.ms()).ConfigureAwait(false);
Console.Error.WriteLine("[StartInternal]: startCmd: {0}", startCmd);
Console.Error.WriteLine("[StartInternal]: args: {0}", args);
@@ -85,7 +85,7 @@
this.process.ProcessExited += this.Process_Exited;
this.process.Run(startCmd, args, directoriy);
await Task.Delay(500).ConfigureAwait(false);
await Task.Delay(500.ms()).ConfigureAwait(false);
Console.Error.WriteLine("[StartInternal]: after run:");

View File

@@ -0,0 +1,101 @@
namespace ElectronNET.IntegrationTests.Common
{
using System.Runtime.InteropServices;
using Xunit.Sdk;
/// <summary>
/// Custom fact attribute with a default timeout of 20 seconds, allowing tests to be skipped on specific environments.
/// </summary>
/// <seealso cref="Xunit.FactAttribute" />
[AttributeUsage(AttributeTargets.Method)]
[XunitTestCaseDiscoverer("Xunit.Sdk.SkippableFactDiscoverer", "Xunit.SkippableFact")]
internal sealed class IntegrationFactAttribute : FactAttribute
{
private static readonly bool IsOnWsl;
private static readonly bool IsOnCI;
static IntegrationFactAttribute()
{
IsOnWsl = DetectWsl();
IsOnCI = DetectCI();
}
/// <summary>
/// Initializes a new instance of the <see cref="IntegrationFactAttribute" /> class.
/// </summary>
public IntegrationFactAttribute()
{
this.Timeout = 20_000;
}
public bool SkipOnWsl { get; set; }
public bool SkipOnCI { get; set; }
/// <summary>
/// Marks the test so that it will not be run, and gets or sets the skip reason
/// </summary>
public override string Skip {
get
{
if (IsOnWsl && this.SkipOnWsl)
{
return "Skipping test on WSL environment.";
}
if (IsOnCI && this.SkipOnCI)
{
return "Skipping test on CI environment.";
}
return base.Skip;
}
set
{
base.Skip = value;
}
}
private static bool DetectWsl()
{
try
{
if (!RuntimeInformation.IsOSPlatform(OSPlatform.Linux))
{
return false;
}
if (!string.IsNullOrEmpty(Environment.GetEnvironmentVariable("WSL_DISTRO_NAME")) ||
!string.IsNullOrEmpty(Environment.GetEnvironmentVariable("WSL_INTEROP")))
{
return true;
}
return false;
}
catch
{
return false;
}
}
private static bool DetectCI()
{
try
{
if (!string.IsNullOrEmpty(Environment.GetEnvironmentVariable("TF_BUILD")) ||
!string.IsNullOrEmpty(Environment.GetEnvironmentVariable("GITHUB_ACTIONS")))
{
return true;
}
return false;
}
catch
{
return false;
}
}
}
}

View File

@@ -0,0 +1,23 @@
namespace ElectronNET.IntegrationTests.Common
{
using ElectronNET.API;
using ElectronNET.API.Entities;
// Base class for integration tests providing shared access to MainWindow and OS platform constants
public abstract class IntegrationTestBase
{
protected IntegrationTestBase(ElectronFixture fixture)
{
Fixture = fixture;
MainWindow = fixture.MainWindow;
}
protected ElectronFixture Fixture { get; }
protected BrowserWindow MainWindow { get; }
// Constants for SupportedOSPlatform attributes
public const string Windows = "Windows";
public const string MacOS = "macOS";
public const string Linux = "Linux";
}
}

View File

@@ -1,49 +0,0 @@
namespace ElectronNET.IntegrationTests.Common
{
using System.Runtime.InteropServices;
[AttributeUsage(AttributeTargets.Method)]
internal sealed class SkipOnWslFactAttribute : FactAttribute
{
private static readonly bool IsOnWsl;
static SkipOnWslFactAttribute()
{
IsOnWsl = DetectWsl();
}
/// <summary>
/// Initializes a new instance of the <see cref="SkipOnWslFactAttribute" /> class.
/// </summary>
public SkipOnWslFactAttribute()
{
if (IsOnWsl)
{
this.Skip = "Skipping test on WSL environment.";
}
}
private static bool DetectWsl()
{
try
{
if (!RuntimeInformation.IsOSPlatform(OSPlatform.Linux))
{
return false;
}
if (!string.IsNullOrEmpty(Environment.GetEnvironmentVariable("WSL_DISTRO_NAME")) ||
!string.IsNullOrEmpty(Environment.GetEnvironmentVariable("WSL_INTEROP")))
{
return true;
}
return false;
}
catch
{
return false;
}
}
}
}

View File

@@ -4,6 +4,7 @@ namespace ElectronNET.IntegrationTests
using System.Reflection;
using ElectronNET.API;
using ElectronNET.API.Entities;
using ElectronNET.Common;
// Shared fixture that starts Electron runtime once
[SuppressMessage("ReSharper", "MethodHasAsyncOverload")]
@@ -26,7 +27,7 @@ namespace ElectronNET.IntegrationTests
await runtimeController.Start();
Console.Error.WriteLine("[ElectronFixture] Waiting for Ready...");
await Task.WhenAny(runtimeController.WaitReadyTask, Task.Delay(TimeSpan.FromSeconds(10)));
await Task.WhenAny(runtimeController.WaitReadyTask, Task.Delay(10.seconds()));
if (!runtimeController.WaitReadyTask.IsCompleted)
{

View File

@@ -6,19 +6,16 @@ namespace ElectronNET.IntegrationTests.Tests
using System.IO;
using System.Runtime.Versioning;
using System.Threading.Tasks;
using ElectronNET.IntegrationTests.Common;
[Collection("ElectronCollection")]
public class AppTests
public class AppTests : IntegrationTestBase
{
// ReSharper disable once NotAccessedField.Local
private readonly ElectronFixture fx;
public AppTests(ElectronFixture fx)
public AppTests(ElectronFixture fx) : base(fx)
{
this.fx = fx;
}
[Fact(Timeout = 20000)]
[IntegrationFact]
public async Task Can_get_app_path()
{
var path = await Electron.App.GetAppPathAsync();
@@ -26,7 +23,7 @@ namespace ElectronNET.IntegrationTests.Tests
Directory.Exists(path).Should().BeTrue();
}
[Fact(Timeout = 20000)]
[IntegrationFact]
public async Task Can_get_version_and_locale()
{
var version = await Electron.App.GetVersionAsync();
@@ -35,7 +32,7 @@ namespace ElectronNET.IntegrationTests.Tests
locale.Should().NotBeNullOrWhiteSpace();
}
[Fact(Timeout = 20000)]
[IntegrationFact]
public async Task Can_get_special_paths()
{
var userData = await Electron.App.GetPathAsync(PathName.UserData);
@@ -47,7 +44,7 @@ namespace ElectronNET.IntegrationTests.Tests
Directory.Exists(temp).Should().BeTrue();
}
[Fact(Timeout = 20000)]
[IntegrationFact]
public async Task Can_get_app_metrics()
{
var metrics = await Electron.App.GetAppMetricsAsync();
@@ -55,23 +52,23 @@ namespace ElectronNET.IntegrationTests.Tests
metrics.Length.Should().BeGreaterThan(0);
}
[Fact(Timeout = 20000)]
[IntegrationFact]
public async Task Can_get_gpu_feature_status()
{
var status = await Electron.App.GetGpuFeatureStatusAsync();
status.Should().NotBeNull();
}
[SkippableFact(Timeout = 20000)]
[SupportedOSPlatform("macOS")]
[SupportedOSPlatform("Windows")]
[IntegrationFact]
[SupportedOSPlatform(MacOS)]
[SupportedOSPlatform(Windows)]
public async Task Can_get_login_item_settings()
{
var settings = await Electron.App.GetLoginItemSettingsAsync();
settings.Should().NotBeNull();
}
[Fact(Timeout = 20000)]
[IntegrationFact]
public async Task CommandLine_append_and_query_switch()
{
var switchName = "integration-switch";
@@ -80,9 +77,9 @@ namespace ElectronNET.IntegrationTests.Tests
(await Electron.App.CommandLine.GetSwitchValueAsync(switchName)).Should().Be("value123");
}
[SkippableFact(Timeout = 20000)]
[SupportedOSPlatform("macOS")]
[SupportedOSPlatform("Windows")]
[IntegrationFact]
[SupportedOSPlatform(MacOS)]
[SupportedOSPlatform(Windows)]
public async Task Accessibility_support_toggle()
{
Electron.App.SetAccessibilitySupportEnabled(true);
@@ -91,7 +88,7 @@ namespace ElectronNET.IntegrationTests.Tests
Electron.App.SetAccessibilitySupportEnabled(false);
}
[Fact(Timeout = 20000)]
[IntegrationFact]
public async Task UserAgentFallback_roundtrip()
{
var original = await Electron.App.UserAgentFallbackAsync;
@@ -101,9 +98,9 @@ namespace ElectronNET.IntegrationTests.Tests
Electron.App.UserAgentFallback = original; // restore
}
[SkippableFact(Timeout = 20000)]
[SupportedOSPlatform("Linux")]
[SupportedOSPlatform("macOS")]
[IntegrationFact]
[SupportedOSPlatform(Linux)]
[SupportedOSPlatform(MacOS)]
public async Task BadgeCount_set_and_reset_where_supported()
{
await Electron.App.SetBadgeCountAsync(2);
@@ -113,14 +110,14 @@ namespace ElectronNET.IntegrationTests.Tests
await Electron.App.SetBadgeCountAsync(0);
}
[Fact(Timeout = 20000)]
[IntegrationFact]
public async Task App_metrics_have_cpu_info()
{
var metrics = await Electron.App.GetAppMetricsAsync();
metrics[0].Cpu.Should().NotBeNull();
}
[Fact(Timeout = 20000)]
[IntegrationFact]
public async Task App_gpu_feature_status_has_some_fields()
{
var status = await Electron.App.GetGpuFeatureStatusAsync();

View File

@@ -2,18 +2,17 @@
{
using API;
using System.Threading.Tasks;
using ElectronNET.Common;
using ElectronNET.IntegrationTests.Common;
[Collection("ElectronCollection")]
public class AutoUpdaterTests
public class AutoUpdaterTests : IntegrationTestBase
{
private readonly ElectronFixture fx;
public AutoUpdaterTests(ElectronFixture fx)
public AutoUpdaterTests(ElectronFixture fx) : base(fx)
{
this.fx = fx;
}
[Fact(Timeout = 20000)]
[IntegrationFact]
public async Task AutoDownload_check()
{
Electron.AutoUpdater.AutoDownload = false;
@@ -24,7 +23,7 @@
test2.Should().BeTrue();
}
[Fact(Timeout = 20000)]
[IntegrationFact]
public async Task AutoInstallOnAppQuit_check()
{
Electron.AutoUpdater.AutoInstallOnAppQuit = false;
@@ -35,7 +34,7 @@
test2.Should().BeTrue();
}
[Fact(Timeout = 20000)]
[IntegrationFact]
public async Task AllowPrerelease_check()
{
Electron.AutoUpdater.AllowPrerelease = false;
@@ -46,7 +45,7 @@
test2.Should().BeTrue();
}
[Fact(Timeout = 20000)]
[IntegrationFact]
public async Task FullChangelog_check()
{
Electron.AutoUpdater.FullChangelog = false;
@@ -57,7 +56,7 @@
test2.Should().BeTrue();
}
[Fact(Timeout = 20000)]
[IntegrationFact]
public async Task AllowDowngrade_check()
{
Electron.AutoUpdater.AllowDowngrade = false;
@@ -68,14 +67,14 @@
test2.Should().BeTrue();
}
[Fact(Timeout = 20000)]
[IntegrationFact]
public async Task UpdateConfigPath_check()
{
var test1 = Electron.AutoUpdater.UpdateConfigPath;
test1.Should().Be(string.Empty);
}
[Fact(Timeout = 20000)]
[IntegrationFact]
public async Task CurrentVersionAsync_check()
{
var semver = await Electron.AutoUpdater.CurrentVersionAsync;
@@ -83,18 +82,18 @@
semver.Major.Should().BeGreaterThan(0);
}
[Fact(Timeout = 20000)]
[IntegrationFact]
public async Task ChannelAsync_check()
{
var test = await Electron.AutoUpdater.ChannelAsync;
test.Should().Be(string.Empty);
Electron.AutoUpdater.SetChannel = "beta";
await Task.Delay(500);
await Task.Delay(500.ms());
test = await Electron.AutoUpdater.ChannelAsync;
test.Should().Be("beta");
}
[Fact(Timeout = 20000)]
[IntegrationFact]
public async Task RequestHeadersAsync_check()
{
var headers = new Dictionary<string, string>
@@ -104,28 +103,28 @@
var test = await Electron.AutoUpdater.RequestHeadersAsync;
test.Should().BeNull();
Electron.AutoUpdater.RequestHeaders = headers;
await Task.Delay(500);
await Task.Delay(500.ms());
test = await Electron.AutoUpdater.RequestHeadersAsync;
test.Should().NotBeNull();
test.Count.Should().Be(1);
test["key1"].Should().Be("value1");
}
[Fact(Timeout = 20000)]
[IntegrationFact]
public async Task CheckForUpdatesAsync_check()
{
var test = await Electron.AutoUpdater.CheckForUpdatesAsync();
test.Should().BeNull();
}
[Fact(Timeout = 20000)]
[IntegrationFact]
public async Task CheckForUpdatesAndNotifyAsync_check()
{
var test = await Electron.AutoUpdater.CheckForUpdatesAsync();
test.Should().BeNull();
}
[Fact(Timeout = 20000)]
[IntegrationFact]
public async Task GetFeedURLAsync_check()
{
var test = await Electron.AutoUpdater.GetFeedURLAsync();

View File

@@ -2,22 +2,20 @@ namespace ElectronNET.IntegrationTests.Tests
{
using ElectronNET.API;
using ElectronNET.API.Entities;
using ElectronNET.IntegrationTests.Common;
[Collection("ElectronCollection")]
public class BrowserViewTests
public class BrowserViewTests : IntegrationTestBase
{
private readonly ElectronFixture fx;
public BrowserViewTests(ElectronFixture fx)
public BrowserViewTests(ElectronFixture fx) : base(fx)
{
this.fx = fx;
}
[Fact(Timeout = 20000)]
[IntegrationFact]
public async Task Create_browser_view_and_adjust_bounds()
{
var view = await Electron.WindowManager.CreateBrowserViewAsync(new BrowserViewConstructorOptions());
this.fx.MainWindow.SetBrowserView(view);
this.MainWindow.SetBrowserView(view);
view.Bounds = new Rectangle { X = 0, Y = 0, Width = 300, Height = 200 };
// Access bounds again (synchronous property fetch)
var current = view.Bounds;

View File

@@ -1,144 +1,163 @@
namespace ElectronNET.IntegrationTests.Tests
{
using System.Runtime.InteropServices;
using System.Runtime.Versioning;
using ElectronNET.API;
using ElectronNET.API.Entities;
using ElectronNET.Common;
using ElectronNET.IntegrationTests.Common;
[Collection("ElectronCollection")]
public class BrowserWindowTests
public class BrowserWindowTests : IntegrationTestBase
{
private readonly ElectronFixture fx;
public BrowserWindowTests(ElectronFixture fx)
public BrowserWindowTests(ElectronFixture fx) : base(fx)
{
this.fx = fx;
}
[Fact(Timeout = 20000)]
[IntegrationFact]
public async Task Can_set_and_get_title()
{
const string title = "Integration Test Title";
this.fx.MainWindow.SetTitle(title);
await Task.Delay(500);
var roundTrip = await this.fx.MainWindow.GetTitleAsync();
this.MainWindow.SetTitle(title);
await Task.Delay(500.ms());
var roundTrip = await this.MainWindow.GetTitleAsync();
roundTrip.Should().Be(title);
}
[Fact(Timeout = 20000)]
[IntegrationFact]
public async Task Can_resize_and_get_size()
{
this.fx.MainWindow.SetSize(643, 482);
await Task.Delay(500);
var size = await this.fx.MainWindow.GetSizeAsync();
this.MainWindow.SetSize(643, 482);
await Task.Delay(500.ms());
var size = await this.MainWindow.GetSizeAsync();
size.Should().HaveCount(2);
size[0].Should().Be(643);
size[1].Should().Be(482);
}
[Fact(Timeout = 20000)]
[IntegrationFact]
public async Task Can_set_progress_bar_and_clear()
{
this.fx.MainWindow.SetProgressBar(0.5);
this.MainWindow.SetProgressBar(0.5);
// No direct getter; rely on absence of error. Try changing again.
this.fx.MainWindow.SetProgressBar(-1); // clears
await Task.Delay(50);
this.MainWindow.SetProgressBar(-1); // clears
await Task.Delay(50.ms());
}
[SkipOnWslFact(Timeout = 20000)]
[IntegrationFact(SkipOnWsl = true)]
public async Task Can_set_and_get_position()
{
this.fx.MainWindow.SetPosition(134, 246);
await Task.Delay(500);
var pos = await this.fx.MainWindow.GetPositionAsync();
this.MainWindow.SetPosition(134, 246);
await Task.Delay(500.ms());
var pos = await this.MainWindow.GetPositionAsync();
pos.Should().BeEquivalentTo([134, 246]);
}
[Fact(Timeout = 20000)]
[IntegrationFact]
public async Task Can_set_and_get_bounds()
{
var bounds = new Rectangle { X = 10, Y = 20, Width = 400, Height = 300 };
this.fx.MainWindow.SetBounds(bounds);
await Task.Delay(500);
var round = await this.fx.MainWindow.GetBoundsAsync();
this.MainWindow.SetBounds(bounds);
await Task.Delay(500.ms());
var round = await this.MainWindow.GetBoundsAsync();
round.Should().BeEquivalentTo(bounds);
round.Width.Should().Be(400);
round.Height.Should().Be(300);
}
[Fact(Timeout = 20000)]
[IntegrationFact]
public async Task Can_set_and_get_content_bounds()
{
var bounds = new Rectangle { X = 0, Y = 0, Width = 300, Height = 200 };
this.fx.MainWindow.SetContentBounds(bounds);
await Task.Delay(500);
var round = await this.fx.MainWindow.GetContentBoundsAsync();
this.MainWindow.SetContentBounds(bounds);
await Task.Delay(500.ms());
var round = await this.MainWindow.GetContentBoundsAsync();
round.Width.Should().BeGreaterThan(0);
round.Height.Should().BeGreaterThan(0);
}
[Fact(Timeout = 20000)]
[IntegrationFact]
public async Task Show_hide_visibility_roundtrip()
{
this.fx.MainWindow.Show();
await Task.Delay(500);
(await this.fx.MainWindow.IsVisibleAsync()).Should().BeTrue();
this.fx.MainWindow.Hide();
await Task.Delay(500);
(await this.fx.MainWindow.IsVisibleAsync()).Should().BeFalse();
BrowserWindow window = null;
try
{
window = await Electron.WindowManager.CreateWindowAsync(new BrowserWindowOptions { Show = true }, "about:blank");
await Task.Delay(100.ms());
window.Show();
await Task.Delay(500.ms());
(await window.IsVisibleAsync()).Should().BeTrue();
window.Hide();
await Task.Delay(500.ms());
(await window.IsVisibleAsync()).Should().BeFalse();
}
finally
{
window?.Destroy();
}
}
[Fact(Timeout = 20000)]
[IntegrationFact]
public async Task AlwaysOnTop_toggle_and_query()
{
this.fx.MainWindow.SetAlwaysOnTop(true);
await Task.Delay(500);
(await this.fx.MainWindow.IsAlwaysOnTopAsync()).Should().BeTrue();
this.fx.MainWindow.SetAlwaysOnTop(false);
await Task.Delay(500);
(await this.fx.MainWindow.IsAlwaysOnTopAsync()).Should().BeFalse();
this.MainWindow.SetAlwaysOnTop(true);
await Task.Delay(500.ms());
(await this.MainWindow.IsAlwaysOnTopAsync()).Should().BeTrue();
this.MainWindow.SetAlwaysOnTop(false);
await Task.Delay(500.ms());
(await this.MainWindow.IsAlwaysOnTopAsync()).Should().BeFalse();
}
[SkippableFact(Timeout = 20000)]
[SupportedOSPlatform("Linux")]
[SupportedOSPlatform("Windows")]
[IntegrationFact]
[SupportedOSPlatform(Linux)]
[SupportedOSPlatform(Windows)]
public async Task MenuBar_auto_hide_and_visibility()
{
this.fx.MainWindow.SetAutoHideMenuBar(true);
await Task.Delay(500);
(await this.fx.MainWindow.IsMenuBarAutoHideAsync()).Should().BeTrue();
this.fx.MainWindow.SetMenuBarVisibility(false);
await Task.Delay(500);
(await this.fx.MainWindow.IsMenuBarVisibleAsync()).Should().BeFalse();
this.fx.MainWindow.SetMenuBarVisibility(true);
await Task.Delay(500);
(await this.fx.MainWindow.IsMenuBarVisibleAsync()).Should().BeTrue();
this.MainWindow.SetAutoHideMenuBar(true);
await Task.Delay(500.ms());
(await this.MainWindow.IsMenuBarAutoHideAsync()).Should().BeTrue();
this.MainWindow.SetMenuBarVisibility(false);
await Task.Delay(500.ms());
(await this.MainWindow.IsMenuBarVisibleAsync()).Should().BeFalse();
this.MainWindow.SetMenuBarVisibility(true);
await Task.Delay(500.ms());
(await this.MainWindow.IsMenuBarVisibleAsync()).Should().BeTrue();
}
[Fact(Timeout = 20000)]
[IntegrationFact]
public async Task ReadyToShow_event_fires_after_content_ready()
{
var window = await Electron.WindowManager.CreateWindowAsync(new BrowserWindowOptions { Show = false }, "about:blank");
var tcs = new TaskCompletionSource();
window.OnReadyToShow += () => tcs.TrySetResult();
BrowserWindow window = null;
// Trigger a navigation and wait for DOM ready so the renderer paints, which emits ready-to-show
var domReadyTcs = new TaskCompletionSource();
window.WebContents.OnDomReady += () => domReadyTcs.TrySetResult();
await Task.Delay(500);
await window.WebContents.LoadURLAsync("about:blank");
await domReadyTcs.Task;
try
{
window = await Electron.WindowManager.CreateWindowAsync(new BrowserWindowOptions { Show = false }, "about:blank");
var tcs = new TaskCompletionSource();
window.OnReadyToShow += () => tcs.TrySetResult();
var completed = await Task.WhenAny(tcs.Task, Task.Delay(3000));
completed.Should().Be(tcs.Task);
// Trigger a navigation and wait for DOM ready so the renderer paints, which emits ready-to-show
var domReadyTcs = new TaskCompletionSource();
window.WebContents.OnDomReady += () => domReadyTcs.TrySetResult();
await Task.Delay(500.ms());
await window.WebContents.LoadURLAsync("about:blank");
await domReadyTcs.Task;
// Typical usage is to show once ready
window.Show();
var completed = await Task.WhenAny(tcs.Task, Task.Delay(3.seconds()));
completed.Should().Be(tcs.Task);
}
finally
{
window?.Destroy();
}
}
[Fact(Timeout = 20000)]
[IntegrationFact]
public async Task PageTitleUpdated_event_fires_on_title_change()
{
var window = await Electron.WindowManager.CreateWindowAsync(new BrowserWindowOptions { Show = true }, "about:blank");
@@ -148,90 +167,90 @@ namespace ElectronNET.IntegrationTests.Tests
// Navigate and wait for DOM ready, then change the document.title to trigger the event
var domReadyTcs = new TaskCompletionSource();
window.WebContents.OnDomReady += () => domReadyTcs.TrySetResult();
await Task.Delay(500);
await Task.Delay(500.ms());
await window.WebContents.LoadURLAsync("about:blank");
await domReadyTcs.Task;
await window.WebContents.ExecuteJavaScriptAsync<string>("document.title='NewTitle';");
// Wait for event up to a short timeout
var completed2 = await Task.WhenAny(tcs.Task, Task.Delay(3000));
var completed2 = await Task.WhenAny(tcs.Task, Task.Delay(3.seconds()));
completed2.Should().Be(tcs.Task);
(await tcs.Task).Should().Be("NewTitle");
}
[Fact(Timeout = 20000)]
[IntegrationFact]
public async Task Resize_event_fires_on_size_change()
{
var window = await Electron.WindowManager.CreateWindowAsync(new BrowserWindowOptions { Show = false }, "about:blank");
var resized = false;
window.OnResize += () => resized = true;
await Task.Delay(500);
await Task.Delay(500.ms());
window.SetSize(500, 400);
await Task.Delay(300);
await Task.Delay(300.ms());
resized.Should().BeTrue();
}
[Fact(Timeout = 20000)]
[IntegrationFact]
public async Task Progress_bar_and_always_on_top_toggle()
{
var win = this.fx.MainWindow;
var win = this.MainWindow;
win.SetProgressBar(0.5);
await Task.Delay(50);
await Task.Delay(50.ms());
win.SetProgressBar(0.8, new ProgressBarOptions());
await Task.Delay(50);
await Task.Delay(50.ms());
win.SetAlwaysOnTop(true);
await Task.Delay(500);
await Task.Delay(500.ms());
(await win.IsAlwaysOnTopAsync()).Should().BeTrue();
win.SetAlwaysOnTop(false);
await Task.Delay(500);
await Task.Delay(500.ms());
(await win.IsAlwaysOnTopAsync()).Should().BeFalse();
}
[SkippableFact(Timeout = 20000)]
[SupportedOSPlatform("Linux")]
[SupportedOSPlatform("Windows")]
[IntegrationFact]
[SupportedOSPlatform(Linux)]
[SupportedOSPlatform(Windows)]
public async Task Menu_bar_visibility_and_auto_hide()
{
var win = this.fx.MainWindow;
var win = this.MainWindow;
win.SetAutoHideMenuBar(true);
await Task.Delay(500);
await Task.Delay(500.ms());
(await win.IsMenuBarAutoHideAsync()).Should().BeTrue();
win.SetMenuBarVisibility(true);
await Task.Delay(500);
await Task.Delay(500.ms());
(await win.IsMenuBarVisibleAsync()).Should().BeTrue();
}
[Fact(Timeout = 20000)]
[IntegrationFact]
public async Task Parent_child_relationship_roundtrip()
{
var child = await Electron.WindowManager.CreateWindowAsync(new BrowserWindowOptions { Show = false, Width = 300, Height = 200 }, "about:blank");
this.fx.MainWindow.SetParentWindow(null); // ensure top-level
child.SetParentWindow(this.fx.MainWindow);
await Task.Delay(500);
this.MainWindow.SetParentWindow(null); // ensure top-level
child.SetParentWindow(this.MainWindow);
await Task.Delay(500.ms());
var parent = await child.GetParentWindowAsync();
parent.Id.Should().Be(this.fx.MainWindow.Id);
var kids = await this.fx.MainWindow.GetChildWindowsAsync();
parent.Id.Should().Be(this.MainWindow.Id);
var kids = await this.MainWindow.GetChildWindowsAsync();
kids.Select(k => k.Id).Should().Contain(child.Id);
child.Destroy();
}
[SkippableFact(Timeout = 20000)]
[SupportedOSPlatform("macOS")]
[IntegrationFact]
[SupportedOSPlatform(MacOS)]
public async Task Represented_filename_and_edited_flags()
{
var win = this.fx.MainWindow;
var win = this.MainWindow;
var temp = Path.Combine(Path.GetTempPath(), "electronnet_test.txt");
File.WriteAllText(temp, "test");
win.SetRepresentedFilename(temp);
await Task.Delay(500);
await Task.Delay(500.ms());
var represented = await win.GetRepresentedFilenameAsync();
represented.Should().Be(temp);
win.SetDocumentEdited(true);
await Task.Delay(500);
await Task.Delay(500.ms());
var edited = await win.IsDocumentEditedAsync();
edited.Should().BeTrue();

View File

@@ -2,19 +2,16 @@ namespace ElectronNET.IntegrationTests.Tests
{
using System.Runtime.Versioning;
using ElectronNET.API;
using ElectronNET.IntegrationTests.Common;
[Collection("ElectronCollection")]
public class ClipboardTests
public class ClipboardTests : IntegrationTestBase
{
// ReSharper disable once NotAccessedField.Local
private readonly ElectronFixture fx;
public ClipboardTests(ElectronFixture fx)
public ClipboardTests(ElectronFixture fx) : base(fx)
{
this.fx = fx;
}
[Fact(Timeout = 20000)]
[IntegrationFact]
public async Task Clipboard_text_roundtrip()
{
var text = $"Hello Electron {Guid.NewGuid()}";
@@ -23,7 +20,7 @@ namespace ElectronNET.IntegrationTests.Tests
read.Should().Be(text);
}
[Fact(Timeout = 20000)]
[IntegrationFact]
public async Task Available_formats_contains_text_after_write()
{
var text = "FormatsTest";
@@ -32,9 +29,9 @@ namespace ElectronNET.IntegrationTests.Tests
formats.Should().Contain(f => f.Contains("text") || f.Contains("TEXT") || f.Contains("plain"));
}
[SkippableFact(Timeout = 20000)]
[SupportedOSPlatform("macOS")]
[SupportedOSPlatform("Windows")]
[IntegrationFact]
[SupportedOSPlatform(MacOS)]
[SupportedOSPlatform(Windows)]
public async Task Bookmark_write_and_read()
{
var url = "https://electron-test.com";

View File

@@ -1,26 +1,26 @@
namespace ElectronNET.IntegrationTests.Tests
{
[Collection("ElectronCollection")]
public class CookiesTests
{
private readonly ElectronFixture fx;
using ElectronNET.Common;
using ElectronNET.IntegrationTests.Common;
public CookiesTests(ElectronFixture fx)
[Collection("ElectronCollection")]
public class CookiesTests : IntegrationTestBase
{
public CookiesTests(ElectronFixture fx) : base(fx)
{
this.fx = fx;
}
[Fact(Skip = "Cookie set/get requires navigation to domain; skipping until test harness serves page")]
[IntegrationFact(Skip = "Cookie set/get requires navigation to domain; skipping until test harness serves page")]
public async Task Cookie_set_get_remove_sequence()
{
var session = this.fx.MainWindow.WebContents.Session;
var session = this.MainWindow.WebContents.Session;
var changed = false;
session.Cookies.OnChanged += (cookie, cause, removed) => changed = true;
// Navigate to example.com so cookie domain matches
await this.fx.MainWindow.WebContents.LoadURLAsync("https://example.com");
await this.MainWindow.WebContents.LoadURLAsync("https://example.com");
// Set via renderer for now
await this.fx.MainWindow.WebContents.ExecuteJavaScriptAsync<string>("document.cookie='integration_cookie=1;path=/';");
await Task.Delay(500);
await this.MainWindow.WebContents.ExecuteJavaScriptAsync<string>("document.cookie='integration_cookie=1;path=/';");
await Task.Delay(500.ms());
changed.Should().BeTrue();
}
}

View File

@@ -2,11 +2,16 @@ namespace ElectronNET.IntegrationTests.Tests
{
using System.Runtime.InteropServices;
using ElectronNET.API;
using ElectronNET.IntegrationTests.Common;
[Collection("ElectronCollection")]
public class GlobalShortcutTests
public class GlobalShortcutTests : IntegrationTestBase
{
[Fact(Timeout = 20000)]
public GlobalShortcutTests(ElectronFixture fx) : base(fx)
{
}
[IntegrationFact]
public async Task Can_register_and_unregister()
{
var accel = RuntimeInformation.IsOSPlatform(OSPlatform.OSX) ? "Cmd+Alt+G" : "Ctrl+Alt+G";

View File

@@ -1,11 +1,16 @@
namespace ElectronNET.IntegrationTests.Tests
{
using ElectronNET.API;
using ElectronNET.IntegrationTests.Common;
[Collection("ElectronCollection")]
public class HostHookTests
public class HostHookTests : IntegrationTestBase
{
[Fact(Skip = "Requires HostHook setup; skipping")]
public HostHookTests(ElectronFixture fx) : base(fx)
{
}
[IntegrationFact(Skip = "Requires HostHook setup; skipping")]
public async Task HostHook_call_returns_value()
{
var result = await Electron.HostHook.CallAsync<string>("create-excel-file", ".");

View File

@@ -1,18 +1,17 @@
namespace ElectronNET.IntegrationTests.Tests
{
using ElectronNET.API;
using ElectronNET.Common;
using ElectronNET.IntegrationTests.Common;
[Collection("ElectronCollection")]
public class IpcMainTests
public class IpcMainTests : IntegrationTestBase
{
private readonly ElectronFixture fx;
public IpcMainTests(ElectronFixture fx)
public IpcMainTests(ElectronFixture fx) : base(fx)
{
this.fx = fx;
}
[Fact(Timeout = 20000)]
[IntegrationFact]
public async Task Ipc_On_receives_message_from_renderer()
{
object received = null;
@@ -24,7 +23,7 @@ namespace ElectronNET.IntegrationTests.Tests
tcs.TrySetResult(obj as string);
});
await this.fx.MainWindow.WebContents.ExecuteJavaScriptAsync<string>("require('electron').ipcRenderer.send('ipc-on-test','payload123')");
await this.MainWindow.WebContents.ExecuteJavaScriptAsync<string>("require('electron').ipcRenderer.send('ipc-on-test','payload123')");
var result = await tcs.Task.WaitAsync(TimeSpan.FromSeconds(5));
@@ -33,28 +32,28 @@ namespace ElectronNET.IntegrationTests.Tests
result.Should().Be("payload123");
}
[Fact(Timeout = 20000)]
[IntegrationFact]
public async Task Ipc_Once_only_fires_once()
{
var count = 0;
Electron.IpcMain.Once("ipc-once-test", _ => count++);
await this.fx.MainWindow.WebContents.ExecuteJavaScriptAsync<string>("const {ipcRenderer}=require('electron'); ipcRenderer.send('ipc-once-test','a'); ipcRenderer.send('ipc-once-test','b');");
await Task.Delay(500);
await this.MainWindow.WebContents.ExecuteJavaScriptAsync<string>("const {ipcRenderer}=require('electron'); ipcRenderer.send('ipc-once-test','a'); ipcRenderer.send('ipc-once-test','b');");
await Task.Delay(500.ms());
count.Should().Be(1);
}
[Fact(Timeout = 20000)]
[IntegrationFact]
public async Task Ipc_RemoveAllListeners_stops_receiving()
{
var fired = false;
await Electron.IpcMain.On("ipc-remove-test", _ => fired = true);
Electron.IpcMain.RemoveAllListeners("ipc-remove-test");
await this.fx.MainWindow.WebContents.ExecuteJavaScriptAsync<string>("require('electron').ipcRenderer.send('ipc-remove-test','x')");
await Task.Delay(400);
await this.MainWindow.WebContents.ExecuteJavaScriptAsync<string>("require('electron').ipcRenderer.send('ipc-remove-test','x')");
await Task.Delay(400.ms());
fired.Should().BeFalse();
}
[Fact(Timeout = 20000)]
[IntegrationFact]
public async Task Ipc_OnSync_returns_value()
{
object received = null;
@@ -64,7 +63,7 @@ namespace ElectronNET.IntegrationTests.Tests
received = obj;
return "pong";
});
var ret = await this.fx.MainWindow.WebContents.ExecuteJavaScriptAsync<string>("require('electron').ipcRenderer.sendSync('ipc-sync-test','ping')");
var ret = await this.MainWindow.WebContents.ExecuteJavaScriptAsync<string>("require('electron').ipcRenderer.sendSync('ipc-sync-test','ping')");
received.Should().BeOfType<string>();
received.Should().Be("ping");
@@ -72,23 +71,23 @@ namespace ElectronNET.IntegrationTests.Tests
ret.Should().Be("pong");
}
[Fact(Timeout = 20000)]
[IntegrationFact]
public async Task Ipc_Send_from_main_reaches_renderer()
{
// Listener: store raw arg; if Electron packs differently we will normalize later
await this.fx.MainWindow.WebContents.ExecuteJavaScriptAsync<string>(@"(function(){ const {ipcRenderer}=require('electron'); ipcRenderer.once('main-to-render',(e,arg)=>{ globalThis.__mainToRender = arg;}); return 'ready'; })();");
Electron.IpcMain.Send(this.fx.MainWindow, "main-to-render", "hello-msg");
await this.MainWindow.WebContents.ExecuteJavaScriptAsync<string>(@"(function(){ const {ipcRenderer}=require('electron'); ipcRenderer.once('main-to-render',(e,arg)=>{ globalThis.__mainToRender = arg;}); return 'ready'; })();");
Electron.IpcMain.Send(this.MainWindow, "main-to-render", "hello-msg");
string value = "";
for (int i = 0; i < 20; i++)
{
var jsVal = await this.fx.MainWindow.WebContents.ExecuteJavaScriptAsync<string>("globalThis.__mainToRender === undefined ? '' : (typeof globalThis.__mainToRender === 'string' ? globalThis.__mainToRender : JSON.stringify(globalThis.__mainToRender))");
var jsVal = await this.MainWindow.WebContents.ExecuteJavaScriptAsync<string>("globalThis.__mainToRender === undefined ? '' : (typeof globalThis.__mainToRender === 'string' ? globalThis.__mainToRender : JSON.stringify(globalThis.__mainToRender))");
value = jsVal?.ToString() ?? "";
if (!string.IsNullOrEmpty(value))
{
break;
}
await Task.Delay(100);
await Task.Delay(100.ms());
}
// Normalize possible JSON array ["hello-msg"] case

View File

@@ -2,18 +2,17 @@ namespace ElectronNET.IntegrationTests.Tests
{
using ElectronNET.API;
using ElectronNET.API.Entities;
using ElectronNET.Common;
using ElectronNET.IntegrationTests.Common;
[Collection("ElectronCollection")]
public class MenuTests
public class MenuTests : IntegrationTestBase
{
private readonly ElectronFixture fx;
public MenuTests(ElectronFixture fx)
public MenuTests(ElectronFixture fx) : base(fx)
{
this.fx = fx;
}
[Fact(Timeout = 20000)]
[IntegrationFact]
public async Task ApplicationMenu_click_invokes_handler()
{
var clicked = false;
@@ -30,29 +29,29 @@ namespace ElectronNET.IntegrationTests.Tests
};
Electron.Menu.SetApplicationMenu(items);
var targetId = items[0].Submenu[0].Id;
await this.fx.MainWindow.WebContents.ExecuteJavaScriptAsync<string>($"require('electron').ipcRenderer.send('integration-click-application-menu','{targetId}')");
await this.MainWindow.WebContents.ExecuteJavaScriptAsync<string>($"require('electron').ipcRenderer.send('integration-click-application-menu','{targetId}')");
for (int i = 0; i < 20 && !clicked; i++)
{
await Task.Delay(100);
await Task.Delay(100.ms());
}
clicked.Should().BeTrue();
}
[Fact(Timeout = 20000)]
[IntegrationFact]
public async Task ContextMenu_popup_registers_items()
{
var win = this.fx.MainWindow;
var win = this.MainWindow;
var ctxClicked = false;
var ctxItems = new[] { new MenuItem { Label = "Ctx", Click = () => ctxClicked = true } };
Electron.Menu.SetContextMenu(win, ctxItems);
var ctxId = ctxItems[0].Id;
// simulate popup then click
Electron.Menu.ContextMenuPopup(win);
await this.fx.MainWindow.WebContents.ExecuteJavaScriptAsync<string>($"require('electron').ipcRenderer.send('integration-click-context-menu',{win.Id},'{ctxId}')");
await this.MainWindow.WebContents.ExecuteJavaScriptAsync<string>($"require('electron').ipcRenderer.send('integration-click-context-menu',{win.Id},'{ctxId}')");
for (int i = 0; i < 20 && !ctxClicked; i++)
{
await Task.Delay(100);
await Task.Delay(100.ms());
}
ctxClicked.Should().BeTrue();

View File

@@ -1,13 +1,12 @@
namespace ElectronNET.IntegrationTests.Tests
{
[Collection("ElectronCollection")]
public class MultiEventRegistrationTests
{
private readonly ElectronFixture fx;
using ElectronNET.IntegrationTests.Common;
public MultiEventRegistrationTests(ElectronFixture fx)
[Collection("ElectronCollection")]
public class MultiEventRegistrationTests : IntegrationTestBase
{
public MultiEventRegistrationTests(ElectronFixture fx) : base(fx)
{
this.fx = fx;
}
private static async Task<bool> WaitAllOrTimeout(TimeSpan timeout, params Task[] tasks)
@@ -17,10 +16,10 @@ namespace ElectronNET.IntegrationTests.Tests
return ReferenceEquals(completed, all) && all.IsCompletedSuccessfully;
}
[Fact(Timeout = 20000)]
[IntegrationFact]
public async Task BrowserWindow_OnResize_multiple_handlers_called()
{
var win = this.fx.MainWindow;
var win = this.MainWindow;
var h1 = new TaskCompletionSource();
var h2 = new TaskCompletionSource();
var h3 = new TaskCompletionSource();
@@ -41,10 +40,10 @@ namespace ElectronNET.IntegrationTests.Tests
}
}
[Fact(Timeout = 20000)]
[IntegrationFact]
public async Task WebContents_OnDomReady_multiple_handlers_called()
{
var wc = this.fx.MainWindow.WebContents;
var wc = this.MainWindow.WebContents;
var r1 = new TaskCompletionSource();
var r2 = new TaskCompletionSource();

View File

@@ -1,15 +1,20 @@
using System.Drawing;
using ElectronNET.API.Entities;
using ElectronNET.IntegrationTests.Common;
using System.Runtime.Versioning;
using RectangleEntity = ElectronNET.API.Entities.Rectangle;
namespace ElectronNET.IntegrationTests.Tests
{
using System.Drawing;
using ElectronNET.API.Entities;
[SupportedOSPlatform("Windows")]
public class NativeImageTests
[Collection("ElectronCollection")]
[SupportedOSPlatform(Windows)]
public class NativeImageTests : IntegrationTestBase
{
[SkippableFact(Timeout = 20000)]
public NativeImageTests(ElectronFixture fx) : base(fx)
{
}
[IntegrationFact]
public async Task Create_from_bitmap_and_to_png()
{
using var bmp = new Bitmap(10, 10);
@@ -27,7 +32,7 @@ namespace ElectronNET.IntegrationTests.Tests
png!.Length.Should().BeGreaterThan(0);
}
[SkippableFact(Timeout = 20000)]
[IntegrationFact]
public async Task Create_from_buffer_and_to_data_url()
{
// Prepare PNG bytes
@@ -46,7 +51,7 @@ namespace ElectronNET.IntegrationTests.Tests
dataUrl!.StartsWith("data:image/", StringComparison.Ordinal).Should().BeTrue();
}
[SkippableFact(Timeout = 20000)]
[IntegrationFact]
public async Task Resize_and_crop_produce_expected_sizes()
{
using var bmp = new Bitmap(12, 10);
@@ -66,7 +71,7 @@ namespace ElectronNET.IntegrationTests.Tests
csize.Height.Should().Be(3);
}
[SkippableFact(Timeout = 20000)]
[IntegrationFact]
public async Task Add_representation_for_scale_factor()
{
using var bmp = new Bitmap(5, 5);

View File

@@ -3,29 +3,35 @@ namespace ElectronNET.IntegrationTests.Tests
using System.Runtime.Versioning;
using ElectronNET.API;
using ElectronNET.API.Entities;
using ElectronNET.Common;
using ElectronNET.IntegrationTests.Common;
[Collection("ElectronCollection")]
public class NativeThemeTests
public class NativeThemeTests : IntegrationTestBase
{
[Fact(Timeout = 20000)]
public NativeThemeTests(ElectronFixture fx) : base(fx)
{
}
[IntegrationFact]
public async Task ThemeSource_roundtrip()
{
// Capture initial
_ = await Electron.NativeTheme.ShouldUseDarkColorsAsync();
// Force light
await Task.Delay(50);
await Task.Delay(50.ms());
Electron.NativeTheme.SetThemeSource(ThemeSourceMode.Light);
await Task.Delay(500);
await Task.Delay(500.ms());
var useDarkAfterLight = await Electron.NativeTheme.ShouldUseDarkColorsAsync();
var themeSourceLight = await Electron.NativeTheme.GetThemeSourceAsync();
// Force dark
Electron.NativeTheme.SetThemeSource(ThemeSourceMode.Dark);
await Task.Delay(500);
await Task.Delay(500.ms());
var useDarkAfterDark = await Electron.NativeTheme.ShouldUseDarkColorsAsync();
var themeSourceDark = await Electron.NativeTheme.GetThemeSourceAsync();
// Restore system
Electron.NativeTheme.SetThemeSource(ThemeSourceMode.System);
await Task.Delay(500);
await Task.Delay(500.ms());
var themeSourceSystem = await Electron.NativeTheme.GetThemeSourceAsync();
// Assertions are tolerant (platform dependent)
useDarkAfterLight.Should().BeFalse("forcing Light should result in light colors");
@@ -35,34 +41,34 @@ namespace ElectronNET.IntegrationTests.Tests
themeSourceSystem.Should().Be(ThemeSourceMode.System);
}
[Fact(Timeout = 20000)]
[IntegrationFact]
public async Task Updated_event_fires_on_change()
{
var fired = false;
Electron.NativeTheme.Updated += () => fired = true;
Electron.NativeTheme.SetThemeSource(ThemeSourceMode.Dark);
await Task.Delay(400);
await Task.Delay(400.ms());
Electron.NativeTheme.SetThemeSource(ThemeSourceMode.Light);
for (int i = 0; i < 10 && !fired; i++)
{
await Task.Delay(100);
await Task.Delay(100.ms());
}
fired.Should().BeTrue();
}
[SkippableFact(Timeout = 20000)]
[SupportedOSPlatform("macOS")]
[SupportedOSPlatform("Windows")]
[IntegrationFact]
[SupportedOSPlatform(MacOS)]
[SupportedOSPlatform(Windows)]
public async Task Should_use_high_contrast_colors_check()
{
var metrics = await Electron.NativeTheme.ShouldUseHighContrastColorsAsync();
metrics.Should().Be(false);
}
[SkippableFact(Timeout = 20000)]
[SupportedOSPlatform("macOS")]
[SupportedOSPlatform("Windows")]
[IntegrationFact]
[SupportedOSPlatform(MacOS)]
[SupportedOSPlatform(Windows)]
public async Task Should_use_inverted_colors_check()
{
var metrics = await Electron.NativeTheme.ShouldUseInvertedColorSchemeAsync();

View File

@@ -3,11 +3,17 @@ namespace ElectronNET.IntegrationTests.Tests
using System.Runtime.InteropServices;
using ElectronNET.API;
using ElectronNET.API.Entities;
using ElectronNET.Common;
using ElectronNET.IntegrationTests.Common;
[Collection("ElectronCollection")]
public class NotificationTests
public class NotificationTests : IntegrationTestBase
{
[SkippableFact(Timeout = 20000)]
public NotificationTests(ElectronFixture fx) : base(fx)
{
}
[IntegrationFact]
public async Task Notification_create_check()
{
Skip.If(RuntimeInformation.IsOSPlatform(OSPlatform.Linux), "Always returns false. Might need full-blown desktop environment");
@@ -17,16 +23,16 @@ namespace ElectronNET.IntegrationTests.Tests
var options = new NotificationOptions("Notification Title", "Notification test 123");
options.OnShow = () => tcs.SetResult();
await Task.Delay(500);
await Task.Delay(500.ms());
Electron.Notification.Show(options);
await Task.WhenAny(tcs.Task, Task.Delay(5_000));
await Task.WhenAny(tcs.Task, Task.Delay(5.seconds()));
tcs.Task.IsCompletedSuccessfully.Should().BeTrue();
}
[SkippableFact(Timeout = 20000)]
[IntegrationFact]
public async Task Notification_is_supported_check()
{
Skip.If(RuntimeInformation.IsOSPlatform(OSPlatform.Linux), "Always returns false. Might need full-blown desktop environment");

View File

@@ -1,11 +1,16 @@
namespace ElectronNET.IntegrationTests.Tests
{
using ElectronNET.API;
using ElectronNET.IntegrationTests.Common;
[Collection("ElectronCollection")]
public class ProcessTests
public class ProcessTests : IntegrationTestBase
{
[Fact(Timeout = 20000)]
public ProcessTests(ElectronFixture fx) : base(fx)
{
}
[IntegrationFact]
public async Task Process_info_is_accessible()
{
// Use renderer to fetch process info and round-trip
@@ -14,7 +19,7 @@ namespace ElectronNET.IntegrationTests.Tests
result.Should().Be("ok");
}
[Fact(Timeout = 20000)]
[IntegrationFact]
public async Task Process_properties_are_populated()
{
var execPath = await Electron.Process.ExecPathAsync;

View File

@@ -6,17 +6,13 @@ namespace ElectronNET.IntegrationTests.Tests
using ElectronNET.IntegrationTests.Common;
[Collection("ElectronCollection")]
public class ScreenTests
public class ScreenTests : IntegrationTestBase
{
// ReSharper disable once NotAccessedField.Local
private readonly ElectronFixture fx;
public ScreenTests(ElectronFixture fx)
public ScreenTests(ElectronFixture fx) : base(fx)
{
this.fx = fx;
}
[SkipOnWslFact(Timeout = 20000)]
[IntegrationFact(SkipOnWsl = true)]
public async Task Primary_display_has_positive_dimensions()
{
var display = await Electron.Screen.GetPrimaryDisplayAsync();
@@ -24,7 +20,7 @@ namespace ElectronNET.IntegrationTests.Tests
display.Size.Height.Should().BeGreaterThan(0);
}
[SkipOnWslFact(Timeout = 20000)]
[IntegrationFact(SkipOnWsl = true)]
public async Task GetAllDisplays_returns_at_least_one()
{
var displays = await Electron.Screen.GetAllDisplaysAsync();
@@ -32,17 +28,15 @@ namespace ElectronNET.IntegrationTests.Tests
displays.Length.Should().BeGreaterThan(0);
}
[Fact(Timeout = 20000)]
[IntegrationFact]
public async Task GetCursorScreenPoint_check()
{
var point = await Electron.Screen.GetCursorScreenPointAsync();
point.Should().NotBeNull();
point.X.Should().BeGreaterThanOrEqualTo(0);
point.Y.Should().BeGreaterThanOrEqualTo(0);
}
[SkippableFact(Timeout = 20000)]
[SupportedOSPlatform("macOS")]
[IntegrationFact]
[SupportedOSPlatform(MacOS)]
public async Task GetMenuBarWorkArea_check()
{
var area = await Electron.Screen.GetMenuBarWorkAreaAsync();
@@ -53,7 +47,7 @@ namespace ElectronNET.IntegrationTests.Tests
area.Width.Should().BeGreaterThan(0);
}
[SkipOnWslFact(Timeout = 20000)]
[IntegrationFact(SkipOnWsl = true)]
public async Task GetDisplayNearestPoint_check()
{
var point = new Point
@@ -67,7 +61,7 @@ namespace ElectronNET.IntegrationTests.Tests
display.Size.Height.Should().BeGreaterThan(0);
}
[SkipOnWslFact(Timeout = 20000)]
[IntegrationFact(SkipOnWsl = true)]
public async Task GetDisplayMatching_check()
{
var rectangle = new Rectangle

View File

@@ -1,21 +1,19 @@
namespace ElectronNET.IntegrationTests.Tests
{
using ElectronNET.API.Entities;
using ElectronNET.IntegrationTests.Common;
[Collection("ElectronCollection")]
public class SessionTests
public class SessionTests : IntegrationTestBase
{
private readonly ElectronFixture fx;
public SessionTests(ElectronFixture fx)
public SessionTests(ElectronFixture fx) : base(fx)
{
this.fx = fx;
}
[Fact(Timeout = 20000)]
[IntegrationFact]
public async Task Session_preloads_roundtrip()
{
var session = this.fx.MainWindow.WebContents.Session;
var session = this.MainWindow.WebContents.Session;
_ = await session.GetPreloadsAsync();
// Use a dummy path; API should store value
session.SetPreloads(new[] { "/tmp/preload_dummy.js" });
@@ -23,10 +21,10 @@ namespace ElectronNET.IntegrationTests.Tests
preloadsAfter.Should().Contain("/tmp/preload_dummy.js");
}
[Fact(Timeout = 20000)]
[IntegrationFact]
public async Task Session_proxy_set_and_resolve()
{
var session = this.fx.MainWindow.WebContents.Session;
var session = this.MainWindow.WebContents.Session;
// Provide all ctor args (pacScript empty to ignore, proxyRules direct, bypass empty)
await session.SetProxyAsync(new ProxyConfig("", "direct://", ""));
var proxy = await session.ResolveProxyAsync("https://example.com");
@@ -34,10 +32,10 @@ namespace ElectronNET.IntegrationTests.Tests
}
[Fact(Timeout = 20000)]
[IntegrationFact]
public async Task Session_clear_cache_and_storage_completes()
{
var session = this.fx.MainWindow.WebContents.Session;
var session = this.MainWindow.WebContents.Session;
await session.ClearCacheAsync();
await session.ClearStorageDataAsync();
await session.ClearHostResolverCacheAsync();
@@ -46,10 +44,10 @@ namespace ElectronNET.IntegrationTests.Tests
ua.Should().NotBeNullOrWhiteSpace();
}
[Fact(Timeout = 20000)]
[IntegrationFact]
public async Task Session_preloads_set_multiple_and_clear()
{
var session = this.fx.MainWindow.WebContents.Session;
var session = this.MainWindow.WebContents.Session;
session.SetPreloads(new[] { "/tmp/a.js", "/tmp/b.js" });
var after = await session.GetPreloadsAsync();
after.Should().Contain("/tmp/a.js").And.Contain("/tmp/b.js");
@@ -59,40 +57,40 @@ namespace ElectronNET.IntegrationTests.Tests
empty.Should().NotContain("/tmp/a.js");
}
[Fact(Timeout = 20000)]
[IntegrationFact]
public async Task Clear_auth_cache_overloads()
{
var session = this.fx.MainWindow.WebContents.Session;
var session = this.MainWindow.WebContents.Session;
await session.ClearAuthCacheAsync();
await session.ClearAuthCacheAsync(new RemovePassword("password") { Origin = "https://example.com", Username = "user", Password = "pw", Realm = "realm", Scheme = Scheme.basic });
}
[Fact(Timeout = 20000)]
[IntegrationFact]
public async Task Clear_storage_with_options()
{
var session = this.fx.MainWindow.WebContents.Session;
var session = this.MainWindow.WebContents.Session;
await session.ClearStorageDataAsync(new ClearStorageDataOptions { Storages = new[] { "cookies" }, Quotas = new[] { "temporary" } });
}
[Fact(Timeout = 20000)]
[IntegrationFact]
public async Task Enable_disable_network_emulation()
{
var session = this.fx.MainWindow.WebContents.Session;
var session = this.MainWindow.WebContents.Session;
session.EnableNetworkEmulation(new EnableNetworkEmulationOptions { Offline = false, Latency = 10, DownloadThroughput = 50000, UploadThroughput = 20000 });
session.DisableNetworkEmulation();
}
[Fact(Timeout = 20000)]
[IntegrationFact]
public async Task Flush_storage_data_does_not_throw()
{
var session = this.fx.MainWindow.WebContents.Session;
var session = this.MainWindow.WebContents.Session;
session.FlushStorageData();
}
[Fact(Timeout = 20000)]
[IntegrationFact]
public async Task Set_user_agent_affects_new_navigation()
{
var session = this.fx.MainWindow.WebContents.Session;
var session = this.MainWindow.WebContents.Session;
// Set UA and verify via session API (navigator.userAgent on existing WebContents may not reflect the override)
session.SetUserAgent("IntegrationAgent/1.0");
var ua = await session.GetUserAgent();

View File

@@ -1,11 +1,16 @@
namespace ElectronNET.IntegrationTests.Tests
{
using ElectronNET.API;
using ElectronNET.IntegrationTests.Common;
[Collection("ElectronCollection")]
public class ShellTests
public class ShellTests : IntegrationTestBase
{
[Fact(Skip = "This can keep the test process hanging until the e-mail window is closed")]
public ShellTests(ElectronFixture fx) : base(fx)
{
}
[IntegrationFact(Skip = "This can keep the test process hanging until the e-mail window is closed")]
public async Task OpenExternal_invalid_scheme_returns_error_or_empty()
{
var error = await Electron.Shell.OpenExternalAsync("mailto:test@example.com");

View File

@@ -2,28 +2,26 @@ namespace ElectronNET.IntegrationTests.Tests
{
using System.Runtime.Versioning;
using ElectronNET.API.Entities;
using ElectronNET.IntegrationTests.Common;
[Collection("ElectronCollection")]
public class ThumbarButtonTests
public class ThumbarButtonTests : IntegrationTestBase
{
private readonly ElectronFixture fx;
public ThumbarButtonTests(ElectronFixture fx)
public ThumbarButtonTests(ElectronFixture fx) : base(fx)
{
this.fx = fx;
}
[SkippableFact(Timeout = 20000)]
[SupportedOSPlatform("Windows")]
[IntegrationFact]
[SupportedOSPlatform(Windows)]
public async Task SetThumbarButtons_returns_success()
{
var btn = new ThumbarButton("icon.png") { Tooltip = "Test" };
var success = await this.fx.MainWindow.SetThumbarButtonsAsync(new[] { btn });
var success = await this.MainWindow.SetThumbarButtonsAsync(new[] { btn });
success.Should().BeTrue();
}
[SkippableFact(Timeout = 20000)]
[SupportedOSPlatform("Windows")]
[IntegrationFact]
[SupportedOSPlatform(Windows)]
public async Task Thumbar_button_click_invokes_callback()
{
var icon = Path.Combine(Directory.GetCurrentDirectory(), "ElectronNET.WebApp", "wwwroot", "icon.png");
@@ -34,7 +32,7 @@ namespace ElectronNET.IntegrationTests.Tests
var tcs = new TaskCompletionSource<bool>();
var btn = new ThumbarButton(icon) { Tooltip = "Test", Flags = new[] { ThumbarButtonFlag.enabled }, Click = () => tcs.TrySetResult(true) };
var ok = await this.fx.MainWindow.SetThumbarButtonsAsync(new[] { btn });
var ok = await this.MainWindow.SetThumbarButtonsAsync(new[] { btn });
ok.Should().BeTrue();
}
}

View File

@@ -1,19 +1,16 @@
namespace ElectronNET.IntegrationTests.Tests
{
using ElectronNET.API;
using ElectronNET.IntegrationTests.Common;
[Collection("ElectronCollection")]
public class TrayTests
public class TrayTests : IntegrationTestBase
{
// ReSharper disable once NotAccessedField.Local
private readonly ElectronFixture fx;
public TrayTests(ElectronFixture fx)
public TrayTests(ElectronFixture fx) : base(fx)
{
this.fx = fx;
}
[Fact(Timeout = 20000)]
[IntegrationFact]
public async Task Can_create_tray_and_destroy()
{
//await Electron.Tray.Show("assets/icon.png");

View File

@@ -2,56 +2,56 @@ using System.Runtime.InteropServices;
namespace ElectronNET.IntegrationTests.Tests
{
using ElectronNET.API;
using ElectronNET.API.Entities;
using ElectronNET.Common;
using ElectronNET.IntegrationTests.Common;
[Collection("ElectronCollection")]
public class WebContentsTests
public class WebContentsTests : IntegrationTestBase
{
private readonly ElectronFixture fx;
public WebContentsTests(ElectronFixture fx)
public WebContentsTests(ElectronFixture fx) : base(fx)
{
this.fx = fx;
}
[Fact(Timeout = 20000)]
[IntegrationFact]
public async Task Can_get_url_after_navigation()
{
var wc = this.fx.MainWindow.WebContents;
var wc = this.MainWindow.WebContents;
await wc.LoadURLAsync("https://example.com");
var url = await wc.GetUrl();
url.Should().Contain("example.com");
}
[Fact(Timeout = 20000)]
[IntegrationFact]
public async Task ExecuteJavaScript_returns_title()
{
var wc = this.fx.MainWindow.WebContents;
var wc = this.MainWindow.WebContents;
await wc.LoadURLAsync("https://example.com");
var title = await wc.ExecuteJavaScriptAsync<string>("document.title");
title.Should().NotBeNull();
}
[Fact(Timeout = 20000)]
[IntegrationFact]
public async Task DomReady_event_fires()
{
var wc = this.fx.MainWindow.WebContents;
var wc = this.MainWindow.WebContents;
var fired = false;
wc.OnDomReady += () => fired = true;
await wc.LoadURLAsync("https://example.com");
await Task.Delay(500);
await Task.Delay(500.ms());
fired.Should().BeTrue();
}
[Fact(Timeout = 20000)]
[IntegrationFact]
public async Task Can_print_to_pdf()
{
var html = "data:text/html,<html><body><h1>PDF Test</h1><p>Electron.NET</p></body></html>";
await this.fx.MainWindow.WebContents.LoadURLAsync(html);
await this.MainWindow.WebContents.LoadURLAsync(html);
var tmp = Path.Combine(Path.GetTempPath(), $"electronnet_pdf_{Guid.NewGuid():N}.pdf");
try
{
var ok = await this.fx.MainWindow.WebContents.PrintToPDFAsync(tmp);
var ok = await this.MainWindow.WebContents.PrintToPDFAsync(tmp);
ok.Should().BeTrue();
File.Exists(tmp).Should().BeTrue();
new FileInfo(tmp).Length.Should().BeGreaterThan(0);
@@ -65,92 +65,130 @@ namespace ElectronNET.IntegrationTests.Tests
}
}
[Fact(Timeout = 20000)]
[IntegrationFact]
public async Task Can_basic_print()
{
var html = "data:text/html,<html><body><h2>Print Test</h2></body></html>";
await this.fx.MainWindow.WebContents.LoadURLAsync(html);
var ok = await this.fx.MainWindow.WebContents.PrintAsync(new PrintOptions { Silent = true, PrintBackground = true });
await this.MainWindow.WebContents.LoadURLAsync(html);
var ok = await this.MainWindow.WebContents.PrintAsync(new PrintOptions { Silent = true, PrintBackground = true });
ok.Should().BeTrue();
}
[SkippableFact(Timeout = 20000)]
[IntegrationFact]
public async Task GetPrintersAsync_check()
{
Skip.If(Environment.GetEnvironmentVariable("GITHUB_RUN_ID") != null, "Skipping printer test in CI environment.");
var info = await fx.MainWindow.WebContents.GetPrintersAsync();
var info = await this.MainWindow.WebContents.GetPrintersAsync();
info.Should().NotBeNull();
}
[Fact(Timeout = 20000)]
[IntegrationFact]
public async Task GetSetZoomFactor_check()
{
await fx.MainWindow.WebContents.GetZoomFactorAsync();
var ok = await fx.MainWindow.WebContents.GetZoomFactorAsync();
await this.MainWindow.WebContents.GetZoomFactorAsync();
var ok = await this.MainWindow.WebContents.GetZoomFactorAsync();
ok.Should().BeGreaterThan(0.0);
fx.MainWindow.WebContents.SetZoomFactor(2.0);
await Task.Delay(500);
ok = await fx.MainWindow.WebContents.GetZoomFactorAsync();
this.MainWindow.WebContents.SetZoomFactor(2.0);
await Task.Delay(500.ms());
ok = await this.MainWindow.WebContents.GetZoomFactorAsync();
ok.Should().Be(2.0);
}
[SkippableFact(Timeout = 20000)]
[IntegrationFact]
public async Task GetSetZoomLevel_check()
{
Skip.If(Environment.GetEnvironmentVariable("GITHUB_RUN_ID") != null && RuntimeInformation.IsOSPlatform(OSPlatform.Windows), "Skipping test on Windows CI.");
await fx.MainWindow.WebContents.GetZoomLevelAsync();
var ok = await fx.MainWindow.WebContents.GetZoomLevelAsync();
ok.Should().Be(0);
fx.MainWindow.WebContents.SetZoomLevel(2);
await Task.Delay(500);
ok = await fx.MainWindow.WebContents.GetZoomLevelAsync();
ok.Should().Be(2);
BrowserWindow window = null;
try
{
window = await Electron.WindowManager.CreateWindowAsync(new BrowserWindowOptions { Show = true }, "about:blank");
await Task.Delay(100.ms());
window.WebContents.SetZoomLevel(0);
await Task.Delay(500.ms());
var ok = await window.WebContents.GetZoomLevelAsync();
ok.Should().Be(0);
window.WebContents.SetZoomLevel(2);
await Task.Delay(500.ms());
ok = await window.WebContents.GetZoomLevelAsync();
ok.Should().Be(2);
}
finally
{
window?.Destroy();
}
}
[SkippableFact(Timeout = 20000)]
[IntegrationFact]
public async Task DevTools_check()
{
Skip.If(Environment.GetEnvironmentVariable("GITHUB_RUN_ID") != null && RuntimeInformation.IsOSPlatform(OSPlatform.OSX), "Skipping test on macOS CI.");
fx.MainWindow.WebContents.IsDevToolsOpened().Should().BeFalse();
fx.MainWindow.WebContents.OpenDevTools();
await Task.Delay(500);
fx.MainWindow.WebContents.IsDevToolsOpened().Should().BeTrue();
fx.MainWindow.WebContents.CloseDevTools();
await Task.Delay(500);
fx.MainWindow.WebContents.IsDevToolsOpened().Should().BeFalse();
fx.MainWindow.WebContents.ToggleDevTools();
await Task.Delay(500);
fx.MainWindow.WebContents.IsDevToolsOpened().Should().BeTrue();
BrowserWindow window = null;
try
{
window = await Electron.WindowManager.CreateWindowAsync(new BrowserWindowOptions { Show = true }, "about:blank");
await Task.Delay(3.seconds());
window.WebContents.IsDevToolsOpened().Should().BeFalse();
window.WebContents.OpenDevTools();
await Task.Delay(5.seconds());
window.WebContents.IsDevToolsOpened().Should().BeTrue();
window.WebContents.CloseDevTools();
await Task.Delay(2.seconds());
window.WebContents.IsDevToolsOpened().Should().BeFalse();
}
finally
{
window?.Destroy();
}
}
[Fact(Timeout = 20000)]
[IntegrationFact]
public async Task GetSetAudioMuted_check()
{
fx.MainWindow.WebContents.SetAudioMuted(true);
await Task.Delay(500);
var ok = await fx.MainWindow.WebContents.IsAudioMutedAsync();
this.MainWindow.WebContents.SetAudioMuted(true);
await Task.Delay(500.ms());
var ok = await this.MainWindow.WebContents.IsAudioMutedAsync();
ok.Should().BeTrue();
fx.MainWindow.WebContents.SetAudioMuted(false);
await Task.Delay(500);
ok = await fx.MainWindow.WebContents.IsAudioMutedAsync();
this.MainWindow.WebContents.SetAudioMuted(false);
await Task.Delay(500.ms());
ok = await this.MainWindow.WebContents.IsAudioMutedAsync();
ok.Should().BeFalse();
// Assuming no audio is playing, IsCurrentlyAudibleAsync should return false
// there is no way to play audio in this test
ok = await fx.MainWindow.WebContents.IsCurrentlyAudibleAsync();
ok = await this.MainWindow.WebContents.IsCurrentlyAudibleAsync();
ok.Should().BeFalse();
}
[SkippableFact(Timeout = 20000)]
[IntegrationFact]
public async Task GetSetUserAgent_check()
{
Skip.If(Environment.GetEnvironmentVariable("GITHUB_RUN_ID") != null && RuntimeInformation.IsOSPlatform(OSPlatform.Windows), "Skipping test on Windows CI.");
var ok = await fx.MainWindow.WebContents.GetUserAgentAsync();
ok.Should().NotBeNullOrEmpty();
fx.MainWindow.WebContents.SetUserAgent("MyUserAgent/1.0");
await Task.Delay(1000);
ok = await fx.MainWindow.WebContents.GetUserAgentAsync();
ok.Should().Be("MyUserAgent/1.0");
BrowserWindow window = null;
try
{
window = await Electron.WindowManager.CreateWindowAsync(new BrowserWindowOptions { Show = true }, "about:blank");
await Task.Delay(3.seconds());
window.WebContents.SetUserAgent("MyUserAgent/1.0");
await Task.Delay(1.seconds());
var ok = await window.WebContents.GetUserAgentAsync();
ok.Should().Be("MyUserAgent/1.0");
}
finally
{
window?.Destroy();
}
}
}

View File

@@ -1,6 +1,8 @@
<wpf:ResourceDictionary xml:space="preserve" xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml" xmlns:s="clr-namespace:System;assembly=mscorlib" xmlns:ss="urn:shemas-jetbrains-com:settings-storage-xaml" xmlns:wpf="http://schemas.microsoft.com/winfx/2006/xaml/presentation">
<s:String x:Key="/Default/CodeInspection/Highlighting/InspectionSeverities/=ConvertToExtensionBlock/@EntryIndexedValue">DO_NOT_SHOW</s:String>
<s:Boolean x:Key="/Default/CodeStyle/CodeFormatting/CSharpFormat/LINE_FEED_AT_FILE_END/@EntryValue">False</s:Boolean>
<s:Boolean x:Key="/Default/CodeStyle/CodeFormatting/CSharpFormat/PLACE_SIMPLE_ACCESSOR_ON_SINGLE_LINE/@EntryValue">False</s:Boolean>
<s:String x:Key="/Default/CodeStyle/Naming/CSharpNaming/Abbreviations/=CI/@EntryIndexedValue">CI</s:String>
<s:Boolean x:Key="/Default/Environment/SettingsMigration/IsMigratorApplied/=JetBrains_002EReSharper_002EPsi_002ECSharp_002ECodeStyle_002ECSharpKeepExistingMigration/@EntryIndexedValue">True</s:Boolean>
<s:Boolean x:Key="/Default/Environment/SettingsMigration/IsMigratorApplied/=JetBrains_002EReSharper_002EPsi_002ECSharp_002ECodeStyle_002ECSharpPlaceEmbeddedOnSameLineMigration/@EntryIndexedValue">True</s:Boolean>
<s:Boolean x:Key="/Default/Environment/SettingsMigration/IsMigratorApplied/=JetBrains_002EReSharper_002EPsi_002ECSharp_002ECodeStyle_002ECSharpUseContinuousIndentInsideBracesMigration/@EntryIndexedValue">True</s:Boolean>