BCards/src/BCards.IntegrationTests/Tests/ModerationWorkflowTests.cs
2025-07-14 23:21:25 -03:00

204 lines
8.5 KiB
C#

using Xunit;
using FluentAssertions;
using Microsoft.Extensions.DependencyInjection;
using MongoDB.Driver;
using BCards.Web.Models;
using BCards.Web.ViewModels;
using BCards.Web.Services;
using BCards.IntegrationTests.Fixtures;
using BCards.IntegrationTests.Helpers;
using System.Net;
namespace BCards.IntegrationTests.Tests;
public class ModerationWorkflowTests : IClassFixture<BCardsWebApplicationFactory>, IAsyncLifetime
{
private readonly BCardsWebApplicationFactory _factory;
private readonly HttpClient _client;
private MongoDbTestFixture _dbFixture = null!;
public ModerationWorkflowTests(BCardsWebApplicationFactory factory)
{
_factory = factory;
_client = _factory.CreateClient();
}
public async Task InitializeAsync()
{
using var scope = _factory.Services.CreateScope();
var database = scope.ServiceProvider.GetRequiredService<IMongoDatabase>();
_dbFixture = new MongoDbTestFixture(database);
await _factory.CleanDatabaseAsync();
await _dbFixture.InitializeTestDataAsync();
}
public Task DisposeAsync() => Task.CompletedTask;
[Fact]
public async Task SubmitPageForModeration_ShouldChangeStatusToPendingModeration()
{
// Arrange
var user = await _dbFixture.CreateTestUserAsync(PlanType.Basic);
var page = await _dbFixture.CreateTestUserPageAsync(user.Id, PageStatus.Creating, "tecnologia", 3, 1);
var authenticatedClient = await AuthenticationHelper.CreateAuthenticatedClientAsync(_factory, user);
// Act - Submit page for moderation
var response = await authenticatedClient.PostAsync($"/Admin/SubmitForModeration/{page.Id}", null);
// Assert
response.IsSuccessStatusCode.Should().BeTrue();
// Verify page status changed in database
var updatedPages = await _dbFixture.GetUserPagesAsync(user.Id);
var updatedPage = updatedPages.First();
updatedPage.Status.Should().Be(PageStatus.PendingModeration);
updatedPage.ModerationAttempts.Should().BeGreaterThan(0);
}
[Fact]
public async Task SubmitPageForModeration_WithoutActiveLinks_ShouldFail()
{
// Arrange
var user = await _dbFixture.CreateTestUserAsync(PlanType.Basic);
var page = await _dbFixture.CreateTestUserPageAsync(user.Id, PageStatus.Creating, "tecnologia", 0, 0); // No links
var authenticatedClient = await AuthenticationHelper.CreateAuthenticatedClientAsync(_factory, user);
// Act
var response = await authenticatedClient.PostAsync($"/Admin/SubmitForModeration/{page.Id}", null);
// Assert
response.IsSuccessStatusCode.Should().BeFalse();
// Verify page status didn't change
var updatedPages = await _dbFixture.GetUserPagesAsync(user.Id);
var updatedPage = updatedPages.First();
updatedPage.Status.Should().Be(PageStatus.Creating);
}
[Fact]
public async Task ApprovePage_ShouldChangeStatusToActive()
{
// Arrange
using var scope = _factory.Services.CreateScope();
var moderationService = scope.ServiceProvider.GetRequiredService<IModerationService>();
var user = await _dbFixture.CreateTestUserAsync(PlanType.Basic);
var page = await _dbFixture.CreateTestUserPageAsync(user.Id, PageStatus.PendingModeration, "tecnologia", 3, 1);
// Act - Approve the page
await moderationService.ApprovePageAsync(page.Id, "test-moderator-id", "Page looks good");
// Assert
var updatedPages = await _dbFixture.GetUserPagesAsync(user.Id);
var updatedPage = updatedPages.First();
updatedPage.Status.Should().Be(PageStatus.Active);
updatedPage.ApprovedAt.Should().BeCloseTo(DateTime.UtcNow, TimeSpan.FromMinutes(1));
updatedPage.ModerationHistory.Should().HaveCount(1);
updatedPage.ModerationHistory.First().Status.Should().Be("approved");
}
[Fact]
public async Task RejectPage_ShouldChangeStatusToRejected()
{
// Arrange
using var scope = _factory.Services.CreateScope();
var moderationService = scope.ServiceProvider.GetRequiredService<IModerationService>();
var user = await _dbFixture.CreateTestUserAsync(PlanType.Basic);
var page = await _dbFixture.CreateTestUserPageAsync(user.Id, PageStatus.PendingModeration, "tecnologia", 3, 1);
// Act - Reject the page
await moderationService.RejectPageAsync(page.Id, "test-moderator-id", "Inappropriate content", new List<string> { "spam", "offensive" });
// Assert
var updatedPages = await _dbFixture.GetUserPagesAsync(user.Id);
var updatedPage = updatedPages.First();
updatedPage.Status.Should().Be(PageStatus.Inactive); // First rejection goes to Inactive
updatedPage.ModerationHistory.Should().HaveCount(1);
var rejectionHistory = updatedPage.ModerationHistory.First();
rejectionHistory.Status.Should().Be("rejected");
rejectionHistory.Reason.Should().Be("Inappropriate content");
rejectionHistory.Issues.Should().Contain("spam");
rejectionHistory.Issues.Should().Contain("offensive");
}
[Fact]
public async Task AccessApprovedPage_WithoutPreviewToken_ShouldSucceed()
{
// Arrange
using var scope = _factory.Services.CreateScope();
var moderationService = scope.ServiceProvider.GetRequiredService<IModerationService>();
var user = await _dbFixture.CreateTestUserAsync(PlanType.Basic);
var page = await _dbFixture.CreateTestUserPageAsync(user.Id, PageStatus.PendingModeration, "tecnologia", 3, 1);
// Approve the page
await moderationService.ApprovePageAsync(page.Id, "test-moderator-id", "Approved");
// Act - Access the page without preview token
var response = await _client.GetAsync($"/page/{page.Category}/{page.Slug}");
// Assert
response.StatusCode.Should().Be(HttpStatusCode.OK);
var content = await response.Content.ReadAsStringAsync();
content.Should().Contain(page.DisplayName);
content.Should().NotContain("MODO PREVIEW"); // Should not show preview banner
}
[Fact]
public async Task GetPendingModerationPages_ShouldReturnCorrectPages()
{
// Arrange
using var scope = _factory.Services.CreateScope();
var moderationService = scope.ServiceProvider.GetRequiredService<IModerationService>();
var user1 = await _dbFixture.CreateTestUserAsync(PlanType.Basic, "user1@example.com");
var user2 = await _dbFixture.CreateTestUserAsync(PlanType.Basic, "user2@example.com");
// Create pages in different statuses
await _dbFixture.CreateTestUserPageAsync(user1.Id, PageStatus.PendingModeration, "tecnologia", 3, 1);
await _dbFixture.CreateTestUserPageAsync(user2.Id, PageStatus.PendingModeration, "negocios", 4, 2);
await _dbFixture.CreateTestUserPageAsync(user1.Id, PageStatus.Creating, "pessoal", 2, 0); // Should not appear
await _dbFixture.CreateTestUserPageAsync(user2.Id, PageStatus.Active, "saude", 5, 1); // Should not appear
// Act
var pendingPages = await moderationService.GetPendingModerationAsync();
// Assert
pendingPages.Should().HaveCount(2);
pendingPages.Should().OnlyContain(p => p.Status == PageStatus.PendingModeration);
}
[Fact]
public async Task ModerationStats_ShouldReturnCorrectCounts()
{
// Arrange
using var scope = _factory.Services.CreateScope();
var moderationService = scope.ServiceProvider.GetRequiredService<IModerationService>();
var user = await _dbFixture.CreateTestUserAsync(PlanType.Basic);
// Create pages with different statuses
var pendingPage1 = await _dbFixture.CreateTestUserPageAsync(user.Id, PageStatus.PendingModeration, "tecnologia", 3, 1);
var pendingPage2 = await _dbFixture.CreateTestUserPageAsync(user.Id, PageStatus.PendingModeration, "negocios", 3, 1);
var activePage = await _dbFixture.CreateTestUserPageAsync(user.Id, PageStatus.PendingModeration, "pessoal", 3, 1);
// Approve one page today
await moderationService.ApprovePageAsync(activePage.Id, "moderator", "Good");
// Act
var stats = await moderationService.GetModerationStatsAsync();
// Assert
stats["pending"].Should().Be(2);
stats["approvedToday"].Should().Be(1);
stats["rejectedToday"].Should().Be(0);
}
}