Skip to content

Commit

Permalink
[monei] Test fixes (#116)
Browse files Browse the repository at this point in the history
* Ignore some optional params for RF, RV, CP

Some optional params like billing, customer, merchant must not be
expanded in case of capture, refund and void.

* Improved mock tests, fixes #98

Mock tests now mostly check if the request is correctly built.
Since most requests have common parameters, they are not checked
everywhere.

* Improve integration tests (more cases), fixes #108

* Integration tests no longer use the worker as a workaround for #8
* Added more test cases, can possibly be improved using describe blocks with
local setup.
* There are almost no assertions and it is expected that errors will
bubble up to the pattern matches.
  • Loading branch information
oyeb authored and ashish173 committed Apr 22, 2018
1 parent 1e7a8bd commit 162a1e0
Show file tree
Hide file tree
Showing 4 changed files with 195 additions and 98 deletions.
67 changes: 47 additions & 20 deletions lib/gringotts/gateways/monei.ex
Original file line number Diff line number Diff line change
Expand Up @@ -338,6 +338,8 @@ defmodule Gringotts.Gateways.Monei do
which can be used to effectively process _One-Click_ and _Recurring_ payments,
and return a registration token for reference.
The registration token is available in the `Response.id` field.
It is recommended to associate these details with a "Customer" by passing
customer details in the `opts`.
Expand All @@ -352,7 +354,8 @@ defmodule Gringotts.Gateways.Monei do
future use.
iex> card = %Gringotts.CreditCard{first_name: "Harry", last_name: "Potter", number: "4200000000000000", year: 2099, month: 12, verification_code: "123", brand: "VISA"}
iex> {:ok, store_result} = Gringotts.store(Gringotts.Gateways.Monei, card, [])
iex> {:ok, store_result} = Gringotts.store(Gringotts.Gateways.Monei, card)
iex> store_result.id # This is the registration token
"""
@spec store(CreditCard.t(), keyword) :: {:ok | :error, Response.t()}
def store(%CreditCard{} = card, opts) do
Expand Down Expand Up @@ -438,7 +441,7 @@ defmodule Gringotts.Gateways.Monei do
defp commit(:post, endpoint, params, opts) do
url = "#{base_url(opts)}/#{version(opts)}/#{endpoint}"

case expand_params(opts, params[:paymentType]) do
case expand_params(Keyword.delete(opts, :config), params[:paymentType]) do
{:error, reason} ->
{:error, Response.error(reason: reason)}

Expand Down Expand Up @@ -528,16 +531,16 @@ defmodule Gringotts.Gateways.Monei do
else: {:halt, {:error, "Invalid currency"}}

:customer ->
{:cont, acc ++ make("customer", v)}
{:cont, acc ++ make(action_type, "customer", v)}

:merchant ->
{:cont, acc ++ make("merchant", v)}
{:cont, acc ++ make(action_type, "merchant", v)}

:billing ->
{:cont, acc ++ make("billing", v)}
{:cont, acc ++ make(action_type, "billing", v)}

:shipping ->
{:cont, acc ++ make("shipping", v)}
{:cont, acc ++ make(action_type, "shipping", v)}

:invoice_id ->
{:cont, [{"merchantInvoiceId", v} | acc]}
Expand All @@ -549,23 +552,16 @@ defmodule Gringotts.Gateways.Monei do
{:cont, [{"transactionCategory", v} | acc]}

:shipping_customer ->
{:cont, acc ++ make("shipping.customer", v)}
{:cont, acc ++ make(action_type, "shipping.customer", v)}

:custom ->
{:cont, acc ++ make_custom(v)}

:register ->
{
:cont,
if action_type in ["PA", "DB"] do
[{"createRegistration", true} | acc]
else
acc
end
}

_ ->
{:cont, acc}
{:cont, acc ++ make(action_type, :register, v)}

unsupported ->
{:halt, {:error, "Unsupported optional param '#{unsupported}'"}}
end
end)
end
Expand All @@ -574,8 +570,39 @@ defmodule Gringotts.Gateways.Monei do
currency in @supported_currencies
end

defp make(prefix, param) do
Enum.into(param, [], fn {k, v} -> {"#{prefix}.#{k}", v} end)
defp parse_response(%{"result" => result} = data) do
{address, zip_code} = @avs_code_translator[result["avsResponse"]]

results = [
code: result["code"],
description: result["description"],
risk: data["risk"]["score"],
cvc_result: @cvc_code_translator[result["cvvResponse"]],
avs_result: [address: address, zip_code: zip_code],
raw: data,
token: data["registrationId"]
]

filtered = Enum.filter(results, fn {_, v} -> v != nil end)
verify(filtered)
end

defp verify(results) do
if String.match?(results[:code], ~r{^(000\.000\.|000\.100\.1|000\.[36])}) do
{:ok, results}
else
{:error, [{:reason, results[:description]} | results]}
end
end

defp make(action_type, _prefix, _param) when action_type in ["CP", "RF", "RV"], do: []
defp make(action_type, prefix, param) do
case prefix do
:register ->
if action_type in ["PA", "DB"], do: [createRegistration: true], else: []

_ -> Enum.into(param, [], fn {k, v} -> {"#{prefix}.#{k}", v} end)
end
end

defp make_custom(custom_map) do
Expand Down
12 changes: 6 additions & 6 deletions mix.lock
Original file line number Diff line number Diff line change
Expand Up @@ -12,11 +12,11 @@
"earmark": {:hex, :earmark, "1.2.4", "99b637c62a4d65a20a9fb674b8cffb8baa771c04605a80c911c4418c69b75439", [:mix], [], "hexpm"},
"elixir_xml_to_map": {:hex, :elixir_xml_to_map, "0.1.1", "57e924cd11731947bfd245ce57d0b8dd8b7168bf8edb20cd156a2982ca96fdfa", [:mix], [{:erlsom, "~>1.4", [hex: :erlsom, repo: "hexpm", optional: false]}], "hexpm"},
"erlsom": {:hex, :erlsom, "1.4.1", "53dbacf35adfea6f0714fd0e4a7b0720d495e88c5e24e12c5dc88c7b62bd3e49", [:rebar3], [], "hexpm"},
"ex_cldr": {:hex, :ex_cldr, "1.1.0", "26f4a206307770b70139214ab820c5ed1f6241eb3394dd0db216ff95bf7e213a", [:mix], [{:abnf2, "~> 0.1", [hex: :abnf2, repo: "hexpm", optional: false]}, {:decimal, "~> 1.4", [hex: :decimal, repo: "hexpm", optional: false]}, {:gettext, "~> 0.13", [hex: :gettext, repo: "hexpm", optional: true]}, {:poison, "~> 2.1 or ~> 3.0", [hex: :poison, repo: "hexpm", optional: true]}], "hexpm"},
"ex_cldr_numbers": {:hex, :ex_cldr_numbers, "1.1.0", "75904f202ca602eca5f3af572d56ed3d4a51543fecd08c9ab626ae2d876f44da", [:mix], [{:decimal, "~> 1.4", [hex: :decimal, repo: "hexpm", optional: false]}, {:ex_cldr, "~> 1.0", [hex: :ex_cldr, repo: "hexpm", optional: false]}, {:poison, "~> 2.1 or ~> 3.1", [hex: :poison, repo: "hexpm", optional: false]}], "hexpm"},
"ex_doc": {:hex, :ex_doc, "0.18.1", "37c69d2ef62f24928c1f4fdc7c724ea04aecfdf500c4329185f8e3649c915baf", [:mix], [{:earmark, "~> 1.1", [hex: :earmark, repo: "hexpm", optional: false]}], "hexpm"},
"ex_money": {:hex, :ex_money, "1.1.2", "4336192f1ac263900dfb4f63c1f71bc36a7cdee5d900e81937d3213be3360f9f", [:mix], [{:decimal, "~> 1.4", [hex: :decimal, repo: "hexpm", optional: false]}, {:ecto, "~> 2.1", [hex: :ecto, repo: "hexpm", optional: true]}, {:ex_cldr, "~> 1.0", [hex: :ex_cldr, repo: "hexpm", optional: false]}, {:ex_cldr_numbers, "~> 1.0", [hex: :ex_cldr_numbers, repo: "hexpm", optional: false]}], "hexpm"},
"excoveralls": {:hex, :excoveralls, "0.8.0", "99d2691d3edf8612f128be3f9869c4d44b91c67cec92186ce49470ae7a7404cf", [:mix], [{:exjsx, ">= 3.0.0", [hex: :exjsx, repo: "hexpm", optional: false]}, {:hackney, ">= 0.12.0", [hex: :hackney, repo: "hexpm", optional: false]}], "hexpm"},
"ex_cldr": {:hex, :ex_cldr, "1.4.4", "654966e8724d607e5cf9ecd5509ffcf66868b17e479bbd22ab2e9123595f9103", [:mix], [{:abnf2, "~> 0.1", [hex: :abnf2, repo: "hexpm", optional: false]}, {:decimal, "~> 1.4", [hex: :decimal, repo: "hexpm", optional: false]}, {:gettext, "~> 0.13", [hex: :gettext, repo: "hexpm", optional: true]}, {:jason, "~> 1.0", [hex: :jason, repo: "hexpm", optional: true]}, {:phoenix, "~> 1.3", [hex: :phoenix, repo: "hexpm", optional: true]}, {:plug, "~> 1.4", [hex: :plug, repo: "hexpm", optional: true]}, {:poison, "~> 2.1 or ~> 3.0", [hex: :poison, repo: "hexpm", optional: true]}, {:sweet_xml, "~> 0.6", [hex: :sweet_xml, repo: "hexpm", optional: true]}], "hexpm"},
"ex_cldr_numbers": {:hex, :ex_cldr_numbers, "1.3.1", "50a117654dff8f8ee6958e68a65d0c2835a7e2f1aff94c1ea8f582c04fdf0bd4", [:mix], [{:decimal, "~> 1.4", [hex: :decimal, repo: "hexpm", optional: false]}, {:ex_cldr, "~> 1.4.0", [hex: :ex_cldr, repo: "hexpm", optional: false]}, {:jason, "~> 1.0", [hex: :jason, repo: "hexpm", optional: true]}, {:poison, "~> 2.1 or ~> 3.1", [hex: :poison, repo: "hexpm", optional: true]}], "hexpm"},
"ex_doc": {:hex, :ex_doc, "0.18.3", "f4b0e4a2ec6f333dccf761838a4b253d75e11f714b85ae271c9ae361367897b7", [:mix], [{:earmark, "~> 1.1", [hex: :earmark, repo: "hexpm", optional: false]}], "hexpm"},
"ex_money": {:hex, :ex_money, "1.1.3", "843eed0a5673206de33be47cdc06574401abc3e2d33cbcf6d74e160226791ae4", [:mix], [{:decimal, "~> 1.4", [hex: :decimal, repo: "hexpm", optional: false]}, {:ecto, "~> 2.1", [hex: :ecto, repo: "hexpm", optional: true]}, {:ex_cldr, "~> 1.0", [hex: :ex_cldr, repo: "hexpm", optional: false]}, {:ex_cldr_numbers, "~> 1.0", [hex: :ex_cldr_numbers, repo: "hexpm", optional: false]}], "hexpm"},
"excoveralls": {:hex, :excoveralls, "0.8.1", "0bbf67f22c7dbf7503981d21a5eef5db8bbc3cb86e70d3798e8c802c74fa5e27", [:mix], [{:exjsx, ">= 3.0.0", [hex: :exjsx, repo: "hexpm", optional: false]}, {:hackney, ">= 0.12.0", [hex: :hackney, repo: "hexpm", optional: false]}], "hexpm"},
"exjsx": {:hex, :exjsx, "4.0.0", "60548841e0212df401e38e63c0078ec57b33e7ea49b032c796ccad8cde794b5c", [:mix], [{:jsx, "~> 2.8.0", [hex: :jsx, repo: "hexpm", optional: false]}], "hexpm"},
"gettext": {:hex, :gettext, "0.15.0", "40a2b8ce33a80ced7727e36768499fc9286881c43ebafccae6bab731e2b2b8ce", [:mix], [], "hexpm"},
"hackney": {:hex, :hackney, "1.11.0", "4951ee019df102492dabba66a09e305f61919a8a183a7860236c0fde586134b6", [:rebar3], [{:certifi, "2.0.0", [hex: :certifi, repo: "hexpm", optional: false]}, {:idna, "5.1.0", [hex: :idna, repo: "hexpm", optional: false]}, {:metrics, "1.0.1", [hex: :metrics, repo: "hexpm", optional: false]}, {:mimerl, "1.0.2", [hex: :mimerl, repo: "hexpm", optional: false]}, {:ssl_verify_fun, "1.1.1", [hex: :ssl_verify_fun, repo: "hexpm", optional: false]}], "hexpm"},
Expand All @@ -29,7 +29,7 @@
"mime": {:hex, :mime, "1.2.0", "78adaa84832b3680de06f88f0997e3ead3b451a440d183d688085be2d709b534", [:mix], [], "hexpm"},
"mimerl": {:hex, :mimerl, "1.0.2", "993f9b0e084083405ed8252b99460c4f0563e41729ab42d9074fd5e52439be88", [:rebar3], [], "hexpm"},
"mock": {:hex, :mock, "0.3.1", "994f00150f79a0ea50dc9d86134cd9ebd0d177ad60bd04d1e46336cdfdb98ff9", [:mix], [{:meck, "~> 0.8.8", [hex: :meck, repo: "hexpm", optional: false]}], "hexpm"},
"plug": {:hex, :plug, "1.4.3", "236d77ce7bf3e3a2668dc0d32a9b6f1f9b1f05361019946aae49874904be4aed", [:mix], [{:cowboy, "~> 1.0.1 or ~> 1.1", [hex: :cowboy, repo: "hexpm", optional: true]}, {:mime, "~> 1.0", [hex: :mime, repo: "hexpm", optional: false]}], "hexpm"},
"plug": {:hex, :plug, "1.5.0", "224b25b4039bedc1eac149fb52ed456770b9678bbf0349cdd810460e1e09195b", [:mix], [{:cowboy, "~> 1.0.1 or ~> 1.1 or ~> 2.1", [hex: :cowboy, repo: "hexpm", optional: true]}, {:mime, "~> 1.0", [hex: :mime, repo: "hexpm", optional: false]}], "hexpm"},
"poison": {:hex, :poison, "3.1.0", "d9eb636610e096f86f25d9a46f35a9facac35609a7591b3be3326e99a0484665", [:mix], [], "hexpm"},
"ranch": {:hex, :ranch, "1.3.2", "e4965a144dc9fbe70e5c077c65e73c57165416a901bd02ea899cfd95aa890986", [:rebar3], [], "hexpm"},
"ssl_verify_fun": {:hex, :ssl_verify_fun, "1.1.1", "28a4d65b7f59893bc2c7de786dec1e1555bd742d336043fe644ae956c3497fbe", [:make, :rebar], [], "hexpm"},
Expand Down
110 changes: 74 additions & 36 deletions test/gateways/monei_test.exs
Original file line number Diff line number Diff line change
Expand Up @@ -39,7 +39,7 @@ defmodule Gringotts.Gateways.MoneiTest do
birthDate: "1980-07-31",
mobile: "+15252525252",
email: "masterofdeath@ministryofmagic.gov",
ip: "1.1.1",
ip: "127.0.0.1",
status: "NEW"
}
@merchant %{
Expand Down Expand Up @@ -96,7 +96,7 @@ defmodule Gringotts.Gateways.MoneiTest do
"card":{
"bin":"420000",
"last4Digits":"0000",
"holder":"Jo Doe",
"holder":"Harry Potter",
"expiryMonth":"12",
"expiryYear":"2099"
}
Expand All @@ -123,16 +123,24 @@ defmodule Gringotts.Gateways.MoneiTest do
end

test "when MONEI is down or unreachable.", %{bypass: bypass, auth: auth} do
Bypass.expect_once(bypass, fn conn ->
Plug.Conn.resp(conn, 200, @auth_success)
end)

Bypass.down(bypass)
{:error, response} = Gateway.authorize(@amount42, @card, config: auth)
assert response.reason == "network related failure"

Bypass.up(bypass)
{:ok, _} = Gateway.authorize(@amount42, @card, config: auth)
end

test "that all auth info is picked.", %{bypass: bypass, auth: auth} do
Bypass.expect_once(bypass, "POST", "/v1/payments", fn conn ->
p_conn = parse(conn)
params = p_conn.body_params
assert params["authentication.entityId"] == "some_secret_entity_id"
assert params["authentication.password"] == "some_secret_password"
assert params["authentication.userId"] == "some_secret_user_id"
Plug.Conn.resp(conn, 200, @auth_success)
end)

{:ok, response} = Gateway.purchase(@amount42, @card, config: auth)
assert response.gateway_code == "000.100.110"
end

test "with all extra_params.", %{bypass: bypass, auth: auth} do
Expand All @@ -142,20 +150,21 @@ defmodule Gringotts.Gateways.MoneiTest do
]

Bypass.expect_once(bypass, "POST", "/v1/payments", fn conn ->
conn_ = parse(conn)
assert conn_.body_params["createRegistration"] == "true"
assert conn_.body_params["customParameters"] == @extra_opts[:custom]
assert conn_.body_params["merchantInvoiceId"] == randoms[:invoice_id]
assert conn_.body_params["merchantTransactionId"] == randoms[:transaction_id]
assert conn_.body_params["transactionCategory"] == @extra_opts[:category]
assert conn_.body_params["customer.merchantCustomerId"] == @customer[:merchantCustomerId]

assert conn_.body_params["shipping.customer.merchantCustomerId"] ==
p_conn = parse(conn)
params = p_conn.body_params
assert params["createRegistration"] == "true"
assert params["customParameters"] == @extra_opts[:custom]
assert params["merchantInvoiceId"] == randoms[:invoice_id]
assert params["merchantTransactionId"] == randoms[:transaction_id]
assert params["transactionCategory"] == @extra_opts[:category]
assert params["customer.merchantCustomerId"] == @customer[:merchantCustomerId]

assert params["shipping.customer.merchantCustomerId"] ==
@customer[:merchantCustomerId]

assert conn_.body_params["merchant.submerchantId"] == @merchant[:submerchantId]
assert conn_.body_params["billing.city"] == @billing[:city]
assert conn_.body_params["shipping.method"] == @shipping[:method]
assert params["merchant.submerchantId"] == @merchant[:submerchantId]
assert params["billing.city"] == @billing[:city]
assert params["shipping.method"] == @shipping[:method]
Plug.Conn.resp(conn, 200, @register_success)
end)

Expand All @@ -165,7 +174,7 @@ defmodule Gringotts.Gateways.MoneiTest do
assert response.token == "8a82944a60e09c550160e92da144491e"
end

test "when card has expired.", %{bypass: bypass, auth: auth} do
test "when we get non-json.", %{bypass: bypass, auth: auth} do
Bypass.expect_once(bypass, "POST", "/v1/payments", fn conn ->
Plug.Conn.resp(conn, 400, "<html></html>")
end)
Expand All @@ -177,6 +186,11 @@ defmodule Gringotts.Gateways.MoneiTest do
describe "authorize" do
test "when all is good.", %{bypass: bypass, auth: auth} do
Bypass.expect(bypass, "POST", "/v1/payments", fn conn ->
p_conn = parse(conn)
params = p_conn.body_params
assert params["amount"] == "42.00"
assert params["currency"] == "USD"
assert params["paymentType"] == "PA"
Plug.Conn.resp(conn, 200, @auth_success)
end)

Expand All @@ -188,6 +202,11 @@ defmodule Gringotts.Gateways.MoneiTest do
describe "purchase" do
test "when all is good.", %{bypass: bypass, auth: auth} do
Bypass.expect_once(bypass, "POST", "/v1/payments", fn conn ->
p_conn = parse(conn)
params = p_conn.body_params
assert params["amount"] == "42.00"
assert params["currency"] == "USD"
assert params["paymentType"] == "DB"
Plug.Conn.resp(conn, 200, @auth_success)
end)

Expand All @@ -197,8 +216,9 @@ defmodule Gringotts.Gateways.MoneiTest do

test "with createRegistration.", %{bypass: bypass, auth: auth} do
Bypass.expect_once(bypass, "POST", "/v1/payments", fn conn ->
conn_ = parse(conn)
assert conn_.body_params["createRegistration"] == "true"
p_conn = parse(conn)
params = p_conn.body_params
assert params["createRegistration"] == "true"
Plug.Conn.resp(conn, 200, @register_success)
end)

Expand All @@ -211,6 +231,14 @@ defmodule Gringotts.Gateways.MoneiTest do
describe "store" do
test "when all is good.", %{bypass: bypass, auth: auth} do
Bypass.expect_once(bypass, "POST", "/v1/registrations", fn conn ->
p_conn = parse(conn)
params = p_conn.body_params
params["card.cvv"] == "123"
params["card.expiryMonth"] == "12"
params["card.expiryYear"] == "2099"
params["card.holder"] == "Harry Potter"
params["card.number"] == "4200000000000000"
params["paymentBrand"] == "VISA"
Plug.Conn.resp(conn, 200, @store_success)
end)

Expand All @@ -226,6 +254,11 @@ defmodule Gringotts.Gateways.MoneiTest do
"POST",
"/v1/payments/7214344242e11af79c0b9e7b4f3f6234",
fn conn ->
p_conn = parse(conn)
params = p_conn.body_params
assert params["amount"] == "42.00"
assert params["currency"] == "USD"
assert params["paymentType"] == "CP"
Plug.Conn.resp(conn, 200, @auth_success)
end
)
Expand All @@ -242,8 +275,9 @@ defmodule Gringotts.Gateways.MoneiTest do
"POST",
"/v1/payments/7214344242e11af79c0b9e7b4f3f6234",
fn conn ->
conn_ = parse(conn)
assert :error == Map.fetch(conn_.body_params, "createRegistration")
p_conn = parse(conn)
params = p_conn.body_params
assert :error == Map.fetch(params, "createRegistration")
Plug.Conn.resp(conn, 200, @auth_success)
end
)
Expand All @@ -267,6 +301,11 @@ defmodule Gringotts.Gateways.MoneiTest do
"POST",
"/v1/payments/7214344242e11af79c0b9e7b4f3f6234",
fn conn ->
p_conn = parse(conn)
params = p_conn.body_params
assert params["amount"] == "3.00"
assert params["currency"] == "USD"
assert params["paymentType"] == "RF"
Plug.Conn.resp(conn, 200, @auth_success)
end
)
Expand All @@ -284,6 +323,11 @@ defmodule Gringotts.Gateways.MoneiTest do
"DELETE",
"/v1/registrations/7214344242e11af79c0b9e7b4f3f6234",
fn conn ->
p_conn = parse(conn)
params = p_conn.query_params
assert params["authentication.entityId"] == "some_secret_entity_id"
assert params["authentication.password"] == "some_secret_password"
assert params["authentication.userId"] == "some_secret_user_id"
Plug.Conn.resp(conn, 200, "<html></html>")
end
)
Expand All @@ -300,6 +344,11 @@ defmodule Gringotts.Gateways.MoneiTest do
"POST",
"/v1/payments/7214344242e11af79c0b9e7b4f3f6234",
fn conn ->
p_conn = parse(conn)
params = p_conn.body_params
assert :error == Map.fetch(params, :amount)
assert :error == Map.fetch(params, :currency)
assert params["paymentType"] == "RV"
Plug.Conn.resp(conn, 200, @auth_success)
end
)
Expand All @@ -309,17 +358,6 @@ defmodule Gringotts.Gateways.MoneiTest do
end
end

@tag :skip
test "respond various scenarios, can't test a private function." do
json_200 = %HTTPoison.Response{body: @auth_success, status_code: 200}
json_not_200 = %HTTPoison.Response{body: @auth_success, status_code: 300}
html_200 = %HTTPoison.Response{body: ~s[<html></html>\n], status_code: 200}
html_not_200 = %HTTPoison.Response{body: ~s[<html></html?], status_code: 300}
all = [json_200, json_not_200, html_200, html_not_200]
then = Enum.map(all, &Gateway.respond({:ok, &1}))
assert Keyword.keys(then) == [:ok, :error, :error, :error]
end

def parse(conn, opts \\ []) do
opts = Keyword.put_new(opts, :parsers, [Plug.Parsers.URLENCODED])
Plug.Parsers.call(conn, Plug.Parsers.init(opts))
Expand Down
Loading

0 comments on commit 162a1e0

Please sign in to comment.