diff --git a/app/services/authorization_service.rb b/app/services/authorization_service.rb index b0f9c30a3..4acf226d3 100644 --- a/app/services/authorization_service.rb +++ b/app/services/authorization_service.rb @@ -1,5 +1,6 @@ class AuthorizationService attr_accessor :auth, :signed_in_resource, :cta_variant + def initialize(auth, signed_in_resource = nil, cta_variant = nil) @auth = auth @signed_in_resource = signed_in_resource diff --git a/package.json b/package.json index 3c6f11009..15a3a520e 100644 --- a/package.json +++ b/package.json @@ -22,7 +22,7 @@ "git add" ], "{app,spec}/**/*.rb": [ - "bundle exec rubocop --auto-correct", + "bundle exec rubocop --require rubocop-rspec --auto-correct", "git add" ], "*.json": [ diff --git a/spec/features/user_edits_a_comment_spec.rb b/spec/features/user_edits_a_comment_spec.rb index f1410d8a8..ec74c9051 100644 --- a/spec/features/user_edits_a_comment_spec.rb +++ b/spec/features/user_edits_a_comment_spec.rb @@ -1,40 +1,35 @@ require "rails_helper" -RSpec.describe "Editing Comment", type: :feature, js: true do +RSpec.describe "Editing A Comment", type: :feature, js: true do let(:user) { create(:user) } let(:article) { create(:article, show_comments: true) } - let(:raw_comment) { Faker::Lorem.paragraph } let(:new_comment_text) { Faker::Lorem.paragraph } - let(:comment) do - create(:comment, commentable_id: article.id, user_id: user.id, body_markdown: raw_comment) - end before do + create(:comment, commentable: article, user: user, body_markdown: Faker::Lorem.paragraph) sign_in user - comment end - describe "User edits their own comment on the bottom of the article" do - it "User clicks the edit button and autofocuses to the text field" do - visit article.path.to_s - find(:xpath, "//a[@class='edit-butt' and text()='EDIT']").click - expect(page).to have_css("textarea[autofocus='autofocus']") - end + def assert_updated + expect(page).to have_css("textarea[autofocus='autofocus']") + fill_in "text-area", with: new_comment_text + click_button("SUBMIT") + expect(page).to have_text(new_comment_text) + end - it "User submits a new edit on their comment" do + context "when user edits comment on the bottom of the article" do + it "updates" do visit article.path.to_s - find(:xpath, "//a[@class='edit-butt' and text()='EDIT']").click - fill_in "text-area", with: new_comment_text - click_button("SUBMIT") - expect(page).to have_text(new_comment_text) + click_link("EDIT") + assert_updated end end - describe "User edits comment their own comment on their permalink page" do - it "User clicks the edit button and autofocuses to the text field" do - visit comment.path.to_s - find(:xpath, "//a[@class='edit-butt' and text()='EDIT']").click - expect(page).to have_css("textarea[autofocus='autofocus']") + context "when user edits via permalinks" do + it "updates" do + visit user.comments.last.path.to_s + click_link("EDIT") + assert_updated end end end diff --git a/spec/models/mentor_relationship_spec.rb b/spec/models/mentor_relationship_spec.rb index 5cc0568fc..371d05ebd 100644 --- a/spec/models/mentor_relationship_spec.rb +++ b/spec/models/mentor_relationship_spec.rb @@ -3,21 +3,21 @@ require "rails_helper" RSpec.describe MentorRelationship, type: :model do let(:mentor) { create(:user) } let(:mentee) { create(:user) } - let(:relationship) { MentorRelationship.create(mentor_id: mentor.id, mentee_id: mentee.id) } + let(:relationship) { MentorRelationship.new(mentor: mentor, mentee_id: mentee) } + + describe "validations" do + subject { MentorRelationship.new(mentor: mentor, mentee: mentee) } + + it { is_expected.to belong_to(:mentor) } + it { is_expected.to belong_to(:mentee) } + it { is_expected.to validate_uniqueness_of(:mentor_id).scoped_to(:mentee_id) } + end it "is active" do expect(relationship.active).to eq(true) end - it { is_expected.to belong_to(:mentor) } - it { is_expected.to belong_to(:mentee) } - it "is not the same user" do - expect(MentorRelationship.create(mentor_id: mentor.id, mentee_id: mentor.id)).to be_invalid - end - - it "cannot be a duplicate record" do - relationship - expect(MentorRelationship.create(mentor_id: mentor.id, mentee_id: mentee.id)).to be_invalid + expect(MentorRelationship.new(mentor_id: mentor.id, mentee_id: mentor.id)).to be_invalid end end diff --git a/spec/models/user_spec.rb b/spec/models/user_spec.rb index 8846354fa..0d3d0b5e7 100644 --- a/spec/models/user_spec.rb +++ b/spec/models/user_spec.rb @@ -10,6 +10,8 @@ RSpec.describe User, type: :model do let(:org) { create(:organization) } let (:second_org) { create(:organization) } + before { mock_auth_hash } + it { is_expected.to have_many(:articles) } it { is_expected.to have_many(:badge_achievements).dependent(:destroy) } it { is_expected.to have_many(:badges).through(:badge_achievements) } diff --git a/spec/rails_helper.rb b/spec/rails_helper.rb index 48704e68d..83765e476 100644 --- a/spec/rails_helper.rb +++ b/spec/rails_helper.rb @@ -1,28 +1,18 @@ -# This file is copied to spec/ when you run 'rails generate rspec:install' ENV["RAILS_ENV"] = "test" +require "spec_helper" require File.expand_path("../config/environment", __dir__) require "rspec/rails" -Dir[Rails.root.join("spec/support/**/*.rb")].each { |f| require f } - -# Prevent database truncation if the environment is production abort("The Rails environment is running in production mode!") if Rails.env.production? -require "spec_helper" -require "webmock/rspec" -require "capybara/rspec" -require "stream_rails" -require "selenium/webdriver" -require "rspec/retry" -require "algolia/webmock" -require "approvals/rspec" -require "shoulda/matchers" -require "pundit/rspec" -require "pundit/matchers" - -WebMock.disable_net_connect!(allow_localhost: true) # Add additional requires below this line. Rails is not loaded until this point! +require "algolia/webmock" +require "pundit/matchers" +require "pundit/rspec" +require "stream_rails" +require "webmock/rspec" + # Requires supporting ruby files with custom matchers and macros, etc, in # spec/support/ and its subdirectories. Files matching `spec/**/*_spec.rb` are # run as spec files by default. This means that files in spec/support that end @@ -35,42 +25,26 @@ WebMock.disable_net_connect!(allow_localhost: true) # of increasing the boot-up time by auto-requiring all files in the support # directory. Alternatively, in the individual `*_spec.rb` files, manually # require only the support files necessary. -# -# Dir[Rails.root.join('spec/support/**/*.rb')].each { |f| require f } + +Dir[Rails.root.join("spec/support/**/*.rb")].each { |f| require f } # Checks for pending migrations before tests are run. # If you are not using ActiveRecord, you can remove this line. ActiveRecord::Migration.maintain_test_schema! +# Disable internet connection with Webmock +WebMock.disable_net_connect!(allow_localhost: true) + RSpec.configure do |config| - # Remove this line if you're not using ActiveRecord or ActiveRecord fixtures config.fixture_path = "#{::Rails.root}/spec/fixtures" - Approvals.configure do |approvals_config| - approvals_config.approvals_path = "#{::Rails.root}/spec/support/fixtures/approvals/" - end - - config.include Devise::Test::ControllerHelpers, type: :view - config.include Devise::Test::ControllerHelpers, type: :controller - config.include RequestSpecHelper, type: :request config.include ApplicationHelper - # config.include CommentsHelper, type: :view - - config.use_transactional_fixtures = false - config.include FactoryBot::Syntax::Methods - - # Apply rack_session_access integrated with devise. + config.include Devise::Test::ControllerHelpers, type: :controller + config.include Devise::Test::ControllerHelpers, type: :view config.include Devise::Test::IntegrationHelpers, type: :feature - - # show retry status in spec process - config.verbose_retry = true - # show exception that triggers a retry if verbose_retry is set to true - config.display_try_failure_messages = true - - # run retry only on features - config.around :each, :js do |ex| - ex.run_with_retry retry: 3 - end + config.include FactoryBot::Syntax::Methods + config.include OmniauthMacros + config.include RequestSpecHelper, type: :request config.before do ActiveRecord::Base.observers.disable :all # <-- Turn 'em all off! @@ -116,67 +90,9 @@ RSpec.configure do |config| stub_request(:get, /us-east-api.stream-io-api.com\/api/).to_rack(FakeStream) end - # Stub Stream.io StreamRails.enabled = false - - # Omniauth mock - OmniAuth.config.test_mode = true - raw_info = Hashie::Mash.new - raw_info.email = "yourname@email.com" - raw_info.first_name = "fname" - raw_info.gender = "female" - raw_info.id = "123456" - raw_info.last_name = "lname" - raw_info.link = "http://www.facebook.com/url”" - raw_info.lang = "fr" - raw_info.locale = "en_US" - raw_info.name = "fname lname" - raw_info.timezone = 5.5 - raw_info.updated_time = "2012-06-08T13:09:47+0000" - raw_info.username = "fname.lname" - raw_info.verified = true - raw_info.followers_count = 100 - raw_info.friends_count = 1000 - raw_info.created_at = "2017-06-08T13:09:47+0000" - - extra_info = Hashie::Mash.new - extra_info.raw_info = raw_info - - info = OmniAuth::AuthHash::InfoHash.new - info.first_name = "fname" - # info.image = "http://graph.facebook.com/123456/picture?type=square”" - info.last_name = "lname" - info.location = "location,state,country" - info.name = "fname lname" - info.nickname = "fname.lname" - info.verified = true - - credentials = OmniAuth::AuthHash::InfoHash.new - credentials.token = "2735246777-jlOnuFlGlvybuwDJfyrIyESLUEgoo6CffyJCQUO" - credentials.secret = "o0cu6ACtypMQfLyWhme3Vj99uSds7rjr4szuuTiykSYcN" - - twitter_auth_hash = OmniAuth::AuthHash.new - twitter_auth_hash.provider = "twitter" - twitter_auth_hash.uid = "123456" - twitter_auth_hash.info = info - twitter_auth_hash.extra = extra_info - twitter_auth_hash.credentials = credentials - - github_auth_hash = OmniAuth::AuthHash.new - github_auth_hash.provider = "github" - github_auth_hash.uid = "1234567" - github_auth_hash.info = info - github_auth_hash.extra = extra_info - github_auth_hash.credentials = credentials - - OmniAuth.config.mock_auth[:twitter] = twitter_auth_hash - - OmniAuth.config.mock_auth[:github] = github_auth_hash - - ######### - config.infer_spec_type_from_file_location! # Filter lines from Rails gems in backtraces. @@ -184,30 +100,3 @@ RSpec.configure do |config| # arbitrary gems may also be filtered via: # config.filter_gems_from_backtrace("gem name") end - -Shoulda::Matchers.configure do |config| - config.integrate do |with| - with.test_framework :rspec - with.library :rails - end -end - -Capybara.register_driver :chrome do |app| - Capybara::Selenium::Driver.new(app, browser: :chrome) -end - -Capybara.register_driver :headless_chrome do |app| - capabilities = Selenium::WebDriver::Remote::Capabilities.chrome( - chromeOptions: { args: %w(headless disable-gpu no-sandbox window-size=1400,2000) }, - ) - - Capybara::Selenium::Driver.new app, - browser: :chrome, - desired_capabilities: capabilities -end - -# The current driveres implemented are -# - chrome-helper (:chrome) => Use this for browser-based testing -# - headless-chrome (:headless_chrome) => headless version of chrome-helper - -Capybara.javascript_driver = :headless_chrome diff --git a/spec/support/database_cleaner.rb b/spec/support/database_cleaner.rb deleted file mode 100644 index 720a47032..000000000 --- a/spec/support/database_cleaner.rb +++ /dev/null @@ -1,21 +0,0 @@ -RSpec.configure do |config| - config.before(:suite) do - DatabaseCleaner.clean_with(:truncation) - end - - config.before do - DatabaseCleaner.strategy = :transaction - end - - config.before(:each, js: true) do - DatabaseCleaner.strategy = :truncation - end - - config.before do - DatabaseCleaner.start - end - - config.after do - DatabaseCleaner.clean - end -end diff --git a/spec/support/initializers/approvals.rb b/spec/support/initializers/approvals.rb new file mode 100644 index 000000000..9b863ed90 --- /dev/null +++ b/spec/support/initializers/approvals.rb @@ -0,0 +1,5 @@ +require "approvals/rspec" + +Approvals.configure do |approvals_config| + approvals_config.approvals_path = "#{::Rails.root}/spec/support/fixtures/approvals/" +end diff --git a/spec/support/initializers/capybara.rb b/spec/support/initializers/capybara.rb new file mode 100644 index 000000000..5f5b23ebd --- /dev/null +++ b/spec/support/initializers/capybara.rb @@ -0,0 +1,19 @@ +require "capybara/rspec" +require "selenium/webdriver" + +Capybara.server = :puma, { Silent: true } +Capybara.default_max_wait_time = 5 + +Capybara.register_driver :chrome do |app| + Capybara::Selenium::Driver.new(app, browser: :chrome) +end + +Capybara.register_driver :headless_chrome do |app| + Capybara::Selenium::Driver.new app, + browser: :chrome, + desired_capabilities: Selenium::WebDriver::Remote::Capabilities.chrome( + chromeOptions: { args: %w(headless disable-gpu no-sandbox window-size=1400,2000) }, + ) +end + +Capybara.javascript_driver = :headless_chrome diff --git a/spec/support/initializers/database_cleaner.rb b/spec/support/initializers/database_cleaner.rb new file mode 100644 index 000000000..39cc8bef1 --- /dev/null +++ b/spec/support/initializers/database_cleaner.rb @@ -0,0 +1,46 @@ +require "database_cleaner" + +RSpec.configure do |config| + config.use_transactional_fixtures = false + + config.before(:suite) do + if config.use_transactional_fixtures? + raise(<<-MSG) + Delete line `config.use_transactional_fixtures = true` from rails_helper.rb + (or set it to false) to prevent uncommitted transactions being used in + JavaScript-dependent specs. + + During testing, the app-under-test that the browser driver connects to + uses a different database connection to the database connection used by + the spec. The app's database connection would not be able to access + uncommitted transaction data setup over the spec's database connection. + MSG + end + DatabaseCleaner.clean_with(:truncation) + end + + config.before do + DatabaseCleaner.strategy = :transaction + end + + config.before(:each, type: :feature) do + # :rack_test driver's Rack app under test shares database connection + # with the specs, so continue to use transaction strategy for speed. + driver_shares_db_connection_with_specs = Capybara.current_driver == :rack_test + + unless driver_shares_db_connection_with_specs + # Driver is probably for an external browser with an app + # under test that does *not* share a database connection with the + # specs, so use truncation strategy. + DatabaseCleaner.strategy = :truncation + end + end + + config.before do + DatabaseCleaner.start + end + + config.append_after do + DatabaseCleaner.clean + end +end diff --git a/spec/support/initializers/rspec_retry.rb b/spec/support/initializers/rspec_retry.rb new file mode 100644 index 000000000..7e5b4b00e --- /dev/null +++ b/spec/support/initializers/rspec_retry.rb @@ -0,0 +1,10 @@ +require "rspec/retry" + +RSpec.configure do |config| + config.verbose_retry = true + config.display_try_failure_messages = true + config.around :each, :js do |ex| + # retry only on features in CI + ex.run_with_retry retry: ENV["CI"] ? 3 : 1 + end +end diff --git a/spec/support/initializers/shoulda_matchers.rb b/spec/support/initializers/shoulda_matchers.rb new file mode 100644 index 000000000..cea4e884c --- /dev/null +++ b/spec/support/initializers/shoulda_matchers.rb @@ -0,0 +1,8 @@ +require "shoulda/matchers" + +Shoulda::Matchers.configure do |config| + config.integrate do |with| + with.test_framework :rspec + with.library :rails + end +end diff --git a/spec/support/vcr.rb b/spec/support/initializers/vcr.rb similarity index 100% rename from spec/support/vcr.rb rename to spec/support/initializers/vcr.rb diff --git a/spec/support/omniauth_macros.rb b/spec/support/omniauth_macros.rb new file mode 100644 index 000000000..ba03e9b5e --- /dev/null +++ b/spec/support/omniauth_macros.rb @@ -0,0 +1,60 @@ +module OmniauthMacros + INFO = OmniAuth::AuthHash::InfoHash.new( + first_name: "fname", + last_name: "lname", + location: "location,state,country", + name: "fname lname", + nickname: "fname.lname", + email: "yourname@email.com", + verified: true, + # info.image = "http://graph.facebook.com/123456/picture?type=square”" + ) + + EXTRA_INFO = Hashie::Mash.new(raw_info: Hashie::Mash.new( + email: "yourname@email.com", + first_name: "fname", + gender: "female", + id: "123456", + last_name: "lname", + link: "http://www.facebook.com/url”", + lang: "fr", + locale: "en_US", + name: "fname lname", + timezone: 5.5, + updated_time: "2012-06-08T13:09:47+0000", + username: "fname.lname", + verified: true, + followers_count: 100, + friends_count: 1000, + created_at: "2017-06-08T13:09:47+0000", + )) + + CREDENTIAL = OmniAuth::AuthHash::InfoHash.new( + token: "2735246777-jlOnuFlGlvybuwDJfyrIyESLUEgoo6CffyJCQUO", + secret: "o0cu6ACtypMQfLyWhme3Vj99uSds7rjr4szuuTiykSYcN", + ) + + BASIC_INFO = { + uid: "1234567", + info: INFO, + extra: EXTRA_INFO, + credentials: CREDENTIAL, + } + + def mock_auth_hash + mock_twitter + mock_github + end + + def mock_twitter + OmniAuth.config.mock_auth[:twitter] = OmniAuth::AuthHash.new( + BASIC_INFO.merge(provider: "twitter"), + ) + end + + def mock_github + OmniAuth.config.mock_auth[:github] = OmniAuth::AuthHash.new( + BASIC_INFO.merge(provider: "github"), + ) + end +end