From 1097d8ddf55e5bfb5cf12529ac1c6614228a0cb7 Mon Sep 17 00:00:00 2001 From: Leonid Pershin Date: Fri, 21 Aug 2026 02:46:30 +0300 Subject: [PATCH] Add review tests for notices, scene prompts, and Play lock. Co-authored-by: Cursor --- src/HSchool.Client/src/ui/gameScreen.test.ts | 29 +++++++++++ tests/HSchool.Content.Tests/EventDefTests.cs | 18 +++++++ .../PortraitSceneCollectorTests.cs | 51 +++++++++++++++++++ 3 files changed, 98 insertions(+) diff --git a/src/HSchool.Client/src/ui/gameScreen.test.ts b/src/HSchool.Client/src/ui/gameScreen.test.ts index 7e8161c..8f5a775 100644 --- a/src/HSchool.Client/src/ui/gameScreen.test.ts +++ b/src/HSchool.Client/src/ui/gameScreen.test.ts @@ -292,6 +292,35 @@ describe('GameScreen view restore', () => { expect(location.search).toContain('tab=people'); }); + it('disables Play while a pausing notice is open', () => { + const screen = new GameScreen({ + onLeave: () => {}, + onSetRunning: () => {}, + onSetSpeed: () => {}, + onSkip: () => {}, + }); + document.body.append(screen.element); + screen.show(school({ running: false })); + + const play = screen.element.querySelector('.clock__controls .button--icon'); + expect(play?.disabled).toBe(false); + + screen.applyNotice({ + type: 'notice', + id: 4, + defName: 'GenerationFailed', + severity: 2, + pause: true, + ttlMs: 0, + personId: 0, + action: 'none', + }); + + expect(play?.disabled).toBe(true); + expect(play?.title).toBe(t('noticePauseLocked')); + expect(screen.element.querySelector('.notice-modal')).not.toBeNull(); + }); + it('keeps a guest on overview even when the URL asks for manage', () => { history.replaceState(null, '', '/?school=3&mode=manage'); const screen = new GameScreen({ diff --git a/tests/HSchool.Content.Tests/EventDefTests.cs b/tests/HSchool.Content.Tests/EventDefTests.cs index e6cd997..5e78cf0 100644 --- a/tests/HSchool.Content.Tests/EventDefTests.cs +++ b/tests/HSchool.Content.Tests/EventDefTests.cs @@ -53,6 +53,24 @@ public class EventDefTests Assert.Contains("fullMoon", ex.Message, StringComparison.Ordinal); } + [Fact] + public void UnknownAction_FailsTheCatalog() + { + var documents = PackDocuments.FromDirectory( + CatalogLoader.CorePackId, + Path.Combine(AppContext.BaseDirectory, "vanilla")) + .Append(PackDocuments.Def( + CatalogLoader.CorePackId, + "events", + "bad-action", + """{ "defName": "BadAct", "severity": "info", "ttlMs": 1, "trigger": "dayStart", "action": "teleport" }""")) + .ToList(); + + var ex = Assert.Throws(() => _loader.Load([CatalogLoader.CorePackId], documents)); + Assert.Contains("action", ex.Message, StringComparison.Ordinal); + Assert.Contains("teleport", ex.Message, StringComparison.Ordinal); + } + private DefCatalog LoadVanilla() { var root = Path.Combine(AppContext.BaseDirectory, "vanilla"); diff --git a/tests/HSchool.Server.Tests/PortraitSceneCollectorTests.cs b/tests/HSchool.Server.Tests/PortraitSceneCollectorTests.cs index e44c106..10967fc 100644 --- a/tests/HSchool.Server.Tests/PortraitSceneCollectorTests.cs +++ b/tests/HSchool.Server.Tests/PortraitSceneCollectorTests.cs @@ -1,4 +1,5 @@ using HSchool.Content; +using HSchool.Server.Api; using HSchool.Server.Game; using HSchool.Simulation; @@ -101,6 +102,56 @@ public class PortraitSceneCollectorTests Assert.DoesNotContain(scene.PositiveFragments, fragment => fragment.Contains("= 0 && sceneAt > clothesAt); + + var chairs = PortraitSceneCollector.Collect( + catalog, map, "chairs", Precipitation.None, "TestClimate", [], [], Budget); + var (without, _) = PortraitPromptBuilder.Build(card, profile, PortraitKind.Avatar, scene: chairs); + Assert.DoesNotContain("blackboard", without, StringComparison.OrdinalIgnoreCase); + Assert.DoesNotContain("chair", without, StringComparison.OrdinalIgnoreCase); + } + + private static PersonCardResponse SampleWornCard() => + new( + "f0.c0", + "Maria Ivanova", + "Ivanova", + "Maria", + "", + true, + 12, + new DateTime(2000, 3, 14, 0, 0, 0, DateTimeKind.Utc), + ["student"], + 5, + "A", + "class-1", + null, + null, + [new LabeledStatResponse("HairColor", "Hair colour", "Black")], + [], + [], + [], + null, + null, + new PersonFamilyResponse([], [], [], []), + [new WornItemResponse("Shirt", "Shirt", "White", "White", [new DefLabelResponse(ApparelLayers.Top, "Top")], 1f, "new", [ApparelLayers.Underwear])], + [], + 0f, + 0f); + private DefCatalog LoadCatalog() { return _loader.Load(