Skip to content
Merged
Show file tree
Hide file tree
Changes from 5 commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
55 changes: 55 additions & 0 deletions EssentialCSharp.Web.Tests/FunctionalTests.cs
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,44 @@ public async Task WhenTheApplicationStarts_ItCanLoadLoadPages(string relativeUrl
Assert.Equal(HttpStatusCode.OK, response.StatusCode);
}

[Theory]
[InlineData("/guidelines?rid=test-referral-id")]
[InlineData("/about?rid=abc123")]
[InlineData("/hello-world?rid=user-referral")]
public async Task WhenPagesAreAccessedWithRidParameter_TheyReturnContentSuccessfully(string relativeUrl)
{
using WebApplicationFactory factory = new();

HttpClient client = factory.CreateClient();
using HttpResponseMessage response = await client.GetAsync(relativeUrl);

Assert.Equal(HttpStatusCode.OK, response.StatusCode);

// Ensure the response has content (not blank)
string content = await response.Content.ReadAsStringAsync();
Assert.NotEmpty(content);

// Verify it's actually HTML content, not just whitespace
Assert.Contains("<html", content, StringComparison.OrdinalIgnoreCase);
}

[Theory]
[InlineData("/guidelines?rid=")]
[InlineData("/about?rid= ")]
public async Task WhenPagesAreAccessedWithEmptyRidParameter_TheyStillWork(string relativeUrl)
{
using WebApplicationFactory factory = new();

HttpClient client = factory.CreateClient();
using HttpResponseMessage response = await client.GetAsync(relativeUrl);

Assert.Equal(HttpStatusCode.OK, response.StatusCode);

string content = await response.Content.ReadAsStringAsync();
Assert.NotEmpty(content);
Assert.Contains("<html", content, StringComparison.OrdinalIgnoreCase);
}

[Fact]
public async Task WhenTheApplicationStarts_NonExistingPage_GivesCorrectStatusCode()
{
Expand All @@ -30,4 +68,21 @@ public async Task WhenTheApplicationStarts_NonExistingPage_GivesCorrectStatusCod

Assert.Equal(HttpStatusCode.NotFound, response.StatusCode);
}

[Theory]
[InlineData("/guidelines?foo=bar")]
[InlineData("/about?someOtherParam=value")]
public async Task WhenPagesAreAccessedWithNonRidParameters_TheyStillWork(string relativeUrl)
{
using WebApplicationFactory factory = new();

HttpClient client = factory.CreateClient();
using HttpResponseMessage response = await client.GetAsync(relativeUrl);

Assert.Equal(HttpStatusCode.OK, response.StatusCode);

string content = await response.Content.ReadAsStringAsync();
Assert.NotEmpty(content);
Assert.Contains("<html", content, StringComparison.OrdinalIgnoreCase);
}
}
21 changes: 18 additions & 3 deletions EssentialCSharp.Web.Tests/WebApplicationFactory.cs
Original file line number Diff line number Diff line change
@@ -1,13 +1,17 @@
using EssentialCSharp.Web.Data;
using Microsoft.AspNetCore.Hosting;
using Microsoft.AspNetCore.Mvc.Testing;
using Microsoft.Data.Sqlite;
using Microsoft.EntityFrameworkCore;
using Microsoft.Extensions.DependencyInjection;

namespace EssentialCSharp.Web.Tests;

internal sealed class WebApplicationFactory : WebApplicationFactory<Program>
{
private static string SqlConnectionString => $"DataSource=file:{Guid.NewGuid()}?mode=memory&cache=shared";
private SqliteConnection? _Connection;

protected override void ConfigureWebHost(IWebHostBuilder builder)
{
builder.ConfigureServices(services =>
Expand All @@ -21,19 +25,30 @@ protected override void ConfigureWebHost(IWebHostBuilder builder)
services.Remove(descriptor);
}

_Connection = new SqliteConnection(SqlConnectionString);
_Connection.Open();

services.AddDbContext<EssentialCSharpWebContext>(options =>
{
options.UseSqlite("Data Source=:memory:");
options.UseSqlite(_Connection);
});

using ServiceProvider serviceProvider = services.BuildServiceProvider();

using IServiceScope scope = serviceProvider.CreateScope();
IServiceProvider scopedServices = scope.ServiceProvider;
EssentialCSharpWebContext db = scopedServices.GetRequiredService<EssentialCSharpWebContext>();

db.Database.OpenConnection();
db.Database.EnsureCreated();
});
}

protected override void Dispose(bool disposing)
{
base.Dispose(disposing);
if (disposing && _Connection != null)
{
_Connection.Dispose();
_Connection = null;
}
}
}
8 changes: 6 additions & 2 deletions EssentialCSharp.Web/Middleware/ReferralTrackingMiddleware.cs
Original file line number Diff line number Diff line change
@@ -1,4 +1,3 @@
using System.Security.Claims;
using System.Web;
using EssentialCSharp.Web.Areas.Identity.Data;
using EssentialCSharp.Web.Services.Referrals;
Expand All @@ -9,10 +8,12 @@ namespace EssentialCSharp.Web.Middleware;
public sealed class ReferralMiddleware
{
private readonly RequestDelegate _Next;
private readonly ILogger<ReferralMiddleware> _Logger;

public ReferralMiddleware(RequestDelegate next)
public ReferralMiddleware(RequestDelegate next, ILogger<ReferralMiddleware> logger)
{
_Next = next;
_Logger = logger;
}

public async Task InvokeAsync(HttpContext context, IReferralService referralService, UserManager<EssentialCSharpWebUser> userManager)
Expand All @@ -25,6 +26,7 @@ public async Task InvokeAsync(HttpContext context, IReferralService referralServ
await _Next(context);
return;
}

if (context.User is { Identity.IsAuthenticated: true } claimsUser)
{
referralService.TrackReferralAsync(referralId, claimsUser);
Expand All @@ -33,5 +35,7 @@ public async Task InvokeAsync(HttpContext context, IReferralService referralServ
{
referralService.TrackReferralAsync(referralId, null);
}

await _Next(context);
}
}