ApiFactory поднимает реальный API на одноразовом postgres:16-alpine (Ryuk off — сеть к Docker Hub нестабильна, образ закэширован; RateLimiting off через env, т.к. лимитер читает конфиг эагерно). Program сделан public partial для фабрики. Сценарии (10 зелёных): - signup-flow: signup→token→/api/me с org; дубль-signup 400; слабый пароль 400. - tenant isolation A vs B: контрагент A не виден B (список + прямой GET 404). - permission: кастомная роль без ProductsEdit → PUT товара 403, GET 200; админ не 403. - supply post→unpost: остаток 0→10, Cost=70 (скользящее среднее), unpost→0; двойной post 409. - retail overselling: продажа сверх остатка → 409; недоплата → 400. Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
55 lines
1.9 KiB
C#
55 lines
1.9 KiB
C#
using System.Net;
|
|
using System.Net.Http.Json;
|
|
using System.Text.Json;
|
|
using FluentAssertions;
|
|
using foodmarket.IntegrationTests.Support;
|
|
using Xunit;
|
|
|
|
namespace foodmarket.IntegrationTests;
|
|
|
|
[Collection(ApiCollection.Name)]
|
|
public class SignupFlowTests
|
|
{
|
|
private readonly ApiFactory _factory;
|
|
public SignupFlowTests(ApiFactory factory) => _factory = factory;
|
|
|
|
[Fact]
|
|
public async Task Signup_then_login_yields_token_with_org()
|
|
{
|
|
var actor = new ApiActor(_factory.CreateClient());
|
|
var email = $"signup-{Guid.NewGuid():N}@example.kz";
|
|
const string password = "Passw0rd!";
|
|
|
|
var signup = await actor.SignupAsync(email, password, "Signup Org");
|
|
signup.StatusCode.Should().Be(HttpStatusCode.OK);
|
|
|
|
var token = await actor.TokenAsync(email, password);
|
|
token.Should().NotBeNullOrEmpty();
|
|
actor.UseToken(token);
|
|
|
|
var me = await actor.GetJsonAsync("/api/me");
|
|
me.GetProperty("email").GetString().Should().Be(email);
|
|
me.GetProperty("orgId").GetString().Should().NotBeNullOrEmpty();
|
|
me.GetProperty("hasLiveOrg").GetBoolean().Should().BeTrue();
|
|
}
|
|
|
|
[Fact]
|
|
public async Task Duplicate_signup_is_rejected()
|
|
{
|
|
var actor = new ApiActor(_factory.CreateClient());
|
|
var email = $"dup-{Guid.NewGuid():N}@example.kz";
|
|
|
|
(await actor.SignupAsync(email, "Passw0rd!", "Dup Org 1")).StatusCode.Should().Be(HttpStatusCode.OK);
|
|
var second = await actor.SignupAsync(email, "Passw0rd!", "Dup Org 2");
|
|
second.StatusCode.Should().Be(HttpStatusCode.BadRequest);
|
|
}
|
|
|
|
[Fact]
|
|
public async Task Weak_password_is_rejected()
|
|
{
|
|
var actor = new ApiActor(_factory.CreateClient());
|
|
var resp = await actor.SignupAsync($"weak-{Guid.NewGuid():N}@example.kz", "short", "Weak Org");
|
|
resp.StatusCode.Should().Be(HttpStatusCode.BadRequest);
|
|
}
|
|
}
|