require "rails_helper" RSpec.describe Html::Parser, type: :service do it "has the correct raw tag delimiters" do expect(described_class::RAW_TAG_DELIMITERS).to match_array(["{", "}", "raw", "endraw", "----"]) end describe "#remove_nested_linebreak_in_list" do context "when html is nil" do it "doesn't raise an error" do expect { described_class.new(nil).remove_nested_linebreak_in_list.html }.not_to raise_error end end context "when html is empty" do it "doesn't raise an error" do expect { described_class.new("").remove_nested_linebreak_in_list.html }.not_to raise_error end end it "returns an instance of Html::Parser" do html_parser = described_class.new("
Hello World
").remove_nested_linebreak_in_list expect(html_parser).to be_a described_class end it "renders nested lists without linebreaks" do html = "- [A](#a)\n - [B](#b)\n- [C](#c)" parsed_html = described_class.new(html).remove_nested_linebreak_in_list.html expect(parsed_html).not_to include("
") end end describe "#prefix_all_images" do context "when html is nil" do it "doesn't raise an error" do expect { described_class.new(nil).prefix_all_images.html }.not_to raise_error end end context "when html is empty" do it "doesn't raise an error" do expect { described_class.new("").prefix_all_images.html }.not_to raise_error end end it "returns an instance of Html::Parser" do html_parser = described_class.new("
Hello World
").prefix_all_images expect(html_parser).to be_a described_class end context "when using gifs from Giphy as images" do it "does not wrap giphy images with Cloudinary" do html = "" parsed_html = Nokogiri::HTML(described_class.new(html).prefix_all_images.html) img_src = parsed_html.search("img")[0]["src"] expect(img_src).not_to include("https://res.cloudinary.com") end it "uses the raw gif from i.giphy.com" do html = "" parsed_html = Nokogiri::HTML(described_class.new(html).prefix_all_images.html) img_src = parsed_html.search("img")[0]["src"] expect(img_src).to start_with("https://i.giphy.com") end end context "when an image is used" do it "wraps the image with Cloudinary", cloudinary: true do html = "" parsed_html = described_class.new(html).prefix_all_images.html expect(parsed_html).to include("https://res.cloudinary.com") end it "detects height and width" do allow(FastImage).to receive(:size).and_return([100, 200]) html = "" parsed_html = described_class.new(html).prefix_all_images(width: 350, synchronous_detail_detection: true).html expect(parsed_html).to include("height=\"200\"") end end end describe "#wrap_all_images_in_links" do context "when html is nil" do it "doesn't raise an error" do expect { described_class.new(nil).wrap_all_images_in_links.html }.not_to raise_error end end context "when html is empty" do it "doesn't raise an error" do expect { described_class.new("").wrap_all_images_in_links.html }.not_to raise_error end end it "returns an instance of Html::Parser" do html_parser = described_class.new("
Hello World
").wrap_all_images_in_links expect(html_parser).to be_a described_class end it "wraps image in link" do html = "

Hello World").add_control_class_to_codeblock expect(html_parser).to be_a described_class end context "when the highlight class is present" do it "adds the control panel" do html = "

Hello world!
" parsed_html = described_class.new(html).add_control_class_to_codeblock.html expect(parsed_html).to include("js-code-highlight") end end context "when the highlight class is not present" do it "doesn't add the control panel" do html = "
Hello world!
" parsed_html = described_class.new(html).add_control_class_to_codeblock.html expect(parsed_html).not_to include("js-code-highlight") end end end describe "#add_control_panel_to_codeblock" do context "when html is nil" do it "doesn't raise an error" do expect { described_class.new(nil).add_control_panel_to_codeblock.html }.not_to raise_error end end context "when html is empty" do it "doesn't raise an error" do expect { described_class.new("").add_control_panel_to_codeblock.html }.not_to raise_error end end it "returns an instance of Html::Parser" do html_parser = described_class.new("
Hello World
").add_control_panel_to_codeblock expect(html_parser).to be_a described_class end context "when the highlight class is present" do it "adds the control panel" do html = "
Hello world!
" parsed_html = described_class.new(html).add_control_panel_to_codeblock.html expect(parsed_html).to include("highlight__panel", "js-actions-panel") end end context "when the highlight class is not present" do it "doesn't add the control panel" do html = "
Hello world!
" parsed_html = described_class.new(html).add_control_panel_to_codeblock.html expect(parsed_html).not_to include("highlight__panel", "js-actions-panel") end end end describe "#add_fullscreen_button_to_panel" do context "when html is nil" do it "doesn't raise an error" do expect { described_class.new(nil).add_fullscreen_button_to_panel.html }.not_to raise_error end end context "when html is empty" do it "doesn't raise an error" do expect { described_class.new("").add_fullscreen_button_to_panel.html }.not_to raise_error end end it "returns an instance of Html::Parser" do html_parser = described_class.new("
Hello World
").add_fullscreen_button_to_panel expect(html_parser).to be_a described_class end it "adds the fullscreen button" do html = "
Hello World
" parsed_html = described_class.new(html).add_fullscreen_button_to_panel.html expect(parsed_html).to include("Enter fullscreen mode") end end describe "#wrap_all_tables" do context "when html is nil" do it "doesn't raise an error" do expect { described_class.new(nil).wrap_all_tables.html }.not_to raise_error end end context "when html is empty" do it "doesn't raise an error" do expect { described_class.new("").wrap_all_tables.html }.not_to raise_error end end it "returns an instance of Html::Parser" do html_parser = described_class.new("
Hello World
").wrap_all_tables expect(html_parser).to be_a described_class end it "wraps all tables" do html = "
Header
Data
" parsed_html = described_class.new(html).wrap_all_tables.html expect(parsed_html).to include("table-wrapper-paragraph") end end describe "#remove_empty_paragraphs" do context "when html is nil" do it "doesn't raise an error" do expect { described_class.new(nil).remove_empty_paragraphs.html }.not_to raise_error end end context "when html is empty" do it "doesn't raise an error" do expect { described_class.new("").remove_empty_paragraphs.html }.not_to raise_error end end it "returns an instance of Html::Parser" do html_parser = described_class.new("
Hello World
").remove_empty_paragraphs expect(html_parser).to be_a described_class end context "when a paragraph is empty" do it "deletes the paragraph" do html = "

" parsed_html = described_class.new(html).remove_empty_paragraphs.html expect(parsed_html).not_to include("

") end end context "when a paragraph is not empty" do it "doesn't delete the paragraph" do html = "

Hello World!

" parsed_html = described_class.new(html).remove_empty_paragraphs.html expect(parsed_html).to eq html end end end describe "#escape_colon_emojis_in_codeblock" do context "when html is nil" do it "doesn't raise an error" do expect { described_class.new(nil).escape_colon_emojis_in_codeblock.html }.not_to raise_error end end context "when html is empty" do it "doesn't raise an error" do expect { described_class.new("").escape_colon_emojis_in_codeblock.html }.not_to raise_error end end it "returns an instance of Html::Parser" do html_parser = described_class.new("
Hello World
").escape_colon_emojis_in_codeblock expect(html_parser).to be_a described_class end context "when a colon emoji is used" do it "doesn't change text in codeblock" do html = ":o::o::o::o::o::o::o:" parsed_html = described_class.new(html).escape_colon_emojis_in_codeblock.html expect(parsed_html).to include(":o::o:") end end end describe "#unescape_raw_tag_in_codeblocks" do context "when html is nil" do it "doesn't raise an error" do expect { described_class.new(nil).unescape_raw_tag_in_codeblocks.html }.not_to raise_error end end context "when html is empty" do it "doesn't raise an error" do expect { described_class.new("").unescape_raw_tag_in_codeblocks.html }.not_to raise_error end end it "returns an instance of Html::Parser" do html_parser = described_class.new("
Hello World
").unescape_raw_tag_in_codeblocks expect(html_parser).to be_a described_class end it "escapes the `raw` Liquid tag in codeblocks" do code_block = "```\n{% raw %}some text{% endraw %}\n```" parsed_html = described_class.new(code_block).unescape_raw_tag_in_codeblocks.html expect(parsed_html).to include("{% raw %}", "{% endraw %}") end it "does not render the escaped dashes when using a `raw` Liquid tag in codeblocks with syntax highlighting" do code_block = "```js\n{% raw %}some text{% endraw %}\n```" parsed_html = described_class.new(code_block).unescape_raw_tag_in_codeblocks.html expect(parsed_html).not_to include("----") end it "does not remove the non-'raw tag related' four dashes" do code_block = "```\n----\n```" parsed_html = described_class.new(code_block).unescape_raw_tag_in_codeblocks.html expect(parsed_html).to include("----") end it "escapes the `raw` Liquid tag in codespans" do code_block = "``{% raw %}some text{% endraw %}``" parsed_html = described_class.new(code_block).unescape_raw_tag_in_codeblocks.html expect(parsed_html).to include("{% raw %}", "{% endraw %}") end it "escapes the `raw` Liquid tag in inline code" do code_block = "`{% raw %}some text{% endraw %}`" parsed_html = described_class.new(code_block).unescape_raw_tag_in_codeblocks.html expect(parsed_html).to include("{% raw %}", "{% endraw %}") end end describe "#wrap_all_figures_with_tags" do context "when html is nil" do it "doesn't raise an error" do expect { described_class.new(nil).wrap_all_figures_with_tags.html }.not_to raise_error end end context "when html is empty" do it "doesn't raise an error" do expect { described_class.new("").wrap_all_figures_with_tags.html }.not_to raise_error end end it "returns an instance of Html::Parser" do html_parser = described_class.new("
Hello World
").wrap_all_figures_with_tags expect(html_parser).to be_a described_class end it "wraps figcaptions with figures" do html = "

case:

Statement

\n
A fig
" parsed_html = described_class.new(html).wrap_all_figures_with_tags.html expect(parsed_html).to include("figure") end it "does not wrap figcaptions already in figures" do html = "

Statement

\n
A fig
" parsed_html = described_class.new(html).wrap_all_figures_with_tags.html expect(parsed_html).to eq(html) end it "does not wrap figcaptions without predecessors" do html = "
A fig
" parsed_html = described_class.new(html).wrap_all_figures_with_tags.html expect(parsed_html).to eq(html) end end describe "#wrap_mentions_with_links" do let(:user) { build_stubbed(:user) } before { allow(User).to receive(:find_by).with(username: user.username).and_return(user) } context "when html is nil" do it "doesn't raise an error" do expect { described_class.new(nil).wrap_mentions_with_links.html }.not_to raise_error end end context "when html is empty" do it "doesn't raise an error" do expect { described_class.new("").wrap_mentions_with_links.html }.not_to raise_error end end it "returns an instance of Html::Parser" do html_parser = described_class.new("
Hello World
").wrap_mentions_with_links expect(html_parser).to be_a described_class end it "links mentions" do html = "@#{user.username}" parsed_html = described_class.new(html).wrap_mentions_with_links.html expect(parsed_html).to include("Hello World").parse_emojis expect(html_parser).to be_a described_class end # rubocop:disable Rails/DynamicFindBy it "converts emoji names wrapped in colons into unicode" do joy_emoji_unicode = Emoji.find_by_alias("joy").raw parsed_html = described_class.new(":joy:").parse_emojis.html expect(parsed_html).to include(joy_emoji_unicode) end it "converts disability emojis as well", :aggregate_failures do disability_emojis = %w[ guide_dog service_dog person_with_probing_cane man_with_probing_cane woman_with_probing_cane probing_cane person_in_motorized_wheelchair man_in_motorized_wheelchair woman_in_motorized_wheelchair person_in_manual_wheelchair man_in_manual_wheelchair woman_in_manual_wheelchair manual_wheelchair motorized_wheelchair wheelchair ] disability_emojis.each do |emoji| unicode = Emoji.find_by_alias(emoji).raw parsed_html = described_class.new(":#{emoji}:").parse_emojis.html expect(parsed_html).to include(unicode) end end it "leaves original text between colons when no emoji is found" do emoji_text = ":no_one_will_ever_create_an_emoji_with_this_alias:" parsed_html = described_class.new(emoji_text).parse_emojis.html expect(parsed_html).to include(emoji_text) end # rubocop:enable Rails/DynamicFindBy end end