140 lines
4.2 KiB
TypeScript
140 lines
4.2 KiB
TypeScript
import { signal } from '@angular/core';
|
|
import { TestBed } from '@angular/core/testing';
|
|
import { vi } from 'vitest';
|
|
import type { QuestView } from '../../core/api/game-api.models';
|
|
import { QuestPageComponent } from './quest-page.component';
|
|
import { QuestStore } from './quest.store';
|
|
|
|
function quest(over: Partial<QuestView> = {}): QuestView {
|
|
return {
|
|
key: 'trouble-beyond-the-gate',
|
|
title: 'Trouble Beyond the Gate',
|
|
description: 'The warden wants five Ashen Pelts.',
|
|
status: 'ACTIVE',
|
|
objectives: [
|
|
{
|
|
key: 'collect-pelts-first',
|
|
description: 'Collect Ashen Pelts',
|
|
type: 'COLLECT_ITEM',
|
|
targetKey: 'ash-pelt',
|
|
required: 5,
|
|
current: 1,
|
|
completed: false,
|
|
},
|
|
],
|
|
currentObjectiveKey: 'collect-pelts-first',
|
|
hint: null,
|
|
...over,
|
|
};
|
|
}
|
|
|
|
async function setup(quests: QuestView[], error: string | null = null) {
|
|
const questsSignal = signal(quests);
|
|
const store = {
|
|
quests: questsSignal.asReadonly(),
|
|
activeQuests: signal(quests.filter((entry) => entry.status === 'ACTIVE')),
|
|
completedQuests: signal(
|
|
quests.filter((entry) => entry.status === 'COMPLETED'),
|
|
),
|
|
availableQuests: signal(
|
|
quests.filter((entry) => entry.status === 'AVAILABLE'),
|
|
),
|
|
loading: signal(false),
|
|
error: signal(error),
|
|
load: vi.fn().mockResolvedValue(undefined),
|
|
setQuest: vi.fn(),
|
|
};
|
|
|
|
await TestBed.configureTestingModule({
|
|
imports: [QuestPageComponent],
|
|
providers: [{ provide: QuestStore, useValue: store }],
|
|
}).compileComponents();
|
|
|
|
const fixture = TestBed.createComponent(QuestPageComponent);
|
|
fixture.detectChanges();
|
|
return { fixture, store, text: () => fixture.nativeElement.textContent ?? '' };
|
|
}
|
|
|
|
describe('QuestPageComponent', () => {
|
|
it('loads the quest log on init', async () => {
|
|
const { store } = await setup([quest()]);
|
|
|
|
expect(store.load).toHaveBeenCalledOnce();
|
|
});
|
|
|
|
it('renders the active quest with its current objective', async () => {
|
|
const { fixture, text } = await setup([quest()]);
|
|
|
|
expect(text()).toContain('Trouble Beyond the Gate');
|
|
expect(text()).toContain('The warden wants five Ashen Pelts.');
|
|
expect(
|
|
fixture.nativeElement.querySelector('[data-objective-description]')
|
|
.textContent,
|
|
).toContain('Collect Ashen Pelts');
|
|
});
|
|
|
|
it('renders collect progress as current over required', async () => {
|
|
const { fixture } = await setup([quest()]);
|
|
|
|
// The block slice §12 prints verbatim.
|
|
expect(
|
|
fixture.nativeElement
|
|
.querySelector('[data-objective-progress]')
|
|
.textContent.replace(/\s+/g, ' ')
|
|
.trim(),
|
|
).toBe('1 / 5');
|
|
});
|
|
|
|
it('renders the blocked hint under the objective', async () => {
|
|
const { fixture } = await setup([
|
|
quest({
|
|
hint: 'You cannot carry enough pelts. Return to the South Gate Warden.',
|
|
}),
|
|
]);
|
|
|
|
expect(
|
|
fixture.nativeElement.querySelector('[data-objective-hint]').textContent,
|
|
).toContain('You cannot carry enough pelts.');
|
|
});
|
|
|
|
it('shows no hint when the step is merely unfinished', async () => {
|
|
const { fixture } = await setup([quest()]);
|
|
|
|
expect(
|
|
fixture.nativeElement.querySelector('[data-objective-hint]'),
|
|
).toBeNull();
|
|
});
|
|
|
|
it('shows an empty state when nothing is taken on', async () => {
|
|
const { text } = await setup([]);
|
|
|
|
expect(text()).toContain('You have taken nothing on.');
|
|
});
|
|
|
|
it('lists completed quests separately from active ones', async () => {
|
|
const { fixture, text } = await setup([
|
|
quest({
|
|
key: 'done-quest',
|
|
title: 'An Older Errand',
|
|
status: 'COMPLETED',
|
|
currentObjectiveKey: null,
|
|
}),
|
|
]);
|
|
|
|
expect(text()).toContain('An Older Errand');
|
|
expect(
|
|
fixture.nativeElement.querySelector('[data-quest-completed]'),
|
|
).not.toBeNull();
|
|
// The active panel is still empty, so the two do not blur together.
|
|
expect(text()).toContain('You have taken nothing on.');
|
|
});
|
|
|
|
it('offers a retry when the log could not be read', async () => {
|
|
const { fixture, store } = await setup([], 'Could not load your quests.');
|
|
|
|
fixture.nativeElement.querySelector('[data-quest-retry]').click();
|
|
|
|
expect(store.load).toHaveBeenCalledTimes(2);
|
|
});
|
|
});
|