discourse/spec/jobs/change_display_name_spec.rb
Régis Hanol 255c1dfaf3
FIX: Preserve display name in quotes when using the rich text editor (#38078)
When `display_name_on_posts` is enabled and `prioritize_username_in_ux`
is disabled, quoting a post in markdown mode correctly attributes the
quote to the user's full name (e.g. `[quote="Robin Ward, post:1,
topic:2, username:eviltrout"]`). However, the rich text editor lost the
display name during the markdown→ProseMirror→markdown round-trip,
falling back to just the username.

The ProseMirror quote node only stored `username` in its attributes.
When BBCode with a `username:` param was parsed, the display name was
discarded. On serialization, only the username survived.

This commit:
- Adds a `displayName` attribute to the ProseMirror quote node spec
- Emits `data-display-name` on the markdown-it aside token so the
ProseMirror parser can pick it up
- Updates the serializer to output the display name and `username:`
param when present
- Fixes a latent issue where `displayName` remained as an array instead
of being joined into a string when the name contains no commas

https://meta.discourse.org/t/397049/12
2026-02-26 21:04:07 +01:00

72 lines
2.6 KiB
Ruby

# frozen_string_literal: true
RSpec.describe Jobs::ChangeDisplayName do
before { stub_image_size }
let(:username) { "codinghorror" }
let(:old_display_name) { "|| Jeff ||" }
let(:new_display_name) { "|| Mr. Atwood ||" }
let(:user) { Fabricate(:user, username: username, name: old_display_name) }
let(:topic) { Fabricate(:topic, user: user) }
let!(:post) { create_post(post_attributes.merge(topic_id: topic.id)) }
let!(:quoted_post) { create_post(user: user, topic: topic, post_number: 1, raw: "quoted post") }
let(:avatar_url) { user.avatar_template_url.gsub("{size}", "48") }
let(:post_attributes) { { raw: <<~RAW } }
[quote="#{old_display_name}, post:1, topic:#{quoted_post.topic.id}, username:#{username}"]
quoted post
[/quote]
RAW
let(:revised_post_attributes) { { raw: <<~RAW } }
[quote="#{old_display_name}, post:1, topic:#{quoted_post.topic.id}, username:#{username}"]
quoted post
[/quote]
Forgot something.
RAW
let(:args) { { user_id: user.id, old_name: old_display_name, new_name: new_display_name } }
describe "#execute" do
context "when the renamed user has been quoted" do
it "rewrites the raw quote display name" do
expect { described_class.new.execute(args) }.to change { post.reload.raw }.to(<<~RAW.strip)
[quote="#{new_display_name}, post:1, topic:#{quoted_post.topic.id}, username:#{username}"]
quoted post
[/quote]
RAW
end
it "rewrites the cooked quote display name" do
expect { described_class.new.execute(args) }.to change { post.reload.cooked }.to(
match_html(<<~HTML.strip),
<aside class="quote no-group" data-username="#{username}" data-display-name="#{new_display_name}" data-post="1" data-topic="#{quoted_post.topic.id}">
<div class="title">
<div class="quote-controls"></div>
<img alt="" width="24" height="24" src="#{avatar_url}" class="avatar"> #{new_display_name}:</div>
<blockquote>
<p>quoted post</p>
</blockquote>
</aside>
HTML
)
end
end
context "when the user has been quoted in revisions" do
before { post.revise(post.user, revised_post_attributes, force_new_version: true) }
it "rewrites the quote in revisions" do
expect { described_class.new.execute(args) }.to change {
post.reload.revisions[0].modifications["raw"][0]
}.to(<<~RAW.strip)
[quote="#{new_display_name}, post:1, topic:#{quoted_post.topic.id}, username:#{username}"]
quoted post
[/quote]
RAW
end
end
end
end