# frozen_string_literal: true

require 'test_helper'


class OmniauthableIntegrationTest < Devise::IntegrationTest
  FACEBOOK_INFO = {
    "id" => '12345',
    "link" => 'http://facebook.com/josevalim',
    "email" => 'user@example.com',
    "first_name" => 'Jose',
    "last_name" => 'Valim',
    "website" => 'http://blog.plataformatec.com.br'
  }

  setup do
    OmniAuth.config.test_mode = true
    OmniAuth.config.mock_auth[:facebook] = {
      "uid" => '12345',
      "provider" => 'facebook',
      "user_info" => {"nickname" => 'josevalim'},
      "credentials" => {"token" => 'plataformatec'},
      "extra" => {"user_hash" => FACEBOOK_INFO}
    }
    OmniAuth.config.add_camelization 'facebook', 'FaceBook'
    if OmniAuth.config.respond_to?(:request_validation_phase)
      OmniAuth.config.request_validation_phase = ->(env) {}
    end
  end

  teardown do
    OmniAuth.config.camelizations.delete('facebook')
    OmniAuth.config.test_mode = false
  end

  def stub_action!(name)
    Users::OmniauthCallbacksController.class_eval do
      alias_method :__old_facebook, :facebook
      alias_method :facebook, name
    end
    yield
  ensure
    Users::OmniauthCallbacksController.class_eval do
      alias_method :facebook, :__old_facebook
    end
  end

  test "omniauth sign in should not run model validations" do
    stub_action!(:sign_in_facebook) do
      create_user
      post "/users/auth/facebook"
      follow_redirect!
      assert warden.authenticated?(:user)

      assert_not User.validations_performed
    end
  end

  test "can access omniauth.auth in the env hash" do
    post "/users/auth/facebook"
    follow_redirect!

    json = ActiveSupport::JSON.decode(response.body)

    assert_equal "12345",         json["uid"]
    assert_equal "facebook",      json["provider"]
    assert_equal "josevalim",     json["user_info"]["nickname"]
    assert_equal FACEBOOK_INFO,   json["extra"]["user_hash"]
    assert_equal "plataformatec", json["credentials"]["token"]
  end

  test "cleans up session on sign up" do
    assert_no_difference "User.count" do
      post "/users/auth/facebook"
      follow_redirect!
    end

    assert session["devise.facebook_data"]

    assert_difference "User.count" do
      visit "/users/sign_up"
      fill_in "Password", with: "12345678"
      fill_in "Password confirmation", with: "12345678"
      click_button "Sign up"
    end

    assert_current_url "/"
    assert_contain "You have signed up successfully."
    assert_contain "Hello User user@example.com"
    assert_not session["devise.facebook_data"]
  end

  test "cleans up session on cancel" do
    assert_no_difference "User.count" do
      post "/users/auth/facebook"
      follow_redirect!
    end

    assert session["devise.facebook_data"]
    visit "/users/cancel"
    assert_not session["devise.facebook_data"]
  end

  test "cleans up session on sign in" do
    assert_no_difference "User.count" do
      post "/users/auth/facebook"
      follow_redirect!
    end

    assert session["devise.facebook_data"]
    sign_in_as_user
    assert_not session["devise.facebook_data"]
  end

  test "sign in and send remember token if configured" do
    post "/users/auth/facebook"
    follow_redirect!
    assert_nil warden.cookies["remember_user_token"]

    stub_action!(:sign_in_facebook) do
      create_user
      post "/users/auth/facebook"
      follow_redirect!
      assert warden.authenticated?(:user)
      assert warden.cookies["remember_user_token"]
    end
  end

  test "authorization path via GET when Omniauth allowed_request_methods includes GET" do
    original_allowed = OmniAuth.config.allowed_request_methods
    OmniAuth.config.allowed_request_methods = [:get, :post]

    get "/users/auth/facebook"

    assert_response(:redirect)
  ensure
    OmniAuth.config.allowed_request_methods = original_allowed
  end

  test "authorization path via GET when Omniauth allowed_request_methods doesn't include GET" do
    original_allowed = OmniAuth.config.allowed_request_methods
    OmniAuth.config.allowed_request_methods = [:post]

    assert_raises(ActionController::RoutingError) do
      get "/users/auth/facebook"
    end
  ensure
    OmniAuth.config.allowed_request_methods = original_allowed
  end

  test "generates a link to authenticate with provider" do
    visit "/users/sign_in"
    assert_select "form[action=?][method=post]", "/users/auth/facebook" do
      assert_select "input[type=submit][value=?]", "Sign in with FaceBook"
    end
  end

  test "generates a proper link when SCRIPT_NAME is set" do
    header 'SCRIPT_NAME', '/q'
    visit "/users/sign_in"
    assert_select "form[action=?][method=post]", "/q/users/auth/facebook" do
      assert_select "input[type=submit][value=?]", "Sign in with FaceBook"
    end
  end

  test "handles callback error parameter according to the specification" do
    OmniAuth.config.mock_auth[:facebook] = :access_denied
    visit "/users/auth/facebook/callback?error=access_denied"
    assert_current_url "/users/sign_in"
    assert_contain 'Could not authenticate you from FaceBook because "Access denied".'
  end

  test "handles other exceptions from OmniAuth" do
    OmniAuth.config.mock_auth[:facebook] = :invalid_credentials

    post "/users/auth/facebook"
    follow_redirect!
    follow_redirect!

    assert_contain 'Could not authenticate you from FaceBook because "Invalid credentials".'
  end
end
