# frozen_string_literal: true RSpec.describe Onebox::Helpers do describe '.blank?' do it { expect(described_class.blank?("")).to be(true) } it { expect(described_class.blank?(" ")).to be(true) } it { expect(described_class.blank?("test")).to be(false) } it { expect(described_class.blank?(["test", "testing"])).to be(false) } it { expect(described_class.blank?([])).to be(true) } it { expect(described_class.blank?({})).to be(true) } it { expect(described_class.blank?(nil)).to be(true) } it { expect(described_class.blank?(true)).to be(false) } it { expect(described_class.blank?(false)).to be(true) } it { expect(described_class.blank?(a: 'test')).to be(false) } end describe ".truncate" do let(:test_string) { "Chops off on spaces" } it { expect(described_class.truncate(test_string)).to eq(test_string) } it { expect(described_class.truncate(test_string, 5)).to eq("Chops...") } it { expect(described_class.truncate(test_string, 7)).to eq("Chops...") } it { expect(described_class.truncate(test_string, 9)).to eq("Chops off...") } it { expect(described_class.truncate(test_string, 10)).to eq("Chops off...") } it { expect(described_class.truncate(test_string, 100)).to eq("Chops off on spaces") } it { expect(described_class.truncate(" #{test_string} ", 6)).to eq(" Chops...") } end describe "fetch_response" do around do |example| previous_options = Onebox.options.to_h Onebox.options = { max_download_kb: 1 } stub_request(:get, "http://example.com/large-file").to_return(status: 200, body: onebox_response("slides")) example.run Onebox.options = previous_options end it "raises an exception when responses are larger than our limit" do expect { described_class.fetch_response('http://example.com/large-file') }.to raise_error(Onebox::Helpers::DownloadTooLarge) end end describe "fetch_html_doc" do it "can handle unicode URIs" do uri = 'https://www.reddit.com/r/UFOs/comments/k18ukd/๐จ๐๐ข_๐ฑ๐ฟ๐ผ๐ฝ๐_๐ฐ๐ผ๐_๐๐ต๐ฟ๐ผ๐๐ด๐ต_๐ฏ๐ฎ๐ฟ๐ป_๐ฟ๐ผ๐ผ๐ณ/' stub_request(:get, uri).to_return(status: 200, body: "
success
") expect(described_class.fetch_html_doc(uri).to_s).to match("success") end context "canonical link" do it "follows canonical link" do uri = 'https://www.example.com' stub_request(:get, uri).to_return(status: 200, body: "invalid
") stub_request(:get, 'http://foobar.com').to_return(status: 200, body: "success
") stub_request(:head, 'http://foobar.com').to_return(status: 200, body: "") expect(described_class.fetch_html_doc(uri).to_s).to match("success") end it "does not follow canonical link pointing at localhost" do uri = 'https://www.example.com' stub_request(:get, uri).to_return(status: 200, body: "success
") expect(described_class.fetch_html_doc(uri).to_s).to match("success") end end end describe "redirects" do describe "redirect limit" do before do codes = [301, 302, 303, 307, 308] (1..6).each do |i| code = codes.pop || 302 stub_request(:get, "https://httpbin.org/redirect/#{i}") .to_return(status: code, body: "", headers: { location: "https://httpbin.org/redirect/#{i - 1}" }) end stub_request(:get, "https://httpbin.org/redirect/0").to_return(status: 200, body: "success
") end it "can follow redirects" do expect(described_class.fetch_response("https://httpbin.org/redirect/2")).to match("success") end it "errors on long redirect chains" do expect { described_class.fetch_response("https://httpbin.org/redirect/6") }.to raise_error(Net::HTTPError, /redirect too deep/) end end describe "cookie handling" do it "naively forwards cookies to the next request" do stub_request(:get, "https://httpbin.org/cookies/set/a/b").to_return( status: 302, headers: { location: "/cookies", "set-cookie": "a=b; Path=/", } ) stub_request(:get, "https://httpbin.org/cookies") .with(headers: { cookie: "a=b; Path=/" }) .to_return(status: 200, body: "success, cookie readback not implemented") expect(described_class.fetch_response('https://httpbin.org/cookies/set/a/b')).to match("success") end it "does not send cookies to the wrong domain" do skip("unimplemented") stub_request(:get, "https://httpbin.org/cookies/set/a/b").to_return( status: 302, headers: { location: "https://evil.com/show_cookies", "set-cookie": "a=b; Path=/", } ) stub_request(:get, "https://evil.com/show_cookies") .with(headers: { cookie: nil }) .to_return(status: 200, body: "success, cookie readback not implemented") described_class.fetch_response('https://httpbin.org/cookies/set/a/b') end end end describe "user_agent" do context "default" do it "has the default Discourse user agent" do stub_request(:get, "http://example.com/some-resource") .with(headers: { "user-agent" => /Discourse Forum Onebox/ }) .to_return(status: 200, body: "test") described_class.fetch_response('http://example.com/some-resource') end end context "Custom option" do around do |example| previous_options = Onebox.options.to_h Onebox.options = { user_agent: "EvilTroutBot v0.1" } example.run Onebox.options = previous_options end it "has the custom user agent" do stub_request(:get, "http://example.com/some-resource") .with(headers: { "user-agent" => "EvilTroutBot v0.1" }) .to_return(status: 200, body: "test") described_class.fetch_response('http://example.com/some-resource') end end end describe '.normalize_url_for_output' do it { expect(described_class.normalize_url_for_output('http://example.com/fo o')).to eq("http://example.com/fo%20o") } it { expect(described_class.normalize_url_for_output("http://example.com/fo'o")).to eq("http://example.com/fo'o") } it { expect(described_class.normalize_url_for_output('http://example.com/fo"o')).to eq("http://example.com/fo"o") } it { expect(described_class.normalize_url_for_output('http://example.com/fo