require 'rails_helper' require 'pretty_text' describe PrettyText do let(:wrapped_image) { "
" } let(:wrapped_image_excerpt) { } describe "Cooking" do describe "off topic quoting" do it "can correctly populate topic title" do topic = Fabricate(:topic, title: "this is a test topic :slight_smile:") expected = <HTML expect(PrettyText.cook("[quote=\"EvilTrout, post:2, topic:#{topic.id}\"]ddd\n[/quote]", topic_id: 1)).to match_html expected end end describe "with avatar" do let(:default_avatar) { "//test.localhost/uploads/default/avatars/42d/57c/46ce7ee487/{size}.png" } let(:user) { Fabricate(:user) } before do User.stubs(:default_template).returns(default_avatar) end it "produces a quote even with new lines in it" do expect(PrettyText.cook("[quote=\"#{user.username}, post:123, topic:456, full:true\"]ddd\n[/quote]")).to match_html "" end it "should produce a quote" do expect(PrettyText.cook("[quote=\"#{user.username}, post:123, topic:456, full:true\"]ddd[/quote]")).to match_html "" end it "trims spaces on quote params" do expect(PrettyText.cook("[quote=\"#{user.username}, post:555, topic: 666\"]ddd[/quote]")).to match_html "" end end it "should handle 3 mentions in a row" do expect(PrettyText.cook('@hello @hello @hello')).to match_html "ddd
@hello @hello @hello
" end it "should handle group mentions with a hyphen and without" do expect(PrettyText.cook('@hello @hello-hello')).to match_html "@hello @hello-hello
" end it "should sanitize the html" do expect(PrettyText.cook("")).to match_html "" end it 'should allow for @mentions to have punctuation' do expect(PrettyText.cook("hello @bob's @bob,@bob; @bob\"")).to match_html( "hello @bob's @bob,@bob; @bob\"
" ) end # see: https://github.com/sparklemotion/nokogiri/issues/1173 skip 'allows html entities correctly' do expect(PrettyText.cook("ℵ£¢")).to eq("ℵ£¢
") end end describe "rel nofollow" do before do SiteSetting.stubs(:add_rel_nofollow_to_user_content).returns(true) SiteSetting.stubs(:exclude_rel_nofollow_domains).returns("foo.com|bar.com") end it "should inject nofollow in all user provided links" do expect(PrettyText.cook('cnn')).to match(/nofollow noopener/) end it "should not inject nofollow in all local links" do expect(PrettyText.cook("cnn") !~ /nofollow/).to eq(true) end it "should not inject nofollow in all subdomain links" do expect(PrettyText.cook("cnn") !~ /nofollow/).to eq(true) end it "should inject nofollow in all non subdomain links" do expect(PrettyText.cook("cnn")).to match(/nofollow/) end it "should not inject nofollow for foo.com" do expect(PrettyText.cook("cnn") !~ /nofollow/).to eq(true) end it "should inject nofollow for afoo.com" do expect(PrettyText.cook("cnn")).to match(/nofollow/) end it "should not inject nofollow for bar.foo.com" do expect(PrettyText.cook("cnn") !~ /nofollow/).to eq(true) end it "should not inject nofollow if omit_nofollow option is given" do expect(PrettyText.cook('cnn', omit_nofollow: true) !~ /nofollow/).to eq(true) end end describe "Excerpt" do it "sanitizes attempts to inject invalid attributes" do spinner = "",100)).to eq("[image]") end it "should keep alt tags" do expect(PrettyText.excerpt("",100)).to eq("[car]") end it "should keep title tags" do expect(PrettyText.excerpt("",100)).to eq("[car]") end it "should convert images to markdown if the option is set" do expect(PrettyText.excerpt("", 100, markdown_images: true)).to eq("![car](http://cnn.com/a.gif)") end it "should keep spoilers" do expect(PrettyText.excerpt("", 100)).to match_html "[image]" expect(PrettyText.excerpt("spoiler", 100)).to match_html "spoiler" end it "should remove meta informations" do expect(PrettyText.excerpt(wrapped_image, 100)).to match_html "[image]" end end it "should have an option to strip links" do expect(PrettyText.excerpt("cnn",100, strip_links: true)).to eq("cnn") end it "should preserve links" do expect(PrettyText.excerpt("cnn",100)).to match_html "cnn" end it "should deal with special keys properly" do expect(PrettyText.excerpt("",100)).to eq("") end it "should truncate stuff properly" do expect(PrettyText.excerpt("hello world",5)).to eq("hello…") expect(PrettyText.excerpt("
hello
world
",6)).to eq("hello w…") end it "should insert a space between to Ps" do expect(PrettyText.excerpt("a
b
",5)).to eq("a b") end it "should strip quotes" do expect(PrettyText.excerpt("boom",5)).to eq("boom") end it "should not count the surrounds of a link" do expect(PrettyText.excerpt("cnn",3)).to match_html "cnn" end it "uses an ellipsis instead of html entities if provided with the option" do expect(PrettyText.excerpt("cnn", 2, text_entities: true)).to match_html "cn..." end it "should truncate links" do expect(PrettyText.excerpt("cnn",2)).to match_html "cn…" end it "doesn't extract empty quotes as links" do expect(PrettyText.extract_links("\n").to_a).to be_empty end it "doesn't extract links from elided parts" do expect(PrettyText.extract_links("<h3>Hours</h3>
",100)).to eq("<h3>Hours</h3>")
end
it "should handle nil" do
expect(PrettyText.excerpt(nil,100)).to eq('')
end
it "handles span excerpt at the beginning of a post" do
expect(PrettyText.excerpt("hi test",100)).to eq('hi')
post = Fabricate(:post, raw: "hi test")
expect(post.excerpt).to eq("hi")
end
it "ignores max excerpt length if a span excerpt is specified" do
two_hundred = "123456789 " * 20 + "."
text = two_hundred + "#{two_hundred}" + two_hundred
expect(PrettyText.excerpt(text, 100)).to eq(two_hundred)
post = Fabricate(:post, raw: text)
expect(post.excerpt).to eq(two_hundred)
end
it "unescapes html entities when we want text entities" do
expect(PrettyText.excerpt("'", 500, text_entities: true)).to eq("'")
end
it "should have an option to preserve emoji images" do
emoji_image = ""
expect(PrettyText.excerpt(emoji_image, 100, { keep_emoji_images: true })).to match_html(emoji_image)
end
it "should have an option to remap emoji to code points" do
emoji_image = "I you "
expect(PrettyText.excerpt(emoji_image, 100, { remap_emoji: true })).to match_html("I ā¤ you :unknown:")
end
it "should have an option to preserve emoji codes" do
emoji_code = ""
expect(PrettyText.excerpt(emoji_code, 100)).to eq(":heart:")
end
end
describe "strip links" do
it "returns blank for blank input" do
expect(PrettyText.strip_links("")).to be_blank
end
it "does nothing to a string without links" do
expect(PrettyText.strip_links("I'm the batman")).to eq("I'm the batman")
end
it "strips links but leaves the text content" do
expect(PrettyText.strip_links("I'm the linked batman")).to eq("I'm the linked batman")
end
it "escapes the text content" do
expect(PrettyText.strip_links("I'm the linked <batman>")).to eq("I'm the linked <batman>")
end
end
describe "strip_image_wrapping" do
def strip_image_wrapping(html)
doc = Nokogiri::HTML.fragment(html)
described_class.strip_image_wrapping(doc)
doc.to_html
end
it "doesn't change HTML when there's no wrapped image" do
html = ""
expect(strip_image_wrapping(html)).to eq(html)
end
it "strips the metadata" do
expect(strip_image_wrapping(wrapped_image)).to match_html ""
end
end
describe 'format_for_email' do
let(:base_url) { "http://baseurl.net" }
let(:post) { Fabricate(:post) }
before do
Discourse.stubs(:base_url).returns(base_url)
end
it 'does not crash' do
PrettyText.format_for_email('test', post)
end
it "adds base url to relative links" do
html = "@wiseguy, @trollol what do you guys think?
" output = described_class.format_for_email(html, post) expect(output).to eq("@wiseguy, @trollol what do you guys think?
") end it "doesn't change external absolute links" do html = "Check out this guy.
" expect(described_class.format_for_email(html, post)).to eq(html) end it "doesn't change internal absolute links" do html = "Check out this guy.
" expect(described_class.format_for_email(html, post)).to eq(html) end it "can tolerate invalid URLs" do html = "Check out this guy.
" expect { described_class.format_for_email(html, post) }.to_not raise_error end end it 'can escape *' do expect(PrettyText.cook("***a***a")).to match_html("aa
") expect(PrettyText.cook("***\\****a")).to match_html("*a
") end it 'can include code class correctly' do expect(PrettyText.cook("```cpp\ncpp\n```")).to match_html("cpp
")
end
it 'indents code correctly' do
code = "X\n```\n\n #\n x\n```"
cooked = PrettyText.cook(code)
expect(cooked).to match_html("X
#\n x
")
end
it 'can substitute s3 cdn correctly' do
SiteSetting.enable_s3_uploads = true
SiteSetting.s3_access_key_id = "XXX"
SiteSetting.s3_secret_access_key = "XXX"
SiteSetting.s3_upload_bucket = "test"
SiteSetting.s3_cdn_url = "https://awesome.cdn"
# add extra img tag to ensure it does not blow up
raw = <
HTML
cooked = < test |
---|
a |
test |
---|
a |
test |
---|
a |
#unknown::tag #known
") end # TODO does it make sense to generate hashtags for tags that are missing in action? end describe "custom emoji" do it "replaces the custom emoji" do Emoji.stubs(:custom).returns([ Emoji.create_from_path('trout') ]) expect(PrettyText.cook("hello :trout:")).to match(/]+trout[^>]+>/) end end describe "censored_pattern site setting" do it "can be cleared if it causes cooking to timeout" do SiteSetting.censored_pattern = "evilregex" described_class.stubs(:markdown).raises(MiniRacer::ScriptTerminatedError) PrettyText.cook("Protect against it plz.") rescue nil expect(SiteSetting.censored_pattern).to be_blank end end end