Skip to content
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
6 changes: 6 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
@@ -1,5 +1,11 @@
# Changelog

## v0.2.3 (2025-07-22)

### Bug Fixes

- Fixed `max_calls` and `min_calls` options not being respected in `expect_request!`

## v0.2.2 (2025-04-30)

### Bug Fixes
Expand Down
2 changes: 1 addition & 1 deletion README.md
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,7 @@ by adding `http_ex` to your list of dependencies in `mix.exs`:
```elixir
def deps do
[
{:http_ex, "~> 0.2.2"}
{:http_ex, "~> 0.2.3"}
]
end
```
1 change: 1 addition & 0 deletions lib/http_ex/backend/mock.ex
Original file line number Diff line number Diff line change
Expand Up @@ -112,6 +112,7 @@ defmodule HTTPEx.Backend.Mock do
@allwed_expect_request_options [
:body,
:body_format,
:calls,
:description,
:expect_body,
:expect_body_format,
Expand Down
17 changes: 13 additions & 4 deletions lib/http_ex/backend/mock/expectation.ex
Original file line number Diff line number Diff line change
Expand Up @@ -169,7 +169,8 @@ defmodule HTTPEx.Backend.Mock.Expectation do
- expect_headers
- expect_path
- expect_query
- calls
- min_calls
- max_calls
- stacktrace

## Examples
Expand All @@ -184,9 +185,17 @@ defmodule HTTPEx.Backend.Mock.Expectation do

{min_calls, max_calls} =
case type do
:stub -> {0, :infinity}
:reject -> {0, 0}
:assert -> {1, Keyword.get(opts, :calls, 1)}
:stub ->
{0, :infinity}

:reject ->
{0, 0}

:assert ->
min = Keyword.get(opts, :min_calls, 1)
max = Keyword.get(opts, :max_calls) || Keyword.get(opts, :calls, min)

{min, max}
end

expectation_type =
Expand Down
2 changes: 1 addition & 1 deletion mix.exs
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,7 @@ defmodule HttpEx.MixProject do
source_url: "https://github.com/wuunder/http_ex",
start_permanent: Mix.env() == :prod,
test_coverage: [tool: ExCoveralls],
version: "0.2.2"
version: "0.2.3"
]
end

Expand Down
139 changes: 139 additions & 0 deletions test/http_ex/backend/mock_test.exs
Original file line number Diff line number Diff line change
Expand Up @@ -183,5 +183,144 @@ defmodule HTTPEx.Backend.MockTest do
Mock.verify!(self())
end
end

test "raise when less requests than min_calls expects are made" do
Mock.expect_request!(
endpoint: "http://www.example.com",
min_calls: 3,
response: %{status: 200, body: "OK"}
)

Enum.each(1..2, fn _ ->
Mock.request(%Request{
client: :httpoison,
url: "http://www.example.com",
method: :get
})
end)

assert_raise AssertionError,
~r/An expected HTTP call was called 2 but was expected to be called 3 times/,
fn ->
Mock.verify!(self())
end
end

test "does not raise an error when minimum amount of calls is reached" do
Mock.expect_request!(
endpoint: "http://www.example.com",
min_calls: 2,
response: %{status: 200, body: "OK"}
)

Enum.each(1..2, fn _ ->
Mock.request(%Request{
client: :httpoison,
url: "http://www.example.com",
method: :get
})
end)

Mock.verify!(self())
end

test "does not raise an error with the accepted amount of requests" do
Mock.expect_request!(
endpoint: "http://www.example.com",
min_calls: 1,
max_calls: 5,
response: %{status: 200, body: "OK"}
)

Enum.each(1..3, fn _ ->
Mock.request(%Request{
client: :httpoison,
url: "http://www.example.com",
method: :get
})
end)

Mock.verify!(self())
end

test "raises when too many requests are made" do
Mock.expect_request!(
endpoint: "http://www.example.com",
min_calls: 2,
max_calls: 3,
response: %{status: 200, body: "OK"}
)

Enum.each(1..3, fn _ ->
Mock.request(%Request{
client: :httpoison,
url: "http://www.example.com",
method: :get
})
end)

assert_raise AssertionError,
~r/Maximum number of HTTP calls already made for request/,
fn ->
Mock.request(%Request{
client: :httpoison,
url: "http://www.example.com",
method: :get
})
end
end

test "backward compatibility with calls option" do
Mock.expect_request!(
endpoint: "http://www.example.com",
calls: 2,
response: %{status: 200, body: "OK"}
)

Enum.each(1..2, fn _ ->
Mock.request(%Request{
client: :httpoison,
url: "http://www.example.com",
method: :get
})
end)

assert_raise AssertionError,
~r/Maximum number of HTTP calls already made for request/,
fn ->
Mock.request(%Request{
client: :httpoison,
url: "http://www.example.com",
method: :get
})
end
end

test "max_calls takes precedence over calls option" do
Mock.expect_request!(
endpoint: "http://www.example.com",
calls: 5,
max_calls: 2,
response: %{status: 200, body: "OK"}
)

Enum.each(1..2, fn _ ->
Mock.request(%Request{
client: :httpoison,
url: "http://www.example.com",
method: :get
})
end)

assert_raise AssertionError,
~r/Maximum number of HTTP calls already made for request/,
fn ->
Mock.request(%Request{
client: :httpoison,
url: "http://www.example.com",
method: :get
})
end
end
end
end