Skip to content

Commit 50a1685

Browse files
authored
Add automated Blazor WebView test using Photino (#50347) (#50743)
Adds a test that launches a Photino-based app and clicks a Blazor counter button and verifies that the HTML is in fact updated.
1 parent ab03fba commit 50a1685

17 files changed

+474
-36
lines changed

AspNetCore.sln

Lines changed: 19 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1774,6 +1774,8 @@ Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "MvcFormSample", "src\Mvc\sa
17741774
EndProject
17751775
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}"
17761776
EndProject
1777+
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}"
1778+
EndProject
17771779
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}"
17781780
EndProject
17791781
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}"
@@ -10667,6 +10669,22 @@ Global
1066710669
{137AD17B-066F-4ED4-80FA-8D21C7B76CA6}.Release|x64.Build.0 = Release|Any CPU
1066810670
{137AD17B-066F-4ED4-80FA-8D21C7B76CA6}.Release|x86.ActiveCfg = Release|Any CPU
1066910671
{137AD17B-066F-4ED4-80FA-8D21C7B76CA6}.Release|x86.Build.0 = Release|Any CPU
10672+
{CAEB7F57-28A8-451C-95D0-45FCAA3C726C}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
10673+
{CAEB7F57-28A8-451C-95D0-45FCAA3C726C}.Debug|Any CPU.Build.0 = Debug|Any CPU
10674+
{CAEB7F57-28A8-451C-95D0-45FCAA3C726C}.Debug|arm64.ActiveCfg = Debug|Any CPU
10675+
{CAEB7F57-28A8-451C-95D0-45FCAA3C726C}.Debug|arm64.Build.0 = Debug|Any CPU
10676+
{CAEB7F57-28A8-451C-95D0-45FCAA3C726C}.Debug|x64.ActiveCfg = Debug|Any CPU
10677+
{CAEB7F57-28A8-451C-95D0-45FCAA3C726C}.Debug|x64.Build.0 = Debug|Any CPU
10678+
{CAEB7F57-28A8-451C-95D0-45FCAA3C726C}.Debug|x86.ActiveCfg = Debug|Any CPU
10679+
{CAEB7F57-28A8-451C-95D0-45FCAA3C726C}.Debug|x86.Build.0 = Debug|Any CPU
10680+
{CAEB7F57-28A8-451C-95D0-45FCAA3C726C}.Release|Any CPU.ActiveCfg = Release|Any CPU
10681+
{CAEB7F57-28A8-451C-95D0-45FCAA3C726C}.Release|Any CPU.Build.0 = Release|Any CPU
10682+
{CAEB7F57-28A8-451C-95D0-45FCAA3C726C}.Release|arm64.ActiveCfg = Release|Any CPU
10683+
{CAEB7F57-28A8-451C-95D0-45FCAA3C726C}.Release|arm64.Build.0 = Release|Any CPU
10684+
{CAEB7F57-28A8-451C-95D0-45FCAA3C726C}.Release|x64.ActiveCfg = Release|Any CPU
10685+
{CAEB7F57-28A8-451C-95D0-45FCAA3C726C}.Release|x64.Build.0 = Release|Any CPU
10686+
{CAEB7F57-28A8-451C-95D0-45FCAA3C726C}.Release|x86.ActiveCfg = Release|Any CPU
10687+
{CAEB7F57-28A8-451C-95D0-45FCAA3C726C}.Release|x86.Build.0 = Release|Any CPU
1067010688
{A939893A-B3CD-48F6-80D3-340C8A6E275B}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
1067110689
{A939893A-B3CD-48F6-80D3-340C8A6E275B}.Debug|Any CPU.Build.0 = Debug|Any CPU
1067210690
{A939893A-B3CD-48F6-80D3-340C8A6E275B}.Debug|arm64.ActiveCfg = Debug|Any CPU
@@ -11575,6 +11593,7 @@ Global
1157511593
{F7BCD3AD-31E2-4223-B215-851C3D0AB78A} = {B55A5DE1-5AF3-4B18-AF04-C1735B071DA6}
1157611594
{055F86AA-FB37-40CC-B39E-C29CE7547BB7} = {B8825E86-B8EA-4666-B681-C443D027C95D}
1157711595
{137AD17B-066F-4ED4-80FA-8D21C7B76CA6} = {AA5ABFBC-177C-421E-B743-005E0FD1248B}
11596+
{CAEB7F57-28A8-451C-95D0-45FCAA3C726C} = {C445B129-0A4D-41F5-8347-6534B6B12303}
1157811597
{A939893A-B3CD-48F6-80D3-340C8A6E275B} = {AA5ABFBC-177C-421E-B743-005E0FD1248B}
1157911598
{F232B503-D412-45EE-8B31-EFD46B9FA302} = {AA5ABFBC-177C-421E-B743-005E0FD1248B}
1158011599
EndGlobalSection

eng/Versions.props

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -308,7 +308,7 @@
308308
<NewtonsoftJsonBsonVersion>1.0.2</NewtonsoftJsonBsonVersion>
309309
<NewtonsoftJsonVersion>13.0.3</NewtonsoftJsonVersion>
310310
<NSwagApiDescriptionClientVersion>13.0.4</NSwagApiDescriptionClientVersion>
311-
<PhotinoNETVersion>1.1.6</PhotinoNETVersion>
311+
<PhotinoNETVersion>2.4.0</PhotinoNETVersion>
312312
<MicrosoftPlaywrightVersion>1.28.0</MicrosoftPlaywrightVersion>
313313
<PollyExtensionsHttpVersion>3.0.0</PollyExtensionsHttpVersion>
314314
<PollyVersion>7.2.4</PollyVersion>

src/Components/Components.slnf

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -42,6 +42,7 @@
4242
"src\\Components\\WebView\\Samples\\PhotinoPlatform\\testassets\\PhotinoTestApp\\PhotinoTestApp.csproj",
4343
"src\\Components\\WebView\\WebView\\src\\Microsoft.AspNetCore.Components.WebView.csproj",
4444
"src\\Components\\WebView\\WebView\\test\\Microsoft.AspNetCore.Components.WebView.Test.csproj",
45+
"src\\Components\\WebView\\test\\E2ETest\\Microsoft.AspNetCore.Components.WebViewE2E.Test.csproj",
4546
"src\\Components\\Web\\src\\Microsoft.AspNetCore.Components.Web.csproj",
4647
"src\\Components\\Web\\test\\Microsoft.AspNetCore.Components.Web.Tests.csproj",
4748
"src\\Components\\benchmarkapps\\BlazingPizza.Server\\BlazingPizza.Server.csproj",

src/Components/WebView/Samples/PhotinoPlatform/src/BlazorWindow.cs

Lines changed: 20 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -12,7 +12,6 @@ namespace Microsoft.AspNetCore.Components.WebView.Photino;
1212
/// </summary>
1313
public class BlazorWindow
1414
{
15-
private readonly PhotinoWindow _window;
1615
private readonly PhotinoWebViewManager _manager;
1716
private readonly string _pathBase;
1817

@@ -28,22 +27,28 @@ public BlazorWindow(
2827
string title,
2928
string hostPage,
3029
IServiceProvider services,
31-
Action<PhotinoWindowOptions>? configureWindow = null,
30+
Action<PhotinoWindow>? configureWindow = null,
3231
string? pathBase = null)
3332
{
34-
_window = new PhotinoWindow(title, options =>
33+
PhotinoWindow = new PhotinoWindow
3534
{
36-
options.CustomSchemeHandlers.Add(PhotinoWebViewManager.BlazorAppScheme, HandleWebRequest);
37-
configureWindow?.Invoke(options);
38-
}, width: 1600, height: 1200, left: 300, top: 300);
35+
Title = title,
36+
Width = 1600,
37+
Height = 1200,
38+
Left = 300,
39+
Top = 300,
40+
};
41+
PhotinoWindow.RegisterCustomSchemeHandler(PhotinoWebViewManager.BlazorAppScheme, HandleWebRequest);
42+
43+
configureWindow?.Invoke(PhotinoWindow);
3944

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

46-
var dispatcher = new PhotinoDispatcher(_window);
51+
var dispatcher = new PhotinoDispatcher(PhotinoWindow);
4752
var jsComponents = new JSComponentConfigurationStore();
4853

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

56-
_manager = new PhotinoWebViewManager(_window, services, dispatcher, appBaseUri, fileProvider, jsComponents, hostPageRelativePath);
61+
_manager = new PhotinoWebViewManager(PhotinoWindow, services, dispatcher, appBaseUri, fileProvider, jsComponents, hostPageRelativePath);
5762
RootComponents = new BlazorWindowRootComponents(_manager, jsComponents);
5863
}
5964

6065
/// <summary>
61-
/// Gets the underlying <see cref="PhotinoWindow"/>.
66+
/// Gets the underlying <see cref="PhotinoNET.PhotinoWindow"/>.
6267
/// </summary>
63-
public PhotinoWindow Photino => _window;
68+
public PhotinoWindow PhotinoWindow { get; }
6469

6570
/// <summary>
6671
/// Gets configuration for the root components in the window.
@@ -73,9 +78,12 @@ public BlazorWindow(
7378
public void Run()
7479
{
7580
_manager.Navigate(_pathBase);
76-
_window.WaitForClose();
81+
82+
// This line actually starts Photino and makes the window appear
83+
Console.WriteLine($"Starting Photino window...");
84+
PhotinoWindow.WaitForClose();
7785
}
7886

79-
private Stream HandleWebRequest(string url, out string contentType)
87+
private Stream HandleWebRequest(object sender, string scheme, string url, out string contentType)
8088
=> _manager.HandleWebRequest(url, out contentType!)!;
8189
}

src/Components/WebView/Samples/PhotinoPlatform/src/PhotinoSynchronizationContext.cs

Lines changed: 16 additions & 20 deletions
Original file line numberDiff line numberDiff line change
@@ -35,7 +35,6 @@ internal class PhotinoSynchronizationContext : SynchronizationContext
3535

3636
private readonly PhotinoWindow _window;
3737
private readonly int _uiThreadId;
38-
private readonly MethodInfo _invokeMethodInfo;
3938

4039
public PhotinoSynchronizationContext(PhotinoWindow window)
4140
: this(window, new State())
@@ -51,9 +50,6 @@ private PhotinoSynchronizationContext(PhotinoWindow window, State state)
5150
_uiThreadId = (int)_window.GetType()
5251
.GetField("_managedThreadId", BindingFlags.NonPublic | BindingFlags.Instance)!
5352
.GetValue(_window)!;
54-
55-
_invokeMethodInfo = _window.GetType()
56-
.GetMethod("Invoke", BindingFlags.NonPublic | BindingFlags.Instance)!;
5753
}
5854

5955
private readonly State _state;
@@ -251,23 +247,23 @@ private void ExecuteSynchronously(
251247
{
252248
// Anything run on the sync context should actually be dispatched as far as Photino
253249
// is concerned, so that it's safe to interact with the native window/WebView.
254-
_invokeMethodInfo.Invoke(_window, new Action[] { () =>
250+
_window.Invoke(() =>
251+
{
252+
var original = Current;
253+
try
255254
{
256-
var original = Current;
257-
try
258-
{
259-
_state.IsBusy = true;
260-
SetSynchronizationContext(this);
261-
d(state);
262-
}
263-
finally
264-
{
265-
_state.IsBusy = false;
266-
SetSynchronizationContext(original);
267-
268-
completion?.SetResult();
269-
}
270-
}});
255+
_state.IsBusy = true;
256+
SetSynchronizationContext(this);
257+
d(state);
258+
}
259+
finally
260+
{
261+
_state.IsBusy = false;
262+
SetSynchronizationContext(original);
263+
264+
completion?.SetResult();
265+
}
266+
});
271267
}
272268

273269
private void ExecuteBackground(WorkItem item)

src/Components/WebView/Samples/PhotinoPlatform/testassets/PhotinoTestApp/PhotinoTestApp.csproj

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,7 @@
22

33
<PropertyGroup>
44
<TargetFramework>$(DefaultNetCoreTargetFramework)</TargetFramework>
5-
<OutputType>WinExe</OutputType>
5+
<OutputType>Exe</OutputType>
66
<IsShippingPackage>false</IsShippingPackage>
77
<SignAssembly>false</SignAssembly>
88
</PropertyGroup>

src/Components/WebView/Samples/PhotinoPlatform/testassets/PhotinoTestApp/Program.cs

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -25,7 +25,9 @@ static void Main(string[] args)
2525

2626
AppDomain.CurrentDomain.UnhandledException += (sender, error) =>
2727
{
28-
mainWindow.Photino.OpenAlertWindow("Fatal exception", error.ExceptionObject.ToString());
28+
Console.Write(
29+
"Fatal exception" + Environment.NewLine +
30+
error.ExceptionObject.ToString() + Environment.NewLine);
2931
};
3032

3133
mainWindow.RootComponents.Add<BasicTestApp.Index>("root");
Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,7 @@
1+
@using System.Net.Http
2+
@using System.Net.Http.Json
3+
@using Microsoft.AspNetCore.Components.Forms
4+
@using Microsoft.AspNetCore.Components.Routing
5+
@using Microsoft.AspNetCore.Components.Web
6+
@using Microsoft.AspNetCore.Components.Web.Virtualization
7+
@using Microsoft.JSInterop

src/Components/WebView/WebView/test/Microsoft.AspNetCore.Components.WebView.Test.csproj

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
<Project Sdk="Microsoft.NET.Sdk">
1+
<Project Sdk="Microsoft.NET.Sdk">
22

33
<PropertyGroup>
44
<TargetFramework>$(DefaultNetCoreTargetFramework)</TargetFramework>

0 commit comments

Comments
 (0)