diff --git a/spec/rails_helper.rb b/spec/rails_helper.rb index 111364c8..11da5afa 100644 --- a/spec/rails_helper.rb +++ b/spec/rails_helper.rb @@ -2,7 +2,7 @@ # This file is copied to spec/ when you run 'rails generate rspec:install' ENV["RAILS_ENV"] ||= "test" -require File.expand_path("../../config/environment", __FILE__) +require File.expand_path("../config/environment", __dir__) # Prevent database truncation if the environment is production abort("The Rails environment is running in production mode!") if Rails.env.production? require "spec_helper" @@ -26,6 +26,7 @@ require "rspec-sidekiq" # require only the support files necessary. # # Dir[Rails.root.join('spec/support/**/*.rb')].each { |f| require f } +require "support/nokogiri_matchers" # Checks for pending migration and applies them before tests are run. # If you are not using ActiveRecord, you can remove this line. @@ -33,7 +34,7 @@ ActiveRecord::Migration.maintain_test_schema! RSpec.configure do |config| # Remove this line if you're not using ActiveRecord or ActiveRecord fixtures - config.fixture_path = "#{::Rails.root}/spec/fixtures" + config.fixture_path = Rails.root.join("spec/fixtures") # If you're not using ActiveRecord, or you'd prefer not to run each of your # examples within a transaction, remove the following line or assign false @@ -76,4 +77,4 @@ Shoulda::Matchers.configure do |config| end end -Dir[Rails.root.join "spec", "shared_examples", "*.rb"].sort.each { |f| require f } +Dir[Rails.root.join("spec/shared_examples/*.rb")].each { |f| require f } diff --git a/spec/support/nokogiri_matchers.rb b/spec/support/nokogiri_matchers.rb new file mode 100644 index 00000000..1be2bf7c --- /dev/null +++ b/spec/support/nokogiri_matchers.rb @@ -0,0 +1,15 @@ +# frozen_string_literal: true + +module NokogiriMatchers + RSpec::Matchers.matcher :have_css do |css| + description { %(have at least one element matching the CSS selector #{css.inspect}) } + + match do |rendered| + Nokogiri::HTML.parse(rendered).css(css).size.positive? + end + end +end + +RSpec.configure do |c| + c.include NokogiriMatchers, view: true +end diff --git a/spec/views/inbox/_entry.html.haml_spec.rb b/spec/views/inbox/_entry.html.haml_spec.rb new file mode 100644 index 00000000..72243982 --- /dev/null +++ b/spec/views/inbox/_entry.html.haml_spec.rb @@ -0,0 +1,121 @@ +# frozen_string_literal: true + +require "rails_helper" + +describe "inbox/_entry.html.haml", type: :view do + let(:inbox_entry) { Inbox.create(user: inbox_user, question:, new:) } + let(:inbox_user) { user } + let(:user) { FactoryBot.create(:user, sharing_enabled:, sharing_custom_url:) } + let(:sharing_enabled) { true } + let(:sharing_custom_url) { nil } + let(:question) { FactoryBot.create(:question, content: "owo what's this?", author_is_anonymous:, user: question_user, answer_count:) } + let(:author_is_anonymous) { true } + let(:question_user) { nil } + let(:answer_count) { 0 } + let(:new) { false } + + before do + sign_in user + end + + subject(:rendered) do + render partial: "inbox/entry", locals: { + i: inbox_entry, + } + end + + it "does not set the inbox-entry--new class on non-new inbox entries" do + html = Nokogiri::HTML.parse(rendered) + classes = html.css("#inbox_#{inbox_entry.id}").attr("class").value + expect(classes).not_to include "inbox-entry--new" + end + + context "when the inbox entry is new" do + let(:new) { true } + + it "sets the inbox-entry--new class" do + html = Nokogiri::HTML.parse(rendered) + classes = html.css("#inbox_#{inbox_entry.id}").attr("class").value + expect(classes).to include "inbox-entry--new" + end + end + + context "when question author is not anonymous" do + let(:question_user) { FactoryBot.create(:user) } + let(:author_is_anonymous) { false } + + it "has an avatar" do + expect(rendered).to have_css(%(img.answerbox__question-user-avatar)) + end + + it "does not have an icon indicating the author is anonymous" do + expect(rendered).not_to have_css(%(i.fas.fa-user-secret)) + end + + context "when the question already has some answers" do + let(:answer_count) { 9001 } + + it "has a link to the question view" do + html = Nokogiri::HTML.parse(rendered) + selector = %(a[href="/@#{question_user.screen_name}/q/#{question.id}"]) + expect(rendered).to have_css(selector) + expect(html.css(selector).text.strip).to eq "9001 answers" + end + end + end + + it "has an icon indicating the author is anonymous" do + expect(rendered).to have_css(%(i.fas.fa-user-secret)) + end + + it "contains the question text" do + expect(rendered).to match "owo what's this?" + end + + it "has interactive elements" do + expect(rendered).to have_css(%(textarea[name="ib-answer"][data-id="#{inbox_entry.id}"])) + expect(rendered).to have_css(%(button[name="ib-answer"][data-ib-id="#{inbox_entry.id}"])) + expect(rendered).to have_css(%(button[name="ib-destroy"][data-ib-id="#{inbox_entry.id}"])) + end + + it "has a hidden sharing bit" do + expect(rendered).to have_css(%(.inbox-entry__sharing.d-none)) + end + + it "has a link-button to share to tumblr" do + expect(rendered).to have_css(%(.inbox-entry__sharing a.btn[data-inbox-sharing-target="tumblr"])) + end + + it "has a link-button to share to twitter" do + expect(rendered).to have_css(%(.inbox-entry__sharing a.btn[data-inbox-sharing-target="twitter"])) + end + + it "does not have a link-button to share to a custom site" do + expect(rendered).not_to have_css(%(.inbox-entry__sharing a.btn[data-inbox-sharing-target="custom"])) + end + + context "when the user has a custom share url set" do + let(:sharing_custom_url) { "https://pounced-on.me/share?text=" } + + it "has a link-button to share to a custom site" do + html = Nokogiri::HTML.parse(rendered) + selector = %(.inbox-entry__sharing a.btn[data-inbox-sharing-target="custom"]) + expect(rendered).to have_css(selector) + expect(html.css(selector).text.strip).to eq "pounced-on.me" + end + end + + context "when the inbox entry does not belong to the current user" do + let(:inbox_user) { FactoryBot.create(:user) } + + it "does not have any interactive elements" do + expect(rendered).not_to have_css(%(textarea[name="ib-answer"][data-id="#{inbox_entry.id}"])) + expect(rendered).not_to have_css(%(button[name="ib-answer"][data-ib-id="#{inbox_entry.id}"])) + expect(rendered).not_to have_css(%(button[name="ib-destroy"][data-ib-id="#{inbox_entry.id}"])) + end + + it "does not have the sharing bit" do + expect(rendered).not_to have_css(%(.inbox-entry__sharing.d-none)) + end + end +end