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().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=")) } } } } // 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. /// - Parameter assetVersion: the version token appended to the page's asset URLs. /// - Returns: the configured application. func app( assetVersion: String? ) -> some ApplicationProtocol { let router = Router(context: WebsiteRequestContext.self) router.addMiddleware { LocalizationMiddleware() } router.addRoutes(RootController( assetVersion: assetVersion ).routes) return Application(router: router) } }