ueberauth / ueberauth_example

Example Phoenix application using Überauth for authentication
http://ueberauth-example.herokuapp.com
MIT License
220 stars 73 forks source link

`AuthController` test example #22

Closed pdawczak closed 5 years ago

pdawczak commented 8 years ago

Hey!

First of all, thank you very much for your hard work! Your contribution is great!

This repository has great value filling in the big picture when looking for more information beyond the documentation! I'm pretty sure, many of us - developers would appreciate if you were able to add some examples of how to test the callback functions (how to set proper :assigns for both of :ueberauth_failure and :ueberauth_auth).

I'm not sure how to tackle that properly - I've tried with naive approach like:

  test "GET /auth/facebook/callback", %{conn: conn} do
    conn =
      conn
      |> assign(:ueberauth_failure, "failed!")

    conn = get conn, "/auth/facebook/callback"

    assert html_response(conn, 200) =~ "Oh noes"
  end

but unfortunately, the plug tries to do it's job effectively failing the tests.

As a proof, when IO.inspect-ing the the ueberauth_failure: failure:

%Ueberauth.Failure{errors: [%Ueberauth.Failure.Error{message: "No code received",
   message_key: "missing_code"}], provider: :facebook,
 strategy: Ueberauth.Strategy.Facebook}

Thank you for your help!

abitdodgy commented 7 years ago

@pdawczak how did you end up writing your tests for the callback function?

doomspork commented 7 years ago

Howdy @pdawczak / @abitdodgy, adding a test harness to Ueberauth is something that we'd love to tackle but none of us had the bandwidth to focus on.

Until such time, I have found bypass to be a great solution for testing the entire flow (not just the callbacks).

Papipo commented 6 years ago

@doomspork do you have any example? I've been struggling for two days with this, there must be something I am missing :(

abitdodgy commented 6 years ago

@doomspork I'm pressed for time, but if you have a couple of days I'll share some code with you on how to do this. It's fairly straightforward, actually.

doomspork commented 6 years ago

@abitdodgy show me how to do what exactly? Was that meant for @Papipo?

@Papipo I'm sorry I've been busy dealing with some family matters and trying to keep on top of all of these other things. I unfortunately do not have any code I would be allowed to share with you from my existing projects but I wrote a lesson on using Bypass here: https://elixirschool.com/en/lessons/libraries/bypass/

You need to identify the requests to-and-from the service and set them up in Bypass. There's not a really clean way to do that at the moment without a lot of manual setup. Perhaps the MVP test harness is nothing more than mocked responses you can easily plug into Bypass.

sbrink commented 5 years ago

I know this is a fairly old issue. But it's maybe the 3rd I looked for a solution.

You don't need an external lib. Here's my current solution as starting point:

test "when callback succeeds", %{conn: conn} do
  auth = %Ueberauth.Auth{
    provider: :google,
    info: %{
      first_name: "John",
      last_name: "Doe",
      email: "john.doe@example.com",
      image: "https://example.com/image.jpg"
    }
  }

  conn =
    conn
    |> bypass_through(PlatformWeb.Router, [:browser])
    |> get("/auth/google/callback")
    |> assign(:ueberauth_auth, auth)
    |> CallbackController.callback(%{})

  assert get_flash(conn, :info) == "Successfully authenticated."
end

This callback itself is just a function. The trick is to initialize the connection correctly. For flash messages, session, etc. you use bypass_through. The assign should be clear.

Just for reference my controller:

def callback(%{assigns: %{ueberauth_auth: auth}} = conn, _params) do
  case UserFromAuth.find_or_create(auth) do
    {:ok, user} ->
      conn
      |> CurrentUserPlug.sign_in(user)
      |> put_flash(:info, "Successfully authenticated.")
      |> redirect(to: "/")

    {:error, _reason} ->
      conn
      |> put_flash(:error, "Could not authenticate user.")
      |> redirect(to: "/")
  end
end
doomspork commented 5 years ago

@sbrink would you be willing to add something to the Ueberauth documentation or even update this example with your test?

popo63301 commented 4 years ago

Thanks @sbrink ! That was really helpful.

Here is my contribution for the failing test:

test "when callback fails", %{conn: conn} do
  auth = %Ueberauth.Failure{}

  conn =
    conn
    |> bypass_through(PlatformWeb.Router, [:browser])
    |> get("/auth/google/callback")
    |> assign(:ueberauth_failure, auth)
    |> CallbackController.callback(%{})

  assert get_flash(conn, :error) == "Failed to authenticate."
end