Add home hero with intro and buttons from the body, next-event card and page tiles
This commit is contained in:
1 parent
b737f57ef7
commit
e51afeb34b
23 files changed
+1262
-65
No files matched your search
@@ -1,6 +1,8 @@
|
||||
using System.Net;
|
||||
using System.Text.RegularExpressions;
|
||||
using Microsoft.AspNetCore.Mvc.Testing;
|
||||
using Microsoft.AspNetCore.TestHost;
|
||||
using Microsoft.Extensions.DependencyInjection;
|
||||
|
||||
namespace Elternbeirat.Web.Tests;
|
||||
|
||||
@@ -29,10 +31,25 @@ public sealed partial class RouteSmokeTests : IDisposable
|
||||
// the value from appsettings. UseSetting (not ConfigureAppConfiguration)
|
||||
// because it wins over appsettings.Development.json, which otherwise pins the
|
||||
// client to localhost:8090 while the test container uses a random port.
|
||||
_factory = _baseFactory.WithWebHostBuilder(builder =>
|
||||
builder.UseSetting("PocketBase:BaseUrl", pocketBase.BaseUrl.ToString()));
|
||||
_factory = WithClock(
|
||||
_baseFactory.WithWebHostBuilder(builder =>
|
||||
builder.UseSetting("PocketBase:BaseUrl", pocketBase.BaseUrl.ToString())),
|
||||
BeforeFixtureEvents);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// "Now" for the default factory: a week before the fixture's first event, so
|
||||
/// "upcoming" stays true no matter when the tests run.
|
||||
/// </summary>
|
||||
private static readonly DateTimeOffset BeforeFixtureEvents = new(2026, 10, 1, 10, 0, 0, TimeSpan.Zero);
|
||||
|
||||
/// <summary>
|
||||
/// Wraps <paramref name="factory"/> so the app's clock shows <paramref name="now"/>.
|
||||
/// </summary>
|
||||
private static WebApplicationFactory<Program> WithClock(WebApplicationFactory<Program> factory, DateTimeOffset now) =>
|
||||
factory.WithWebHostBuilder(builder =>
|
||||
builder.ConfigureTestServices(services => services.AddSingleton<TimeProvider>(new FixedTimeProvider(now))));
|
||||
|
||||
public void Dispose()
|
||||
{
|
||||
_factory.Dispose();
|
||||
@@ -261,6 +278,56 @@ public sealed partial class RouteSmokeTests : IDisposable
|
||||
response.StatusCode.ShouldBe(HttpStatusCode.ServiceUnavailable);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public async Task Home_hero_takes_title_and_buttons_from_the_body()
|
||||
{
|
||||
var client = _factory.CreateClient();
|
||||
|
||||
var html = await client.GetStringAsync(new Uri("/", UriKind.Relative));
|
||||
|
||||
html.ShouldContain(">Willkommen</h1>");
|
||||
html.ShouldNotContain(">Elternbeirat der IGMH</h1>"); // the fallback title
|
||||
html.ShouldContain("""<a class="btn btn-primary" href="/events">""");
|
||||
html.ShouldContain("""<a class="btn btn-secondary" href="/contact">""");
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public async Task Home_tiles_are_exactly_the_public_header_pages()
|
||||
{
|
||||
var client = _factory.CreateClient();
|
||||
|
||||
var html = await client.GetStringAsync(new Uri("/", UriKind.Relative));
|
||||
|
||||
var tiles = HomeTiles().Match(html);
|
||||
tiles.Success.ShouldBeTrue();
|
||||
Href().Matches(tiles.Value).Select(match => match.Groups[1].Value)
|
||||
.ShouldBe(["/board", "/patrons", "/faqs", "/downloads", "/posts", "/events"]);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public async Task Home_shows_the_next_event_when_one_is_upcoming()
|
||||
{
|
||||
var client = _factory.CreateClient();
|
||||
|
||||
var html = await client.GetStringAsync(new Uri("/", UriKind.Relative));
|
||||
|
||||
html.ShouldContain("Nächster Termin");
|
||||
html.ShouldContain("Elternbeiratssitzung");
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public async Task Home_hides_the_next_event_when_none_is_upcoming()
|
||||
{
|
||||
// After the fixture's last event nothing is upcoming; the card must vanish
|
||||
// instead of showing an empty frame.
|
||||
await using var factory = WithClock(_factory, new DateTimeOffset(2027, 1, 1, 10, 0, 0, TimeSpan.Zero));
|
||||
var client = factory.CreateClient();
|
||||
|
||||
var html = await client.GetStringAsync(new Uri("/", UriKind.Relative));
|
||||
|
||||
html.ShouldNotContain("Nächster Termin");
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Matches a resource reference that points at an absolute URL, with or without
|
||||
/// scheme (<c>https://</c>, <c>http://</c> or protocol-relative <c>//</c>): the
|
||||
@@ -282,4 +349,11 @@ public sealed partial class RouteSmokeTests : IDisposable
|
||||
/// </summary>
|
||||
[GeneratedRegex(@"\bhref=""([^""]*)""")]
|
||||
private static partial Regex Href();
|
||||
|
||||
/// <summary>
|
||||
/// Matches the home page's tile navigation, from its opening tag to the closing
|
||||
/// one. It nests no other <c><nav></c>.
|
||||
/// </summary>
|
||||
[GeneratedRegex("""<nav class="home-tiles".*?</nav>""", RegexOptions.Singleline)]
|
||||
private static partial Regex HomeTiles();
|
||||
}
|
||||
Reference in new issue
Block a user