Extra tags and Social Card integration in the Infrastructure package (#28)
This PR contains the work done to extends the `Page` protocol with the head tags that control search snippets and link previews: a meta description, a canonical URL, and a social card rendered as _Open Graph_ and _Twitter_ meta tags. All three are optional with nil defaults, so existing conformers compile and render unchanged. Reviewed-on: rock-n-code/loud-amsterdam#28 Co-authored-by: Javier Cicchelli <javier@rock-n-code.com>
This commit is contained in:
@@ -47,6 +47,56 @@ struct PageTests {
|
||||
#expect(content.lowerBound < script.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(#"<meta name="description" content="A stub page.">"#))
|
||||
#expect(html.contains(#"<link rel="canonical" href="https://stub.example/">"#))
|
||||
}
|
||||
|
||||
@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(#"<meta property="og:type" content="website">"#))
|
||||
#expect(html.contains(#"<meta property="og:title" content="Stub Page">"#))
|
||||
#expect(html.contains(#"<meta property="og:description" content="A stub page.">"#))
|
||||
#expect(html.contains(#"<meta property="og:url" content="https://stub.example/">"#))
|
||||
#expect(html.contains(#"<meta property="og:image" content="https://stub.example/img/card.png">"#))
|
||||
#expect(html.contains(#"<meta property="og:image:width" content="2400">"#))
|
||||
#expect(html.contains(#"<meta property="og:image:height" content="1260">"#))
|
||||
#expect(html.contains(#"<meta name="twitter:card" content="summary_large_image">"#))
|
||||
}
|
||||
|
||||
@Test
|
||||
func `appends the version token to the asset URLs`() {
|
||||
let html = StubPage(assetVersion: "0123456789abcdef").render()
|
||||
|
||||
@@ -0,0 +1,84 @@
|
||||
import Testing
|
||||
|
||||
@testable import Infrastructure
|
||||
|
||||
@Suite(
|
||||
"SocialCard type",
|
||||
.tags(.type)
|
||||
)
|
||||
struct SocialCardTests {
|
||||
|
||||
// MARK: Functional tests
|
||||
|
||||
@Test
|
||||
func `derives the full tag list from a complete card`() {
|
||||
let card = SocialCard(
|
||||
title: "A Title",
|
||||
summary: "A summary.",
|
||||
url: "https://site.example/",
|
||||
siteName: "A Site",
|
||||
locale: "en",
|
||||
image: .init(
|
||||
url: "https://site.example/img/card.png",
|
||||
width: 2400,
|
||||
height: 1260,
|
||||
alt: "An image."
|
||||
)
|
||||
)
|
||||
|
||||
#expect(card.tags == [
|
||||
.init(attribute: .property, content: "website", name: .type),
|
||||
.init(attribute: .property, content: "A Site", name: .siteName),
|
||||
.init(attribute: .property, content: "A Title", name: .title),
|
||||
.init(attribute: .property, content: "A summary.", name: .description),
|
||||
.init(attribute: .property, content: "https://site.example/", name: .url),
|
||||
.init(attribute: .property, content: "en", name: .locale),
|
||||
.init(attribute: .property, content: "https://site.example/img/card.png", name: .image),
|
||||
.init(attribute: .property, content: "2400", name: .imageWidth),
|
||||
.init(attribute: .property, content: "1260", name: .imageHeight),
|
||||
.init(attribute: .property, content: "An image.", name: .imageAlt),
|
||||
.init(attribute: .name, content: "summary_large_image", name: .twitter),
|
||||
])
|
||||
}
|
||||
|
||||
@Test
|
||||
func `omits the tags of the facts a minimal card does not carry`() {
|
||||
let card = SocialCard(title: "A Title")
|
||||
|
||||
#expect(card.tags == [
|
||||
.init(attribute: .property, content: "website", name: .type),
|
||||
.init(attribute: .property, content: "A Title", name: .title),
|
||||
.init(attribute: .name, content: "summary_large_image", name: .twitter),
|
||||
])
|
||||
}
|
||||
|
||||
@Test
|
||||
func `omits the image alt tag when the image carries none`() {
|
||||
let card = SocialCard(
|
||||
title: "A Title",
|
||||
image: .init(
|
||||
url: "https://site.example/img/card.png",
|
||||
width: 2400,
|
||||
height: 1260
|
||||
)
|
||||
)
|
||||
|
||||
let names = card.tags.map(\.name)
|
||||
|
||||
#expect(names.contains(.image))
|
||||
#expect(!names.contains(.imageAlt))
|
||||
}
|
||||
|
||||
@Test
|
||||
func `carries the type and style it is given`() {
|
||||
let card = SocialCard(
|
||||
title: "A Title",
|
||||
type: "article",
|
||||
style: .summary
|
||||
)
|
||||
|
||||
#expect(card.tags.contains(.init(attribute: .property, content: "article", name: .type)))
|
||||
#expect(card.tags.contains(.init(attribute: .name, content: "summary", name: .twitter)))
|
||||
}
|
||||
|
||||
}
|
||||
Reference in New Issue
Block a user