Skip to content

Commit

Permalink
[Paymill] refactor and tests (#152)
Browse files Browse the repository at this point in the history
* New public methods: refund
* `store` has been removed because Paymill does not have a
  direct API integration for card token generation
* Improved docs and uses Money protocol

Refactors
----------
* refactored add_amount -> amount_params
* updated tests and clubbed a few parse clauses
* refactored commit and response functions

Tests
------
* Paymill mock (#159)
* Added mock test cases for paymill.
* Configured mock files to get compiled in `:test` env.
* Moved paymill responses in mocks folder.
  • Loading branch information
anantanant2015 authored and oyeb committed Jun 6, 2018
1 parent 0036a02 commit 9414bb4
Show file tree
Hide file tree
Showing 15 changed files with 805 additions and 335 deletions.
657 changes: 334 additions & 323 deletions lib/gringotts/gateways/paymill.ex

Large diffs are not rendered by default.

14 changes: 12 additions & 2 deletions mix.exs
Original file line number Diff line number Diff line change
Expand Up @@ -16,11 +16,16 @@ defmodule Gringotts.Mixfile do
test_coverage: [
tool: ExCoveralls
],
elixirc_paths: elixirc_paths(Mix.env()),
preferred_cli_env: [
coveralls: :test,
"coveralls.detail": :test,
"coveralls.json": :test,
"coveralls.html": :test
"coveralls.html": :test,
vcr: :test,
"vcr.delete": :test,
"vcr.check": :test,
"vcr.show": :test
],
deps: deps(),
docs: docs()
Expand All @@ -36,6 +41,10 @@ defmodule Gringotts.Mixfile do
]
end

# Specifies which paths to compile per environment.
defp elixirc_paths(:test), do: ["lib", "test/mocks"]
defp elixirc_paths(_), do: ["lib"]

# Dependencies can be hex.pm packages:
#
# {:mydep, "~> 0.3.0"}
Expand Down Expand Up @@ -67,7 +76,8 @@ defmodule Gringotts.Mixfile do
{:credo, "~> 0.3", only: [:dev, :test]},
{:inch_ex, "~> 0.5", only: :docs},
{:dialyxir, "~> 0.3", only: :dev},
{:timex, "~> 3.2"}
{:timex, "~> 3.2"},
{:exvcr, "~> 0.10", only: :test}
]
end

Expand Down
2 changes: 2 additions & 0 deletions mix.lock
Original file line number Diff line number Diff line change
Expand Up @@ -16,8 +16,10 @@
"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"},
"exactor": {:hex, :exactor, "2.2.4", "5efb4ddeb2c48d9a1d7c9b465a6fffdd82300eb9618ece5d34c3334d5d7245b1", [:mix], [], "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"},
"exvcr": {:hex, :exvcr, "0.10.0", "5150808404d9f48dbda636f70f7f8fefd93e2433cd39f695f810e73b3a9d1736", [:mix], [{:exactor, "~> 2.2", [hex: :exactor, repo: "hexpm", optional: false]}, {:exjsx, "~> 4.0", [hex: :exjsx, repo: "hexpm", optional: false]}, {:httpoison, "~> 0.13", [hex: :httpoison, repo: "hexpm", optional: true]}, {:httpotion, "~> 3.0", [hex: :httpotion, repo: "hexpm", optional: true]}, {:ibrowse, "~> 4.4", [hex: :ibrowse, repo: "hexpm", optional: true]}, {:meck, "~> 0.8.8", [hex: :meck, 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"},
"httpoison": {:hex, :httpoison, "0.13.0", "bfaf44d9f133a6599886720f3937a7699466d23bb0cd7a88b6ba011f53c6f562", [:mix], [{:hackney, "~> 1.8", [hex: :hackney, repo: "hexpm", optional: false]}], "hexpm"},
Expand Down
1 change: 0 additions & 1 deletion test/gateways/authorize_net_test.exs
Original file line number Diff line number Diff line change
@@ -1,5 +1,4 @@
defmodule Gringotts.Gateways.AuthorizeNetTest do
Code.require_file("../mocks/authorize_net_mock.exs", __DIR__)
use ExUnit.Case, async: false
alias Gringotts.Gateways.AuthorizeNetMock, as: MockResponse
alias Gringotts.CreditCard
Expand Down
11 changes: 8 additions & 3 deletions test/gateways/cams_test.exs
Original file line number Diff line number Diff line change
@@ -1,5 +1,4 @@
defmodule Gringotts.Gateways.CamsTest do
Code.require_file("../mocks/cams_mock.exs", __DIR__)
use ExUnit.Case, async: false

alias Gringotts.{
Expand Down Expand Up @@ -103,13 +102,19 @@ defmodule Gringotts.Gateways.CamsTest do

describe "capture" do
test "with full amount" do
with_mock HTTPoison, post: fn _url, _body, _headers -> MockResponse.successful_capture() end do
with_mock HTTPoison,
post: fn _url, _body, _headers ->
MockResponse.successful_capture()
end do
assert {:ok, %Response{}} = Gateway.capture(@money, @id, @options)
end
end

test "with partial amount" do
with_mock HTTPoison, post: fn _url, _body, _headers -> MockResponse.successful_capture() end do
with_mock HTTPoison,
post: fn _url, _body, _headers ->
MockResponse.successful_capture()
end do
assert {:ok, %Response{}} = Gateway.capture(@money_less, @id, @options)
end
end
Expand Down
1 change: 0 additions & 1 deletion test/gateways/global_collect_test.exs
Original file line number Diff line number Diff line change
@@ -1,5 +1,4 @@
defmodule Gringotts.Gateways.GlobalCollectTest do
Code.require_file("../mocks/global_collect_mock.exs", __DIR__)
use ExUnit.Case, async: false
alias Gringotts.Gateways.GlobalCollectMock, as: MockResponse
alias Gringotts.Gateways.GlobalCollect
Expand Down
215 changes: 215 additions & 0 deletions test/gateways/paymill_test.exs
Original file line number Diff line number Diff line change
@@ -0,0 +1,215 @@
defmodule Gringotts.Gateways.PaymillTest do
use ExUnit.Case, async: true

alias Gringotts.Gateways.Paymill, as: Gateway
alias Gringotts.Gateways.PaymillMock, as: Mock
alias Plug.{Conn, Parsers}

setup do
bypass = Bypass.open()

opts = %{
private_key: "merchant_secret_key",
public_key: "merchant_public_key",
test_url: "http://localhost:#{bypass.port}/"
}

{:ok, bypass: bypass, opts: opts}
end

@amount_42 Money.new(42, :EUR)
@valid_token "tok_d26e611c47d64693a281e8411934"
@invalid_token "tok_d26e611c47d64693a281e841193"

@transaction_id "tran_de77d38b85d6eee2984accc8b2cc"
@invalid_transaction_id "tran_023d3b5769321c649435"
@capture_preauth_id "preauth_d654694c8116109af903"
@void_id "preauth_0bfc975c2858980a6023"

describe "authorize" do
test "when token is valid", %{bypass: bypass, opts: opts} do
Bypass.expect(bypass, "POST", "/preauthorizations", fn conn ->
p_conn = parse(conn)
params = p_conn.body_params
assert params["amount"] == "4200"
assert params["currency"] == "EUR"
assert params["token"] == "tok_d26e611c47d64693a281e8411934"
Conn.resp(conn, 200, Mock.auth_success())
end)

{:ok, response} = Gateway.authorize(@amount_42, @valid_token, config: opts)
assert response.gateway_code == 20000
end

test "when paymill is down or unreachable", %{bypass: bypass, opts: opts} do
Bypass.down(bypass)
{:error, response} = Gateway.authorize(@amount_42, @valid_token, config: opts)
assert response.reason == "network related failure"
Bypass.up(bypass)
end

test "when token is invalid", %{bypass: bypass, opts: opts} do
Bypass.expect(bypass, "POST", "/preauthorizations", fn conn ->
p_conn = parse(conn)
params = p_conn.body_params
assert params["amount"] == "4200"
assert params["currency"] == "EUR"
assert params["token"] == "tok_d26e611c47d64693a281e841193"
Conn.resp(conn, 400, Mock.auth_purchase_invalid_token())
end)

{:error, response} = Gateway.authorize(@amount_42, @invalid_token, config: opts)
assert response.status_code == 400
end
end

describe "capture" do
test "when preauthorization is valid", %{bypass: bypass, opts: opts} do
Bypass.expect(bypass, "POST", "/transactions", fn conn ->
p_conn = parse(conn)
params = p_conn.body_params
assert params["amount"] == "4200"
assert params["currency"] == "EUR"
assert params["preauthorization"] == "preauth_d654694c8116109af903"
Conn.resp(conn, 200, Mock.capture_success())
end)

{:ok, response} = Gateway.capture(@capture_preauth_id, @amount_42, config: opts)
assert response.gateway_code == 20000
end

test "when preauthorization not found", %{bypass: bypass, opts: opts} do
Bypass.expect(bypass, "POST", "/transactions", fn conn ->
p_conn = parse(conn)
params = p_conn.body_params
assert params["amount"] == "4200"
assert params["currency"] == "EUR"
assert params["preauthorization"] == "preauth_d654694c8116109af903"
Conn.resp(conn, 200, Mock.bad_preauth())
end)

{:error, response} = Gateway.capture(@capture_preauth_id, @amount_42, config: opts)
assert response.status_code == 200
assert response.reason == "Preauthorize not found"
end

test "when preauthorization done before", %{bypass: bypass, opts: opts} do
Bypass.expect(bypass, "POST", "/transactions", fn conn ->
p_conn = parse(conn)
params = p_conn.body_params
assert params["amount"] == "4200"
assert params["currency"] == "EUR"
assert params["preauthorization"] == "preauth_d654694c8116109af903"
Conn.resp(conn, 200, Mock.capture_preauth_done_before())
end)

{:error, response} = Gateway.capture(@capture_preauth_id, @amount_42, config: opts)
assert response.status_code == 200
assert response.reason == "Preauthorization has already been used"
end
end

describe "purchase" do
test "when token is valid", %{bypass: bypass, opts: opts} do
Bypass.expect(bypass, "POST", "/transactions", fn conn ->
p_conn = parse(conn)
params = p_conn.body_params
assert params["amount"] == "4200"
assert params["currency"] == "EUR"
assert params["token"] == "tok_d26e611c47d64693a281e841193"
Conn.resp(conn, 200, Mock.purchase_valid_token())
end)

{:ok, response} = Gateway.purchase(@amount_42, @invalid_token, config: opts)
assert response.gateway_code == 20000
assert response.fraud_review == true
assert response.status_code == 200
end

test "when token is invalid", %{bypass: bypass, opts: opts} do
Bypass.expect(bypass, "POST", "/transactions", fn conn ->
p_conn = parse(conn)
params = p_conn.body_params
assert params["amount"] == "4200"
assert params["currency"] == "EUR"
assert params["token"] == "tok_d26e611c47d64693a281e841193"
Conn.resp(conn, 200, Mock.auth_purchase_invalid_token())
end)

{:error, response} = Gateway.purchase(@amount_42, @invalid_token, config: opts)
assert response.reason["field"] == "token"

assert response.reason["messages"]["regexNotMatch"] ==
"'tok_d26e611c47d64693a281e841193' does not match against pattern '\/^[a-zA-Z0-9_]{32}$\/'"

assert response.status_code == 200
end
end

describe "refund" do
test "when transaction is valid", %{bypass: bypass, opts: opts} do
Bypass.expect(bypass, "POST", "/refunds/#{@transaction_id}", fn conn ->
p_conn = parse(conn)
params = p_conn.body_params
assert params["amount"] == "4200"
Conn.resp(conn, 200, Mock.refund_success())
end)

{:ok, response} = Gateway.refund(@amount_42, @transaction_id, config: opts)
assert response.gateway_code == 20000
assert response.status_code == 200
end

test "when transaction is used again", %{bypass: bypass, opts: opts} do
Bypass.expect(bypass, "POST", "/refunds/#{@transaction_id}", fn conn ->
p_conn = parse(conn)
params = p_conn.body_params
assert params["amount"] == "4200"
Conn.resp(conn, 200, Mock.refund_again())
end)

{:error, response} = Gateway.refund(@amount_42, @transaction_id, config: opts)
assert response.reason == "Amount to high"
assert response.status_code == 200
end

test "when transaction not found", %{bypass: bypass, opts: opts} do
Bypass.expect(bypass, "POST", "/refunds/#{@invalid_transaction_id}", fn conn ->
p_conn = parse(conn)
params = p_conn.body_params
assert params["amount"] == "4200"
Conn.resp(conn, 200, Mock.refund_bad_transaction())
end)

{:error, response} = Gateway.refund(@amount_42, @invalid_transaction_id, config: opts)
assert response.reason == "Transaction not found"
assert response.status_code == 200
end
end

describe "void" do
test "when preauthorization is valid", %{bypass: bypass, opts: opts} do
Bypass.expect(bypass, "DELETE", "/preauthorizations/#{@void_id}", fn conn ->
Conn.resp(conn, 200, Mock.void_success())
end)

{:ok, response} = Gateway.void(@void_id, config: opts)
assert response.gateway_code == 50810
end

test "when preauthorization used before", %{bypass: bypass, opts: opts} do
Bypass.expect(bypass, "DELETE", "/preauthorizations/#{@void_id}", fn conn ->
Conn.resp(conn, 200, Mock.void_done_before())
end)

{:error, response} = Gateway.void(@void_id, config: opts)
assert response.reason == "Preauthorization was not found"
assert response.status_code == 200
end
end

def parse(conn, opts \\ []) do
opts = Keyword.put_new(opts, :parsers, [Parsers.URLENCODED])
Parsers.call(conn, Parsers.init(opts))
end
end
1 change: 0 additions & 1 deletion test/gateways/trexle_test.exs
Original file line number Diff line number Diff line change
@@ -1,5 +1,4 @@
defmodule Gringotts.Gateways.TrexleTest do
Code.require_file("../mocks/trexle_mock.exs", __DIR__)
use ExUnit.Case, async: false
alias Gringotts.Gateways.TrexleMock, as: MockResponse
alias Gringotts.Gateways.Trexle
Expand Down
2 changes: 0 additions & 2 deletions test/gateways/wire_card_test.exs
Original file line number Diff line number Diff line change
Expand Up @@ -8,8 +8,6 @@ defmodule Gringotts.Gateways.WireCardTest do
# TEST_PURCHASE_GUWID = 'C865402121385575982910'
# TEST_CAPTURE_GUWID = 'C833707121385268439116'

# credit_card = %CreditCard{name: "Longbob", number: "4200000000000000", cvc: "123", expiration: {2015, 11}}

# config = %{credentails: {'user', 'pass'}, default_currency: "EUR"}
:ok
end
Expand Down
Loading

0 comments on commit 9414bb4

Please sign in to comment.