Files
once-campfire/test/system/unfurling_links_test.rb
T
Rosa Gutierrez e6022a52c3 Assert only that the preview image gained no extra attributes
Pinning the exact attribute set also pinned which of them Trix's own
sanitizer keeps, which is not what this test is about.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_0186eyzivcTn6wqjEE4Wnxdt
2026-09-11 21:10:57 +02:00

113 lines
3.3 KiB
Ruby

require "application_system_test_case"
require "socket"
class UnfurlingLinksTest < ApplicationSystemTestCase
setup do
@website = Website.new
@website.start
RestrictedHTTP::PrivateNetworkGuard.stubs(:resolve).returns("127.0.0.1")
sign_in "jz@37signals.com"
join_room rooms(:designers)
end
teardown do
@website.stop
end
test "a quote in the opengraph image URL cannot add attributes to the preview" do
paste_into_composer @website.page_url
assert_selector "trix-editor .og-embed__title", text: "A normal looking link"
assert_equal @website.image_url, preview_image_attributes["src"]
assert_empty preview_image_attributes.keys - %w[ src class alt ]
end
private
def paste_into_composer(url)
page.execute_script(<<~JS, url)
const editor = document.querySelector("trix-editor")
editor.focus()
const clipboardData = new DataTransfer()
clipboardData.setData("text/plain", arguments[0])
editor.dispatchEvent(new ClipboardEvent("paste", { clipboardData, bubbles: true, cancelable: true }))
JS
end
def preview_image_attributes
page.evaluate_script(<<~JS)
Object.fromEntries(Array.from(document.querySelector("trix-editor .og-embed__image img").attributes, attribute => [ attribute.name, attribute.value ]))
JS
end
# Serves a page whose og:image URL carries a double quote, so an unescaped
# preview closes the src attribute early and takes the rest as attributes.
class Website
def start
@socket = TCPServer.new("127.0.0.1", 0)
@thread = Thread.new { serve }
end
def stop
@thread&.kill
@socket&.close
end
def page_url
"http://127.0.0.1:#{port}/page.html"
end
def image_url
%(http://127.0.0.1:#{port}/image.png?from=" style="outline:9px solid red)
end
private
def port
@socket.addr[1]
end
def serve
loop do
client = @socket.accept
Thread.new(client) { |connection| respond_to(connection) }
end
rescue IOError, Errno::EBADF
nil
end
def respond_to(client)
request_line = client.gets.to_s
nil while (line = client.gets) && line != "\r\n"
method, path = request_line.split(" ")
if path.to_s.start_with?("/image.png")
respond client, "image/png", method == "HEAD" ? "" : "not really a PNG"
else
respond client, "text/html", page
end
rescue IOError, Errno::ECONNRESET
nil
ensure
client.close rescue nil
end
def respond(client, content_type, body)
client.write "HTTP/1.1 200 OK\r\nContent-Type: #{content_type}\r\nContent-Length: #{body.bytesize}\r\nConnection: close\r\n\r\n#{body}"
end
def page
<<~HTML
<html><head>
<meta property="og:url" content="https://example.com/harmless">
<meta property="og:title" content="A normal looking link">
<meta property="og:description" content="Nothing to see here">
<meta property="og:image" content='#{image_url}'>
</head><body>Hello</body></html>
HTML
end
end
end