test: add auth system and attachment regression coverage

This commit is contained in:
cesnimda
2026-03-22 14:36:52 +01:00
parent 0b3d65e24b
commit 779ba9fc6d
3 changed files with 159 additions and 0 deletions
@@ -0,0 +1,121 @@
using JobTrackerApi.Controllers;
using JobTrackerApi.Models;
using JobTrackerApi.Services;
using Microsoft.AspNetCore.Http;
using Microsoft.AspNetCore.Identity;
using Microsoft.AspNetCore.Mvc;
using Microsoft.Extensions.Configuration;
using Microsoft.Extensions.Logging.Abstractions;
using Microsoft.Extensions.Options;
using Moq;
using Xunit;
namespace JobTrackerApi.Tests;
public sealed class AuthAndSystemControllerTests
{
[Fact]
public async Task Update_profile_applies_trimmed_profile_fields()
{
var user = new ApplicationUser { Email = "old@example.com", UserName = "olduser" };
var userManager = CreateUserManager();
userManager.Setup(x => x.GetUserAsync(It.IsAny<System.Security.Claims.ClaimsPrincipal>())).ReturnsAsync(user);
userManager.Setup(x => x.UpdateAsync(user)).ReturnsAsync(IdentityResult.Success);
var controller = new AuthController(BuildConfig(), userManager.Object, Mock.Of<ITokenService>(), Mock.Of<IAppEmailSender>(), Mock.Of<IGoogleTokenValidator>());
var result = await controller.UpdateProfile(new AuthController.UpdateProfileRequest(" new@example.com ", " newuser ", " Ada ", " Lovelace ", " Ada L. "));
Assert.IsType<NoContentResult>(result);
Assert.Equal("new@example.com", user.Email);
Assert.Equal("newuser", user.UserName);
Assert.Equal("Ada", user.FirstName);
Assert.Equal("Lovelace", user.LastName);
Assert.Equal("Ada L.", user.DisplayName);
}
[Fact]
public void Me_result_includes_google_link_details_for_local_users()
{
var method = typeof(AuthController).GetMethod("ToMeResult", System.Reflection.BindingFlags.NonPublic | System.Reflection.BindingFlags.Static);
Assert.NotNull(method);
var user = new ApplicationUser
{
Id = "user-1",
Email = "person@example.com",
UserName = "person",
FirstName = "Ada",
LastName = "Lovelace",
DisplayName = "Ada Lovelace",
GoogleSubject = "sub-123",
GoogleEmail = "person@example.com",
GoogleLinkedAt = DateTimeOffset.UtcNow,
};
var result = (AuthController.MeResult)method!.Invoke(null, new object[] { user, new List<string> { "Admin" } })!;
Assert.Equal("local", result.Provider);
Assert.Equal("Ada", result.FirstName);
Assert.Equal("Lovelace", result.LastName);
Assert.Equal("Ada Lovelace", result.DisplayName);
Assert.NotNull(result.GoogleLink);
Assert.True(result.GoogleLink!.Linked);
Assert.Equal("person@example.com", result.GoogleLink.Email);
}
[Fact]
public async Task Admin_system_probe_endpoint_runs_probe_once()
{
var summarizer = new Mock<ISummarizerService>();
summarizer.Setup(x => x.RunProbeAsync(It.IsAny<CancellationToken>())).Returns(Task.CompletedTask);
var controller = new AdminSystemController(BuildConfig(), new AppPaths(BuildConfig(), new FakeHostEnv()), null!, summarizer.Object, new FakeEnv());
var result = await controller.RunSummarizerProbe(CancellationToken.None);
Assert.IsType<NoContentResult>(result);
summarizer.Verify(x => x.RunProbeAsync(It.IsAny<CancellationToken>()), Times.Once);
}
private static IConfiguration BuildConfig()
{
return new ConfigurationBuilder()
.AddInMemoryCollection(new Dictionary<string, string?>())
.Build();
}
private static Mock<UserManager<ApplicationUser>> CreateUserManager()
{
var store = new Mock<IUserStore<ApplicationUser>>();
return new Mock<UserManager<ApplicationUser>>(
store.Object,
Options.Create(new IdentityOptions()),
new PasswordHasher<ApplicationUser>(),
Array.Empty<IUserValidator<ApplicationUser>>(),
Array.Empty<IPasswordValidator<ApplicationUser>>(),
new UpperInvariantLookupNormalizer(),
new IdentityErrorDescriber(),
null!,
new NullLogger<UserManager<ApplicationUser>>()
);
}
private sealed class FakeHostEnv : Microsoft.Extensions.Hosting.IHostEnvironment
{
public string EnvironmentName { get; set; } = "Test";
public string ApplicationName { get; set; } = "JobTrackerApi";
public string ContentRootPath { get; set; } = AppContext.BaseDirectory;
public Microsoft.Extensions.FileProviders.IFileProvider ContentRootFileProvider { get; set; } = null!;
}
private sealed class FakeEnv : Microsoft.AspNetCore.Hosting.IWebHostEnvironment
{
public string ApplicationName { get; set; } = "JobTrackerApi";
public Microsoft.Extensions.FileProviders.IFileProvider WebRootFileProvider { get; set; } = null!;
public string WebRootPath { get; set; } = string.Empty;
public string EnvironmentName { get; set; } = "Test";
public string ContentRootPath { get; set; } = AppContext.BaseDirectory;
public Microsoft.Extensions.FileProviders.IFileProvider ContentRootFileProvider { get; set; } = null!;
}
}
@@ -13,6 +13,7 @@
<IncludeAssets>runtime; build; native; contentfiles; analyzers; buildtransitive</IncludeAssets>
<PrivateAssets>all</PrivateAssets>
</PackageReference>
<PackageReference Include="Moq" Version="4.20.72" />
</ItemGroup>
<ItemGroup>
+37
View File
@@ -0,0 +1,37 @@
import React from 'react';
import '@testing-library/jest-dom';
import { fireEvent, render, screen } from '@testing-library/react';
import { ConfirmProvider } from './confirm';
import { PromptProvider } from './prompt';
import Attachments from './components/Attachments';
import { ToastProvider } from './toast';
import { api } from './api';
jest.mock('./api', () => ({
api: {
get: jest.fn(),
post: jest.fn(),
patch: jest.fn(),
delete: jest.fn(),
},
}));
const mockedApi = api as jest.Mocked<typeof api>;
test('attachments empty state renders drag and drop guidance', async () => {
mockedApi.get.mockResolvedValueOnce({ data: [] } as any);
render(
<ToastProvider>
<ConfirmProvider>
<PromptProvider>
<Attachments jobId={42} />
</PromptProvider>
</ConfirmProvider>
</ToastProvider>,
);
expect(await screen.findByText(/drag and drop files here/i)).toBeInTheDocument();
expect(screen.getByText(/no attachments yet/i)).toBeInTheDocument();
expect(screen.getByText(/max 10 mb each/i)).toBeInTheDocument();
});