import Elementary import Foundation import Testing @testable import Infrastructure @Suite( "Page protocol", .tags(.`protocol`) ) struct PageTests { // MARK: Functional tests @Test func `assembles the document around the page's parts`() { let html = StubPage().render() #expect(html.contains("Stub Page")) #expect(html.contains(#"lang="en""#)) #expect(html.contains(#"name="viewport""#)) #expect(html.contains(#""#)) #expect(html.contains(#""#)) #expect(html.contains(#""#)) #expect(html.contains("Stub content")) } @Test func `places the metadata between the viewport and the stylesheets`() throws { let html = StubPage().render() let viewport = try #require(html.range(of: #"name="viewport""#)) let metadata = try #require(html.range(of: #"name="stub""#)) let stylesheet = try #require(html.range(of: "/css/stub.css")) #expect(viewport.lowerBound < metadata.lowerBound) #expect(metadata.lowerBound < stylesheet.lowerBound) } @Test func `renders the scripts deferred in the head, after the stylesheets`() throws { let html = StubPage().render() let stylesheet = try #require(html.range(of: "/css/stub.css")) let script = try #require(html.range(of: "/js/stub.js")) let content = try #require(html.range(of: "Stub content")) // Deferred head scripts start downloading during head parsing but still execute, in order, only after the // document is parsed — the semantics end-of-body tags gave, minus the late download start. #expect(stylesheet.lowerBound < script.lowerBound) #expect(script.lowerBound < content.lowerBound) } @Test func `omits the summary and canonical tags by default`() { let html = StubPage().render() #expect(!html.contains(#"name="description""#)) #expect(!html.contains(#"rel="canonical""#)) } @Test func `renders the summary and canonical tags when provided`() { let html = StubPage( canonicalURL: "https://stub.example/", summary: "A stub page." ).render() #expect(html.contains(#""#)) #expect(html.contains(#""#)) } @Test func `omits the social card tags by default`() { let html = StubPage().render() #expect(!html.contains(#"property="og:"#)) #expect(!html.contains(#"name="twitter:card""#)) } @Test func `renders the social card tags when provided`() { let html = StubPage(socialCard: .init( title: "Stub Page", summary: "A stub page.", url: "https://stub.example/", image: .init( url: "https://stub.example/img/card.png", width: 2400, height: 1260 ) )).render() #expect(html.contains(#""#)) #expect(html.contains(#""#)) #expect(html.contains(#""#)) #expect(html.contains(#""#)) #expect(html.contains(#""#)) #expect(html.contains(#""#)) #expect(html.contains(#""#)) #expect(html.contains(#""#)) } @Test func `omits the structured data script by default`() { let html = StubPage().render() #expect(!html.contains("application/ld+json")) } @Test func `renders the structured data script when provided`() { let html = StubPage(structuredData: .init( name: "Stub Site", url: "https://stub.example/", logo: "https://stub.example/logo.png", profiles: ["https://social.example/stub"] )).render() #expect(html.contains( #""# )) } @Test func `omits the analytics tracker by default`() { let html = StubPage().render() #expect(!html.contains("data-website-id")) } @Test func `renders the analytics tracker when provided`() { let html = StubPage(analytics: .init( scriptURL: "https://analytics.example.com/script", websiteID: "0000-website-id", domains: "example.com" )).render() #expect(html.contains(#""#)) } @Test func `omits the analytics behavior flags that are disabled`() { let html = StubPage(analytics: .init( scriptURL: "https://analytics.example.com/script", websiteID: "0000-website-id", domains: "example.com", excludeHash: true, doNotTrack: false, performance: false )).render() #expect(html.contains(#""#)) #expect(!html.contains("data-do-not-track")) #expect(!html.contains("data-performance")) } @Test func `appends the version token to the asset URLs`() { let html = StubPage(assetVersion: "0123456789abcdef").render() #expect(html.contains("/css/stub.css?v=0123456789abcdef")) #expect(html.contains("/js/stub.js?v=0123456789abcdef")) } @Test func `derives the document language from the locale`() { let html = StubPage(locale: .init(identifier: "de-DE")).render() #expect(html.contains(#"lang="de""#)) } }