(UndefinedFunctionError) function HTTPoison.request/5 is undefined (module HTTPoison is not available

I am facing a unique(?) problem.

I have unit tests and integration tests

Both call the same set of functions.

All the integration tests pass (mix test --include integration test/integration/gateways/mercadopago_test.exs)

All the unit tests fail (mix test test/gateways/mercadopago_test.exs)

For every unit test , I get the same error :

** (UndefinedFunctionError) function HTTPoison.request/5 is undefined (module HTTPoison is not available)

Stack trace points to lib/gringotts/gateways/mercadopago.ex:264: Gringotts.Gateways.Mercadopago.commit/5

Searching for module not available points to solutions that do not apply.

Most suggest including httpoison in mix.exs - which was already have (https://github.com/aviabird/gringotts/blob/mercadopago-2020/mix.exs#L40)

Other suggestion is about elixirc_paths - which also taken care of (https://github.com/aviabird/gringotts/blob/mercadopago-2020/mix.exs#L19)

BTW, I’m a n00b at elixir, so I may be overlooking something obvious.

I’ve already asked for helped in local elixir discord channel. No luck.

Thanks for any suggestions/ideas.

1 Like

So, many versions of Elixir ago, you had to manage the applications list as you are doing here. That is no longer true and will cause issues. I’d remove that line entirely.

Have you tried the simple rm -rf _build and recompile approach?

Also, what version of elixir are you running? elixir --version

1 Like
$ elixir --version
Erlang/OTP 20 [erts-9.2] [source] [64-bit] [smp:4:4] [ds:4:4:10] [async-threads:10] [kernel-poll:false]

Elixir 1.7.4 (compiled with Erlang/OTP 20)

BTW, this is the highest version I can use. (project’s travis.yml uses 1.5.3/1.6.5)

I tried rm -rf _build followed directly by mix test test/gateways/mercadopago_test.exs

Same results :cry:

I’m pretty sure that your test errors are related to the use of the Mock library, but I’m not sure what the resolution would be if you still want to use the library (I’m generally not a fan of that approach to mocking). Also running the tests under Elixir 1.10.2 with Erlang 22.1.7 I get the following error:

  1) test purchase with valid card (Gringotts.Gateways.GlobalCollectTest)
     test/gateways/global_collect_test.exs:92

** (ErlangError) Erlang error: {:compile_forms, {:error, [{[], [{:none, :compile, {:crash, :sys_core_fold, {{:case_clause, {:EXIT, {:function_clause, [{:sys_core_fold, :module, [[{:attribute, 44, :file, {'lib/httpoison.ex', 44}}, {:attribute, 44, :module, HTTPoison_meck_original}, {:attribute, 44, :compile, [:no_auto_import]}, {:attribute, 66, :spec, {{:transformer, 1}, [{:type, 66, :fun, [{:type, 66, :product, [{:type, 66, :pid, ...}]}, {:atom, 0, :ok}]}]}}, {:attribute, 66, :spec, {{:stream_next, 1}, [{:type, 66, :fun, [{:type, 66, :product, [{:remote_type, 66, ...}]}, {:type, 66, :union, [{:type, ...}, {...}]}]}]}}, {:attribute, 66, :spec, {{:request!, 5}, [{:type, 66, :fun, [{:type, 66, :product, [{:type, ...}, {...}, ...]}, {:type, 66, :union, [{...}, ...]}]}]}}, {:attribute, 66, :spec, {{:request, 5}, [{:type, 66, :fun, [{:type, 66, :product, [{...}, ...]}, {:type, 66, :union, [...]}]}]}}, {:attribute, 66, :spec, {{:put!, 4}, [{:type, 66, :fun, [{:type, 66, :product, [...]}, {:type, 66, :union, ...}]}]}}, {:attribute, 66, :spec, {{:put, 4}, [{:type, 66, :fun, [{:type, 66, :product, ...}, {:type, 66, ...}]}]}}, {:attribute, 66, :spec, {{:process_response_body, 1}, [{:type, 66, :fun, [{:type, 66, ...}, {:type, ...}]}]}}, {:attribute, 66, :spec, {{:process_request_headers, 1}, [{:type, 66, :fun, [{:type, ...}, {...}]}]}}, {:attribute, 66, :spec, {{:process_request_body, 1}, [{:type, 66, :fun, [{...}, ...]}]}}, {:attribute, 66, :spec, {{:post!, 4}, [{:type, 66, :fun, [...]}]}}, {:attribute, 66, :spec, {{:post, 4}, [{:type, 66, :fun, ...}]}}, {:attribute, 66, :spec, {{:patch!, 4}, [{:type, 66, ...}]}}, {:attribute, 66, :spec, {{:patch, 4}, [{:type, ...}]}}, {:attribute, 66, :spec, {{:options!, 3}, [{...}]}}, {:attribute, 66, :spec, {{:options, ...}, [...]}}, {:attribute, 66, :spec, {{...}, ...}}, {:attribute, 66, :spec, {...}}, {:attribute, 66, :spec, ...}, {:attribute, 66, ...}, {:attribute, ...}, {...}, ...], [:binary, :return_errors, :debug_info, :no_spawn_compiler_process, :from_core, :no_auto_import]], [file: 'sys_core_fold.erl', line: 109]}, {:compile, :"-select_passes/2-anonymous-2-", 3, [file: 'compile.erl', line: 675]}, {:compile, :"-internal_comp/5-anonymous-1-", 3, [file: 'compile.erl', line: 399]}, {:compile, :fold_comp, 4, [file: 'compile.erl', line: 426]}, {:compile, :internal_comp, 5, [file: 'compile.erl', line: 410]}, {:compile, :"-do_compile/2-anonymous-0-", 2, [file: 'compile.erl', line: 207]}, {:meck_code, :compile_and_load_forms, 2, [file: '/home/jason/dev/forks/tmp/gringotts/deps/meck/src/meck_code.erl', line: 71]}, {:meck_proc, :backup_original, 3, [file: '/home/jason/dev/forks/tmp/gringotts/deps/meck/src/meck_proc.erl', line: 363]}, {:meck_proc, :init, 1, [file: '/home/jason/dev/forks/tmp/gringotts/deps/meck/src/meck_proc.erl', line: 206]}, {:gen_server, :init_it, 2, [file: 'gen_server.erl', line: 374]}, {:gen_server, :init_it, 6, [file: 'gen_server.erl', line: 342]}, {:proc_lib, :init_p_do_apply, 3, [file: 'proc_lib.erl', line: 249]}]}}}, [{:compile, :"-select_passes/2-anonymous-2-", 3, [file: 'compile.erl', line: 675]}, {:compile, :"-internal_comp/5-anonymous-1-", 3, [file: 'compile.erl', line: 399]}, {:compile, :fold_comp, 4, [file: 'compile.erl', line: 426]}, {:compile, :internal_comp, 5, [file: 'compile.erl', line: 410]}, {:compile, :"-do_compile/2-anonymous-0-", 2, [file: 'compile.erl', line: 207]}, {:meck_code, :compile_and_load_forms, 2, [file: '/home/jason/dev/forks/tmp/gringotts/deps/meck/src/meck_code.erl', line: 71]}, {:meck_proc, :backup_original, 3, [file: '/home/jason/dev/forks/tmp/gringotts/deps/meck/src/meck_proc.erl', line: 363]}, {:meck_proc, :init, 1, [file: '/home/jason/dev/forks/tmp/gringotts/deps/meck/src/meck_proc.erl', line: 206]}, {:gen_server, :init_it, 2, [file: 'gen_server.erl', line: 374]}, {:gen_server, :init_it, 6, [file: 'gen_server.erl', line: 342]}, {:proc_lib, :init_p_do_apply, 3, [file: 'proc_lib.erl', line: 249]}]}}}]}], []}}

As I mentioned, we can’t use latest Elixir/Erlang. I tried 1.9.x (at first) and I too got errors, though I don’t remember what those were.
Even 1.8 wouldn’t work.

Anyway - why do you think this is related to Mock library ?
There are two more payment gateway integrations authorize.net and cams in the same repo.

Their unit tests pass successfully :man_shrugging:

All the unit tests start with a similar structure:

with_mock HTTPoison, post: fn _url, _body, _headers ->

that’s mocking the post function on HTTPoison. But the line that’s failing is using a lower-level HTTPoison function:

    res = HTTPoison.request(method, url, body, headers,
      opts ++ [params: [access_token: opts[:config][:access_token]]])

Under the hood, HTTPoison.post calls HTTPoison.request:

Also note this important detail from the Mock documentation

By default, only the functions being mocked can be accessed from within the test.

@al2o3cr What you say makes sense. I’m gonna use Bypass instead of Mock

But I’m wondering why do other two test (files) for cams and authorize.net that use similar pattern (and Mock) work ? I confirmed that these two directly use HTTPoison.post inside commit function - hence their with_mock block works.

1 Like