mirror of
https://github.com/aaronpo97/the-biergarten-app.git
synced 2026-10-15 18:14:44 +00:00
Fix Api.Specs test failures: stale Timer column refs and missing test.user fixture
This commit is contained in:
@@ -14,6 +14,7 @@ Scenario: Successful registration with valid details
|
|||||||
|
|
||||||
Scenario: Registration fails with existing username
|
Scenario: Registration fails with existing username
|
||||||
Given the API is running
|
Given the API is running
|
||||||
|
And I have an existing account
|
||||||
When I submit a registration request with values:
|
When I submit a registration request with values:
|
||||||
| Username | FirstName | LastName | Email | DateOfBirth | Password |
|
| Username | FirstName | LastName | Email | DateOfBirth | Password |
|
||||||
| test.user | Test | User | example@example.com | 2001-11-11 | Password1! |
|
| test.user | Test | User | example@example.com | 2001-11-11 | Password1! |
|
||||||
@@ -21,6 +22,7 @@ Scenario: Registration fails with existing username
|
|||||||
|
|
||||||
Scenario: Registration fails with existing email
|
Scenario: Registration fails with existing email
|
||||||
Given the API is running
|
Given the API is running
|
||||||
|
And I have an existing account
|
||||||
When I submit a registration request with values:
|
When I submit a registration request with values:
|
||||||
| Username | FirstName | LastName | Email | DateOfBirth | Password |
|
| Username | FirstName | LastName | Email | DateOfBirth | Password |
|
||||||
| newuser | New | User | test.user@thebiergarten.app | 1990-01-01 | Password1! |
|
| newuser | New | User | test.user@thebiergarten.app | 1990-01-01 | Password1! |
|
||||||
|
|||||||
@@ -83,10 +83,59 @@ public class AuthSteps(ScenarioContext scenario)
|
|||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private const string FixtureUsername = "test.user";
|
||||||
|
private const string FixturePassword = "Password1!";
|
||||||
|
private const string FixtureEmail = "test.user@thebiergarten.app";
|
||||||
|
|
||||||
|
// Scenarios run in parallel across feature classes, and this fixture is shared by name.
|
||||||
|
// Serializing provisioning avoids two scenarios racing to INSERT the same username/email,
|
||||||
|
// which would otherwise surface as a raw SQL unique-constraint error instead of a clean 409.
|
||||||
|
private static readonly SemaphoreSlim FixtureProvisioningLock = new(1, 1);
|
||||||
|
|
||||||
[Given("I have an existing account")]
|
[Given("I have an existing account")]
|
||||||
public void GivenIHaveAnExistingAccount()
|
public async Task GivenIHaveAnExistingAccount()
|
||||||
{
|
{
|
||||||
scenario[TestUserKey] = ("test.user", "password");
|
scenario[TestUserKey] = (FixtureUsername, FixturePassword);
|
||||||
|
|
||||||
|
HttpClient client = GetClient();
|
||||||
|
var registrationData = new
|
||||||
|
{
|
||||||
|
username = FixtureUsername,
|
||||||
|
firstName = "Test",
|
||||||
|
lastName = "User",
|
||||||
|
email = FixtureEmail,
|
||||||
|
dateOfBirth = "1990-01-01",
|
||||||
|
password = FixturePassword,
|
||||||
|
};
|
||||||
|
|
||||||
|
HttpRequestMessage requestMessage = new(HttpMethod.Post, "/api/auth/register")
|
||||||
|
{
|
||||||
|
Content = new StringContent(
|
||||||
|
JsonSerializer.Serialize(registrationData),
|
||||||
|
Encoding.UTF8,
|
||||||
|
"application/json"
|
||||||
|
),
|
||||||
|
};
|
||||||
|
|
||||||
|
// Registration is used (rather than relying on seeded data) so the fixture account is
|
||||||
|
// guaranteed to exist regardless of run order. A 409 means another scenario in this run
|
||||||
|
// already provisioned it, which is equally fine.
|
||||||
|
await FixtureProvisioningLock.WaitAsync();
|
||||||
|
HttpResponseMessage response;
|
||||||
|
try
|
||||||
|
{
|
||||||
|
response = await client.SendAsync(requestMessage);
|
||||||
|
}
|
||||||
|
finally
|
||||||
|
{
|
||||||
|
FixtureProvisioningLock.Release();
|
||||||
|
}
|
||||||
|
|
||||||
|
if ((int)response.StatusCode is not (201 or 409))
|
||||||
|
throw new InvalidOperationException(
|
||||||
|
$"Failed to provision fixture account '{FixtureUsername}': "
|
||||||
|
+ $"{(int)response.StatusCode} {response.StatusCode}"
|
||||||
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
[Given("I do not have an existing account")]
|
[Given("I do not have an existing account")]
|
||||||
@@ -320,7 +369,7 @@ public class AuthSteps(ScenarioContext scenario)
|
|||||||
public async Task GivenIAmLoggedIn()
|
public async Task GivenIAmLoggedIn()
|
||||||
{
|
{
|
||||||
HttpClient client = GetClient();
|
HttpClient client = GetClient();
|
||||||
var loginData = new { username = "test.user", password = "password" };
|
var loginData = new { username = FixtureUsername, password = FixturePassword };
|
||||||
string body = JsonSerializer.Serialize(loginData);
|
string body = JsonSerializer.Serialize(loginData);
|
||||||
|
|
||||||
HttpRequestMessage requestMessage = new(HttpMethod.Post, "/api/auth/login")
|
HttpRequestMessage requestMessage = new(HttpMethod.Post, "/api/auth/login")
|
||||||
|
|||||||
@@ -45,7 +45,7 @@ public class AuthRepositoryTests
|
|||||||
("CreatedAt", typeof(DateTime)),
|
("CreatedAt", typeof(DateTime)),
|
||||||
("UpdatedAt", typeof(DateTime?)),
|
("UpdatedAt", typeof(DateTime?)),
|
||||||
("DateOfBirth", typeof(DateTime)),
|
("DateOfBirth", typeof(DateTime)),
|
||||||
("Timer", typeof(byte[]))
|
("RowVersion", typeof(byte[]))
|
||||||
)
|
)
|
||||||
.AddRow(
|
.AddRow(
|
||||||
expectedUserId,
|
expectedUserId,
|
||||||
@@ -99,7 +99,7 @@ public class AuthRepositoryTests
|
|||||||
("CreatedAt", typeof(DateTime)),
|
("CreatedAt", typeof(DateTime)),
|
||||||
("UpdatedAt", typeof(DateTime?)),
|
("UpdatedAt", typeof(DateTime?)),
|
||||||
("DateOfBirth", typeof(DateTime)),
|
("DateOfBirth", typeof(DateTime)),
|
||||||
("Timer", typeof(byte[]))
|
("RowVersion", typeof(byte[]))
|
||||||
)
|
)
|
||||||
.AddRow(
|
.AddRow(
|
||||||
userId,
|
userId,
|
||||||
@@ -157,7 +157,7 @@ public class AuthRepositoryTests
|
|||||||
("CreatedAt", typeof(DateTime)),
|
("CreatedAt", typeof(DateTime)),
|
||||||
("UpdatedAt", typeof(DateTime?)),
|
("UpdatedAt", typeof(DateTime?)),
|
||||||
("DateOfBirth", typeof(DateTime)),
|
("DateOfBirth", typeof(DateTime)),
|
||||||
("Timer", typeof(byte[]))
|
("RowVersion", typeof(byte[]))
|
||||||
)
|
)
|
||||||
.AddRow(
|
.AddRow(
|
||||||
userId,
|
userId,
|
||||||
@@ -210,7 +210,7 @@ public class AuthRepositoryTests
|
|||||||
("UserAccountId", typeof(Guid)),
|
("UserAccountId", typeof(Guid)),
|
||||||
("Hash", typeof(string)),
|
("Hash", typeof(string)),
|
||||||
("CreatedAt", typeof(DateTime)),
|
("CreatedAt", typeof(DateTime)),
|
||||||
("Timer", typeof(byte[]))
|
("RowVersion", typeof(byte[]))
|
||||||
)
|
)
|
||||||
.AddRow(credentialId, userId, "hashed_password_value", DateTime.UtcNow, null)
|
.AddRow(credentialId, userId, "hashed_password_value", DateTime.UtcNow, null)
|
||||||
);
|
);
|
||||||
|
|||||||
@@ -17,7 +17,7 @@ public class AuthRepository(ISqlConnectionFactory connectionFactory)
|
|||||||
IAuthRepository
|
IAuthRepository
|
||||||
{
|
{
|
||||||
private const string SelectColumns =
|
private const string SelectColumns =
|
||||||
"UserAccountID, Username, FirstName, LastName, Email, CreatedAt, UpdatedAt, DateOfBirth, Timer";
|
"UserAccountID, Username, FirstName, LastName, Email, CreatedAt, UpdatedAt, DateOfBirth, RowVersion";
|
||||||
|
|
||||||
/// <inheritdoc />
|
/// <inheritdoc />
|
||||||
/// <remarks>The account and credential are inserted within a single database transaction.</remarks>
|
/// <remarks>The account and credential are inserted within a single database transaction.</remarks>
|
||||||
@@ -92,7 +92,7 @@ public class AuthRepository(ISqlConnectionFactory connectionFactory)
|
|||||||
await using DbConnection connection = await CreateConnection();
|
await using DbConnection connection = await CreateConnection();
|
||||||
return await connection.QueryFirstOrDefaultAsync<UserCredential>(
|
return await connection.QueryFirstOrDefaultAsync<UserCredential>(
|
||||||
"""
|
"""
|
||||||
SELECT UserCredentialId, UserAccountId, Hash, CreatedAt, Timer
|
SELECT UserCredentialId, UserAccountId, Hash, CreatedAt, RowVersion
|
||||||
FROM dbo.UserCredential
|
FROM dbo.UserCredential
|
||||||
WHERE UserAccountId = @UserAccountId AND IsRevoked = 0
|
WHERE UserAccountId = @UserAccountId AND IsRevoked = 0
|
||||||
""",
|
""",
|
||||||
|
|||||||
@@ -29,7 +29,7 @@ public class UserAccountRepositoryTests
|
|||||||
("CreatedAt", typeof(DateTime)),
|
("CreatedAt", typeof(DateTime)),
|
||||||
("UpdatedAt", typeof(DateTime?)),
|
("UpdatedAt", typeof(DateTime?)),
|
||||||
("DateOfBirth", typeof(DateTime)),
|
("DateOfBirth", typeof(DateTime)),
|
||||||
("Timer", typeof(byte[]))
|
("RowVersion", typeof(byte[]))
|
||||||
)
|
)
|
||||||
.AddRow(
|
.AddRow(
|
||||||
Guid.Parse("aaaaaaaa-aaaa-aaaa-aaaa-aaaaaaaaaaaa"),
|
Guid.Parse("aaaaaaaa-aaaa-aaaa-aaaa-aaaaaaaaaaaa"),
|
||||||
@@ -70,7 +70,7 @@ public class UserAccountRepositoryTests
|
|||||||
("CreatedAt", typeof(DateTime)),
|
("CreatedAt", typeof(DateTime)),
|
||||||
("UpdatedAt", typeof(DateTime?)),
|
("UpdatedAt", typeof(DateTime?)),
|
||||||
("DateOfBirth", typeof(DateTime)),
|
("DateOfBirth", typeof(DateTime)),
|
||||||
("Timer", typeof(byte[]))
|
("RowVersion", typeof(byte[]))
|
||||||
)
|
)
|
||||||
.AddRow(
|
.AddRow(
|
||||||
Guid.NewGuid(),
|
Guid.NewGuid(),
|
||||||
@@ -118,7 +118,7 @@ public class UserAccountRepositoryTests
|
|||||||
("CreatedAt", typeof(DateTime)),
|
("CreatedAt", typeof(DateTime)),
|
||||||
("UpdatedAt", typeof(DateTime?)),
|
("UpdatedAt", typeof(DateTime?)),
|
||||||
("DateOfBirth", typeof(DateTime)),
|
("DateOfBirth", typeof(DateTime)),
|
||||||
("Timer", typeof(byte[]))
|
("RowVersion", typeof(byte[]))
|
||||||
)
|
)
|
||||||
.AddRow(
|
.AddRow(
|
||||||
Guid.NewGuid(),
|
Guid.NewGuid(),
|
||||||
@@ -155,7 +155,7 @@ public class UserAccountRepositoryTests
|
|||||||
("CreatedAt", typeof(DateTime)),
|
("CreatedAt", typeof(DateTime)),
|
||||||
("UpdatedAt", typeof(DateTime?)),
|
("UpdatedAt", typeof(DateTime?)),
|
||||||
("DateOfBirth", typeof(DateTime)),
|
("DateOfBirth", typeof(DateTime)),
|
||||||
("Timer", typeof(byte[]))
|
("RowVersion", typeof(byte[]))
|
||||||
)
|
)
|
||||||
.AddRow(
|
.AddRow(
|
||||||
Guid.NewGuid(),
|
Guid.NewGuid(),
|
||||||
|
|||||||
@@ -14,7 +14,7 @@ public class UserAccountRepository(ISqlConnectionFactory connectionFactory)
|
|||||||
IUserAccountRepository
|
IUserAccountRepository
|
||||||
{
|
{
|
||||||
private const string SelectColumns =
|
private const string SelectColumns =
|
||||||
"UserAccountID, Username, FirstName, LastName, Email, CreatedAt, UpdatedAt, DateOfBirth, Timer";
|
"UserAccountID, Username, FirstName, LastName, Email, CreatedAt, UpdatedAt, DateOfBirth, RowVersion";
|
||||||
|
|
||||||
/// <inheritdoc />
|
/// <inheritdoc />
|
||||||
public async Task<UserAccount?> GetByIdAsync(Guid id)
|
public async Task<UserAccount?> GetByIdAsync(Guid id)
|
||||||
|
|||||||
Reference in New Issue
Block a user