From 5490cfb247ce2db1d29cc18ab5aa723fe4cea780 Mon Sep 17 00:00:00 2001 From: Leonid Pershin Date: Thu, 20 Aug 2026 16:06:59 +0300 Subject: [PATCH] Show a bare dash on ownerless school cards. MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The design asked for the owner name or an em dash; wrapping the dash in the Owner template produced Хозяин: —. Low-speed clock tests now cover x1/2 and x2 as well as x1. --- src/HSchool.Client/src/ui/mainMenu.test.ts | 7 ++-- src/HSchool.Client/src/ui/mainMenu.ts | 3 +- src/HSchool.Client/src/ui/schoolCard.test.ts | 32 ++++++++++++++++++- src/HSchool.Client/src/ui/schoolCard.ts | 3 +- .../ClockTempoTests.cs | 11 ++++--- 5 files changed, 47 insertions(+), 9 deletions(-) diff --git a/src/HSchool.Client/src/ui/mainMenu.test.ts b/src/HSchool.Client/src/ui/mainMenu.test.ts index 292b22b..44a6c4b 100644 --- a/src/HSchool.Client/src/ui/mainMenu.test.ts +++ b/src/HSchool.Client/src/ui/mainMenu.test.ts @@ -37,8 +37,11 @@ describe('MainMenu ownership', () => { const orphan = menu.element.querySelector('[data-school-id="3"]'); expect((foreign?.querySelector('.button--danger') as HTMLElement).hidden).toBe(true); expect((orphan?.querySelector('.button--danger') as HTMLElement).hidden).toBe(false); - expect(foreign?.textContent).toContain('Bob'); - expect(orphan?.textContent).toContain(t('schoolOwnerless')); + expect(foreign?.querySelector('.card__owner')?.textContent).toBe(t('schoolOwner', { owner: 'Bob' })); + expect(orphan?.querySelector('.card__owner')?.textContent).toBe(t('schoolOwnerless')); + expect(orphan?.querySelector('.card__owner')?.textContent).not.toBe( + t('schoolOwner', { owner: t('schoolOwnerless') }), + ); }); }); diff --git a/src/HSchool.Client/src/ui/mainMenu.ts b/src/HSchool.Client/src/ui/mainMenu.ts index 41ef429..5d17d32 100644 --- a/src/HSchool.Client/src/ui/mainMenu.ts +++ b/src/HSchool.Client/src/ui/mainMenu.ts @@ -181,7 +181,8 @@ export class MainMenu { const menuSchool: MenuSchool = { ...other, mine: false }; this.patchCard(menuSchool, 'other', this.othersGrid, { canDelete: other.owner === null, - ownerLabel: other.owner ?? t('schoolOwnerless'), + ownerLabel: + other.owner === null ? t('schoolOwnerless') : t('schoolOwner', { owner: other.owner }), }); } diff --git a/src/HSchool.Client/src/ui/schoolCard.test.ts b/src/HSchool.Client/src/ui/schoolCard.test.ts index a82fac5..60a1b8c 100644 --- a/src/HSchool.Client/src/ui/schoolCard.test.ts +++ b/src/HSchool.Client/src/ui/schoolCard.test.ts @@ -2,6 +2,7 @@ * @vitest-environment happy-dom */ import { describe, expect, it } from 'vitest'; +import { t } from '../i18n/strings.ts'; import { SchoolCard } from './schoolCard.ts'; describe('SchoolCard ownership', () => { @@ -21,12 +22,41 @@ describe('SchoolCard ownership', () => { onOpen: () => {}, onDelete: () => {}, canDelete: false, - ownerLabel: 'Bob', + ownerLabel: t('schoolOwner', { owner: 'Bob' }), }, ); document.body.append(card.element); expect((card.element.querySelector('.button--danger') as HTMLElement).hidden).toBe(true); + expect(card.element.querySelector('.card__owner')?.textContent).toBe(t('schoolOwner', { owner: 'Bob' })); + }); + + it('shows a bare dash on an ownerless card, not Owner: —', () => { + const card = new SchoolCard( + { + id: 3, + name: 'Orphan', + gameTime: '2012-03-31T06:00:00.000Z', + running: true, + speedIndex: 1, + seed: 2, + mine: false, + owner: null, + }, + { + onOpen: () => {}, + onDelete: () => {}, + canDelete: true, + ownerLabel: t('schoolOwnerless'), + }, + ); + + document.body.append(card.element); + + expect(card.element.querySelector('.card__owner')?.textContent).toBe(t('schoolOwnerless')); + expect(card.element.querySelector('.card__owner')?.textContent).not.toBe( + t('schoolOwner', { owner: t('schoolOwnerless') }), + ); }); }); diff --git a/src/HSchool.Client/src/ui/schoolCard.ts b/src/HSchool.Client/src/ui/schoolCard.ts index 8c2222d..7a12679 100644 --- a/src/HSchool.Client/src/ui/schoolCard.ts +++ b/src/HSchool.Client/src/ui/schoolCard.ts @@ -68,6 +68,7 @@ export class SchoolCard { this.update(this.school); } + /** `label` is already painted: `Owner: Bob` or a bare dash — do not wrap it again. */ setOwnerLabel(label: string | null): void { if (label === null) { this.owner.hidden = true; @@ -76,7 +77,7 @@ export class SchoolCard { } this.owner.hidden = false; - this.owner.textContent = t('schoolOwner', { owner: label }); + this.owner.textContent = label; } update(school: MenuSchool): void { diff --git a/tests/HSchool.Simulation.Tests/ClockTempoTests.cs b/tests/HSchool.Simulation.Tests/ClockTempoTests.cs index c6bfdf5..30bc2f8 100644 --- a/tests/HSchool.Simulation.Tests/ClockTempoTests.cs +++ b/tests/HSchool.Simulation.Tests/ClockTempoTests.cs @@ -23,18 +23,21 @@ public class ClockTempoTests Assert.Equal(1d, school.LastHeavyGameMinutes); } - [Fact] - public void AtX1_EveryImpulseRunsHeavySystems() + [Theory] + [InlineData(0, 0.5)] + [InlineData(1, 1d)] + [InlineData(2, 2d)] + public void LowSpeed_EveryImpulseRunsHeavySystems(int speedIndex, double expectedMinutes) { using var school = School.Create(1, "Каждый импульс", Start); - school.Clock.SpeedIndex = 1; + school.Clock.SpeedIndex = speedIndex; for (var i = 0; i < 20; i++) { school.Tick(OneTwentiethOfASecond, GameMinutesPerRealSecond); } - Assert.Equal(Start.AddMinutes(1), school.Clock.Time); + Assert.Equal(Start.AddMinutes(expectedMinutes), school.Clock.Time); Assert.Equal(20, school.HeavySystemsInvocations); }