Skip to content

Commit

Permalink
Increase unit test coverage (#338)
Browse files Browse the repository at this point in the history
* Add unit tests for permissionclient

* Add unit tests for ConnectClient

* Bugfix use correct links for capture

* Add more assert statements to verify the settlement and capture response classes

* add unit tests for verify that balance links are deserialized correctly

* Add missing Dashboard link in ProfileResponse

* Add unit tests for GetProfileListAsync

* Add unit tests for QR code deserialisation and Credit card specific response parameters

* Add missing ShippingAddress to PayPalPaymentResponse class

* Add more payment method specific unit tests

* Remove unused code

* Add unit tests for DictionaryExtensions.AddValueIfTrue

* Bugfix where banktransfer specific links were not deserialized

* Add unit tests for retrieving banktransfer specific details

* Add unit tests for retrieving gift card specific details

* Add unit test for CreateOrderRefundAsync method

* Expand unit test to retrieve a payment by testing alot more additional properties

* Add more unit tests to verify deserializing various payment specific details are deserialized correctly

* Add more tests to cover payment specific requests
  • Loading branch information
Viincenttt authored Dec 28, 2023
1 parent 010c27c commit a18de0f
Show file tree
Hide file tree
Showing 20 changed files with 1,959 additions and 535 deletions.
7 changes: 0 additions & 7 deletions src/Mollie.Api/Client/InvoicesClient.cs
Original file line number Diff line number Diff line change
Expand Up @@ -36,12 +36,5 @@ public async Task<ListResponse<InvoiceResponse>> GetInvoiceListAsync(
public async Task<ListResponse<InvoiceResponse>> GetInvoiceListAsync(UrlObjectLink<ListResponse<InvoiceResponse>> url) {
return await this.GetAsync(url).ConfigureAwait(false);
}

private Dictionary<string, string> BuildQueryParameters(string profileId, bool testmode) {
var result = new Dictionary<string, string>();
result.AddValueIfNotNullOrEmpty("profileId", profileId);
result.AddValueIfTrue("testmode", testmode);
return result;
}
}
}
1 change: 0 additions & 1 deletion src/Mollie.Api/Client/OrderClient.cs
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,6 @@
using Mollie.Api.Models;
using Mollie.Api.Models.List;
using Mollie.Api.Models.Order;
using Mollie.Api.Models.Order.Request;
using Mollie.Api.Models.Order.Request.ManageOrderLines;
using Mollie.Api.Models.Payment.Response;
using Mollie.Api.Models.Refund;
Expand Down

This file was deleted.

This file was deleted.

6 changes: 0 additions & 6 deletions src/Mollie.Api/Extensions/DictionaryExtensions.cs
Original file line number Diff line number Diff line change
Expand Up @@ -25,11 +25,5 @@ public static void AddValueIfTrue(this IDictionary<string, string> dictionary, s
dictionary.Add(key, bool.TrueString.ToLower());
}
}

public static void AddValueIfTrue(this IDictionary<string, string> dictionary, string key, bool? value) {
if (value == true) {
dictionary.Add(key, bool.TrueString.ToLower());
}
}
}
}
15 changes: 0 additions & 15 deletions src/Mollie.Api/Extensions/JsonConvertExtensions.cs

This file was deleted.

Original file line number Diff line number Diff line change
@@ -1,6 +1,5 @@
using System;
using Mollie.Api.Framework.Factories;
using Mollie.Api.Models.Balance.Response;
using Mollie.Api.Models.Balance.Response.BalanceReport;
using Newtonsoft.Json.Linq;

Expand Down
22 changes: 17 additions & 5 deletions src/Mollie.Api/Models/Capture/Response/CaptureResponseLinks.cs
Original file line number Diff line number Diff line change
@@ -1,18 +1,30 @@
using Mollie.Api.Models.Url;
using Mollie.Api.Models.Payment.Response;
using Mollie.Api.Models.Settlement;
using Mollie.Api.Models.Shipment;
using Mollie.Api.Models.Url;

namespace Mollie.Api.Models.Capture {
public class CaptureResponseLinks {
/// <summary>
/// The API resource URL of the order itself.
/// The API resource URL of the capture itself.
/// </summary>
public UrlObjectLink<CaptureResponse> Self { get; set; }

/// <summary>
/// The URL your customer should visit to make the payment for the order.
/// This is where you should redirect the customer to after creating the order.
/// The API resource URL of the payment the capture belongs to.
/// </summary>
public UrlLink Checkout { get; set; }
public UrlObjectLink<PaymentResponse> Payment { get; set; }

/// <summary>
/// The API resource URL of the shipment that triggered the capture to be created.
/// </summary>
public UrlObjectLink<ShipmentResponse> Shipment { get; set; }

/// <summary>
/// The API resource URL of the settlement this capture has been settled with. Not present if not yet settled.
/// </summary>
public UrlObjectLink<SettlementResponse> Settlement { get; set; }

/// <summary>
/// The URL to the order retrieval endpoint documentation.
/// </summary>
Expand Down
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
using Mollie.Api.Models.Url;
using Newtonsoft.Json;

namespace Mollie.Api.Models.Payment.Response.Specific {
public class BankTransferPaymentResponse : PaymentResponse {
Expand All @@ -7,6 +8,7 @@ public class BankTransferPaymentResponse : PaymentResponse {
/// <summary>
/// For bank transfer payments, the _links object will contain some additional URL objects relevant to the payment.
/// </summary>
[JsonProperty("_links")]
public new BankTransferPaymentResponseLinks Links { get; set; }
}

Expand All @@ -33,23 +35,23 @@ public class BankTransferPaymentResponseDetails {
public string TransferReference { get; set; }

/// <summary>
/// Only available if the payment has been completed The consumer's name.
/// Only available if the payment has been completed The consumer's name.
/// </summary>
public string ConsumerName { get; set; }

/// <summary>
/// Only available if the payment has been completed The consumer's bank account. This may be an IBAN, or it may be a
/// Only available if the payment has been completed The consumer's bank account. This may be an IBAN, or it may be a
/// domestic account number.
/// </summary>
public string ConsumerAccount { get; set; }

/// <summary>
/// Only available if the payment has been completed The consumer's bank's BIC / SWIFT code.
/// Only available if the payment has been completed The consumer's bank's BIC / SWIFT code.
/// </summary>
public string ConsumerBic { get; set; }

/// <summary>
/// Only available if filled out in the API or by the consumer The email address which the consumer asked the payment
/// Only available if filled out in the API or by the consumer The email address which the consumer asked the payment
/// instructions to be sent to.
/// </summary>
public string BillingEmail { get; set; }
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -31,6 +31,11 @@ public class PayPalPaymentResponseDetails {
/// </summary>
public string SellerProtection { get; set; }

/// <summary>
/// The shipping address details.
/// </summary>
public AddressObject ShippingAddress { get; set; }

/// <summary>
/// The amount of fee PayPal will charge for this transaction. This field is omitted if PayPal will not charge a fee
/// for this transaction.
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@
namespace Mollie.Api.Models.Profile.Response {
public class ProfileResponseLinks {
public UrlObjectLink<ProfileResponse> Self { get; set; }
public UrlLink Dashboard { get; set; }
public UrlObjectLink<ListResponse<ChargebackResponse>> Chargebacks { get; set; }
public UrlObjectLink<ListResponse<PaymentResponse>> Methods { get; set; }
public UrlObjectLink<ListResponse<PaymentMethodResponse>> Payments { get; set; }
Expand Down
5 changes: 5 additions & 0 deletions tests/Mollie.Tests.Unit/Client/BalanceClientTests.cs
Original file line number Diff line number Diff line change
Expand Up @@ -47,6 +47,11 @@ public async Task GetBalanceAsync_DefaultBehaviour_ResponseIsParsed() {
balanceResponse.TransferDestination.Type.Should().Be(getBalanceResponseFactory.TransferDestination.Type);
balanceResponse.TransferDestination.BankAccount.Should().Be(getBalanceResponseFactory.TransferDestination.BankAccount);
balanceResponse.TransferDestination.BeneficiaryName.Should().Be(getBalanceResponseFactory.TransferDestination.BeneficiaryName);
balanceResponse.Links.Should().NotBeNull();
balanceResponse.Links.Self.Href.Should().Be($"https://api.mollie.com/v2/balances/{getBalanceResponseFactory.BalanceId}");
balanceResponse.Links.Self.Type.Should().Be("application/hal+json");
balanceResponse.Links.Documentation.Href.Should().Be($"https://docs.mollie.com/reference/v2/balances-api/get-balance");
balanceResponse.Links.Documentation.Type.Should().Be("text/html");
}

[Theory]
Expand Down
19 changes: 17 additions & 2 deletions tests/Mollie.Tests.Unit/Client/BaseClientTests.cs
Original file line number Diff line number Diff line change
Expand Up @@ -3,16 +3,31 @@

namespace Mollie.Tests.Unit.Client {
public abstract class BaseClientTests {
protected readonly string DefaultRedirectUrl = "http://mysite.com";

protected MockHttpMessageHandler CreateMockHttpMessageHandler(HttpMethod httpMethod, string url, string response, string expectedPartialContent = null) {
MockHttpMessageHandler mockHttp = new MockHttpMessageHandler();
MockedRequest mockedRequest = mockHttp.Expect(httpMethod, url)
.Respond("application/json", response);

if (!string.IsNullOrEmpty(expectedPartialContent)) {
mockedRequest.WithPartialContent(expectedPartialContent);
if (!string.IsNullOrEmpty(expectedPartialContent))
{
mockedRequest.With(x =>
{
string expectedContent = RemoveWhiteSpaces(expectedPartialContent);
string content = RemoveWhiteSpaces(x.Content!.ReadAsStringAsync().Result);
return content.Contains(expectedContent);
});
}

return mockHttp;
}

private string RemoveWhiteSpaces(string input)
{
return input
.Replace(System.Environment.NewLine, string.Empty)
.Replace(" ", string.Empty);
}
}
}
91 changes: 91 additions & 0 deletions tests/Mollie.Tests.Unit/Client/ConnectClientTests.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,91 @@
using System.Collections.Generic;
using System.Net;
using System.Net.Http;
using System.Threading.Tasks;
using FluentAssertions;
using Mollie.Api.Client;
using Mollie.Api.Models.Connect;
using RichardSzalay.MockHttp;
using Xunit;

namespace Mollie.Tests.Unit.Client;

public class ConnectClientTests : BaseClientTests
{
private const string ClientId = "client-id";
private const string ClientSecret = "client-secret";

[Fact]
public void GetAuthorizationUrl_WithSingleScope_GeneratesAuthorizationUrl()
{
// Arrange
HttpClient httpClient = new HttpClient();
ConnectClient connectClient = new ConnectClient(ClientId, ClientSecret, httpClient);
var scopes = new List<string> {AppPermissions.PaymentsRead};

// Act
string authorizationUrl = connectClient.GetAuthorizationUrl("abcde", scopes);

// Assert
string expectedUrl = $"https://www.mollie.com/oauth2/authorize?client_id={ClientId}&state=abcde&scope=payments.read&response_type=code&approval_prompt=auto";
authorizationUrl.Should().Be(expectedUrl);
}

[Theory]
[InlineData("refresh_abcde", "refresh_token")]
[InlineData("abcde", "authorization_code")]
public async Task GetAccessTokenAsync_WithRefreshToken_ResponseIsDeserializedInExpectedFormat(string refreshToken, string expectedGrantType)
{
// Arrange
var mockHttp = new MockHttpMessageHandler();
mockHttp.Expect(HttpMethod.Post, "https://api.mollie.nl/oauth2/tokens")
.Respond("application/json", defaultGetTokenResponse);
HttpClient httpClient = mockHttp.ToHttpClient();
ConnectClient connectClient = new ConnectClient(ClientId, ClientSecret, httpClient);
var tokenRequest = new TokenRequest(refreshToken, DefaultRedirectUrl);

// Act
TokenResponse tokenResponse = await connectClient.GetAccessTokenAsync(tokenRequest);

// Assert
mockHttp.VerifyNoOutstandingExpectation();
tokenRequest.GrantType.Should().Be(expectedGrantType);
tokenResponse.Should().NotBeNull();
tokenResponse.AccessToken.Should().Be("access_46EUJ6x8jFJZZeAvhNH4JVey6qVpqR");
tokenResponse.RefreshToken.Should().Be("refresh_FS4xc3Mgci2xQ5s5DzaLXh3HhaTZOP");
tokenResponse.ExpiresIn.Should().Be(3600);
tokenResponse.TokenType.Should().Be("bearer");
tokenResponse.Scope.Should().Be("payments.read organizations.read");
}

[Fact]
public async Task RevokeTokenAsync_SendsRequest()
{
// Arrange
var mockHttp = new MockHttpMessageHandler();
mockHttp.Expect(HttpMethod.Delete, "https://api.mollie.nl/oauth2/tokens")
.Respond(HttpStatusCode.NoContent);
HttpClient httpClient = mockHttp.ToHttpClient();
ConnectClient connectClient = new ConnectClient(ClientId, ClientSecret, httpClient);
var revokeTokenRequest = new RevokeTokenRequest
{
Token = "access_46EUJ6x8jFJZZeAvhNH4JVey6qVpqR",
TokenTypeHint = "refresh_token"
};

// Act
await connectClient.RevokeTokenAsync(revokeTokenRequest);

// Assert
mockHttp.VerifyNoOutstandingExpectation();
}

private const string defaultGetTokenResponse = @"
{
""access_token"": ""access_46EUJ6x8jFJZZeAvhNH4JVey6qVpqR"",
""refresh_token"": ""refresh_FS4xc3Mgci2xQ5s5DzaLXh3HhaTZOP"",
""expires_in"": 3600,
""token_type"": ""bearer"",
""scope"": ""payments.read organizations.read""
}";
}
Loading

0 comments on commit a18de0f

Please sign in to comment.