Show a bare dash on ownerless school cards.

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.
This commit is contained in:
Leonid Pershin
2026-08-20 16:06:59 +03:00
parent 71a68b44fd
commit 5490cfb247
5 changed files with 47 additions and 9 deletions
+5 -2
View File
@@ -37,8 +37,11 @@ describe('MainMenu ownership', () => {
const orphan = menu.element.querySelector('[data-school-id="3"]'); const orphan = menu.element.querySelector('[data-school-id="3"]');
expect((foreign?.querySelector('.button--danger') as HTMLElement).hidden).toBe(true); expect((foreign?.querySelector('.button--danger') as HTMLElement).hidden).toBe(true);
expect((orphan?.querySelector('.button--danger') as HTMLElement).hidden).toBe(false); expect((orphan?.querySelector('.button--danger') as HTMLElement).hidden).toBe(false);
expect(foreign?.textContent).toContain('Bob'); expect(foreign?.querySelector('.card__owner')?.textContent).toBe(t('schoolOwner', { owner: 'Bob' }));
expect(orphan?.textContent).toContain(t('schoolOwnerless')); expect(orphan?.querySelector('.card__owner')?.textContent).toBe(t('schoolOwnerless'));
expect(orphan?.querySelector('.card__owner')?.textContent).not.toBe(
t('schoolOwner', { owner: t('schoolOwnerless') }),
);
}); });
}); });
+2 -1
View File
@@ -181,7 +181,8 @@ export class MainMenu {
const menuSchool: MenuSchool = { ...other, mine: false }; const menuSchool: MenuSchool = { ...other, mine: false };
this.patchCard(menuSchool, 'other', this.othersGrid, { this.patchCard(menuSchool, 'other', this.othersGrid, {
canDelete: other.owner === null, canDelete: other.owner === null,
ownerLabel: other.owner ?? t('schoolOwnerless'), ownerLabel:
other.owner === null ? t('schoolOwnerless') : t('schoolOwner', { owner: other.owner }),
}); });
} }
+31 -1
View File
@@ -2,6 +2,7 @@
* @vitest-environment happy-dom * @vitest-environment happy-dom
*/ */
import { describe, expect, it } from 'vitest'; import { describe, expect, it } from 'vitest';
import { t } from '../i18n/strings.ts';
import { SchoolCard } from './schoolCard.ts'; import { SchoolCard } from './schoolCard.ts';
describe('SchoolCard ownership', () => { describe('SchoolCard ownership', () => {
@@ -21,12 +22,41 @@ describe('SchoolCard ownership', () => {
onOpen: () => {}, onOpen: () => {},
onDelete: () => {}, onDelete: () => {},
canDelete: false, canDelete: false,
ownerLabel: 'Bob', ownerLabel: t('schoolOwner', { owner: 'Bob' }),
}, },
); );
document.body.append(card.element); document.body.append(card.element);
expect((card.element.querySelector('.button--danger') as HTMLElement).hidden).toBe(true); 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') }),
);
}); });
}); });
+2 -1
View File
@@ -68,6 +68,7 @@ export class SchoolCard {
this.update(this.school); this.update(this.school);
} }
/** `label` is already painted: `Owner: Bob` or a bare dash — do not wrap it again. */
setOwnerLabel(label: string | null): void { setOwnerLabel(label: string | null): void {
if (label === null) { if (label === null) {
this.owner.hidden = true; this.owner.hidden = true;
@@ -76,7 +77,7 @@ export class SchoolCard {
} }
this.owner.hidden = false; this.owner.hidden = false;
this.owner.textContent = t('schoolOwner', { owner: label }); this.owner.textContent = label;
} }
update(school: MenuSchool): void { update(school: MenuSchool): void {
@@ -23,18 +23,21 @@ public class ClockTempoTests
Assert.Equal(1d, school.LastHeavyGameMinutes); Assert.Equal(1d, school.LastHeavyGameMinutes);
} }
[Fact] [Theory]
public void AtX1_EveryImpulseRunsHeavySystems() [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); using var school = School.Create(1, "Каждый импульс", Start);
school.Clock.SpeedIndex = 1; school.Clock.SpeedIndex = speedIndex;
for (var i = 0; i < 20; i++) for (var i = 0; i < 20; i++)
{ {
school.Tick(OneTwentiethOfASecond, GameMinutesPerRealSecond); 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); Assert.Equal(20, school.HeavySystemsInvocations);
} }