External link marker: new tab + icon on links leaving the blog
External links in post bodies now open in a new tab and show a box-with-arrow marker icon, so readers can tell at a glance which links leave the site. - blogex: new Blogex.ExternalLinks.rewrite/1 marks up anchors with http(s) hrefs at compile time with target="_blank", rel="noopener" and class="blogex-external" (idempotent, merges into existing class/rel values, leaves relative, mailto: and #anchor links alone) - blogex: Post.build/3 applies the rewrite, so every blog gets it - app: CSS in .blogex-post-body draws the marker via a mask so it inherits the link colour; empty ::after content stays invisible to screen readers - make test now also runs the blogex suite; it is currently red with 3 pre-existing blog_integration_test failures caused by the vacuous link validator (parked yak link-validator-never-sees-compiled-html-...)
This commit is contained in:
@@ -35,6 +35,52 @@ defmodule FirehoseWeb.BlogTest do
|
||||
end
|
||||
end
|
||||
|
||||
describe "external links in compiled posts" do
|
||||
# The marker markup is applied at compile time by Blogex.ExternalLinks
|
||||
# (blogex/test/blogex/external_links_test.exs covers the rewrite itself);
|
||||
# these tests verify the real compiled posts make it to the page.
|
||||
defp latest_post_with_links,
|
||||
do: Firehose.EngineeringBlog.get_post!("delayed-gratification-in-ai-summer")
|
||||
|
||||
test "wikipedia link carries target, rel and marker class in compiled body" do
|
||||
post = latest_post_with_links()
|
||||
|
||||
assert post.body =~
|
||||
~s(<a href="https://en.wikipedia.org/wiki/Attention_Is_All_You_Need" target="_blank" rel="noopener" class="blogex-external">)
|
||||
end
|
||||
|
||||
test "every external anchor in compiled body is marked up" do
|
||||
post = latest_post_with_links()
|
||||
|
||||
anchors = Regex.scan(~r/<a\s[^>]*>/, post.body) |> List.flatten()
|
||||
|
||||
external_anchors =
|
||||
Enum.filter(anchors, &(&1 =~ ~r<href="https?://>))
|
||||
|
||||
assert length(external_anchors) > 1
|
||||
|
||||
assert Enum.all?(external_anchors, fn anchor ->
|
||||
anchor =~ ~s(target="_blank") and
|
||||
anchor =~ ~s(rel="noopener") and
|
||||
anchor =~ ~s(class="blogex-external")
|
||||
end)
|
||||
end
|
||||
|
||||
test "internal links in compiled body are untouched" do
|
||||
post = latest_post_with_links()
|
||||
|
||||
assert post.body =~
|
||||
~s(<a href="/blog/engineering/swim-the-test">Swim the Test</a>)
|
||||
end
|
||||
|
||||
test "rendered post page shows external links opening in a new tab", %{conn: conn} do
|
||||
body =
|
||||
conn |> get("/blog/engineering/delayed-gratification-in-ai-summer") |> html_response(200)
|
||||
|
||||
assert body =~ "target=\"_blank\" rel=\"noopener\" class=\"blogex-external\""
|
||||
end
|
||||
end
|
||||
|
||||
describe "input validation" do
|
||||
test "GET /blog/nonexistent returns 404", %{conn: conn} do
|
||||
assert conn |> get("/blog/nonexistent") |> html_response(404)
|
||||
|
||||
Reference in New Issue
Block a user