Skip to content

Commit

Permalink
Add automated Blazor WebView test using Photino (#50347)
Browse files Browse the repository at this point in the history
Adds a test that launches a Photino-based app and clicks a Blazor counter button and verifies that the HTML is in fact updated.
  • Loading branch information
Eilon committed Sep 15, 2023
1 parent 6df29ac commit ee6d623
Show file tree
Hide file tree
Showing 17 changed files with 474 additions and 36 deletions.
19 changes: 19 additions & 0 deletions AspNetCore.sln
Original file line number Diff line number Diff line change
Expand Up @@ -1774,6 +1774,8 @@ Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "MvcFormSample", "src\Mvc\sa
EndProject
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Microsoft.AspNetCore.OutputCaching.Microbenchmarks", "src\Middleware\OutputCaching\perf\Microbenchmarks\Microsoft.AspNetCore.OutputCaching.Microbenchmarks.csproj", "{137AD17B-066F-4ED4-80FA-8D21C7B76CA6}"
EndProject
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Microsoft.AspNetCore.Components.WebViewE2E.Test", "src\Components\WebView\test\E2ETest\Microsoft.AspNetCore.Components.WebViewE2E.Test.csproj", "{CAEB7F57-28A8-451C-95D0-45FCAA3C726C}"
EndProject
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Microsoft.AspNetCore.OutputCaching.StackExchangeRedis.Tests", "src\Middleware\Microsoft.AspNetCore.OutputCaching.StackExchangeRedis\test\Microsoft.AspNetCore.OutputCaching.StackExchangeRedis.Tests.csproj", "{A939893A-B3CD-48F6-80D3-340C8A6E275B}"
EndProject
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Microsoft.AspNetCore.OutputCaching.StackExchangeRedis", "src\Middleware\Microsoft.AspNetCore.OutputCaching.StackExchangeRedis\src\Microsoft.AspNetCore.OutputCaching.StackExchangeRedis.csproj", "{F232B503-D412-45EE-8B31-EFD46B9FA302}"
Expand Down Expand Up @@ -10667,6 +10669,22 @@ Global
{137AD17B-066F-4ED4-80FA-8D21C7B76CA6}.Release|x64.Build.0 = Release|Any CPU
{137AD17B-066F-4ED4-80FA-8D21C7B76CA6}.Release|x86.ActiveCfg = Release|Any CPU
{137AD17B-066F-4ED4-80FA-8D21C7B76CA6}.Release|x86.Build.0 = Release|Any CPU
{CAEB7F57-28A8-451C-95D0-45FCAA3C726C}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{CAEB7F57-28A8-451C-95D0-45FCAA3C726C}.Debug|Any CPU.Build.0 = Debug|Any CPU
{CAEB7F57-28A8-451C-95D0-45FCAA3C726C}.Debug|arm64.ActiveCfg = Debug|Any CPU
{CAEB7F57-28A8-451C-95D0-45FCAA3C726C}.Debug|arm64.Build.0 = Debug|Any CPU
{CAEB7F57-28A8-451C-95D0-45FCAA3C726C}.Debug|x64.ActiveCfg = Debug|Any CPU
{CAEB7F57-28A8-451C-95D0-45FCAA3C726C}.Debug|x64.Build.0 = Debug|Any CPU
{CAEB7F57-28A8-451C-95D0-45FCAA3C726C}.Debug|x86.ActiveCfg = Debug|Any CPU
{CAEB7F57-28A8-451C-95D0-45FCAA3C726C}.Debug|x86.Build.0 = Debug|Any CPU
{CAEB7F57-28A8-451C-95D0-45FCAA3C726C}.Release|Any CPU.ActiveCfg = Release|Any CPU
{CAEB7F57-28A8-451C-95D0-45FCAA3C726C}.Release|Any CPU.Build.0 = Release|Any CPU
{CAEB7F57-28A8-451C-95D0-45FCAA3C726C}.Release|arm64.ActiveCfg = Release|Any CPU
{CAEB7F57-28A8-451C-95D0-45FCAA3C726C}.Release|arm64.Build.0 = Release|Any CPU
{CAEB7F57-28A8-451C-95D0-45FCAA3C726C}.Release|x64.ActiveCfg = Release|Any CPU
{CAEB7F57-28A8-451C-95D0-45FCAA3C726C}.Release|x64.Build.0 = Release|Any CPU
{CAEB7F57-28A8-451C-95D0-45FCAA3C726C}.Release|x86.ActiveCfg = Release|Any CPU
{CAEB7F57-28A8-451C-95D0-45FCAA3C726C}.Release|x86.Build.0 = Release|Any CPU
{A939893A-B3CD-48F6-80D3-340C8A6E275B}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{A939893A-B3CD-48F6-80D3-340C8A6E275B}.Debug|Any CPU.Build.0 = Debug|Any CPU
{A939893A-B3CD-48F6-80D3-340C8A6E275B}.Debug|arm64.ActiveCfg = Debug|Any CPU
Expand Down Expand Up @@ -11575,6 +11593,7 @@ Global
{F7BCD3AD-31E2-4223-B215-851C3D0AB78A} = {B55A5DE1-5AF3-4B18-AF04-C1735B071DA6}
{055F86AA-FB37-40CC-B39E-C29CE7547BB7} = {B8825E86-B8EA-4666-B681-C443D027C95D}
{137AD17B-066F-4ED4-80FA-8D21C7B76CA6} = {AA5ABFBC-177C-421E-B743-005E0FD1248B}
{CAEB7F57-28A8-451C-95D0-45FCAA3C726C} = {C445B129-0A4D-41F5-8347-6534B6B12303}
{A939893A-B3CD-48F6-80D3-340C8A6E275B} = {AA5ABFBC-177C-421E-B743-005E0FD1248B}
{F232B503-D412-45EE-8B31-EFD46B9FA302} = {AA5ABFBC-177C-421E-B743-005E0FD1248B}
EndGlobalSection
Expand Down
2 changes: 1 addition & 1 deletion eng/Versions.props
Original file line number Diff line number Diff line change
Expand Up @@ -306,7 +306,7 @@
<NewtonsoftJsonBsonVersion>1.0.2</NewtonsoftJsonBsonVersion>
<NewtonsoftJsonVersion>13.0.3</NewtonsoftJsonVersion>
<NSwagApiDescriptionClientVersion>13.0.4</NSwagApiDescriptionClientVersion>
<PhotinoNETVersion>1.1.6</PhotinoNETVersion>
<PhotinoNETVersion>2.4.0</PhotinoNETVersion>
<MicrosoftPlaywrightVersion>1.28.0</MicrosoftPlaywrightVersion>
<PollyExtensionsHttpVersion>3.0.0</PollyExtensionsHttpVersion>
<PollyVersion>7.2.4</PollyVersion>
Expand Down
1 change: 1 addition & 0 deletions src/Components/Components.slnf
Original file line number Diff line number Diff line change
Expand Up @@ -42,6 +42,7 @@
"src\\Components\\WebView\\Samples\\PhotinoPlatform\\testassets\\PhotinoTestApp\\PhotinoTestApp.csproj",
"src\\Components\\WebView\\WebView\\src\\Microsoft.AspNetCore.Components.WebView.csproj",
"src\\Components\\WebView\\WebView\\test\\Microsoft.AspNetCore.Components.WebView.Test.csproj",
"src\\Components\\WebView\\test\\E2ETest\\Microsoft.AspNetCore.Components.WebViewE2E.Test.csproj",
"src\\Components\\Web\\src\\Microsoft.AspNetCore.Components.Web.csproj",
"src\\Components\\Web\\test\\Microsoft.AspNetCore.Components.Web.Tests.csproj",
"src\\Components\\benchmarkapps\\BlazingPizza.Server\\BlazingPizza.Server.csproj",
Expand Down
32 changes: 20 additions & 12 deletions src/Components/WebView/Samples/PhotinoPlatform/src/BlazorWindow.cs
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,6 @@ namespace Microsoft.AspNetCore.Components.WebView.Photino;
/// </summary>
public class BlazorWindow
{
private readonly PhotinoWindow _window;
private readonly PhotinoWebViewManager _manager;
private readonly string _pathBase;

Expand All @@ -28,22 +27,28 @@ public BlazorWindow(
string title,
string hostPage,
IServiceProvider services,
Action<PhotinoWindowOptions>? configureWindow = null,
Action<PhotinoWindow>? configureWindow = null,
string? pathBase = null)
{
_window = new PhotinoWindow(title, options =>
PhotinoWindow = new PhotinoWindow
{
options.CustomSchemeHandlers.Add(PhotinoWebViewManager.BlazorAppScheme, HandleWebRequest);
configureWindow?.Invoke(options);
}, width: 1600, height: 1200, left: 300, top: 300);
Title = title,
Width = 1600,
Height = 1200,
Left = 300,
Top = 300,
};
PhotinoWindow.RegisterCustomSchemeHandler(PhotinoWebViewManager.BlazorAppScheme, HandleWebRequest);

configureWindow?.Invoke(PhotinoWindow);

// We assume the host page is always in the root of the content directory, because it's
// unclear there's any other use case. We can add more options later if so.
var contentRootDir = Path.GetDirectoryName(Path.GetFullPath(hostPage))!;
var hostPageRelativePath = Path.GetRelativePath(contentRootDir, hostPage);
var fileProvider = new PhysicalFileProvider(contentRootDir);

var dispatcher = new PhotinoDispatcher(_window);
var dispatcher = new PhotinoDispatcher(PhotinoWindow);
var jsComponents = new JSComponentConfigurationStore();

_pathBase = (pathBase ?? string.Empty);
Expand All @@ -53,14 +58,14 @@ public BlazorWindow(
}
var appBaseUri = new Uri(new Uri(PhotinoWebViewManager.AppBaseOrigin), _pathBase);

_manager = new PhotinoWebViewManager(_window, services, dispatcher, appBaseUri, fileProvider, jsComponents, hostPageRelativePath);
_manager = new PhotinoWebViewManager(PhotinoWindow, services, dispatcher, appBaseUri, fileProvider, jsComponents, hostPageRelativePath);
RootComponents = new BlazorWindowRootComponents(_manager, jsComponents);
}

/// <summary>
/// Gets the underlying <see cref="PhotinoWindow"/>.
/// Gets the underlying <see cref="PhotinoNET.PhotinoWindow"/>.
/// </summary>
public PhotinoWindow Photino => _window;
public PhotinoWindow PhotinoWindow { get; }

/// <summary>
/// Gets configuration for the root components in the window.
Expand All @@ -73,9 +78,12 @@ public BlazorWindow(
public void Run()
{
_manager.Navigate(_pathBase);
_window.WaitForClose();

// This line actually starts Photino and makes the window appear
Console.WriteLine($"Starting Photino window...");
PhotinoWindow.WaitForClose();
}

private Stream HandleWebRequest(string url, out string contentType)
private Stream HandleWebRequest(object sender, string scheme, string url, out string contentType)
=> _manager.HandleWebRequest(url, out contentType!)!;
}
Original file line number Diff line number Diff line change
Expand Up @@ -35,7 +35,6 @@ internal class PhotinoSynchronizationContext : SynchronizationContext

private readonly PhotinoWindow _window;
private readonly int _uiThreadId;
private readonly MethodInfo _invokeMethodInfo;

public PhotinoSynchronizationContext(PhotinoWindow window)
: this(window, new State())
Expand All @@ -51,9 +50,6 @@ private PhotinoSynchronizationContext(PhotinoWindow window, State state)
_uiThreadId = (int)_window.GetType()
.GetField("_managedThreadId", BindingFlags.NonPublic | BindingFlags.Instance)!
.GetValue(_window)!;

_invokeMethodInfo = _window.GetType()
.GetMethod("Invoke", BindingFlags.NonPublic | BindingFlags.Instance)!;
}

private readonly State _state;
Expand Down Expand Up @@ -251,23 +247,23 @@ private void ExecuteSynchronously(
{
// Anything run on the sync context should actually be dispatched as far as Photino
// is concerned, so that it's safe to interact with the native window/WebView.
_invokeMethodInfo.Invoke(_window, new Action[] { () =>
_window.Invoke(() =>
{
var original = Current;
try
{
var original = Current;
try
{
_state.IsBusy = true;
SetSynchronizationContext(this);
d(state);
}
finally
{
_state.IsBusy = false;
SetSynchronizationContext(original);
completion?.SetResult();
}
}});
_state.IsBusy = true;
SetSynchronizationContext(this);
d(state);
}
finally
{
_state.IsBusy = false;
SetSynchronizationContext(original);
completion?.SetResult();
}
});
}

private void ExecuteBackground(WorkItem item)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@

<PropertyGroup>
<TargetFramework>$(DefaultNetCoreTargetFramework)</TargetFramework>
<OutputType>WinExe</OutputType>
<OutputType>Exe</OutputType>
<IsShippingPackage>false</IsShippingPackage>
<SignAssembly>false</SignAssembly>
</PropertyGroup>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -25,7 +25,9 @@ static void Main(string[] args)

AppDomain.CurrentDomain.UnhandledException += (sender, error) =>
{
mainWindow.Photino.OpenAlertWindow("Fatal exception", error.ExceptionObject.ToString());
Console.Write(
"Fatal exception" + Environment.NewLine +
error.ExceptionObject.ToString() + Environment.NewLine);
};

mainWindow.RootComponents.Add<BasicTestApp.Index>("root");
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
@using System.Net.Http
@using System.Net.Http.Json
@using Microsoft.AspNetCore.Components.Forms
@using Microsoft.AspNetCore.Components.Routing
@using Microsoft.AspNetCore.Components.Web
@using Microsoft.AspNetCore.Components.Web.Virtualization
@using Microsoft.JSInterop
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
<Project Sdk="Microsoft.NET.Sdk">
<Project Sdk="Microsoft.NET.Sdk">

<PropertyGroup>
<TargetFramework>$(DefaultNetCoreTargetFramework)</TargetFramework>
Expand Down
Loading

0 comments on commit ee6d623

Please sign in to comment.