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

Move HandlersCase to lib and rename to HandlerCase #131

Merged
merged 3 commits into from
Apr 13, 2020
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 2 additions & 2 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -225,7 +225,7 @@ If you want the Elixir formatter to omit the parens on `command/2` and
### Testing Handlers

Alice provides several helpers to make it easy to test your handlers. First
you'll need to invoke to add `use Alice.HandlersCase, handlers: [YourHandler]`
you'll need to invoke to add `use Alice.HandlerCase, handlers: [YourHandler]`
passing it the handler you're trying to test. Then you can use
`message_received()` within your test, which will simulate a message coming in
from the chat backend and route it through to the handlers appropriately. If
Expand All @@ -240,7 +240,7 @@ In `test/alice/handlers/google_images_test.exs`:

```elixir
defmodule Alice.Handlers.GoogleImagesTest do
use Alice.HandlersCase, handlers: Alice.Handlers.GoogleImages
use Alice.HandlerCase, handlers: Alice.Handlers.GoogleImages

test "it fetches an image when asked" do
send_message("img me example image")
Expand Down
16 changes: 12 additions & 4 deletions lib/alice/chat_backends/outbound_client.ex
Original file line number Diff line number Diff line change
@@ -1,9 +1,17 @@
defmodule Alice.ChatBackends.OutboundClient do
@moduledoc """
Documentation for the OutboundClient behavior. This defines a behavior for modules that serve as an outbound connection to a backend.
Documentation for the OutboundClient behavior. This defines a behavior for
modules that serve as an outbound connection to a backend.
"""

@callback send_message(response :: String.t(), channel :: String.t(), backend :: map()) ::
String.t()
@callback indicate_typing(channel :: String.t(), backend :: map()) :: String.t()
@callback send_message(
message :: String.t(),
channel :: String.t(),
service_state :: map()
) :: String.t()

@callback indicate_typing(
channel :: String.t(),
service_state :: map()
) :: String.t()
end
11 changes: 8 additions & 3 deletions lib/alice/chat_backends/slack_outbound.ex
Original file line number Diff line number Diff line change
Expand Up @@ -3,9 +3,14 @@ defmodule Alice.ChatBackends.SlackOutbound do
@behaviour Alice.ChatBackends.OutboundClient

@doc "Sends a message back to slack"
def send_message(response, channel, slack),
do: Slack.Sends.send_message(response, channel, slack)
@spec send_message(message :: String.t(), channel :: String.t(), slack :: map()) :: String.t()
def send_message(message, channel, slack) do
Slack.Sends.send_message(message, channel, slack)
end

@doc "Makes Alice indicate she's typing in the appropriate channel"
def indicate_typing(channel, slack), do: Slack.Sends.indicate_typing(channel, slack)
@spec indicate_typing(channel :: String.t(), slack :: map()) :: String.t()
def indicate_typing(channel, slack) do
Slack.Sends.indicate_typing(channel, slack)
end
end
73 changes: 55 additions & 18 deletions test/support/handlers_case.ex → lib/alice/test/handlers_case.ex
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
defmodule Alice.HandlersCase do
defmodule Alice.HandlerCase do
@moduledoc """
Helpers for writing tests of Alice Handlers.

Expand All @@ -10,7 +10,7 @@ defmodule Alice.HandlersCase do
## Examples

defmodule Alice.Handlers.ExampleHandlerTest do
use Alice.HandlersCase, handlers: Alice.Handlers.ExampleHandler
use Alice.HandlerCase, handlers: Alice.Handlers.ExampleHandler

test "it replies" do
send_message("hello")
Expand All @@ -19,46 +19,73 @@ defmodule Alice.HandlersCase do
end
"""

@type conn() :: %Alice.Conn{}

@doc """
Generates a fake connection for testing purposes.

Can be called as `fake_conn/0` to generate a quick connection. Or it can be
called as `fake_conn/1` to pass a message. Or finally can be called as
`fake_conn/2` to set options with the message.
Can be called as `fake_conn/0` to generate a quick connection.

## Examples

fake_conn()
fake_conn("message")
fake_conn("message", state: %{some: "state"})
fake_conn("message", capture: ~r/pattern/)

test "you can directly use the reply function" do
conn = fake_conn()
reply(conn, "hello world")
assert first_reply() == "hello world"
end
"""
@spec fake_conn() :: conn()
def fake_conn(), do: fake_conn("")

test "you can set state" do
conn = fake_conn("message", state: %{some: "state"})
conn = send_message(conn)
@doc """
Generates a fake connection for testing purposes.

Can be called as `fake_conn/1` to pass a message.

## Examples

test "you can set the message in the conn" do
conn = fake_conn("message")
send_message(conn)
assert first_reply() == "hello world"
assert conn.state.some == "state"
end
"""
def fake_conn(), do: fake_conn("")

@spec fake_conn(String.t()) :: conn()
def fake_conn(text) do
%Alice.Conn{
message: %{text: text, channel: :channel, user: :fake_user},
slack: %{users: %{fake_user: %{id: :fake_user, name: "fake_user"}}, me: %{id: :alice}}
}
end

@doc """
Generates a fake connection for testing purposes.

Can be called as `fake_conn/2` to set options. Options can either be `:state`
or `:capture`, but not both. Using `:capture` is helpful if you want to unit
test your handler functions.

## Examples

test "you can set state" do
conn = fake_conn("message", state: %{some: "state"})
conn = send_message(conn)
assert first_reply() == "hello world"
assert conn.state.some == "state"
end

test "you can set the regix and call the handler directly" do
conn = fake_conn("message", ~r"^(.+)")
MyHandler.do_something(conn)
assert first_reply() == "hello world, you said 'message'"
end
"""
@spec fake_conn(String.t(), opts :: [state: map()]) :: conn()
def fake_conn(text, state: state) do
%{fake_conn(text) | state: state}
end

@spec fake_conn(String.t(), opts :: [capture: Regex.t()]) :: conn()
def fake_conn(text, capture: capture_regex) do
text
|> fake_conn()
Expand All @@ -68,15 +95,22 @@ defmodule Alice.HandlersCase do
@doc """
Sends a message through Alice that can be captured by the handlers.

Can either be called with a `String` or with an `Alice.Conn`
Can either be called with a message `String` or `Alice.Conn`

## Examples

test "it sends a message" do
send_message("test message")
assert first_reply() == "reply from handler"
end

test "it sends a message with a conn" do
conn = fake_conn("test message")
send_message(conn)
assert first_reply() == "reply from handler"
end
"""
@spec send_message(String.t() | conn()) :: conn()
def send_message(conn = %Alice.Conn{}) do
case Alice.Conn.command?(conn) do
true -> Alice.Router.match_commands(conn)
Expand All @@ -101,6 +135,7 @@ defmodule Alice.HandlersCase do
assert all_replies() == ["first", "second"]
end
"""
@spec all_replies() :: [String.t()]
def all_replies() do
message =
receive do
Expand All @@ -126,6 +161,7 @@ defmodule Alice.HandlersCase do
assert first_reply() == "first"
end
"""
@spec first_reply() :: String.t()
def first_reply() do
case all_replies() do
[first_message | _] -> first_message
Expand All @@ -143,6 +179,7 @@ defmodule Alice.HandlersCase do
assert typing?
end
"""
@spec typing?() :: boolean()
def typing?() do
receive do
{:indicate_typing, _} -> true
Expand All @@ -159,7 +196,7 @@ defmodule Alice.HandlersCase do

quote do
use ExUnit.Case
import Alice.HandlersCase
import Alice.HandlerCase

setup do
Alice.Router.start_link(unquote(handlers))
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -5,11 +5,13 @@ defmodule Alice.ChatBackends.OutboundSpy do
@behaviour Alice.ChatBackends.OutboundClient

@doc "Sends the message back to the process so it can be retrieved later during the test"
@spec send_message(message :: String.t(), channel :: String.t(), slack :: map()) :: String.t()
def send_message(response, channel, slack) do
send(self(), {:send_message, %{response: response, channel: channel, slack: slack}})
end

@doc "Sends a message indicating typing back to the process so it can be retrieved later during the test"
@spec indicate_typing(channel :: String.t(), slack :: map()) :: String.t()
def indicate_typing(channel, slack) do
send(self(), {:indicate_typing, %{channel: channel, slack: slack}})
end
Expand Down
3 changes: 0 additions & 3 deletions mix.exs
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,6 @@ defmodule Alice.Mixfile do
app: :alice,
version: "0.4.2",
elixir: "~> 1.7",
elixirc_paths: elixirc_paths(Mix.env()),
build_embedded: Mix.env() == :prod,
start_permanent: Mix.env() == :prod,
description: "A Slack bot",
Expand Down Expand Up @@ -47,6 +46,4 @@ defmodule Alice.Mixfile do
}
]
end

defp elixirc_paths(_), do: ["test/support", "lib"]
end
2 changes: 1 addition & 1 deletion test/alice/earmuffs_test.exs
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
defmodule Alice.EarmuffsTest do
use Alice.HandlersCase, handlers: Alice.Earmuffs
use Alice.HandlerCase, handlers: Alice.Earmuffs

alias Alice.Conn
alias Alice.Earmuffs
Expand Down
2 changes: 1 addition & 1 deletion test/alice/handlers/help_test.exs
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@ defmodule Alice.Handlers.HelpTest do
TestHandler
}

use Alice.HandlersCase, handlers: [Help, TestHandler]
use Alice.HandlerCase, handlers: [Help, TestHandler]

test "general_help lists the handlers as well as some other info" do
send_message("<@alice> help")
Expand Down
2 changes: 1 addition & 1 deletion test/alice/handlers/utils_test.exs
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
defmodule Alice.Handlers.UtilsTest do
use Alice.HandlersCase, handlers: Alice.Handlers.Utils
use Alice.HandlerCase, handlers: Alice.Handlers.Utils

test "it responds to a ping route" do
send_message("ping")
Expand Down
6 changes: 3 additions & 3 deletions test/alice/handlers_case_test.exs
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
defmodule Alice.HandlersCaseTest.TestHandler do
defmodule Alice.HandlerCaseTest.TestHandler do
use Alice.Router

route ~r/type/, :typing_route
Expand All @@ -14,8 +14,8 @@ defmodule Alice.HandlersCaseTest.TestHandler do
end
end

defmodule Alice.HandlersCaseTest do
use Alice.HandlersCase, handlers: Alice.HandlersCaseTest.TestHandler
defmodule Alice.HandlerCaseTest do
use Alice.HandlerCase, handlers: Alice.HandlerCaseTest.TestHandler
alias Alice.Conn

test "fake_conn makes a conn" do
Expand Down
2 changes: 1 addition & 1 deletion test/alice/router/helpers_test.exs
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
defmodule Alice.Router.HelpersTest do
use Alice.HandlersCase
use Alice.HandlerCase
import Alice.Router.Helpers

test "reply returns the conn" do
Expand Down
2 changes: 1 addition & 1 deletion test/alice/router_test.exs
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,7 @@ defmodule Alice.RouterTest.TestHandler do
end

defmodule Alice.RouterTest do
use Alice.HandlersCase, handlers: Alice.RouterTest.TestHandler
use Alice.HandlerCase, handlers: Alice.RouterTest.TestHandler

alias Alice.RouterTest.TestHandler
alias Alice.Router
Expand Down