Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

How to test callback action? #82

Closed
fuchsberger opened this issue Feb 7, 2023 · 5 comments
Closed

How to test callback action? #82

fuchsberger opened this issue Feb 7, 2023 · 5 comments
Labels
discuss documentation Improvements or additions to documentation help wanted Extra attention is needed priority-2 question Further information is requested technical user-feedback

Comments

@fuchsberger
Copy link

fuchsberger commented Feb 7, 2023

I am struggling to find a way to properly test the default controller action from the documentation for 100 % project test coverage.
The problem is that I can't expect a valid code from the Google callback redirect leaving me only able to test an invalid code.

Any advice would be appreciated!

defmodule AppWeb.GoogleAuthController do
  use AppWeb, :controller

  @doc """
  `index/2` handles the callback from Google Auth API redirect.
  """
  def index(conn, %{"code" => code}) do
    {:ok, token} = ElixirAuthGoogle.get_token(code, conn)
    {:ok, profile} = ElixirAuthGoogle.get_user_profile(token.access_token)
    conn
    |> put_view(AppWeb.PageView)
    |> render(:welcome, profile: profile)
  end
end
@nelsonic
Copy link
Member

nelsonic commented Feb 7, 2023

Great question @fuchsberger 💭
thanks for opening this issue to capture it, 👌

@nelsonic nelsonic added documentation Improvements or additions to documentation help wanted Extra attention is needed question Further information is requested discuss priority-2 user-feedback technical labels Feb 7, 2023
@nelsonic nelsonic moved this to 📋 Backlog in dwyl app kanban Feb 7, 2023
@fuchsberger
Copy link
Author

fuchsberger commented Feb 7, 2023

Actually I figured it out. The trick was to use the Mox Library.

Here is what i did:

  1. Create two Modules, a stub and a behavior module.
defmodule DsaWeb.ElixirAuthGoogle do
  @callback get_token(String.t, Plug.Conn.t) :: {:ok, map()}
  @callback get_user_profile(String.t) :: {:ok, map()}

  def get_token(code, conn), do: impl().get_token(code, conn)
  def get_user_profile(access_token), do: impl().get_user_profile(access_token)
  defp impl, do: Application.get_env(:dsa, :elixir_auth_google, ElixirAuthGoogle)
end

defmodule DsaWeb.StubElixirAuthGoogle do
  import Dsa.AccountsFixtures, only: [valid_user_attrs: 1]

  @behaviour DsaWeb.ElixirAuthGoogle

  def get_token(code, _conn) do
    if code == "valid_code" do
      {:ok, %{access_token: "valid access token"}}
    else
      {:ok, %{error: "invalid_grant", error_description: "Malformed auth code."}}
    end
  end

  def get_user_profile(access_token) do
    if access_token == "valid access token" do
      {:ok, valid_user_attrs(given_name: "John", family_name: "Doe")}
    else
      {:ok, %{error: "invalid_request", error_description: "Invalid Credentials"}}
    end
  end
end
  1. Inside test_helpers.exs define the mock:
Mox.defmock(DsaWeb.MockElixirAuthGoogle, for: DsaWeb.ElixirAuthGoogle)
Application.put_env(:dsa, :elixir_auth_google, DsaWeb.MockElixirAuthGoogle)

ExUnit.start()
# ...
  1. In your conn_case.ex enable it for all tests:
  setup _ do
    Mox.stub_with(DsaWeb.MockElixirAuthGoogle, DsaWeb.StubElixirAuthGoogle)
    :ok
  end
  1. Add some tests:
defmodule DsaWeb.ElixirAuthGoogleTest do
  use DsaWeb.ConnCase, async: true

  import Mox
  import DsaWeb.ElixirAuthGoogle, only: [get_token: 2, get_user_profile: 1]

  describe "get_token/2" do

    test "does return access_code if valid code", %{conn: conn} do
      assert {:ok, %{access_token: "access token"} == get_token("valid_code", conn)}
    end

    test "does return error if invalid code", %{conn: conn} do
      assert {:ok, %{error: "invalid_grant", error_description: "Malformed auth code."}} == get_token("invalid code", conn)
    end
  end

  describe "get_user_profile/1" do

    test "does return access_code if valid access token" do
      assert {:ok, %{given_name: "John", family_name: "Doe"}} = get_user_profile("valid access token")
    end

    test "does return error if invalid access token" do
      assert {:ok, %{error: "invalid_request", error_description: "Invalid Credentials"}} = get_user_profile("invalid access token")
    end
  end
end

@github-project-automation github-project-automation bot moved this from 📋 Backlog to ✅ Done in dwyl app kanban Feb 7, 2023
@nelsonic
Copy link
Member

nelsonic commented Feb 8, 2023

@fuchsberger thanks for the reply.
We definitely need to improve the documentation of this package to include clear testing path. 💭

@fuchsberger
Copy link
Author

yes behavior and stub should ideally be handled via the package not by the user leaving the user with just two lines to add for testing.

@nelsonic
Copy link
Member

@fuchsberger apologies for not being more helpful on my previous replies.
The built-in Mock functionality, or "Test Double" has been included with this package since 2020:
https://github.com/dwyl/elixir-auth-google/releases/tag/v1.2.0

The documentation for it is not great. Sorry. 🤦‍♂️
So I've added docs to the PR: https://github.com/dwyl/elixir-auth-google-demo/pull/16/files#r1102952022

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
discuss documentation Improvements or additions to documentation help wanted Extra attention is needed priority-2 question Further information is requested technical user-feedback
Projects
Status: Done
Development

No branches or pull requests

2 participants