1
0
mirror of https://github.com/bitwarden/server.git synced 2024-12-01 13:43:23 +01:00
bitwarden-server/test/Core.Test/Billing/Commands/CancelSubscriptionCommandTests.cs
Alex Morask 59fa6935b4
[AC-1608] Send offboarding survey response to Stripe on subscription cancellation (#3734)
* Added offboarding survey response to cancellation when FF is on.

* Removed service methods to prevent unnecessary upstream registrations

* Forgot to actually remove the injected command in the services

* Rui's feedback

* Add missing summary

* Missed [FromBody]
2024-02-09 11:58:37 -05:00

164 lines
5.8 KiB
C#

using System.Linq.Expressions;
using Bit.Core.AdminConsole.Entities;
using Bit.Core.Billing.Commands.Implementations;
using Bit.Core.Billing.Models;
using Bit.Core.Services;
using Bit.Test.Common.AutoFixture;
using Bit.Test.Common.AutoFixture.Attributes;
using NSubstitute;
using Stripe;
using Xunit;
using static Bit.Core.Test.Billing.Utilities;
namespace Bit.Core.Test.Billing.Commands;
[SutProviderCustomize]
public class CancelSubscriptionCommandTests
{
private const string _subscriptionId = "subscription_id";
private const string _cancellingUserIdKey = "cancellingUserId";
[Theory, BitAutoData]
public async Task CancelSubscription_SubscriptionInactive_ThrowsGatewayException(
SutProvider<CancelSubscriptionCommand> sutProvider)
{
var subscription = new Subscription
{
Status = "canceled"
};
await ThrowsContactSupportAsync(() =>
sutProvider.Sut.CancelSubscription(subscription, new OffboardingSurveyResponse(), false));
await DidNotUpdateSubscription(sutProvider);
await DidNotCancelSubscription(sutProvider);
}
[Theory, BitAutoData]
public async Task CancelSubscription_CancelImmediately_BelongsToOrganization_UpdatesSubscription_CancelSubscriptionImmediately(
SutProvider<CancelSubscriptionCommand> sutProvider)
{
var userId = Guid.NewGuid();
var subscription = new Subscription
{
Id = _subscriptionId,
Status = "active",
Metadata = new Dictionary<string, string>
{
{ "organizationId", "organization_id" }
}
};
var offboardingSurveyResponse = new OffboardingSurveyResponse
{
UserId = userId,
Reason = "missing_features",
Feedback = "Lorem ipsum"
};
await sutProvider.Sut.CancelSubscription(subscription, offboardingSurveyResponse, true);
await UpdatedSubscriptionWith(sutProvider, options => options.Metadata[_cancellingUserIdKey] == userId.ToString());
await CancelledSubscriptionWith(sutProvider, options =>
options.CancellationDetails.Comment == offboardingSurveyResponse.Feedback &&
options.CancellationDetails.Feedback == offboardingSurveyResponse.Reason);
}
[Theory, BitAutoData]
public async Task CancelSubscription_CancelImmediately_BelongsToUser_CancelSubscriptionImmediately(
SutProvider<CancelSubscriptionCommand> sutProvider)
{
var userId = Guid.NewGuid();
var subscription = new Subscription
{
Id = _subscriptionId,
Status = "active",
Metadata = new Dictionary<string, string>
{
{ "userId", "user_id" }
}
};
var offboardingSurveyResponse = new OffboardingSurveyResponse
{
UserId = userId,
Reason = "missing_features",
Feedback = "Lorem ipsum"
};
await sutProvider.Sut.CancelSubscription(subscription, offboardingSurveyResponse, true);
await DidNotUpdateSubscription(sutProvider);
await CancelledSubscriptionWith(sutProvider, options =>
options.CancellationDetails.Comment == offboardingSurveyResponse.Feedback &&
options.CancellationDetails.Feedback == offboardingSurveyResponse.Reason);
}
[Theory, BitAutoData]
public async Task CancelSubscription_DoNotCancelImmediately_UpdateSubscriptionToCancelAtEndOfPeriod(
Organization organization,
SutProvider<CancelSubscriptionCommand> sutProvider)
{
var userId = Guid.NewGuid();
organization.ExpirationDate = DateTime.UtcNow.AddDays(5);
var subscription = new Subscription
{
Id = _subscriptionId,
Status = "active"
};
var offboardingSurveyResponse = new OffboardingSurveyResponse
{
UserId = userId,
Reason = "missing_features",
Feedback = "Lorem ipsum"
};
await sutProvider.Sut.CancelSubscription(subscription, offboardingSurveyResponse, false);
await UpdatedSubscriptionWith(sutProvider, options =>
options.CancelAtPeriodEnd == true &&
options.CancellationDetails.Comment == offboardingSurveyResponse.Feedback &&
options.CancellationDetails.Feedback == offboardingSurveyResponse.Reason &&
options.Metadata[_cancellingUserIdKey] == userId.ToString());
await DidNotCancelSubscription(sutProvider);
}
private static Task<Subscription> DidNotCancelSubscription(SutProvider<CancelSubscriptionCommand> sutProvider)
=> sutProvider
.GetDependency<IStripeAdapter>()
.DidNotReceiveWithAnyArgs()
.SubscriptionCancelAsync(Arg.Any<string>(), Arg.Any<SubscriptionCancelOptions>());
private static Task<Subscription> DidNotUpdateSubscription(SutProvider<CancelSubscriptionCommand> sutProvider)
=> sutProvider
.GetDependency<IStripeAdapter>()
.DidNotReceiveWithAnyArgs()
.SubscriptionUpdateAsync(Arg.Any<string>(), Arg.Any<SubscriptionUpdateOptions>());
private static Task<Subscription> CancelledSubscriptionWith(
SutProvider<CancelSubscriptionCommand> sutProvider,
Expression<Predicate<SubscriptionCancelOptions>> predicate)
=> sutProvider
.GetDependency<IStripeAdapter>()
.Received(1)
.SubscriptionCancelAsync(_subscriptionId, Arg.Is(predicate));
private static Task<Subscription> UpdatedSubscriptionWith(
SutProvider<CancelSubscriptionCommand> sutProvider,
Expression<Predicate<SubscriptionUpdateOptions>> predicate)
=> sutProvider
.GetDependency<IStripeAdapter>()
.Received(1)
.SubscriptionUpdateAsync(_subscriptionId, Arg.Is(predicate));
}