2019-04-30 08:27:42 +08:00
# frozen_string_literal: true
2015-09-25 06:20:59 +08:00
require " stringio "
2014-01-01 03:37:43 +08:00
2022-07-28 10:27:38 +08:00
RSpec . describe TopicEmbed do
2014-12-31 22:55:03 +08:00
it { is_expected . to belong_to :topic }
it { is_expected . to belong_to :post }
it { is_expected . to validate_presence_of :embed_url }
2014-01-01 03:37:43 +08:00
2022-07-27 18:21:10 +08:00
describe " .import " do
2024-01-26 13:25:03 +08:00
fab! ( :user ) { Fabricate ( :user , refresh_auto_groups : true ) }
2014-01-01 03:37:43 +08:00
let ( :title ) { " How to turn a fish from good to evil in 30 seconds " }
let ( :url ) { " http://eviltrout.com/123 " }
2021-11-17 13:39:49 +08:00
let ( :contents ) do
" <p>hello world new post <a href='/hello'>hello</a> <img src='images/wat.jpg'></p> "
2023-01-09 19:18:21 +08:00
end
2023-11-10 06:47:59 +08:00
fab! ( :embeddable_host )
fab! ( :category )
fab! ( :tag )
2014-01-01 03:37:43 +08:00
it " returns nil when the URL is malformed " do
2014-12-31 22:55:03 +08:00
expect ( TopicEmbed . import ( user , " invalid url " , title , contents ) ) . to eq ( nil )
expect ( TopicEmbed . count ) . to eq ( 0 )
2014-01-01 03:37:43 +08:00
end
2024-06-19 09:50:49 +08:00
it " Allows figure, figcaption, details HTML tags " do
2023-04-27 17:57:06 +08:00
html = << ~ HTML
< html >
< head >
< title > Some title < / title>
< / head>
< body >
< div class = 'content' >
< p > some content < / p>
< figure >
< img src = " /a.png " >
< figcaption > Some caption < / figcaption>
2024-06-19 09:50:49 +08:00
< / figure>
< details >
some details
< / details>
2023-04-27 17:57:06 +08:00
< / div>
< / body>
< / html>
HTML
parsed = TopicEmbed . parse_html ( html , " https://blog.discourse.com/somepost.html " )
# div inception is inserted by the readability gem
expected = << ~ HTML
< div > < div >
< div >
< p > some content < / p>
< figure >
< img src = " https://blog.discourse.com/a.png " >
< figcaption > Some caption < / figcaption>
2024-06-19 09:50:49 +08:00
< / figure>
< details >
some details
< / details>
< / div>
2023-04-27 17:57:06 +08:00
< / div>< / div >
HTML
expect ( parsed . body . strip ) . to eq ( expected . strip )
end
2024-06-19 09:50:49 +08:00
# ideally, articles get a heavier weightage than td elements
# so to force that, we do not allow td elements to be scored
it " does not score td tags " do
html = << ~ HTML
< html >
< head >
< title > Some title < / title>
< / head>
< body >
< article >
article content
< table >
< tr >
< td >
< p > cats < / p>
< p > cats < / p>
< / td>
< / tr>
< / table>
< / article>
< / body>
< / html>
HTML
parsed = TopicEmbed . parse_html ( html , " https://blog.discourse.com/somepost.html " )
expected = <<-HTML
< div > < div >
article content
cats
cats
< / div>< / div >
HTML
expect ( parsed . body . strip ) . to eq ( expected . strip )
end
2022-07-28 00:14:14 +08:00
context " when creating a post " do
2014-01-01 03:37:43 +08:00
let! ( :post ) { TopicEmbed . import ( user , url , title , contents ) }
2018-08-24 09:41:54 +08:00
let ( :topic_embed ) { TopicEmbed . find_by ( post : post ) }
2014-01-01 03:37:43 +08:00
it " works as expected with a new URL " do
2014-12-31 22:55:03 +08:00
expect ( post ) . to be_present
2014-01-01 03:37:43 +08:00
# It uses raw_html rendering
2014-12-31 22:55:03 +08:00
expect ( post . cook_method ) . to eq ( Post . cook_methods [ :raw_html ] )
expect ( post . cooked ) . to eq ( post . raw )
2014-01-01 03:37:43 +08:00
# It converts relative URLs to absolute
2015-09-25 06:20:59 +08:00
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 " } )
2014-01-01 03:37:43 +08:00
2024-01-05 21:09:31 +08:00
# It caches the embed content
expect ( post . topic . topic_embed . embed_content_cache ) . to eq ( contents )
2021-11-17 13:39:49 +08:00
# It converts relative URLs to absolute when expanded
stub_request ( :get , url ) . to_return ( status : 200 , body : contents )
expect ( TopicEmbed . expanded_for ( post ) ) . to have_tag (
" img " ,
with : {
src : " http://eviltrout.com/images/wat.jpg " ,
} ,
)
2014-12-31 22:55:03 +08:00
expect ( post . topic . has_topic_embed? ) . to eq ( true )
expect ( TopicEmbed . where ( topic_id : post . topic_id ) ) . to be_present
2015-08-19 05:15:46 +08:00
expect ( post . topic . category ) . to eq ( embeddable_host . category )
2020-10-02 03:40:13 +08:00
expect ( post . topic ) . not_to be_visible
2014-01-01 03:37:43 +08:00
end
2018-08-21 18:19:03 +08:00
it " Supports updating the post content " do
2018-08-24 09:41:54 +08:00
expect do
2020-05-05 11:46:57 +08:00
TopicEmbed . import ( user , url , " New title received " , " <p>muhahaha new contents!</p> " )
2018-08-24 09:41:54 +08:00
end . to change { topic_embed . reload . content_sha1 }
2020-04-21 02:27:43 +08:00
expect ( topic_embed . topic . title ) . to eq ( " New title received " )
2018-04-19 03:22:43 +08:00
2018-08-24 09:41:54 +08:00
expect ( topic_embed . post . cooked ) . to match ( / new contents / )
2018-08-21 18:19:03 +08:00
end
it " Supports updating the post author " do
new_user = Fabricate ( :user )
2018-08-24 09:41:54 +08:00
TopicEmbed . import ( new_user , url , title , contents )
2018-08-21 18:19:03 +08:00
2018-08-24 09:41:54 +08:00
topic_embed . reload
expect ( topic_embed . post . user ) . to eq ( new_user )
expect ( topic_embed . post . topic . user ) . to eq ( new_user )
2014-01-01 03:37:43 +08:00
end
2024-01-05 21:09:31 +08:00
it " Supports updating the embed content cache " do
expect do TopicEmbed . import ( user , url , title , " new contents " ) end . to change {
topic_embed . reload . embed_content_cache
}
expect ( topic_embed . embed_content_cache ) . to eq ( " new contents " )
end
2014-03-27 11:24:57 +08:00
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 " )
2014-12-31 22:55:03 +08:00
expect ( post . cooked ) . to match ( / #{ cased_url } / )
2014-03-27 11:24:57 +08:00
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 " )
2014-12-31 22:55:03 +08:00
expect ( post . cooked ) . to match ( / #{ cased_url } / )
2014-03-27 11:24:57 +08:00
end
2020-04-14 03:17:02 +08:00
2024-03-27 20:57:43 +08:00
shared_examples " topic is unlisted " do
it " unlists the topic until someone replies " do
Jobs . run_immediately!
imported_post =
TopicEmbed . import ( user , " http://eviltrout.com/abcd " , title , " some random content " )
expect ( imported_post . topic ) . not_to be_visible
pc =
PostCreator . new (
Fabricate ( :user ) ,
raw : " this is a reply that will make the topic visible " ,
topic_id : imported_post . topic_id ,
reply_to_post_number : 1 ,
)
pc . create
expect ( imported_post . topic . reload ) . to be_visible
end
2020-04-14 03:17:02 +08:00
end
2020-10-02 03:40:13 +08:00
2024-03-27 20:57:43 +08:00
context " when import embed unlisted is true " do
before { SiteSetting . import_embed_unlisted = true }
include_examples " topic is unlisted "
context " when embed unlisted is false " do
before { SiteSetting . embed_unlisted = false }
include_examples " topic is unlisted "
end
end
context " when import embed unlisted is false " do
before { SiteSetting . import_embed_unlisted = false }
context " when embed unlisted is false " do
before { SiteSetting . embed_unlisted = false }
it " lists the topic " do
Jobs . run_immediately!
imported_post =
TopicEmbed . import ( user , " http://eviltrout.com/abcd " , title , " some random content " )
expect ( imported_post . topic ) . to be_visible
end
end
context " when embed unlisted is true " do
before { SiteSetting . embed_unlisted = true }
include_examples " topic is unlisted "
end
2020-10-02 03:40:13 +08:00
end
2021-08-18 05:17:07 +08:00
it " creates the topic in the category passed as a parameter " do
Jobs . run_immediately!
imported_post =
TopicEmbed . import (
user ,
" http://eviltrout.com/abcd " ,
title ,
" some random content " ,
category_id : category . id ,
)
expect ( imported_post . topic . category ) . not_to eq ( embeddable_host . category )
expect ( imported_post . topic . category ) . to eq ( category )
end
2021-09-02 02:46:39 +08:00
2023-06-14 01:08:08 +08:00
it " does not create duplicate topics with different protocols in the embed_url " do
Jobs . run_immediately!
expect {
TopicEmbed . import ( user , " http://eviltrout.com/abcd " , title , " some random content " )
} . to change { Topic . all . count } . by ( 1 )
expect {
TopicEmbed . import ( user , " https://eviltrout.com/abcd " , title , " some random content " )
} . to_not change { Topic . all . count }
end
2021-09-14 04:01:59 +08:00
it " creates the topic with the tag passed as a parameter " do
Jobs . run_immediately!
SiteSetting . tagging_enabled = true
imported_post =
TopicEmbed . import (
user ,
" http://eviltrout.com/abcd " ,
title ,
" some random content " ,
tags : [ tag . name ] ,
)
expect ( imported_post . topic . tags ) . to include ( tag )
end
2021-09-02 02:46:39 +08:00
it " respects overriding the cook_method when asked " do
Jobs . run_immediately!
SiteSetting . embed_support_markdown = false
stub_request ( :get , " https://www.youtube.com/watch?v=K56soYl0U1w " ) . to_return (
status : 200 ,
body : " " ,
headers : {
2023-01-09 19:18:21 +08:00
} ,
2021-09-02 02:46:39 +08:00
)
stub_request ( :get , " https://www.youtube.com/embed/K56soYl0U1w " ) . to_return (
status : 200 ,
body : " " ,
headers : {
2023-01-09 19:18:21 +08:00
} ,
2021-09-02 02:46:39 +08:00
)
imported_post =
TopicEmbed . import (
user ,
" http://eviltrout.com/abcd " ,
title ,
" https://www.youtube.com/watch?v=K56soYl0U1w " ,
cook_method : Post . cook_methods [ :regular ] ,
)
expect ( imported_post . cooked ) . to match ( / onebox|iframe / )
end
2024-04-05 23:37:53 +08:00
describe " topic_embed_import_create_args modifier " do
after { DiscoursePluginRegistry . clear_modifiers! }
it " can alter the args used to create the topic " do
plugin = Plugin :: Instance . new
plugin . register_modifier ( :topic_embed_import_create_args ) do | args |
args [ :title ] = " MODIFIED: #{ args [ :title ] } "
args
end
Jobs . run_immediately!
imported_post =
TopicEmbed . import (
user ,
" http://eviltrout.com/abcd " ,
title ,
" some random content " ,
category_id : category . id ,
)
expect ( imported_post . topic . title ) . to eq ( " MODIFIED: #{ title } " )
end
it " will revert to defaults if the modifier returns nil " do
plugin = Plugin :: Instance . new
plugin . register_modifier ( :topic_embed_import_create_args ) { | args | nil }
Jobs . run_immediately!
imported_post =
TopicEmbed . import (
user ,
" http://eviltrout.com/abcd " ,
title ,
" some random content " ,
category_id : category . id ,
)
expect ( imported_post . topic . title ) . to eq ( title )
end
end
2014-01-01 03:37:43 +08:00
end
2022-07-28 00:14:14 +08:00
context " when post creation supports markdown rendering " do
2018-03-11 10:26:47 +08:00
before { SiteSetting . embed_support_markdown = true }
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
2019-07-25 21:21:01 +08:00
2024-05-17 03:47:01 +08:00
context " with specified user and tags " do
fab! ( :tag1 ) { Fabricate ( :tag , name : " interesting " ) }
fab! ( :tag2 ) { Fabricate ( :tag , name : " article " ) }
let! ( :new_user ) { Fabricate ( :user ) }
let ( :tags ) { [ tag1 . name , tag2 . name ] }
let ( :imported_post ) { TopicEmbed . import ( new_user , url , title , contents , tags : tags ) }
it " assigns the specified user as the author " do
expect ( imported_post . user ) . to eq ( new_user )
end
it " associates the specified tags with the topic " do
expect ( imported_post . topic . tags ) . to contain_exactly ( tag1 , tag2 )
end
end
2024-05-30 23:04:36 +08:00
context " when the embeddable host specifies the user and tags " do
fab! ( :tag1 ) { Fabricate ( :tag , name : " interesting " ) }
fab! ( :tag2 ) { Fabricate ( :tag , name : " article " ) }
fab! ( :embeddable_host ) { Fabricate ( :embeddable_host , host : " tag-eviltrout.com " ) }
let! ( :new_user ) { Fabricate ( :user ) }
let ( :tags ) { [ tag1 . name , tag2 . name ] }
let ( :embed_url_with_tags ) { " http://tag-eviltrout.com/abcd " }
let ( :imported_post ) do
# passing user = system and tags = nil to ensure we're getting the user and tags from the embeddable host
# and not from the TopicEmbed.import method in the tests
TopicEmbed . import ( Discourse . system_user , embed_url_with_tags , title , contents , tags : nil )
end
before do
embeddable_host . user = new_user
embeddable_host . tags = [ tag1 , tag2 ]
embeddable_host . save!
end
it " assigns the specified user as the author " do
expect ( imported_post . user ) . to eq ( new_user )
end
it " associates the specified tags with the topic " do
expect ( imported_post . topic . tags ) . to contain_exactly ( tag1 , tag2 )
end
end
2024-05-17 03:47:01 +08:00
context " when updating an existing post with new tags and a different user " do
fab! ( :tag1 ) { Fabricate ( :tag , name : " interesting " ) }
fab! ( :tag2 ) { Fabricate ( :tag , name : " article " ) }
let! ( :admin ) { Fabricate ( :admin ) }
let! ( :new_admin ) { Fabricate ( :admin ) }
let ( :tags ) { [ tag1 . name , tag2 . name ] }
before { SiteSetting . tagging_enabled = true }
it " updates the user and adds new tags " do
original_post = TopicEmbed . import ( admin , url , title , contents )
expect ( original_post . user ) . to eq ( admin )
expect ( original_post . topic . tags ) . to be_empty
embeddable_host . update! (
tags : [ tag1 , tag2 ] ,
user : new_admin ,
category : category ,
host : " eviltrout.com " ,
)
edited_post = TopicEmbed . import ( admin , url , title , contents )
expect ( edited_post . user ) . to eq ( new_admin )
expect ( edited_post . topic . tags ) . to match_array ( [ tag1 , tag2 ] )
end
end
2019-07-25 21:21:01 +08:00
describe " embedded content truncation " do
MAX_LENGTH_BEFORE_TRUNCATION = 100
let ( :long_content ) { " <p> #{ " a " * MAX_LENGTH_BEFORE_TRUNCATION } </p> \n <p>more</p> " }
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
2019-08-07 10:45:55 +08:00
it " looks at first div when there is no paragraph " do
no_para = " <div><h>testing it</h></div> "
SiteSetting . embed_truncate = true
post = TopicEmbed . import ( user , url , title , no_para )
expect ( post . raw ) . to include ( " testing it " )
end
2019-07-25 21:21:01 +08:00
end
2014-01-01 03:37:43 +08:00
end
2022-07-27 18:21:10 +08:00
describe " .topic_id_for_embed " do
2018-01-05 02:13:17 +08:00
it " returns correct topic id irrespective of url protocol " do
topic_embed = Fabricate ( :topic_embed , embed_url : " http://example.com/post/248 " )
expect ( TopicEmbed . topic_id_for_embed ( " http://exAMPle.com/post/248 " ) ) . to eq (
topic_embed . topic_id ,
)
expect ( TopicEmbed . topic_id_for_embed ( " https://example.com/post/248/ " ) ) . to eq (
topic_embed . topic_id ,
2023-01-09 19:18:21 +08:00
)
2018-01-05 02:13:17 +08:00
expect ( TopicEmbed . topic_id_for_embed ( " http://example.com/post/248/2 " ) ) . to eq ( nil )
expect ( TopicEmbed . topic_id_for_embed ( " http://examples.com/post/248 " ) ) . to eq ( nil )
expect ( TopicEmbed . topic_id_for_embed ( " http://example.com/post/24 " ) ) . to eq ( nil )
expect ( TopicEmbed . topic_id_for_embed ( " http://example.com/post " ) ) . to eq ( nil )
end
2018-02-14 07:28:16 +08:00
it " finds the topic id when the embed_url contains a query string " do
topic_embed = Fabricate ( :topic_embed , embed_url : " http://example.com/post/248?key=foo " )
expect ( TopicEmbed . topic_id_for_embed ( " http://example.com/post/248?key=foo " ) ) . to eq (
topic_embed . topic_id ,
)
end
2018-01-05 02:13:17 +08:00
end
2015-09-25 06:20:59 +08:00
describe " .find_remote " do
2023-11-10 06:47:59 +08:00
fab! ( :embeddable_host )
2016-08-23 00:43:02 +08:00
2022-07-27 18:21:10 +08:00
describe " .title_scrub " do
2016-08-23 00:43:02 +08:00
let ( :url ) { " http://eviltrout.com/123 " }
let ( :contents ) do
" <title>Through the Looking Glass - Classic Books</title><body>some content here</body> "
end
2021-10-27 16:39:28 +08:00
before { stub_request ( :get , url ) . to_return ( status : 200 , body : contents ) }
2023-01-09 19:18:21 +08:00
2016-08-23 00:43:02 +08:00
it " doesn't scrub the title by default " do
2016-08-31 00:01:04 +08:00
response = TopicEmbed . find_remote ( url )
expect ( response . title ) . to eq ( " Through the Looking Glass - Classic Books " )
2016-08-23 00:43:02 +08:00
end
it " scrubs the title when the option is enabled " do
SiteSetting . embed_title_scrubber = " - Classic Books$ "
2016-08-31 00:01:04 +08:00
response = TopicEmbed . find_remote ( url )
expect ( response . title ) . to eq ( " Through the Looking Glass " )
2016-08-23 00:43:02 +08:00
end
2023-10-27 11:02:20 +08:00
it " doesn't follow redirect when making request " do
FinalDestination . any_instance . stubs ( :resolve ) . returns ( URI ( " https://redirect.com " ) )
stub_request ( :get , " https://redirect.com/ " ) . to_return (
status : 301 ,
body : " <title>Moved permanently</title> " ,
headers : {
" Location " = > " https://www.example.org/ " ,
} ,
)
response = TopicEmbed . find_remote ( url )
expect ( response . title ) . to eq ( " Moved permanently " )
end
2016-08-23 00:43:02 +08:00
end
2022-07-28 00:14:14 +08:00
context 'with post with allowed classes "foo" and "emoji"' do
2023-11-10 06:47:59 +08:00
fab! ( :user )
2015-09-25 06:20:59 +08:00
let ( :url ) { " http://eviltrout.com/123 " }
let ( :contents ) do
" my normal size emoji <p class='foo'>Hi</p> <img class='emoji other foo' src='/images/smiley.jpg'> "
2023-01-09 19:18:21 +08:00
end
2015-09-25 06:20:59 +08:00
2017-07-07 14:09:14 +08:00
before do
2020-07-27 08:23:54 +08:00
SiteSetting . allowed_embed_classnames = " emoji, foo "
2021-10-27 16:39:28 +08:00
stub_request ( :get , url ) . to_return ( status : 200 , body : contents )
2021-10-01 23:48:21 +08:00
@response = TopicEmbed . find_remote ( url )
2016-08-31 00:01:04 +08:00
end
it " has no author tag " do
2021-10-01 23:48:21 +08:00
expect ( @response . author ) . to be_blank
2015-09-25 06:20:59 +08:00
end
it " img node has emoji class " do
2021-10-01 23:48:21 +08:00
expect ( @response . body ) . to have_tag ( " img " , with : { class : " emoji " } )
2015-09-25 06:20:59 +08:00
end
it " img node has foo class " do
2021-10-01 23:48:21 +08:00
expect ( @response . body ) . to have_tag ( " img " , with : { class : " foo " } )
2015-09-25 06:20:59 +08:00
end
it " p node has foo class " do
2021-10-01 23:48:21 +08:00
expect ( @response . body ) . to have_tag ( " p " , with : { class : " foo " } )
2015-09-25 06:20:59 +08:00
end
it " nodes removes classes other than emoji " do
2021-10-01 23:48:21 +08:00
expect ( @response . body ) . to have_tag ( " img " , without : { class : " other " } )
2016-08-31 00:01:04 +08:00
end
end
2022-07-28 00:14:14 +08:00
context " with post with author metadata " do
2019-05-07 11:12:20 +08:00
fab! ( :user ) { Fabricate ( :user , username : " eviltrout " ) }
2016-08-31 00:01:04 +08:00
let ( :url ) { " http://eviltrout.com/321 " }
let ( :contents ) do
'<html><head><meta name="author" content="eviltrout"></head><body>rich and morty</body></html>'
2015-09-25 06:20:59 +08:00
end
2021-10-27 16:39:28 +08:00
before ( :each ) { stub_request ( :get , url ) . to_return ( status : 200 , body : contents ) }
2023-01-09 19:18:21 +08:00
2016-08-31 00:01:04 +08:00
it " has no author tag " do
2021-10-01 23:48:21 +08:00
response = TopicEmbed . find_remote ( url )
2016-08-31 00:01:04 +08:00
expect ( response . author ) . to eq ( user )
end
2015-09-25 06:20:59 +08:00
end
2022-07-28 00:14:14 +08:00
context " with post with no allowed classes " do
2023-11-10 06:47:59 +08:00
fab! ( :user )
2015-09-25 06:20:59 +08:00
let ( :url ) { " http://eviltrout.com/123 " }
let ( :contents ) do
" my normal size emoji <p class='foo'>Hi</p> <img class='emoji other foo' src='/images/smiley.jpg'> "
2023-01-09 19:18:21 +08:00
end
2015-09-25 06:20:59 +08:00
before ( :each ) do
2020-07-27 08:23:54 +08:00
SiteSetting . allowed_embed_classnames = " "
2021-10-27 16:39:28 +08:00
stub_request ( :get , url ) . to_return ( status : 200 , body : contents )
2021-10-01 23:48:21 +08:00
@response = TopicEmbed . find_remote ( url )
2015-09-25 06:20:59 +08:00
end
it 'img node doesn\'t have emoji class' do
2021-10-01 23:48:21 +08:00
expect ( @response . body ) . to have_tag ( " img " , without : { class : " emoji " } )
2015-09-25 06:20:59 +08:00
end
it 'img node doesn\'t have foo class' do
2021-10-01 23:48:21 +08:00
expect ( @response . body ) . to have_tag ( " img " , without : { class : " foo " } )
2015-09-25 06:20:59 +08:00
end
it 'p node doesn\'t foo class' do
2021-10-01 23:48:21 +08:00
expect ( @response . body ) . to have_tag ( " p " , without : { class : " foo " } )
2015-09-25 06:20:59 +08:00
end
it 'img node doesn\'t have other class' do
2021-10-01 23:48:21 +08:00
expect ( @response . body ) . to have_tag ( " img " , without : { class : " other " } )
2015-09-25 06:20:59 +08:00
end
2017-03-08 00:21:26 +08:00
end
2022-07-28 00:14:14 +08:00
context " with non-ascii URL " do
2017-03-08 00:21:26 +08:00
let ( :url ) { " http://eviltrout.com/test/ماهی " }
let ( :contents ) { " <title>سلام</title><body>این یک پاراگراف آزمون است.</body> " }
2015-09-25 06:20:59 +08:00
2021-10-27 16:39:28 +08:00
before { stub_request ( :get , url ) . to_return ( status : 200 , body : contents ) }
2017-03-08 00:21:26 +08:00
it " doesn't throw an error " do
response = TopicEmbed . find_remote ( url )
expect ( response . title ) . to eq ( " سلام " )
end
2015-09-25 06:20:59 +08:00
end
2022-07-28 00:14:14 +08:00
context " with encoded URL " do
2017-09-22 23:36:44 +08:00
let ( :url ) { " http://example.com/hello%20world " }
let ( :contents ) { " <title>Hello World!</title><body></body> " }
2021-10-27 16:39:28 +08:00
before { stub_request ( :get , url ) . to_return ( status : 200 , body : contents ) }
2017-09-22 23:36:44 +08:00
it " doesn't throw an error " do
response = TopicEmbed . find_remote ( url )
expect ( response . title ) . to eq ( " Hello World! " )
end
end
2022-07-28 00:14:14 +08:00
context " with non-http URL " do
2020-05-23 12:56:13 +08:00
it " throws an error " do
2020-05-28 22:59:20 +08:00
url = " /test.txt "
expect ( TopicEmbed . find_remote ( url ) ) . to be_nil
2020-05-23 12:56:13 +08:00
end
end
2022-07-28 00:14:14 +08:00
context " with emails " do
2017-09-22 20:26:06 +08:00
let ( :url ) { " http://example.com/foo " }
let ( :contents ) do
'<p><a href="mailto:foo%40example.com">URL encoded @ symbol</a></p><p><a href="mailto:bar@example.com">normal mailto link</a></p>'
end
2021-10-27 16:39:28 +08:00
before { stub_request ( :get , url ) . to_return ( status : 200 , body : contents ) }
2023-01-09 19:18:21 +08:00
2017-09-22 20:26:06 +08:00
it " handles mailto links " do
response = TopicEmbed . find_remote ( url )
2021-10-01 23:48:21 +08:00
2021-11-17 13:39:49 +08:00
expect ( response . body ) . to have_tag ( " a " , with : { href : " mailto:foo@example.com " } )
2017-09-22 20:26:06 +08:00
expect ( response . body ) . to have_tag ( " a " , with : { href : " mailto:bar@example.com " } )
end
end
2021-04-30 17:10:19 +08:00
2022-07-28 00:14:14 +08:00
context " with malformed href " do
2021-04-30 17:10:19 +08:00
let ( :url ) { " http://example.com/foo " }
let ( :contents ) { '<p><a href="(http://foo.bar)">Baz</a></p>' }
2021-10-27 16:39:28 +08:00
before { stub_request ( :get , url ) . to_return ( status : 200 , body : contents ) }
2021-04-30 17:10:19 +08:00
it " doesn’ t raise an exception " do
expect { TopicEmbed . find_remote ( url ) } . not_to raise_error
end
end
2021-10-01 23:48:21 +08:00
2022-07-28 00:14:14 +08:00
context " with canonical links " do
2023-11-10 06:47:59 +08:00
fab! ( :user )
2023-06-14 01:08:08 +08:00
let ( :title ) { " How to turn a fish from good to evil in 30 seconds " }
2021-10-01 23:48:21 +08:00
let ( :url ) { " http://eviltrout.com/123?asd " }
let ( :canonical_url ) { " http://eviltrout.com/123 " }
2023-06-14 01:08:08 +08:00
let ( :url2 ) { " http://eviltrout.com/blog?post=1&canonical=false " }
let ( :canonical_url2 ) { " http://eviltrout.com/blog?post=1 " }
2021-10-01 23:48:21 +08:00
let ( :content ) { " <head><link rel= \" canonical \" href= \" #{ canonical_url } \" ></head> " }
2023-06-14 01:08:08 +08:00
let ( :content2 ) { " <head><link rel= \" canonical \" href= \" #{ canonical_url2 } \" ></head> " }
2021-10-01 23:48:21 +08:00
let ( :canonical_content ) { " <title>Canonical</title><body></body> " }
before do
2021-10-27 16:39:28 +08:00
stub_request ( :get , url ) . to_return ( status : 200 , body : content )
2021-10-01 23:48:21 +08:00
stub_request ( :head , canonical_url )
2021-10-27 16:39:28 +08:00
stub_request ( :get , canonical_url ) . to_return ( status : 200 , body : canonical_content )
2023-06-14 01:08:08 +08:00
stub_request ( :get , url2 ) . to_return ( status : 200 , body : content2 )
stub_request ( :head , canonical_url2 )
stub_request ( :get , canonical_url2 ) . to_return ( status : 200 , body : canonical_content )
2021-10-01 23:48:21 +08:00
end
2023-06-14 01:08:08 +08:00
it " fetches canonical content " do
2021-10-01 23:48:21 +08:00
response = TopicEmbed . find_remote ( url )
expect ( response . title ) . to eq ( " Canonical " )
2023-06-14 01:08:08 +08:00
expect ( response . url ) . to eq ( canonical_url )
end
it " does not create duplicate topics when url differs from canonical_url " do
Jobs . run_immediately!
expect { TopicEmbed . import_remote ( canonical_url , { title : title , user : user } ) } . to change {
Topic . all . count
} . by ( 1 )
expect { TopicEmbed . import_remote ( url , { title : title , user : user } ) } . to_not change {
Topic . all . count
}
end
it " does not create duplicate topics when url contains extra params " do
Jobs . run_immediately!
expect {
TopicEmbed . import_remote ( canonical_url2 , { title : title , user : user } )
} . to change { Topic . all . count } . by ( 1 )
expect { TopicEmbed . import_remote ( url2 , { title : title , user : user } ) } . to_not change {
Topic . all . count
}
2021-10-01 23:48:21 +08:00
end
end
2015-09-25 06:20:59 +08:00
end
2020-02-07 23:54:24 +08:00
describe " .absolutize_urls " do
2020-12-04 06:16:01 +08:00
it " handles badly formed URIs " do
2022-01-21 10:03:49 +08:00
invalid_url = " http://source.com/ # double # anchor "
contents = " hello world new post <a href='/hello'>hello</a> "
2020-02-07 23:54:24 +08:00
raw = TopicEmbed . absolutize_urls ( invalid_url , contents )
2020-12-04 06:16:01 +08:00
expect ( raw ) . to eq ( " hello world new post <a href= \" http://source.com/hello \" >hello</a> " )
2020-02-07 23:54:24 +08:00
end
2022-01-21 10:03:49 +08:00
it " handles malformed links " do
url = " https://somesource.com "
DEV: Correctly tag heredocs (#16061)
This allows text editors to use correct syntax coloring for the heredoc sections.
Heredoc tag names we use:
languages: SQL, JS, RUBY, LUA, HTML, CSS, SCSS, SH, HBS, XML, YAML/YML, MF, ICS
other: MD, TEXT/TXT, RAW, EMAIL
2022-03-01 03:50:55 +08:00
contents = << ~ HTML
2024-04-05 23:37:53 +08:00
hello world new post < a href = " mailto:somemail@somewhere.org> " > hello < / a>
some image < img src = " https:/><invalidimagesrc/ " >
DEV: Correctly tag heredocs (#16061)
This allows text editors to use correct syntax coloring for the heredoc sections.
Heredoc tag names we use:
languages: SQL, JS, RUBY, LUA, HTML, CSS, SCSS, SH, HBS, XML, YAML/YML, MF, ICS
other: MD, TEXT/TXT, RAW, EMAIL
2022-03-01 03:50:55 +08:00
HTML
2022-01-21 10:03:49 +08:00
raw = TopicEmbed . absolutize_urls ( url , contents )
expect ( raw ) . to eq ( contents )
end
2020-02-07 23:54:24 +08:00
end
2022-08-03 02:49:28 +08:00
describe " .imported_from_html " do
after { I18n . reload! }
it " uses the default site locale for the 'imported_from' footer " do
TranslationOverride . upsert! (
" en " ,
" embed.imported_from " ,
" English translation of embed.imported_from with %{link} " ,
)
TranslationOverride . upsert! (
" de " ,
" embed.imported_from " ,
" German translation of embed.imported_from with %{link} " ,
)
I18n . locale = :en
expected_html = TopicEmbed . imported_from_html ( " some_url " )
I18n . locale = :de
expect ( TopicEmbed . imported_from_html ( " some_url " ) ) . to eq ( expected_html )
end
2023-04-18 15:05:29 +08:00
it " normalize_encodes the url " do
html =
TopicEmbed . imported_from_html (
'http://www.discourse.org/%23<%2Fa><img%20src%3Dx%20onerror%3Dalert("document.domain")%3B>' ,
)
expected_html =
" \n <hr> \n <small>This is a companion discussion topic for the original entry at <a href='http://www.discourse.org/%23%3C/a%3E%3Cimg%20src=x%20onerror=alert(%22document.domain%22);%3E'>http://www.discourse.org/%23%3C/a%3E%3Cimg%20src=x%20onerror=alert(%22document.domain%22);%3E</a></small> \n "
expect ( html ) . to eq ( expected_html )
end
2022-08-03 02:49:28 +08:00
end
2024-01-05 21:09:31 +08:00
describe " .expanded_for " do
fab! ( :user )
let ( :title ) { " How to turn a fish from good to evil in 30 seconds " }
let ( :url ) { " http://eviltrout.com/123 " }
let ( :contents ) { " <p>hello world new post :D</p> " }
fab! ( :embeddable_host )
fab! ( :category )
fab! ( :tag )
it " returns embed content " do
stub_request ( :get , url ) . to_return ( status : 200 , body : contents )
post = TopicEmbed . import ( user , url , title , contents )
expect ( TopicEmbed . expanded_for ( post ) ) . to include ( contents )
end
it " updates the embed content cache " do
stub_request ( :get , url )
. to_return ( status : 200 , body : contents )
. then
. to_return ( status : 200 , body : " contents changed " )
post = TopicEmbed . import ( user , url , title , contents )
TopicEmbed . expanded_for ( post )
expect ( post . topic . topic_embed . reload . embed_content_cache ) . to include ( " contents changed " )
end
end
2014-01-01 03:37:43 +08:00
end