PlanTempusApp/PlanTempus.X.BDD/FeatureFixtures/EmailConfirmationSpecs.cs

165 lines
4.5 KiB
C#
Raw Normal View History

using Autofac;
using Insight.Database;
2025-03-03 00:42:20 +01:00
using LightBDD.Framework;
using LightBDD.Framework.Scenarios;
using LightBDD.MsTest3;
using PlanTempus.Components;
using PlanTempus.Components.Accounts.ConfirmEmail;
using PlanTempus.Components.Accounts.Create;
using PlanTempus.Core.Database;
using PlanTempus.Core.Outbox;
2025-03-03 00:42:20 +01:00
using Shouldly;
namespace PlanTempus.X.BDD.FeatureFixtures;
[TestClass]
2025-03-03 00:42:20 +01:00
[FeatureDescription(@"As a registered user
I want to confirm my email
So I can activate my account")]
public partial class EmailConfirmationSpecs : BddTestFixture
2025-03-03 00:42:20 +01:00
{
protected string _currentEmail;
protected string _securityStamp;
protected bool _emailConfirmed;
2025-03-03 00:42:20 +01:00
protected string _errorMessage;
protected bool _outboxEntryCreated;
2025-03-03 00:42:20 +01:00
public async Task Given_an_account_exists_with_unconfirmed_email(string email)
2025-03-03 00:42:20 +01:00
{
_currentEmail = email;
var command = new CreateAccountCommand
{
CorrelationId = Guid.NewGuid(),
Email = email,
Password = "TestPassword123!"
};
await CommandHandler.Handle(command);
// Hent security_stamp fra database til brug i confirmation
var db = Container.Resolve<IDatabaseOperations>();
using var scope = db.CreateScope(nameof(EmailConfirmationSpecs));
var result = await scope.Connection.QuerySqlAsync<AccountDto>(
"SELECT email_confirmed, security_stamp FROM system.accounts WHERE email = @Email",
new { Email = email });
result.Count.ShouldBe(1);
result[0].EmailConfirmed.ShouldBeFalse();
_securityStamp = result[0].SecurityStamp;
2025-03-03 00:42:20 +01:00
}
public async Task And_a_verification_email_is_queued_in_outbox()
2025-03-03 00:42:20 +01:00
{
var db = Container.Resolve<IDatabaseOperations>();
using var scope = db.CreateScope(nameof(EmailConfirmationSpecs));
var result = await scope.Connection.QuerySqlAsync<OutboxDto>(
@"SELECT type, payload FROM system.outbox
WHERE type = @Type AND payload->>'Email' = @Email",
new { Type = OutboxMessageTypes.VerificationEmail, Email = _currentEmail });
result.Count.ShouldBeGreaterThan(0);
_outboxEntryCreated = true;
2025-03-03 00:42:20 +01:00
}
public async Task And_the_outbox_message_is_processed()
2025-03-03 00:42:20 +01:00
{
// Vent på at OutboxListener når at behandle beskeden
await Task.Delay(1000);
var db = Container.Resolve<IDatabaseOperations>();
using var scope = db.CreateScope(nameof(EmailConfirmationSpecs));
var result = await scope.Connection.QuerySqlAsync<OutboxDto>(
@"SELECT status FROM system.outbox
WHERE type = @Type AND payload->>'Email' = @Email",
new { Type = OutboxMessageTypes.VerificationEmail, Email = _currentEmail });
result.Count.ShouldBeGreaterThan(0);
// Status skal være 'sent' eller 'failed' - begge indikerer at beskeden blev behandlet
result[0].Status.ShouldBeOneOf("sent", "failed");
2025-03-03 00:42:20 +01:00
}
public async Task When_I_confirm_email_with_valid_token()
2025-03-03 00:42:20 +01:00
{
var command = new ConfirmEmailCommand
{
CorrelationId = Guid.NewGuid(),
Email = _currentEmail,
Token = _securityStamp
};
await CommandHandler.Handle(command);
2025-03-03 00:42:20 +01:00
}
public async Task When_I_confirm_email_with_invalid_token()
2025-03-03 00:42:20 +01:00
{
try
{
var command = new ConfirmEmailCommand
{
CorrelationId = Guid.NewGuid(),
Email = _currentEmail ?? "unknown@example.com",
Token = "invalid-token"
};
await CommandHandler.Handle(command);
2025-03-03 00:42:20 +01:00
}
catch (InvalidTokenException ex)
2025-03-03 00:42:20 +01:00
{
_errorMessage = ex.Message;
}
}
public async Task Then_the_accounts_email_should_be_confirmed()
2025-03-03 00:42:20 +01:00
{
var db = Container.Resolve<IDatabaseOperations>();
using var scope = db.CreateScope(nameof(EmailConfirmationSpecs));
var result = await scope.Connection.QuerySqlAsync<AccountDto>(
"SELECT email_confirmed FROM system.accounts WHERE email = @Email",
new { Email = _currentEmail });
result.Count.ShouldBe(1);
result[0].EmailConfirmed.ShouldBeTrue();
2025-03-03 00:42:20 +01:00
}
public async Task Then_I_should_see_an_error_message(string expectedMessage)
2025-03-03 00:42:20 +01:00
{
_errorMessage.ShouldNotBeNull();
_errorMessage.ShouldContain(expectedMessage);
}
public async Task And_the_email_remains_unconfirmed()
{
if (_currentEmail == null) return;
var db = Container.Resolve<IDatabaseOperations>();
using var scope = db.CreateScope(nameof(EmailConfirmationSpecs));
var result = await scope.Connection.QuerySqlAsync<AccountDto>(
"SELECT email_confirmed FROM system.accounts WHERE email = @Email",
new { Email = _currentEmail });
if (result.Count > 0)
2025-03-03 00:42:20 +01:00
{
result[0].EmailConfirmed.ShouldBeFalse();
2025-03-03 00:42:20 +01:00
}
}
private class AccountDto
{
public bool EmailConfirmed { get; set; }
public string SecurityStamp { get; set; }
}
private class OutboxDto
{
public string Type { get; set; }
public string Payload { get; set; }
public string Status { get; set; }
}
}