diff --git a/MyBlog.slnx b/MyBlog.slnx
index 8dbca8d0..345bce4c 100644
--- a/MyBlog.slnx
+++ b/MyBlog.slnx
@@ -7,6 +7,7 @@
+
diff --git a/tests/E2E.Tests/E2E.Tests.csproj b/tests/E2E.Tests/E2E.Tests.csproj
new file mode 100644
index 00000000..288837a2
--- /dev/null
+++ b/tests/E2E.Tests/E2E.Tests.csproj
@@ -0,0 +1,38 @@
+
+
+
+ net10.0
+ enable
+ enable
+ false
+ true
+ MyBlog.E2E.Tests
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ PreserveNewest
+
+
+
+
diff --git a/tests/E2E.Tests/GlobalUsings.cs b/tests/E2E.Tests/GlobalUsings.cs
new file mode 100644
index 00000000..37679129
--- /dev/null
+++ b/tests/E2E.Tests/GlobalUsings.cs
@@ -0,0 +1,13 @@
+//=======================================================
+//Copyright (c) 2026. All rights reserved.
+//File Name : GlobalUsings.cs
+//Company : mpaulosky
+//Author : Matthew Paulosky
+//Solution Name : MyBlog
+//Project Name : E2E.Tests
+//=======================================================
+
+global using FluentAssertions;
+global using Aspire.Hosting.ApplicationModel;
+global using Aspire.Hosting.Testing;
+global using Xunit;
diff --git a/tests/E2E.Tests/WebAppTests.cs b/tests/E2E.Tests/WebAppTests.cs
new file mode 100644
index 00000000..0f3161df
--- /dev/null
+++ b/tests/E2E.Tests/WebAppTests.cs
@@ -0,0 +1,44 @@
+//=======================================================
+//Copyright (c) 2026. All rights reserved.
+//File Name : WebAppTests.cs
+//Company : mpaulosky
+//Author : Matthew Paulosky
+//Solution Name : MyBlog
+//Project Name : E2E.Tests
+//=======================================================
+
+namespace MyBlog.E2E.Tests;
+
+public class WebAppTests
+{
+ private static readonly TimeSpan DefaultTimeout = TimeSpan.FromSeconds(60);
+
+ [Fact]
+ public async Task GetWebResourceRootReturnsOkStatusCode()
+ {
+ // Arrange
+ var cancellationToken = new CancellationTokenSource(DefaultTimeout).Token;
+
+ var appHost = await DistributedApplicationTestingBuilder
+ .CreateAsync(cancellationToken);
+
+ appHost.Services.ConfigureHttpClientDefaults(clientBuilder =>
+ {
+ clientBuilder.AddStandardResilienceHandler();
+ });
+
+ await using var app = await appHost.BuildAsync(cancellationToken).WaitAsync(DefaultTimeout, cancellationToken);
+ await app.StartAsync(cancellationToken).WaitAsync(DefaultTimeout, cancellationToken);
+
+ // Act
+ using var httpClient = app.CreateHttpClient("webfrontend");
+ await app.ResourceNotifications
+ .WaitForResourceHealthyAsync("webfrontend", cancellationToken)
+ .WaitAsync(DefaultTimeout, cancellationToken);
+
+ using var response = await httpClient.GetAsync("/", cancellationToken);
+
+ // Assert
+ response.StatusCode.Should().Be(System.Net.HttpStatusCode.OK);
+ }
+}
diff --git a/tests/E2E.Tests/xunit.runner.json b/tests/E2E.Tests/xunit.runner.json
new file mode 100644
index 00000000..e9c792c6
--- /dev/null
+++ b/tests/E2E.Tests/xunit.runner.json
@@ -0,0 +1,7 @@
+{
+ "$schema": "https://xunit.net/schema/current/xunit.runner.schema.json",
+ "methodDisplay": "method",
+ "methodDisplayOptions": "all",
+ "parallelizeAssembly": false,
+ "parallelizeTestCollections": true
+}