food-market/tests/food-market.IntegrationTests/PlanSignupTests.cs
nns 0ce0e0df77
Some checks are pending
Auto-tag / Create date-tag (push) Waiting to run
CI / Backend (.NET 8) (push) Waiting to run
CI / Web (React + Vite) (push) Waiting to run
CI / POS (WPF, Windows) (push) Waiting to run
Docker API / Build + push API (push) Waiting to run
Docker API / Deploy API on stage (push) Blocked by required conditions
Docker Public / Build + push Public (test + latest) (push) Waiting to run
Docker Public / Deploy :test → test.food-market.kz (push) Blocked by required conditions
Docker Web / Build + push Web (push) Waiting to run
Docker Web / Deploy Web on stage (push) Blocked by required conditions
fix(регистрация): 7 правок этапа «Регистрация» (прогон 12.10)
1. Маска телефона: префикс «+7 », оператор не подставляется заранее.
   Нормализация снимает ведущую «8» и код страны «7» (на 11 цифрах),
   value хранится каноническим «+7»+national и восстанавливается снятием
   литерального «+7» (без 8/11-эвристик) — ввод больше не «скачет».
   Обе копии (public + admin). Проверено на всех вариантах + вставка.
2. Тариф и бесплатный период: Organization.Plan/FreeTrialEndsAt +
   конфигурация «Бизнес» (Phase50, существующие → «start», дата NULL).
   Signup сохраняет план и 90 дней; показ в кабинете владельца и в
   карточке/списке суперадмина. Биллинга/блокировки нет.
3. Ошибки формы: переход к первому полю с ошибкой + фокус; единые
   сообщения «Укажите email/телефон/название магазина», «Придумайте пароль».
4. «Первые шаги»: кнопка «Скрыть» (возврат из настроек организации);
   шаг каталога показывает статус копии реестра («загружается…» /
   «Каталог готов: N товаров — проверьте продажные цены»); ссылка на
   Forgejo заменена на «Базу знаний».
5. «Новые функции»: не считаем изменения до даты регистрации орг
   (новой орг баннер скрыт) + русская плюрализация улучшений/исправлений.
6. Карточка товара: «Закупочная цена» видна и в простом режиме (настройка
   ShowReferencePriceOnProduct), подпись настройки приведена к новой схеме.
7. Копия реестра: первый штрихкод помечается «Основным»; бэкфилл уже
   скопированных товаров без основного (Phase51).

Тесты: PlanSignupTests (3), RegistryCopyPrimaryBarcodeTests (1),
MarkupToggleTests (3, регрессия) — зелёные. Phone-нормализация покрыта
симуляцией ввода/вставки.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-10-12 21:46:15 +05:00

82 lines
3.8 KiB
C#
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

using System.Net.Http.Json;
using System.Text.Json;
using FluentAssertions;
using foodmarket.IntegrationTests.Support;
using Xunit;
namespace foodmarket.IntegrationTests;
/// <summary>Регистрация сохраняет выбранный тариф и бесплатный период (90 дней),
/// а для «Бизнес» — конфигурацию конструктора. Settings-эндпоинт отдаёт их
/// read-only для показа в кабинете владельца. Биллинга/блокировки нет.
/// Решение владельца 12.10.</summary>
[Collection(ApiCollection.Name)]
public class PlanSignupTests
{
private readonly ApiFactory _factory;
public PlanSignupTests(ApiFactory factory) => _factory = factory;
private async Task<JsonElement> SignupWithPlanAndGetSettingsAsync(ApiActor api, string slug, object body)
{
var resp = await api.Http.PostAsJsonAsync("/api/auth/signup", body);
resp.IsSuccessStatusCode.Should().BeTrue(await resp.Content.ReadAsStringAsync());
api.UseToken(await api.TokenAsync($"{slug}@example.kz", "Passw0rd!"));
return await api.GetJsonAsync("/api/organization/settings");
}
[Fact]
public async Task Business_signup_saves_plan_trial_and_config()
{
var api = new ApiActor(_factory.CreateClient());
var slug = $"plan-biz-{Guid.NewGuid():N}";
var s = await SignupWithPlanAndGetSettingsAsync(api, slug, new
{
email = $"{slug}@example.kz", password = "Passw0rd!", organizationName = $"Org {slug}",
phone = "+77010000000", plan = "business",
shops = 3, cashes = 4, warehouses = 2, employees = 25,
});
s.GetProperty("plan").GetString().Should().Be("business");
s.GetProperty("planShops").GetInt32().Should().Be(3);
s.GetProperty("planCashes").GetInt32().Should().Be(4);
s.GetProperty("planWarehouses").GetInt32().Should().Be(2);
s.GetProperty("planEmployees").GetInt32().Should().Be(25);
var trial = s.GetProperty("freeTrialEndsAt").GetDateTime();
var expected = DateTime.UtcNow.AddDays(90);
trial.Should().BeCloseTo(expected, TimeSpan.FromHours(1), "бесплатный период = регистрация + 90 дней");
}
[Fact]
public async Task Start_signup_saves_plan_without_config()
{
var api = new ApiActor(_factory.CreateClient());
var slug = $"plan-start-{Guid.NewGuid():N}";
var s = await SignupWithPlanAndGetSettingsAsync(api, slug, new
{
email = $"{slug}@example.kz", password = "Passw0rd!", organizationName = $"Org {slug}",
phone = "+77010000000", plan = "start",
});
s.GetProperty("plan").GetString().Should().Be("start");
s.GetProperty("freeTrialEndsAt").ValueKind.Should().Be(JsonValueKind.String, "дата бесплатного периода проставлена");
// Конфигурация «Бизнес» не относится к «Старт» — поля null.
s.GetProperty("planShops").ValueKind.Should().Be(JsonValueKind.Null);
s.GetProperty("planEmployees").ValueKind.Should().Be(JsonValueKind.Null);
}
[Fact]
public async Task Unknown_plan_falls_back_to_start()
{
var api = new ApiActor(_factory.CreateClient());
var slug = $"plan-unk-{Guid.NewGuid():N}";
var s = await SignupWithPlanAndGetSettingsAsync(api, slug, new
{
email = $"{slug}@example.kz", password = "Passw0rd!", organizationName = $"Org {slug}",
phone = "+77010000000", plan = "enterprise-xxl",
});
s.GetProperty("plan").GetString().Should().Be("start", "неизвестный тариф нормализуется к «start»");
}
}