Files
ashen-realms/apps/web/src/app/app.spec.ts
Bastian Wagner 048cf80e78 test(slice-0.4): assert migration SQL and top-bar silver/XP rendering
Adds a real-SQL-inspection test for CreateLootAndRewards1788600000000
(mirroring the visible-vertical-slice pattern) so the one-reward-per-combat
unique index and other DB-level invariants can't be silently deleted
without failing a test, and asserts the TopBar renders character.silver
and character.experience values already present in the app.spec.ts fixture.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
2026-08-20 10:25:26 +02:00

115 lines
4.5 KiB
TypeScript

import { signal, WritableSignal } from '@angular/core';
import { TestBed } from '@angular/core/testing';
import { Router, provideRouter } from '@angular/router';
import { CharacterResponse } from './core/api/game-api.models';
import { WorldStore } from './features/world/world.store';
import { AppShellComponent } from './layout/app-shell/app-shell.component';
import { routes } from './app.routes';
describe('App', () => {
let character: WritableSignal<CharacterResponse | null>;
let currentLocation: WritableSignal<null>;
let selectedConnection: WritableSignal<null>;
beforeEach(async () => {
character = signal<CharacterResponse | null>(null);
currentLocation = signal(null);
selectedConnection = signal(null);
await TestBed.configureTestingModule({
imports: [AppShellComponent],
providers: [
provideRouter([
{ path: 'world', children: [] },
{ path: 'hunt', children: [] },
]),
{
provide: WorldStore,
useValue: { character, currentLocation, selectedConnection },
},
],
}).compileComponents();
});
it('renders the reusable game shell with Karte and Jagd available', async () => {
const fixture = TestBed.createComponent(AppShellComponent);
const router = TestBed.inject(Router);
await router.navigateByUrl('/world');
fixture.detectChanges();
await fixture.whenStable();
const element = fixture.nativeElement as HTMLElement;
expect(element.querySelector('app-top-bar')).not.toBeNull();
expect(element.querySelector('app-side-navigation')).not.toBeNull();
expect(element.querySelector('main')).not.toBeNull();
expect(element.querySelector('app-game-footer')).not.toBeNull();
const mapButton = element.querySelector<HTMLButtonElement>('[data-navigation="world"]');
expect(mapButton).not.toBeNull();
expect(mapButton?.disabled).toBe(false);
expect(mapButton?.getAttribute('aria-current')).toBe('page');
expect(mapButton?.getAttribute('aria-label')).toBe('Karte');
const huntButton = element.querySelector<HTMLButtonElement>('[data-navigation="hunt"]');
expect(huntButton).not.toBeNull();
expect(huntButton?.disabled).toBe(false);
expect(huntButton?.getAttribute('aria-current')).toBeNull();
expect(huntButton?.getAttribute('aria-label')).toBe('Jagd');
for (const destination of ['quests', 'inventory', 'character']) {
expect(
element.querySelector<HTMLButtonElement>(`[data-navigation="${destination}"]`)?.disabled,
).toBe(true);
}
expect(element.textContent).not.toContain('Shop');
});
it('marks Jagd as the active navigation entry while on /hunt', async () => {
const fixture = TestBed.createComponent(AppShellComponent);
const router = TestBed.inject(Router);
await router.navigateByUrl('/hunt');
fixture.detectChanges();
await fixture.whenStable();
const element = fixture.nativeElement as HTMLElement;
const mapButton = element.querySelector<HTMLButtonElement>('[data-navigation="world"]');
const huntButton = element.querySelector<HTMLButtonElement>('[data-navigation="hunt"]');
expect(huntButton?.getAttribute('aria-current')).toBe('page');
expect(mapButton?.getAttribute('aria-current')).toBeNull();
});
it('renders loaded character values supplied by the WorldStore', () => {
character.set({
id: 'character-id',
name: 'Mara Ashfall',
level: 7,
experience: 320,
silver: 150,
currentHp: 52,
maxHp: 80,
attack: 12,
currentLocation: { id: 'location-id', key: 'south-gate', name: 'Südtor von Graufurt' },
});
const fixture = TestBed.createComponent(AppShellComponent);
fixture.detectChanges();
expect(fixture.nativeElement.querySelector('app-top-bar')?.textContent).toContain(
'Mara Ashfall',
);
expect(fixture.nativeElement.querySelector('app-top-bar')?.textContent).toContain('Stufe 7');
expect(fixture.nativeElement.querySelector('app-top-bar')?.textContent).toContain('52 / 80');
expect(fixture.nativeElement.querySelector('app-top-bar')?.textContent).toContain('150');
expect(fixture.nativeElement.querySelector('app-top-bar')?.textContent).toContain('320');
});
it('redirects root and unknown routes to the world shell', () => {
expect(routes.find((route) => route.path === '')).toMatchObject({
pathMatch: 'full',
redirectTo: 'world',
});
expect(routes.find((route) => route.path === '**')).toMatchObject({ redirectTo: 'world' });
});
});