diff --git a/CHANGELOG.md b/CHANGELOG.md index 4d91615..2145721 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -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 diff --git a/README.md b/README.md index 0dc8339..dd6b57e 100644 --- a/README.md +++ b/README.md @@ -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 ``` diff --git a/lib/http_ex/backend/mock.ex b/lib/http_ex/backend/mock.ex index caddeea..a436cb0 100644 --- a/lib/http_ex/backend/mock.ex +++ b/lib/http_ex/backend/mock.ex @@ -112,6 +112,7 @@ defmodule HTTPEx.Backend.Mock do @allwed_expect_request_options [ :body, :body_format, + :calls, :description, :expect_body, :expect_body_format, diff --git a/lib/http_ex/backend/mock/expectation.ex b/lib/http_ex/backend/mock/expectation.ex index b34cd33..c1d696d 100644 --- a/lib/http_ex/backend/mock/expectation.ex +++ b/lib/http_ex/backend/mock/expectation.ex @@ -169,7 +169,8 @@ defmodule HTTPEx.Backend.Mock.Expectation do - expect_headers - expect_path - expect_query - - calls + - min_calls + - max_calls - stacktrace ## Examples @@ -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 = diff --git a/mix.exs b/mix.exs index e92c40b..bbc59a6 100644 --- a/mix.exs +++ b/mix.exs @@ -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 diff --git a/test/http_ex/backend/mock_test.exs b/test/http_ex/backend/mock_test.exs index c6eba80..28c4774 100644 --- a/test/http_ex/backend/mock_test.exs +++ b/test/http_ex/backend/mock_test.exs @@ -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