PlanTempusApp/PlanTempus.X.BDD/FeatureFixtures/UserRegistrationSpecs.cs
2025-02-28 17:56:14 +01:00

333 lines
No EOL
8.6 KiB
C#

using LightBDD.Framework;
using LightBDD.Framework.Scenarios;
using LightBDD.MsTest3;
using PlanTempus.X.Services;
using Shouldly;
namespace PlanTempus.X.BDD.FeatureFixtures;
[TestClass]
[FeatureDescription(@"As a new user
I want to register with my email
So I can start using the system")]
public partial class UserRegistrationSpecs : FeatureFixture
{
protected User _currentUser;
protected string _currentEmail;
protected Exception _registrationError;
IUserService _userService;
IEmailService _emailService;
IOrganizationService _organizationService;
public async Task Given_no_user_exists_with_email(string email)
{
// Ensure user doesn't exist with email
var user = await _userService.GetUserByEmailAsync(email);
user.ShouldBeNull();
_currentEmail = email;
}
public async Task When_I_submit_registration_with_name_and_email(string name, string email)
{
try
{
_currentUser = await _userService.CreateUserAsync(email, name);
_currentEmail = email;
}
catch (Exception ex)
{
_registrationError = ex;
}
}
public async Task When_I_submit_registration_with_email(string email)
{
try
{
_currentUser = await _userService.CreateUserAsync(email, "Test User");
_currentEmail = email;
}
catch (Exception ex)
{
_registrationError = ex;
}
}
public void Then_a_new_user_should_be_created_with_email_and_confirmation_status(string email, bool confirmationStatus)
{
_currentUser.ShouldNotBeNull();
_currentUser.Email.ShouldBe(email);
_currentUser.EmailConfirmed.ShouldBe(confirmationStatus);
}
public void Then_a_confirmation_email_should_be_sent()
{
var emailSent = _emailService.WasConfirmationEmailSent(_currentEmail);
emailSent.ShouldBeTrue();
}
public async Task Given_a_user_already_exists_with_email(string email)
{
// Create a user first to ensure it exists
_currentUser = await _userService.CreateUserAsync(email, "Existing User");
_currentUser.ShouldNotBeNull();
_currentEmail = email;
}
public void Then_registration_should_fail_with_error(string expectedErrorMessage)
{
_registrationError.ShouldNotBeNull();
_registrationError.Message.ShouldBe(expectedErrorMessage);
}
}
[TestClass]
[FeatureDescription(@"As a registered user
I want to confirm my email
So I can activate my account")]
public partial class EmailConfirmationSpecs : FeatureFixture
{
IUserService _userService;
IEmailService _emailService;
IOrganizationService _organizationService;
protected User _currentUser;
protected string _currentEmail;
protected string _confirmationLink;
protected bool _redirectedToWelcome;
protected string _errorMessage;
public async Task Given_a_user_exists_with_unconfirmed_email(string email)
{
_currentUser = await _userService.CreateUserAsync(email, "Test User");
_currentUser.EmailConfirmed.ShouldBeFalse();
_currentEmail = email;
}
public async Task When_I_click_the_valid_confirmation_link_for(string email)
{
_confirmationLink = await _emailService.GetConfirmationLinkForEmail(email);
await _userService.ConfirmEmailAsync(_confirmationLink);
_redirectedToWelcome = true; // Simulate redirect
}
public void Then_the_users_email_confirmed_should_be_true()
{
_currentUser = _userService.GetUserByEmail(_currentEmail);
_currentUser.EmailConfirmed.ShouldBeTrue();
}
public void And_I_should_be_redirected_to_the_welcome_page()
{
_redirectedToWelcome.ShouldBeTrue();
}
public async Task When_I_click_an_invalid_confirmation_link()
{
try
{
await _userService.ConfirmEmailAsync("invalid-confirmation-token");
}
catch (Exception ex)
{
_errorMessage = ex.Message;
}
}
public void Then_I_should_see_an_error_message(string expectedErrorMessage)
{
_errorMessage.ShouldBe(expectedErrorMessage);
}
public void And_my_email_remains_unconfirmed()
{
if (_currentUser != null)
{
_currentUser.EmailConfirmed.ShouldBeFalse();
}
}
}
[TestClass]
[FeatureDescription(@"As a user with confirmed email
I want to set up my organization
So I can start using the system with my team")]
public partial class OrganizationSetupSpecs : FeatureFixture
{
IUserService _userService;
IEmailService _emailService;
IOrganizationService _organizationService;
IUserOrganizationService _userOrganizationService;
ITenantService _tenantService;
IAuthService _authService;
protected User _currentUser;
protected Organization _organization;
protected Exception _setupError;
protected List<Organization> _userOrganizations;
public async Task Given_user_has_confirmed_their_email(string email)
{
// Create a user with confirmed email
_currentUser = await _userService.CreateUserAsync(email, "Test User");
var confirmationLink = await _emailService.GetConfirmationLinkForEmail(email);
await _userService.ConfirmEmailAsync(confirmationLink);
_currentUser.EmailConfirmed.ShouldBeTrue();
}
public async Task When_I_submit_organization_name_and_valid_password(string orgName, string password)
{
try
{
_organization = await _organizationService.SetupOrganizationAsync(_currentUser.Id, orgName, password);
}
catch (Exception ex)
{
_setupError = ex;
}
}
public void Then_a_new_organization_should_be_created_with_expected_properties()
{
_organization.ShouldNotBeNull();
_organization.Name.ShouldBe("Acme Corp");
_organization.CreatedBy.ShouldBe(_currentUser.Id);
}
public void And_the_user_should_be_linked_to_the_organization_in_user_organizations()
{
var userOrg = _userOrganizationService.GetUserOrganization(_currentUser.Id, _organization.Id);
userOrg.ShouldNotBeNull();
}
public void And_tenant_tables_should_be_created_for_the_organization()
{
var tenantTablesExist = _tenantService.ValidateTenantTablesExist(_organization.Id);
tenantTablesExist.ShouldBeTrue();
}
public void And_I_should_be_logged_into_the_system()
{
var isAuthenticated = _authService.IsUserAuthenticated(_currentUser.Id);
isAuthenticated.ShouldBeTrue();
}
public async Task When_I_submit_organization_name_without_password(string orgName)
{
try
{
await _organizationService.SetupOrganizationAsync(_currentUser.Id, orgName, "");
}
catch (Exception ex)
{
_setupError = ex;
}
}
public void Then_organization_setup_should_fail_with_error(string expectedErrorMessage)
{
_setupError.ShouldNotBeNull();
_setupError.Message.ShouldBe(expectedErrorMessage);
}
public async Task Given_user_has_completed_initial_setup(string email)
{
await Given_user_has_confirmed_their_email(email);
await When_I_submit_organization_name_and_valid_password("First Org", "ValidP@ssw0rd");
_userOrganizations = new List<Organization> { _organization };
}
public async Task When_I_create_a_new_organization(string orgName)
{
var newOrg = await _organizationService.CreateOrganizationAsync(_currentUser.Id, orgName);
_userOrganizations.Add(newOrg);
}
public void Then_a_new_organization_entry_should_be_created()
{
_userOrganizations.Count.ShouldBe(2);
_userOrganizations[1].Name.ShouldBe("Second Org");
}
public void And_the_user_should_be_linked_to_both_organizations()
{
var userOrgs = _userOrganizationService.GetUserOrganizations(_currentUser.Id);
userOrgs.Count.ShouldBe(2);
}
}
[TestClass]
[FeatureDescription(@"As a system administrator
I want to ensure account security is maintained
So users' data remains protected")]
public partial class AccountSecuritySpecs : FeatureFixture
{
IUserService _userService;
IEmailService _emailService;
IOrganizationService _organizationService;
IAuthService _authService;
protected User _currentUser;
protected DateTime? _lockoutEnd;
protected bool _isLocked;
protected bool _loginSuccessful;
public async Task Given_user_exists(string email)
{
_currentUser = await _userService.GetUserByEmailAsync(email);
if (_currentUser == null)
{
_currentUser = await _userService.CreateUserAsync(email, "Test User");
}
}
public async Task When_I_attempt_5_failed_logins_within_5_minutes()
{
for (var i = 0; i < 5; i++)
{
try
{
await _authService.AttemptLoginAsync(_currentUser.Email, "WrongPassword");
}
catch
{
// Expected exception with wrong password
}
}
}
public void Then_the_account_should_be_locked()
{
_currentUser = _userService.GetUserByEmail(_currentUser.Email);
_isLocked = _currentUser.IsLocked;
_isLocked.ShouldBeTrue();
}
public void And_lockout_end_should_be_set()
{
_lockoutEnd = _currentUser.LockoutEnd;
_lockoutEnd.ShouldNotBeNull();
_lockoutEnd.Value.ShouldBeGreaterThan(DateTime.UtcNow);
}
public async Task And_subsequent_login_attempts_should_fail_until_lockout_end()
{
try
{
_loginSuccessful = await _authService.AttemptLoginAsync(_currentUser.Email, _currentUser.Password);
}
catch
{
_loginSuccessful = false;
}
_loginSuccessful.ShouldBeFalse();
}
}