feat: Add tests for 2023 watch shop tab and room consumables; implement new storefront endpoint and update documentation

This commit is contained in:
Alexa
2026-07-07 23:27:13 +03:00
parent 148d70b048
commit 4378a46f8e
5 changed files with 324 additions and 2 deletions
@@ -176,6 +176,25 @@ public sealed class RoomConsumablesShopTests : IClassFixture<DorkNetServerFactor
Assert.Equal(0, emptied.GetArrayLength());
}
[Fact]
public async Task Unprefixed_2023_commerce_probes_respond()
{
// The 2023 client calls these WITHOUT the api/ prefix on startup;
// a 404 here surfaces as "CleanupPendingTransactions failed" +
// unobserved-HTTP-404 crash reports in Player.log.
using var client = ApiClient();
using var cleanup = await client.PostAsync("/purchase/v1/cleanuppending",
new StringContent("", Encoding.UTF8, "application/x-www-form-urlencoded"));
Assert.True(cleanup.IsSuccessStatusCode);
using var hasSpent = await client.GetAsync("/purchase/v1/hasspentmoney");
Assert.Equal("false", await hasSpent.Content.ReadAsStringAsync());
var bundles = await GetJsonAsync(client, "/reminder/currentTokenBundles/v2");
Assert.Equal(JsonValueKind.Array, bundles.ValueKind);
}
private HttpClient ApiClient(GameClientSession? session = null)
{
var client = _factory.CreateClient(new() { AllowAutoRedirect = false });
@@ -0,0 +1,76 @@
using System.Net.Http.Headers;
using System.Text.Json;
namespace DorkNet.Server.Tests;
/// <summary>
/// The 2023 client's watch Shop tab pipeline: rows come from
/// <c>/api/storefronts/v3/giftdropstore/{id}</c> (each row MUST carry a
/// singular <c>GiftDrop</c> object — the 2023 POGBAGAHGIA formatter
/// ignores the 2020 <c>GiftDrops</c> array, and a null inner desc makes
/// StoreItemListModel's filter predicate NRE so the Shop shows nothing),
/// and the featured strip ids come from <c>/v1/toptoday</c> as a BARE
/// int list that must resolve against those rows.
/// </summary>
public sealed class WatchShop2023Tests : IClassFixture<DorkNetServerFactory>
{
private readonly DorkNetServerFactory _factory;
public WatchShop2023Tests(DorkNetServerFactory factory) => _factory = factory;
[Fact]
public async Task Giftdropstore_rows_carry_singular_giftdrop_and_toptoday_ids_resolve()
{
using var client = ApiClient();
var storefront = await GetJsonAsync(client, "/api/storefronts/v3/giftdropstore/3");
var rows = storefront.GetProperty("StoreItems");
Assert.True(rows.GetArrayLength() > 0, "watch storefront seeded no rows");
var rowIds = new HashSet<int>();
foreach (var row in rows.EnumerateArray())
{
rowIds.Add(row.GetProperty("PurchasableItemId").GetInt32());
Assert.Equal(0, row.GetProperty("Type").GetInt32());
Assert.True(row.GetProperty("Prices").GetArrayLength() > 0);
var giftDrop = row.GetProperty("GiftDrop");
Assert.Equal(JsonValueKind.Object, giftDrop.ValueKind);
Assert.Equal(row.GetProperty("PurchasableItemId").GetInt32(),
giftDrop.GetProperty("GiftDropId").GetInt32());
Assert.Equal(JsonValueKind.String, giftDrop.GetProperty("FriendlyName").ValueKind);
Assert.Equal(JsonValueKind.String, giftDrop.GetProperty("TagList").ValueKind);
var rarity = giftDrop.GetProperty("Rarity").GetInt32();
Assert.Contains(rarity, new[] { 0, 10, 20, 30, 50 });
}
// Featured strip: bare int ids, every one resolvable in the rows.
var topToday = await GetJsonAsync(client, "/api/storefronts/v1/toptoday");
Assert.Equal(JsonValueKind.Array, topToday.ValueKind);
Assert.True(topToday.GetArrayLength() > 0, "toptoday returned no featured ids");
foreach (var id in topToday.EnumerateArray())
{
Assert.Equal(JsonValueKind.Number, id.ValueKind);
Assert.Contains(id.GetInt32(), rowIds);
}
}
private HttpClient ApiClient()
{
var client = _factory.CreateClient(new() { AllowAutoRedirect = false });
client.BaseAddress = new Uri($"http://api.{_factory.ApexDomain}");
client.Timeout = TimeSpan.FromSeconds(30);
client.DefaultRequestHeaders.Accept.ParseAdd("application/json");
client.DefaultRequestHeaders.UserAgent.ParseAdd("RecRoom/2023.03.21");
client.DefaultRequestHeaders.TryAddWithoutValidation("X-DorkNet-Version", "march_2023_03_21");
return client;
}
private static async Task<JsonElement> GetJsonAsync(HttpClient client, string path)
{
using var response = await client.GetAsync(path);
response.EnsureSuccessStatusCode();
using var document = await JsonDocument.ParseAsync(await response.Content.ReadAsStreamAsync());
return document.RootElement.Clone();
}
}