This commit contains the latest updates from the generic Website template, which rework the compression and localization: - Reworked the compression and localization in the Infrastructure package. (3c568e4) - Adopted the reworked compression and localization in the Website service. (08cf3e3) The template commit that only touched the root README (53676ed) was left out, as this project no longer carries that file. Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
229 lines
7.2 KiB
Swift
229 lines
7.2 KiB
Swift
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.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 `serves the landing page with a canonical URL when an origin is configured`() async throws {
|
|
try await app(
|
|
siteOrigin: "https://example.com"
|
|
).test(.router) { client in
|
|
try await client.execute(
|
|
uri: "/",
|
|
method: .get
|
|
) { response in
|
|
#expect(String(buffer: response.body).contains(#"<link rel="canonical" href="https://example.com">"#))
|
|
}
|
|
}
|
|
}
|
|
|
|
/// The template's catalog serves one language, so the default owns every path and no prefixed route is registered.
|
|
@Test
|
|
func `registers no prefixed route for a single-language catalog`() async throws {
|
|
let prefixed = Language.all.filter { !$0.isDefault }
|
|
|
|
#expect(prefixed.isEmpty)
|
|
|
|
try await app.test(.router) { client in
|
|
try await client.execute(
|
|
uri: "/en",
|
|
method: .get
|
|
) { response in
|
|
#expect(response.status == .notFound)
|
|
}
|
|
}
|
|
}
|
|
|
|
@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, derives its absolute links from the given origin, and embeds the given analytics tracker.
|
|
/// - Parameters:
|
|
/// - assetVersion: the version token appended to the page's asset URLs.
|
|
/// - siteOrigin: the public origin the page derives its canonical URL and language alternates from, or `nil` (the default) to omit them.
|
|
/// - analytics: the analytics tracker the landing page embeds, or `nil` (the default) to omit it.
|
|
/// - Returns: the configured application.
|
|
func app(
|
|
assetVersion: String? = nil,
|
|
siteOrigin: String? = nil,
|
|
analytics: Analytics? = nil
|
|
) -> some ApplicationProtocol {
|
|
let router = Router(context: WebsiteRequestContext.self)
|
|
|
|
router.addRoutes(RootController<WebsiteRequestContext>(
|
|
assetVersion: assetVersion,
|
|
siteOrigin: siteOrigin,
|
|
analytics: analytics
|
|
).routes)
|
|
|
|
return Application(router: router)
|
|
}
|
|
|
|
}
|