Files
ccn/Services/Website/Tests/Library/Cases/Public/Controllers/RootControllerTests.swift
T

203 lines
6.1 KiB
Swift
Raw Normal View History

2026-08-19 22:55:00 +02:00
import Hummingbird
import HummingbirdTesting
import Infrastructure
import NIOCore
import Testing
@testable import WebsiteLibrary
@Suite(
"RootController controller",
.tags(.controller)
)
struct RootControllerTests {
// MARK: Constants
private let app: Application = .init(router: {
let router = Router(context: WebsiteRequestContext.self)
router.addMiddleware {
LocalizationMiddleware()
}
router.addRoutes(RootController<WebsiteRequestContext>().routes)
return router
}())
// MARK: Functional tests
@Test
func `serves the landing page at the root path`() async throws {
try await app.test(.router) { client in
try await client.execute(
uri: "/",
method: .get
) { response in
let body = String(buffer: response.body)
#expect(response.status == .ok)
#expect(response.headers[.contentType] == "text/html; charset=utf-8")
#expect(response.headers[.contentLanguage] == "en")
#expect(response.headers[.vary] == "Accept-Language")
#expect(body.contains("Hello world!"))
}
}
}
@Test
func `serves the landing page with revalidation headers`() async throws {
try await app.test(.router) { client in
try await client.execute(
uri: "/",
method: .get
) { response in
let eTag = try #require(response.headers[.eTag])
#expect(eTag.hasPrefix(#"W/""#))
#expect(response.headers[.cacheControl] == "public, no-cache")
}
}
}
@Test
func `revalidates a matching conditional request with a 304`() async throws {
try await app.test(.router) { client in
let eTag = try await client.execute(
uri: "/",
method: .get
) { response in
try #require(response.headers[.eTag])
}
try await client.execute(
uri: "/",
method: .get,
headers: [.ifNoneMatch: eTag]
) { response in
#expect(response.status == .notModified)
#expect(response.headers[.eTag] == eTag)
#expect(response.body.readableBytes == 0)
}
}
}
@Test
func `serves the full page to a non-matching conditional request`() async throws {
try await app.test(.router) { client in
try await client.execute(
uri: "/",
method: .get,
headers: [.ifNoneMatch: #"W/"0123456789abcdef""#]
) { response in
let body = String(buffer: response.body)
#expect(response.status == .ok)
#expect(body.contains("Hello world!"))
}
}
}
@Test
func `renders versioned asset URLs when given a version`() async throws {
try await app(
assetVersion: "0123456789abcdef"
).test(.router) { client in
try await client.execute(
uri: "/",
method: .get
) { response in
let body = String(buffer: response.body)
#expect(body.contains("/css/index.css?v=0123456789abcdef"))
#expect(body.contains("/js/index.js?v=0123456789abcdef"))
}
}
}
@Test
func `renders unversioned asset URLs by default`() async throws {
try await app.test(.router) { client in
try await client.execute(
uri: "/",
method: .get
) { response in
let body = String(buffer: response.body)
#expect(body.contains(#"href="/css/index.css""#))
#expect(!body.contains("?v="))
}
}
}
@Test
func `embeds no analytics tracker by default`() async throws {
try await app.test(.router) { client in
try await client.execute(
uri: "/",
method: .get
) { response in
let body = String(buffer: response.body)
#expect(!body.contains("data-website-id"))
#expect(!body.contains("analytics"))
}
}
}
@Test
func `embeds the analytics tracker when one is configured`() async throws {
try await app(
analytics: .init(
scriptURL: "https://analytics.example.com/script",
websiteID: "0000-website-id",
domains: "example.com"
)
).test(.router) { client in
try await client.execute(
uri: "/",
method: .get
) { response in
let body = String(buffer: response.body)
#expect(body.contains(#"<link rel="preconnect" href="https://analytics.example.com">"#))
#expect(body.contains(#"<script defer src="https://analytics.example.com/script" data-website-id="0000-website-id" data-domains="example.com""#))
}
}
}
}
// MARK: - Helpers
private extension RootControllerTests {
// MARK: Methods
/// Builds an application whose root controller appends the given version token to the landing
/// page's asset URLs and embeds the given analytics tracker.
/// - Parameters:
/// - assetVersion: the version token appended to the page's asset URLs.
/// - analytics: the analytics tracker the landing page embeds, or `nil` (the default) to omit it.
/// - Returns: the configured application.
func app(
assetVersion: String? = nil,
analytics: Analytics? = nil
) -> some ApplicationProtocol {
let router = Router(context: WebsiteRequestContext.self)
router.addMiddleware {
LocalizationMiddleware()
}
router.addRoutes(RootController<WebsiteRequestContext>(
assetVersion: assetVersion,
analytics: analytics
).routes)
return Application(router: router)
}
}