# frozen_string_literal: true
require 'rails_helper'
require 'stringio'
describe TopicEmbed do
it { is_expected.to belong_to :topic }
it { is_expected.to belong_to :post }
it { is_expected.to validate_presence_of :embed_url }
context '.import' do
fab!(:user) { Fabricate(:user) }
let(:title) { "How to turn a fish from good to evil in 30 seconds" }
let(:url) { 'http://eviltrout.com/123' }
let(:contents) { "hello world new post hello
" }
fab!(:embeddable_host) { Fabricate(:embeddable_host) }
it "returns nil when the URL is malformed" do
expect(TopicEmbed.import(user, "invalid url", title, contents)).to eq(nil)
expect(TopicEmbed.count).to eq(0)
end
context 'creation of a post' do
let!(:post) { TopicEmbed.import(user, url, title, contents) }
let(:topic_embed) { TopicEmbed.find_by(post: post) }
it "works as expected with a new URL" do
expect(post).to be_present
# It uses raw_html rendering
expect(post.cook_method).to eq(Post.cook_methods[:raw_html])
expect(post.cooked).to eq(post.raw)
# It converts relative URLs to absolute
expect(post.cooked).to have_tag('a', with: { href: 'http://eviltrout.com/hello' })
expect(post.cooked).to have_tag('img', with: { src: 'http://eviltrout.com/images/wat.jpg' })
expect(post.topic.has_topic_embed?).to eq(true)
expect(TopicEmbed.where(topic_id: post.topic_id)).to be_present
expect(post.topic.category).to eq(embeddable_host.category)
end
it "Supports updating the post content" do
expect do
TopicEmbed.import(user, url, title, "muhahaha new contents!")
end.to change { topic_embed.reload.content_sha1 }
expect(topic_embed.post.cooked).to match(/new contents/)
end
it "Supports updating the post author" do
new_user = Fabricate(:user)
TopicEmbed.import(new_user, url, title, contents)
topic_embed.reload
expect(topic_embed.post.user).to eq(new_user)
expect(topic_embed.post.topic.user).to eq(new_user)
end
it "Should leave uppercase Feed Entry URL untouched in content" do
cased_url = 'http://eviltrout.com/ABCD'
post = TopicEmbed.import(user, cased_url, title, "some random content")
expect(post.cooked).to match(/#{cased_url}/)
end
it "Should leave lowercase Feed Entry URL untouched in content" do
cased_url = 'http://eviltrout.com/abcd'
post = TopicEmbed.import(user, cased_url, title, "some random content")
expect(post.cooked).to match(/#{cased_url}/)
end
end
context "post creation supports markdown rendering" do
before do
SiteSetting.embed_support_markdown = true
end
it "works as expected" do
post = TopicEmbed.import(user, url, title, "some random content")
expect(post).to be_present
# It uses regular rendering
expect(post.cook_method).to eq(Post.cook_methods[:regular])
end
end
describe 'embedded content truncation' do
MAX_LENGTH_BEFORE_TRUNCATION = 100
let(:long_content) { "
#{'a' * MAX_LENGTH_BEFORE_TRUNCATION}
\nmore
" } it 'truncates the imported post when truncation is enabled' do SiteSetting.embed_truncate = true post = TopicEmbed.import(user, url, title, long_content) expect(post.raw).not_to include(long_content) end it 'keeps everything in the imported post when truncation is disabled' do SiteSetting.embed_truncate = false post = TopicEmbed.import(user, url, title, long_content) expect(post.raw).to include(long_content) end it 'looks at first div when there is no paragraph' do no_para = "Hi
" }
fab!(:embeddable_host) { Fabricate(:embeddable_host) }
let!(:file) { StringIO.new }
response = nil
before do
SiteSetting.embed_classname_whitelist = 'emoji, foo'
file.stubs(:read).returns contents
TopicEmbed.stubs(:open).returns file
response = TopicEmbed.find_remote(url)
end
it "has no author tag" do
expect(response.author).to be_blank
end
it 'img node has emoji class' do
expect(response.body).to have_tag('img', with: { class: 'emoji' })
end
it 'img node has foo class' do
expect(response.body).to have_tag('img', with: { class: 'foo' })
end
it 'p node has foo class' do
expect(response.body).to have_tag('p', with: { class: 'foo' })
end
it 'nodes removes classes other than emoji' do
expect(response.body).to have_tag('img', without: { class: 'other' })
end
end
context 'post with author metadata' do
fab!(:user) { Fabricate(:user, username: 'eviltrout') }
let(:url) { 'http://eviltrout.com/321' }
let(:contents) { 'rich and morty' }
fab!(:embeddable_host) { Fabricate(:embeddable_host) }
let!(:file) { StringIO.new }
response = nil
before(:each) do
file.stubs(:read).returns contents
TopicEmbed.stubs(:open).returns file
response = TopicEmbed.find_remote(url)
end
it "has no author tag" do
expect(response.author).to eq(user)
end
end
context 'post with no allowed classes' do
fab!(:user) { Fabricate(:user) }
let(:url) { 'http://eviltrout.com/123' }
let(:contents) { "my normal size emoji Hi
" }
fab!(:embeddable_host) { Fabricate(:embeddable_host) }
let!(:file) { StringIO.new }
response = nil
before(:each) do
SiteSetting.embed_classname_whitelist = ''
file.stubs(:read).returns contents
TopicEmbed.stubs(:open).returns file
response = TopicEmbed.find_remote(url)
end
it 'img node doesn\'t have emoji class' do
expect(response.body).to have_tag('img', without: { class: 'emoji' })
end
it 'img node doesn\'t have foo class' do
expect(response.body).to have_tag('img', without: { class: 'foo' })
end
it 'p node doesn\'t foo class' do
expect(response.body).to have_tag('p', without: { class: 'foo' })
end
it 'img node doesn\'t have other class' do
expect(response.body).to have_tag('img', without: { class: 'other' })
end
end
context "non-ascii URL" do
let(:url) { 'http://eviltrout.com/test/ماهی' }
let(:contents) { "