|
import { describe, it, expect, beforeEach } from 'vitest'; |
|
import { EncounterService } from '../lib/db/encounterService'; |
|
import { db } from '../lib/db'; |
|
import { EncounterType } from '../lib/db/schema'; |
|
import type { Monster, PicletInstance } from '../lib/db/schema'; |
|
|
|
describe('EncounterService', () => { |
|
beforeEach(async () => { |
|
|
|
await db.monsters.clear(); |
|
await db.picletInstances.clear(); |
|
await db.encounters.clear(); |
|
await db.gameState.clear(); |
|
}); |
|
|
|
describe('generateEncounters', () => { |
|
it('should return empty array when no piclets are discovered', async () => { |
|
|
|
const monsterCount = await db.monsters.count(); |
|
const picletCount = await db.picletInstances.count(); |
|
expect(monsterCount).toBe(0); |
|
expect(picletCount).toBe(0); |
|
|
|
|
|
const encounters = await EncounterService.generateEncounters(); |
|
|
|
|
|
expect(encounters).toHaveLength(0); |
|
|
|
|
|
const dbEncounters = await db.encounters.toArray(); |
|
expect(dbEncounters).toHaveLength(0); |
|
}); |
|
|
|
it('should return only "Your First Piclet!" when piclets are discovered but not caught', async () => { |
|
|
|
const testMonster: Omit<Monster, 'id'> = { |
|
name: 'Test Piclet', |
|
imageUrl: 'https://test.com/piclet.png', |
|
concept: 'test', |
|
imagePrompt: 'test prompt', |
|
imageCaption: 'test caption', |
|
createdAt: new Date() |
|
}; |
|
await db.monsters.add(testMonster); |
|
|
|
|
|
const encounters = await EncounterService.generateEncounters(); |
|
|
|
|
|
expect(encounters).toHaveLength(1); |
|
expect(encounters[0].type).toBe(EncounterType.WILD_PICLET); |
|
expect(encounters[0].title).toBe('Your First Piclet!'); |
|
expect(encounters[0].description).toBe('A friendly piclet appears! This one seems easy to catch.'); |
|
expect(encounters[0].enemyLevel).toBe(5); |
|
}); |
|
|
|
it('should return shop, health center, and wild encounters when player has caught piclets', async () => { |
|
|
|
const testPiclet: Omit<PicletInstance, 'id'> = { |
|
typeId: 'test-001', |
|
nickname: 'Testy', |
|
primaryType: 'beast' as any, |
|
level: 5, |
|
xp: 0, |
|
currentHp: 20, |
|
maxHp: 20, |
|
attack: 10, |
|
defense: 10, |
|
fieldAttack: 10, |
|
fieldDefense: 10, |
|
speed: 10, |
|
baseHp: 20, |
|
baseAttack: 10, |
|
baseDefense: 10, |
|
baseFieldAttack: 10, |
|
baseFieldDefense: 10, |
|
baseSpeed: 10, |
|
moves: [], |
|
nature: 'hardy', |
|
isInRoster: true, |
|
rosterPosition: 0, |
|
caughtAt: new Date(), |
|
bst: 60, |
|
tier: 'common', |
|
role: 'balanced', |
|
variance: 1, |
|
imageUrl: 'https://test.com/piclet.png', |
|
imageCaption: 'Test', |
|
concept: 'test', |
|
imagePrompt: 'test' |
|
}; |
|
await db.picletInstances.add(testPiclet); |
|
|
|
|
|
const testMonster = { |
|
name: 'Test Monster', |
|
imageUrl: 'https://test.com/monster.png', |
|
imageCaption: 'A test monster', |
|
concept: 'test concept', |
|
imagePrompt: 'test prompt', |
|
createdAt: new Date() |
|
}; |
|
await db.monsters.add(testMonster); |
|
|
|
|
|
const encounters = await EncounterService.generateEncounters(); |
|
|
|
|
|
expect(encounters.length).toBeGreaterThanOrEqual(4); |
|
|
|
|
|
const encounterTypes = encounters.map(e => e.type); |
|
expect(encounterTypes).toContain(EncounterType.SHOP); |
|
expect(encounterTypes).toContain(EncounterType.HEALTH_CENTER); |
|
|
|
|
|
const wildCount = encounters.filter(e => e.type === EncounterType.WILD_PICLET).length; |
|
expect(wildCount).toBeGreaterThanOrEqual(2); |
|
expect(wildCount).toBeLessThanOrEqual(3); |
|
|
|
|
|
const shopEncounter = encounters.find(e => e.type === EncounterType.SHOP); |
|
expect(shopEncounter?.title).toBe('Piclet Shop'); |
|
|
|
|
|
const healthEncounter = encounters.find(e => e.type === EncounterType.HEALTH_CENTER); |
|
expect(healthEncounter?.title).toBe('Health Center'); |
|
}); |
|
|
|
it('should not include shop/health center with first catch encounter', async () => { |
|
|
|
await db.monsters.add({ |
|
name: 'Discovered Piclet', |
|
imageUrl: 'https://test.com/discovered.png', |
|
concept: 'discovered', |
|
imagePrompt: 'discovered prompt', |
|
imageCaption: 'discovered caption', |
|
createdAt: new Date() |
|
}); |
|
|
|
|
|
const caughtCount = await db.picletInstances.count(); |
|
expect(caughtCount).toBe(0); |
|
|
|
|
|
const encounters = await EncounterService.generateEncounters(); |
|
|
|
|
|
expect(encounters).toHaveLength(1); |
|
expect(encounters[0].title).toBe('Your First Piclet!'); |
|
|
|
|
|
const hasShop = encounters.some(e => e.type === EncounterType.SHOP); |
|
const hasHealthCenter = encounters.some(e => e.type === EncounterType.HEALTH_CENTER); |
|
expect(hasShop).toBe(false); |
|
expect(hasHealthCenter).toBe(false); |
|
}); |
|
}); |
|
|
|
describe('shouldRefreshEncounters', () => { |
|
it('should return true after 2 hours', async () => { |
|
|
|
const twoHoursAgo = new Date(Date.now() - (2.5 * 60 * 60 * 1000)); |
|
await db.gameState.add({ |
|
lastEncounterRefresh: twoHoursAgo, |
|
lastPlayed: new Date(), |
|
progressPoints: 0, |
|
trainersDefeated: 0, |
|
picletsCapured: 0, |
|
battlesLost: 0 |
|
}); |
|
|
|
|
|
const shouldRefresh = await EncounterService.shouldRefreshEncounters(); |
|
|
|
|
|
expect(shouldRefresh).toBe(true); |
|
}); |
|
|
|
it('should return false within 2 hours', async () => { |
|
|
|
const oneHourAgo = new Date(Date.now() - (1 * 60 * 60 * 1000)); |
|
await db.gameState.add({ |
|
lastEncounterRefresh: oneHourAgo, |
|
lastPlayed: new Date(), |
|
progressPoints: 0, |
|
trainersDefeated: 0, |
|
picletsCapured: 0, |
|
battlesLost: 0 |
|
}); |
|
|
|
|
|
const shouldRefresh = await EncounterService.shouldRefreshEncounters(); |
|
|
|
|
|
expect(shouldRefresh).toBe(false); |
|
}); |
|
}); |
|
}); |