Files
PolyTraderSharp/tests/PolyTrader.Tests/WebUi/StopTradingEndpointTests.cs
T
RichardandClaude Opus 5 d33d695db5 WebUI: Trading beenden, ohne die Anwendung zu beenden
Umsetzung von #563.

Entscheidung Richard, 13.09.2026: Beenden soll ueber das WebUI gehen, aber
beschraenkt auf das Trading. Ein Ende der ganzen Anwendung naehme den Webserver
mit; danach waere das WebUI nicht mehr erreichbar.

POST /api/dashboard/stop-trading setzt Live- und Demo-Modus auf Inaktiv und
schaltet die Pause ein. Damit halten CopyTrading und ResolutionFarming (#569)
an, wie beim Ende der Anwendung. Offene Orders an der Boerse werden bewusst
nicht storniert: Das tut auch das Beenden der App nicht, und ein Eingriff in
die CLOB-Integration gehoert nicht in einen Notschalter. Der Dialog sagt das
ausdruecklich.

Die Route verlangt {"confirmed": true}. Ein Aufruf ohne Absicht, etwa aus einem
alten Skript, beendet nichts. Der Vorgang wird als Warnung protokolliert, mit
den Modi vorher.

Im Dashboard steht unter der Notfall-Pause jetzt "Trading beenden ...". Der
Dialog ist wie im Desktop 10 Sekunden gesperrt, Abbrechen und Esc gehen
jederzeit. Wieder aufgenommen wird nur ueber die Modus-Schalter. Die Pause
aufzuheben genuegt nicht, das haelt ein Test fest.

Offen bis #570: Laufende Verkaufsleitern und der REST-Pre-Redeem pruefen die
Pause nicht. Der Inaktiv-Modus, den dieser Knopf setzt, sperrt den Pre-Redeem
bereits; die Leitern friert erst #570 ein.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
2026-09-13 13:51:24 +02:00

90 lines
3.7 KiB
C#

using System;
using System.Linq;
using System.Threading.Tasks;
using PolyTraderSharp;
using PolyTraderSharp.Services;
using Xunit;
namespace PolyTrader.Tests.WebUi
{
/// <summary>
/// Trading beenden über das WebUI, ohne die Anwendung zu beenden (#563).
/// </summary>
public class StopTradingEndpointTests
{
[Fact]
public async Task Beenden_setzt_beide_Modi_auf_Inaktiv_und_die_Pause_an()
{
await using var web = await WebUiTestHost.StartAsync();
web.State.LiveTradingMode = TradingMode.Active;
web.State.DemoTradingMode = TradingMode.SellOnly;
var (status, body) = await web.PostJsonAsync("/api/dashboard/stop-trading", new { confirmed = true });
Assert.Equal(200, status);
Assert.Equal(TradingMode.Inactive, web.State.LiveTradingMode);
Assert.Equal(TradingMode.Inactive, web.State.DemoTradingMode);
Assert.True(web.State.GlobalTradingPaused);
Assert.True(body.GetProperty("globalTradingPaused").GetBoolean());
}
[Fact]
public async Task Ohne_Bestaetigung_bleibt_alles_wie_es_ist()
{
await using var web = await WebUiTestHost.StartAsync();
web.State.LiveTradingMode = TradingMode.Active;
var (withoutBody, _) = await web.PostJsonAsync("/api/dashboard/stop-trading");
var (notConfirmed, _) = await web.PostJsonAsync("/api/dashboard/stop-trading", new { confirmed = false });
Assert.Equal(400, withoutBody);
Assert.Equal(400, notConfirmed);
Assert.Equal(TradingMode.Active, web.State.LiveTradingMode);
Assert.False(web.State.GlobalTradingPaused);
}
[Fact]
public async Task Anwendung_und_WebUI_bleiben_danach_erreichbar()
{
await using var web = await WebUiTestHost.StartAsync();
await web.PostJsonAsync("/api/dashboard/stop-trading", new { confirmed = true });
var summary = await web.GetJsonAsync("/api/dashboard/summary");
Assert.True(summary.GetProperty("globalTradingPaused").GetBoolean());
Assert.Equal("Inactive", summary.GetProperty("liveTradingMode").GetString());
}
[Fact]
public async Task Beenden_wird_als_Warnung_protokolliert()
{
await using var web = await WebUiTestHost.StartAsync();
await web.PostJsonAsync("/api/dashboard/stop-trading", new { confirmed = true });
var entry = web.Logger.GetHistory(TimeSpan.FromMinutes(1))
.LastOrDefault(e => e.Message.Contains("Trading beendet", StringComparison.Ordinal));
Assert.NotNull(entry);
Assert.Equal(LogLevel.Warning, entry!.Level);
Assert.Contains("Orders an der Börse bleiben stehen", entry.Message);
}
[Fact]
public async Task Wiederaufnahme_nur_ausdruecklich_ueber_die_Modus_Schalter()
{
await using var web = await WebUiTestHost.StartAsync();
await web.PostJsonAsync("/api/dashboard/stop-trading", new { confirmed = true });
// Die Pause aufzuheben genuegt nicht: Die Modi stehen weiter auf Inaktiv.
await web.PostJsonAsync("/api/dashboard/trading-mode", new { modeType = "pause", targetMode = "" });
Assert.False(web.State.GlobalTradingPaused);
Assert.Equal(TradingMode.Inactive, web.State.LiveTradingMode);
Assert.Equal(TradingMode.Inactive, web.State.DemoTradingMode);
var (status, _) = await web.PostJsonAsync("/api/dashboard/trading-mode", new { modeType = "demo", targetMode = "Active" });
Assert.Equal(200, status);
Assert.Equal(TradingMode.Active, web.State.DemoTradingMode);
}
}
}