Skip to content

Commit 89b9b4b

Browse files
committed
Add a E2E test
1 parent eec977a commit 89b9b4b

File tree

13 files changed

+176
-11
lines changed

13 files changed

+176
-11
lines changed
Lines changed: 22 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,22 @@
1+
// Copyright (c) .NET Foundation. All rights reserved.
2+
// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information.
3+
4+
using System;
5+
6+
namespace Microsoft.AspNetCore.Components.HotReload
7+
{
8+
internal class HotReloadEnvironment
9+
{
10+
public static readonly HotReloadEnvironment Instance = new(Environment.GetEnvironmentVariable("DOTNET_MODIFIABLE_ASSEMBLIES") == "debug");
11+
12+
public HotReloadEnvironment(bool isHotReloadEnabled)
13+
{
14+
IsHotReloadEnabled = isHotReloadEnabled;
15+
}
16+
17+
/// <summary>
18+
/// Gets a value that determines if HotReload is configured for this application.
19+
/// </summary>
20+
public bool IsHotReloadEnabled { get; }
21+
}
22+
}

src/Components/Components/src/HotReload/HotReloadManager.cs

Lines changed: 1 addition & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -10,12 +10,7 @@ namespace Microsoft.AspNetCore.Components.HotReload
1010
{
1111
internal static class HotReloadManager
1212
{
13-
/// <summary>
14-
/// Gets a value that determines if HotReload is configured for this application.
15-
/// </summary>
16-
public static bool IsHotReloadEnabled { get; } = Environment.GetEnvironmentVariable("DOTNET_MODIFIABLE_ASSEMBLIES") == "debug";
17-
18-
internal static event Action? OnDeltaApplied;
13+
internal static event Action? OnDeltaApplied;
1914

2015
public static void DeltaApplied()
2116
{

src/Components/Components/src/Properties/AssemblyInfo.cs

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -8,5 +8,6 @@
88
[assembly: InternalsVisibleTo("Microsoft.AspNetCore.Components.Tests, PublicKey=0024000004800000940000000602000000240000525341310004000001000100f33a29044fa9d740c9b3213a93e57c84b472c84e0b8a0e1ae48e67a9f8f6de9d5f7f3d52ac23e48ac51801f1dc950abe901da34d2a9e3baadb141a17c77ef3c565dd5ee5054b91cf63bb3c6ab83f72ab3aafe93d0fc3c2348b764fafb0b1c0733de51459aeab46580384bf9d74c4e28164b7cde247f891ba07891c9d872ad2bb")]
99
[assembly: InternalsVisibleTo("Microsoft.AspNetCore.Components.Web.Tests, PublicKey=0024000004800000940000000602000000240000525341310004000001000100f33a29044fa9d740c9b3213a93e57c84b472c84e0b8a0e1ae48e67a9f8f6de9d5f7f3d52ac23e48ac51801f1dc950abe901da34d2a9e3baadb141a17c77ef3c565dd5ee5054b91cf63bb3c6ab83f72ab3aafe93d0fc3c2348b764fafb0b1c0733de51459aeab46580384bf9d74c4e28164b7cde247f891ba07891c9d872ad2bb")]
1010
[assembly: InternalsVisibleTo("Microsoft.AspNetCore.Components.ProtectedBrowserStorage.Tests, PublicKey=0024000004800000940000000602000000240000525341310004000001000100f33a29044fa9d740c9b3213a93e57c84b472c84e0b8a0e1ae48e67a9f8f6de9d5f7f3d52ac23e48ac51801f1dc950abe901da34d2a9e3baadb141a17c77ef3c565dd5ee5054b91cf63bb3c6ab83f72ab3aafe93d0fc3c2348b764fafb0b1c0733de51459aeab46580384bf9d74c4e28164b7cde247f891ba07891c9d872ad2bb")]
11+
[assembly: InternalsVisibleTo("Components.TestServer, PublicKey=0024000004800000940000000602000000240000525341310004000001000100f33a29044fa9d740c9b3213a93e57c84b472c84e0b8a0e1ae48e67a9f8f6de9d5f7f3d52ac23e48ac51801f1dc950abe901da34d2a9e3baadb141a17c77ef3c565dd5ee5054b91cf63bb3c6ab83f72ab3aafe93d0fc3c2348b764fafb0b1c0733de51459aeab46580384bf9d74c4e28164b7cde247f891ba07891c9d872ad2bb")]
1112

1213
[assembly: InternalsVisibleTo("DynamicProxyGenAssembly2, PublicKey=0024000004800000940000000602000000240000525341310004000001000100c547cac37abd99c8db225ef2f6c8a3602f3b3606cc9891605d02baa56104f4cfc0734aa39b93bf7852f7d9266654753cc297e7d2edfe0bac1cdcf9f717241550e0a7b191195b7667bb4f64bcb8e2121380fd1d9d46ad2d92d2d15605093924cceaf74c4861eff62abf69b9291ed0a340e113be11e6a7d3113e92484cf7045cc7")]

src/Components/Components/src/Properties/ILLink.Substitutions.xml

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,9 +1,8 @@
11
<linker>
22
<assembly fullname="Microsoft.AspNetCore.Components" >
33
<!-- Trim away hot-reload -->
4-
<type fullname="Microsoft.AspNetCore.Components.HotReload.HotReloadManager">
4+
<type fullname="Microsoft.AspNetCore.Components.HotReload.HotReloadEnvironment">
55
<method signature="System.Boolean get_IsHotReloadEnabled()" body="stub" value="false" />
6-
<event name="OnDeltaApplied" body="stub" />
76
</type>
87
<type fullname="Microsoft.AspNetCore.Components.HotReload.HotReloadContext">
98
<method signature="System.Boolean get_IsHotReloading()" body="stub" value="false" />

src/Components/Components/src/RenderTree/Renderer.cs

Lines changed: 5 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -33,6 +33,7 @@ public abstract partial class Renderer : IDisposable, IAsyncDisposable
3333
private readonly Dictionary<ulong, ulong> _eventHandlerIdReplacements = new Dictionary<ulong, ulong>();
3434
private readonly ILogger<Renderer> _logger;
3535
private readonly ComponentFactory _componentFactory;
36+
private readonly HotReloadEnvironment _hotReloadEnvironment;
3637
private List<(ComponentState, ParameterView)>? _rootComponents;
3738

3839
private int _nextComponentId = 0; // TODO: change to 'long' when Mono .NET->JS interop supports it
@@ -95,6 +96,8 @@ public Renderer(IServiceProvider serviceProvider, ILoggerFactory loggerFactory,
9596
_logger = loggerFactory.CreateLogger<Renderer>();
9697
_componentFactory = new ComponentFactory(componentActivator);
9798

99+
_hotReloadEnvironment = serviceProvider.GetService<HotReloadEnvironment>() ?? HotReloadEnvironment.Instance;
100+
98101
HotReloadManager.OnDeltaApplied += RenderRootComponentsOnHotReload;
99102
}
100103

@@ -151,7 +154,7 @@ await Dispatcher.InvokeAsync(async () =>
151154
protected IComponent InstantiateComponent([DynamicallyAccessedMembers(Component)] Type componentType)
152155
{
153156
var component = _componentFactory.InstantiateComponent(_serviceProvider, componentType);
154-
if (HotReloadManager.IsHotReloadEnabled && component is IReceiveHotReloadContext receiveHotReloadContext)
157+
if (_hotReloadEnvironment.IsHotReloadEnabled && component is IReceiveHotReloadContext receiveHotReloadContext)
155158
{
156159
receiveHotReloadContext.Receive(HotReloadContext);
157160
}
@@ -222,13 +225,12 @@ protected async Task RenderRootComponentAsync(int componentId, ParameterView ini
222225
// During the asynchronous rendering process we want to wait up until all components have
223226
// finished rendering so that we can produce the complete output.
224227
var componentState = GetRequiredComponentState(componentId);
225-
if (HotReloadManager.IsHotReloadEnabled)
228+
if (_hotReloadEnvironment.IsHotReloadEnabled)
226229
{
227230
// when we're doing hot-reload, stash away the parameters used while rendering root components.
228231
// We'll use this to trigger re-renders on hot reload updates.
229232
_rootComponents ??= new();
230233
_rootComponents.Add((componentState, initialParameters.Clone()));
231-
232234
}
233235

234236
componentState.SetDirectParameters(initialParameters);
Lines changed: 55 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,55 @@
1+
// Copyright (c) .NET Foundation. All rights reserved.
2+
// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information.
3+
4+
using System;
5+
using System.Threading.Tasks;
6+
using BasicTestApp.HotReload;
7+
using Microsoft.AspNetCore.Components.E2ETest.Infrastructure;
8+
using Microsoft.AspNetCore.Components.E2ETest.Infrastructure.ServerFixtures;
9+
using Microsoft.AspNetCore.E2ETesting;
10+
using OpenQA.Selenium;
11+
using TestServer;
12+
using Xunit;
13+
using Xunit.Abstractions;
14+
using System.Net.Http;
15+
16+
namespace Microsoft.AspNetCore.Components.E2ETest.ServerExecutionTests
17+
{
18+
public class HotReloadTest : ServerTestBase<BasicTestAppServerSiteFixture<HotReloadStartup>>
19+
{
20+
public HotReloadTest(
21+
BrowserFixture browserFixture,
22+
BasicTestAppServerSiteFixture<HotReloadStartup> serverFixture,
23+
ITestOutputHelper output)
24+
: base(browserFixture, serverFixture, output)
25+
{
26+
}
27+
28+
public override async Task InitializeAsync()
29+
{
30+
await base.InitializeAsync(Guid.NewGuid().ToString());
31+
}
32+
33+
protected override void InitializeAsyncCore()
34+
{
35+
Navigate(ServerPathBase, noReload: false);
36+
Browser.MountTestComponent<RenderOnHotReload>();
37+
}
38+
39+
[Fact]
40+
public async Task InvokingRender_CausesComponentToRender()
41+
{
42+
Browser.Equal("This component was rendered 1 time(s).", () => Browser.Exists(By.TagName("h2")).Text);
43+
Browser.Equal("Initial title", () => Browser.Exists(By.TagName("h3")).Text);
44+
Browser.Equal("Component with ShouldRender=false was rendered 1 time(s).", () => Browser.Exists(By.TagName("h4")).Text);
45+
46+
using var client = new HttpClient { BaseAddress = _serverFixture.RootUri };
47+
var response = await client.GetAsync("/rerender");
48+
response.EnsureSuccessStatusCode();
49+
50+
Browser.Equal("This component was rendered 2 time(s).", () => Browser.Exists(By.TagName("h2")).Text);
51+
Browser.Equal("Initial title", () => Browser.Exists(By.TagName("h3")).Text);
52+
Browser.Equal("Component with ShouldRender=false was rendered 2 time(s).", () => Browser.Exists(By.TagName("h4")).Text);
53+
}
54+
}
55+
}
Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,6 @@
1+
<h3>@Title</h3>
2+
3+
@code
4+
{
5+
[Parameter] public string Title { get; set; }
6+
}
Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,8 @@
1+
<h4>Component with ShouldRender=false was rendered @(++RenderCount) time(s).</h4>
2+
3+
@code
4+
{
5+
int RenderCount = 0;
6+
7+
protected override bool ShouldRender() => false;
8+
}
Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,10 @@
1+
<h2>This component was rendered @(++RenderCount) time(s).</h2>
2+
3+
<ComponentWithParameter Title="Initial title" />
4+
5+
<ComponentWithShouldRender />
6+
7+
@code
8+
{
9+
int RenderCount = 0;
10+
}

src/Components/test/testassets/BasicTestApp/Index.razor

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -92,6 +92,7 @@
9292
<option value="BasicTestApp.TouchEventComponent">Touch events</option>
9393
<option value="BasicTestApp.VirtualizationComponent">Virtualization</option>
9494
<option value="BasicTestApp.VirtualizationDataChanges">Virtualization data changes</option>
95+
<option value="BasicTestApp.HotReload.RenderOnHotReload">Render on hot reload</option>
9596
</select>
9697

9798
<span id="runtime-info"><code><tt>@System.Runtime.InteropServices.RuntimeInformation.FrameworkDescription</tt></code></span>
Lines changed: 20 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,20 @@
1+
// Copyright (c) .NET Foundation. All rights reserved.
2+
// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information.
3+
4+
using Microsoft.AspNetCore.Components.HotReload;
5+
using Microsoft.AspNetCore.Mvc;
6+
7+
namespace ComponentsApp.Server
8+
{
9+
[ApiController]
10+
public class ReloadController : ControllerBase
11+
{
12+
[HttpGet("/rerender")]
13+
public IActionResult Rerender()
14+
{
15+
HotReloadManager.DeltaApplied();
16+
17+
return Ok();
18+
}
19+
}
20+
}
Lines changed: 45 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,45 @@
1+
// Copyright (c) .NET Foundation. All rights reserved.
2+
// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information.
3+
4+
using System.Globalization;
5+
using Microsoft.AspNetCore.Builder;
6+
using Microsoft.AspNetCore.Components.HotReload;
7+
using Microsoft.AspNetCore.Hosting;
8+
using Microsoft.Extensions.DependencyInjection;
9+
using Microsoft.Extensions.Hosting;
10+
11+
namespace TestServer
12+
{
13+
public class HotReloadStartup
14+
{
15+
public void ConfigureServices(IServiceCollection services)
16+
{
17+
services.AddSingleton(new HotReloadEnvironment(isHotReloadEnabled: true));
18+
services.AddControllers();
19+
services.AddRazorPages();
20+
services.AddServerSideBlazor();
21+
}
22+
23+
public void Configure(IApplicationBuilder app, IWebHostEnvironment env)
24+
{
25+
var enUs = new CultureInfo("en-US");
26+
CultureInfo.DefaultThreadCurrentCulture = enUs;
27+
CultureInfo.DefaultThreadCurrentUICulture = enUs;
28+
29+
if (env.IsDevelopment())
30+
{
31+
app.UseDeveloperExceptionPage();
32+
}
33+
34+
app.UseBlazorFrameworkFiles();
35+
app.UseStaticFiles();
36+
app.UseRouting();
37+
app.UseEndpoints(endpoints =>
38+
{
39+
endpoints.MapControllers();
40+
endpoints.MapBlazorHub();
41+
endpoints.MapFallbackToPage("/_ServerHost");
42+
});
43+
}
44+
}
45+
}

src/Components/test/testassets/TestServer/Program.cs

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -29,6 +29,7 @@ public static async Task Main(string[] args)
2929
["Globalization + Localization (Server-side)"] = (BuildWebHost<InternationalizationStartup>(CreateAdditionalArgs(args)), "/subdir"),
3030
["Server-side blazor"] = (BuildWebHost<ServerStartup>(CreateAdditionalArgs(args)), "/subdir"),
3131
["Hosted client-side blazor"] = (BuildWebHost<ClientStartup>(CreateAdditionalArgs(args)), "/subdir"),
32+
["Hot Reload"] = (BuildWebHost<HotReloadStartup>(CreateAdditionalArgs(args)), "/subdir"),
3233
["Dev server client-side blazor"] = CreateDevServerHost(CreateAdditionalArgs(args))
3334
};
3435

0 commit comments

Comments
 (0)