Files
server/test/Identity.Test/Billing/Controller/AccountsControllerTests.cs
Stephon Brown 4224933c62 [PM-35357] Update Trial Length Parameter (#7597)
* test(billing): Add unit tests for TrialInitiationCache

* feat(billing): Add trial initiation cache interface and implementation

* feat(billing): Register trial initiation cache services

* feat(core): Add trial properties to OrganizationSignup model

* feat(mail): Update trial verification email model and services for TrialInitiationId

* feat(billing): Enhance TrialSendVerificationEmailRequestModel validation

* test(billing): Add tests for TrialSendVerificationEmailRequestModel validation

* feat(billing): Introduce default trial length constant

* refactor(identity): Use constant for default trial length in AccountsController

* test(identity): Update accounts controller tests for default trial length constant

* feat(billing): Integrate trial initiation into email sending command

* feat(billing): Add TrialLength to SubscriptionSetup model

* feat(billing): Map TrialLength in OrganizationSale creation

* feat(billing): Allow custom trial length in organization billing service

* feat(admin-console): Add TrialLength and TrialInitiationId to organization creation requests

* feat(admin-console): Validate trial length during cloud organization signup

* test(admin-console): Add tests for organization create request trial properties

* test(admin-console): Add tests for CloudOrganizationSignUpCommand trial length validation

* refactor(TrialInitiationCache): change validation method to retrieval

* test(TrialInitiationCache): update tests for GetAndRemoveAsync

* feat(OrganizationSignUp): refactor trial validation to command

* test(OrganizationSignUp): add trial validation scenarios

* test(OrganizationSignUp): nullify TrialLength in unrelated tests

* fix(billing): dotnet format

* refactor: remove `TrialInitiationId` property from data models
refactor: update mail service interfaces and implementations

* refactor: remove `ITrialInitiationCache` infrastructure
test: update `CloudOrganizationSignUpCommandTests` for trial validation

* refactor: update `SendTrialInitiationEmailForRegistrationCommand`

* refactor: update `CloudOrganizationSignUpCommand` trial length validation

* test(organization): fix plan call in tests

* test(billing): fix test settings
2026-05-18 09:32:04 -04:00

242 lines
8.4 KiB
C#

using Bit.Core.Billing.Constants;
using Bit.Core.Billing.Enums;
using Bit.Core.Billing.Models.Api.Requests.Accounts;
using Bit.Core.Billing.TrialInitiation.Registration;
using Bit.Identity.Billing.Controller;
using Bit.Test.Common.AutoFixture.Attributes;
using Microsoft.AspNetCore.Mvc;
using NSubstitute;
using Xunit;
namespace Bit.Identity.Test.Billing.Controller;
public class AccountsControllerTests
{
private readonly ISendTrialInitiationEmailForRegistrationCommand _sendTrialInitiationEmailForRegistrationCommand;
private readonly AccountsController _sut;
public AccountsControllerTests()
{
_sendTrialInitiationEmailForRegistrationCommand = Substitute.For<ISendTrialInitiationEmailForRegistrationCommand>();
_sut = new AccountsController(_sendTrialInitiationEmailForRegistrationCommand);
}
[Theory]
[BitAutoData]
public async Task PostTrialInitiationSendVerificationEmailAsync_PaymentOptionalTrue_TrialLengthZero_ReturnsBadRequest(
string email,
string name,
bool receiveMarketingEmails,
ProductTierType productTier,
IEnumerable<ProductType> products)
{
// Arrange
var model = new TrialSendVerificationEmailRequestModel
{
Email = email,
Name = name,
ReceiveMarketingEmails = receiveMarketingEmails,
ProductTier = productTier,
Products = products,
TrialLength = 0,
PaymentOptional = true
};
// Act
var result = await _sut.PostTrialInitiationSendVerificationEmailAsync(model);
// Assert
var badRequestResult = Assert.IsType<BadRequestObjectResult>(result);
Assert.Equal(400, badRequestResult.StatusCode);
var value = badRequestResult.Value;
var messageProperty = value?.GetType().GetProperty("message");
Assert.NotNull(messageProperty);
Assert.Equal("Payment cannot be optional when trial length is zero.", messageProperty.GetValue(value));
await _sendTrialInitiationEmailForRegistrationCommand.DidNotReceive()
.Handle(Arg.Any<string>(), Arg.Any<string>(), Arg.Any<bool>(), Arg.Any<ProductTierType>(),
Arg.Any<IEnumerable<ProductType>>(), Arg.Any<int>(), Arg.Any<bool>());
}
[Theory]
[BitAutoData]
public async Task PostTrialInitiationSendVerificationEmailAsync_PaymentOptionalTrue_TrialLengthNonZero_ReturnsSuccess(
string email,
string name,
bool receiveMarketingEmails,
ProductTierType productTier,
IEnumerable<ProductType> products,
string token)
{
// Arrange
var trialLength = 7;
var model = new TrialSendVerificationEmailRequestModel
{
Email = email,
Name = name,
ReceiveMarketingEmails = receiveMarketingEmails,
ProductTier = productTier,
Products = products,
TrialLength = trialLength,
PaymentOptional = true
};
_sendTrialInitiationEmailForRegistrationCommand
.Handle(email, name, receiveMarketingEmails, productTier, products, trialLength, true)
.Returns(token);
// Act
var result = await _sut.PostTrialInitiationSendVerificationEmailAsync(model);
// Assert
var okResult = Assert.IsType<OkObjectResult>(result);
Assert.Equal(200, okResult.StatusCode);
Assert.Equal(token, okResult.Value);
await _sendTrialInitiationEmailForRegistrationCommand.Received(1)
.Handle(email, name, receiveMarketingEmails, productTier, products, trialLength, true);
}
[Theory]
[BitAutoData]
public async Task PostTrialInitiationSendVerificationEmailAsync_PaymentOptionalFalse_TrialLengthZero_ReturnsSuccess(
string email,
string name,
bool receiveMarketingEmails,
ProductTierType productTier,
IEnumerable<ProductType> products)
{
// Arrange
var model = new TrialSendVerificationEmailRequestModel
{
Email = email,
Name = name,
ReceiveMarketingEmails = receiveMarketingEmails,
ProductTier = productTier,
Products = products,
TrialLength = 0,
PaymentOptional = false
};
_sendTrialInitiationEmailForRegistrationCommand
.Handle(email, name, receiveMarketingEmails, productTier, products, 0, false)
.Returns((string?)null);
// Act
var result = await _sut.PostTrialInitiationSendVerificationEmailAsync(model);
// Assert
var noContentResult = Assert.IsType<NoContentResult>(result);
Assert.Equal(204, noContentResult.StatusCode);
await _sendTrialInitiationEmailForRegistrationCommand.Received(1)
.Handle(email, name, receiveMarketingEmails, productTier, products, 0, false);
}
[Theory]
[BitAutoData]
public async Task PostTrialInitiationSendVerificationEmailAsync_TrialLengthNull_DefaultsToDefaultTrialLength(
string email,
string name,
bool receiveMarketingEmails,
ProductTierType productTier,
IEnumerable<ProductType> products,
string token)
{
// Arrange
var model = new TrialSendVerificationEmailRequestModel
{
Email = email,
Name = name,
ReceiveMarketingEmails = receiveMarketingEmails,
ProductTier = productTier,
Products = products,
TrialLength = null,
PaymentOptional = false
};
_sendTrialInitiationEmailForRegistrationCommand
.Handle(email, name, receiveMarketingEmails, productTier, products,
TrialInitiationConstants.DefaultTrialLengthDays, false)
.Returns(token);
// Act
var result = await _sut.PostTrialInitiationSendVerificationEmailAsync(model);
// Assert
var okResult = Assert.IsType<OkObjectResult>(result);
Assert.Equal(200, okResult.StatusCode);
await _sendTrialInitiationEmailForRegistrationCommand.Received(1)
.Handle(email, name, receiveMarketingEmails, productTier, products,
TrialInitiationConstants.DefaultTrialLengthDays, false);
}
[Theory]
[BitAutoData]
public async Task PostTrialInitiationSendVerificationEmailAsync_CommandReturnsNull_ReturnsNoContent(
string email,
string name,
bool receiveMarketingEmails,
ProductTierType productTier,
IEnumerable<ProductType> products)
{
// Arrange
var model = new TrialSendVerificationEmailRequestModel
{
Email = email,
Name = name,
ReceiveMarketingEmails = receiveMarketingEmails,
ProductTier = productTier,
Products = products,
TrialLength = 7,
PaymentOptional = false
};
_sendTrialInitiationEmailForRegistrationCommand
.Handle(email, name, receiveMarketingEmails, productTier, products, 7, false)
.Returns((string?)null);
// Act
var result = await _sut.PostTrialInitiationSendVerificationEmailAsync(model);
// Assert
var noContentResult = Assert.IsType<NoContentResult>(result);
Assert.Equal(204, noContentResult.StatusCode);
}
[Theory]
[BitAutoData]
public async Task PostTrialInitiationSendVerificationEmailAsync_PaymentOptionalTrue_PassedToCommand(
string email,
string name,
bool receiveMarketingEmails,
ProductTierType productTier,
IEnumerable<ProductType> products)
{
// Arrange
var model = new TrialSendVerificationEmailRequestModel
{
Email = email,
Name = name,
ReceiveMarketingEmails = receiveMarketingEmails,
ProductTier = productTier,
Products = products,
TrialLength = 14,
PaymentOptional = true
};
_sendTrialInitiationEmailForRegistrationCommand
.Handle(email, name, receiveMarketingEmails, productTier, products, 14, true)
.Returns((string?)null);
// Act
await _sut.PostTrialInitiationSendVerificationEmailAsync(model);
// Assert
await _sendTrialInitiationEmailForRegistrationCommand.Received(1)
.Handle(email, name, receiveMarketingEmails, productTier, products, 14, true);
}
}