import { describe, it, expect } from 'vitest'; // ─── Test: CraftingTab barrel export ────────────────────────────────────────── describe('CraftingTab module structure', () => { it('exports CraftingTab from its module', async () => { const mod = await import('./CraftingTab'); expect(mod.CraftingTab).toBeDefined(); expect(typeof mod.CraftingTab).toBe('function'); }); it('CraftingTab has correct displayName', async () => { const { CraftingTab } = await import('./CraftingTab'); expect(CraftingTab.displayName).toBe('CraftingTab'); }); }); // ─── Test: CraftingTab in tabs barrel index ──────────────────────────────────── describe('Tab barrel export', () => { it('includes CraftingTab in the tabs index', async () => { const mod = await import('@/components/game/tabs'); expect(mod.CraftingTab).toBeDefined(); expect(typeof mod.CraftingTab).toBe('function'); }); }); // ─── Test: FabricatorSubTab ──────────────────────────────────────────────────── describe('FabricatorSubTab module', () => { it('exports FabricatorSubTab', async () => { const mod = await import('./CraftingTab/FabricatorSubTab'); expect(mod.FabricatorSubTab).toBeDefined(); expect(typeof mod.FabricatorSubTab).toBe('function'); }); it('FabricatorSubTab has correct displayName', async () => { const { FabricatorSubTab } = await import('./CraftingTab/FabricatorSubTab'); expect(FabricatorSubTab.displayName).toBe('FabricatorSubTab'); }); }); // ─── Test: EnchanterSubTab ───────────────────────────────────────────────────── describe('EnchanterSubTab module', () => { it('exports EnchanterSubTab', async () => { const mod = await import('./CraftingTab/EnchanterSubTab'); expect(mod.EnchanterSubTab).toBeDefined(); expect(typeof mod.EnchanterSubTab).toBe('function'); }); it('EnchanterSubTab has correct displayName', async () => { const { EnchanterSubTab } = await import('./CraftingTab/EnchanterSubTab'); expect(EnchanterSubTab.displayName).toBe('EnchanterSubTab'); }); }); // ─── Test: Fabricator recipes data ───────────────────────────────────────────── describe('Fabricator recipes data', () => { it('exports FABRICATOR_RECIPES', async () => { const mod = await import('@/lib/game/data/fabricator-recipes'); expect(mod.FABRICATOR_RECIPES).toBeDefined(); expect(Object.keys(mod.FABRICATOR_RECIPES).length).toBeGreaterThan(0); }); it('all recipes have required fields', async () => { const { FABRICATOR_RECIPES } = await import('@/lib/game/data/fabricator-recipes'); for (const recipe of Object.values(FABRICATOR_RECIPES)) { expect(recipe.id).toBeTruthy(); expect(recipe.name).toBeTruthy(); expect(recipe.description).toBeTruthy(); expect(recipe.manaType).toBeTruthy(); expect(recipe.equipmentTypeId).toBeTruthy(); expect(recipe.slot).toBeTruthy(); expect(recipe.materials).toBeDefined(); expect(recipe.manaCost).toBeGreaterThan(0); expect(recipe.craftTime).toBeGreaterThan(0); expect(recipe.rarity).toBeTruthy(); expect(recipe.gearTrait).toBeTruthy(); } }); it('only uses valid solid/structural mana types', async () => { const { FABRICATOR_RECIPES } = await import('@/lib/game/data/fabricator-recipes'); const validManaTypes = new Set(['earth', 'metal', 'crystal', 'sand']); for (const recipe of Object.values(FABRICATOR_RECIPES)) { expect(validManaTypes.has(recipe.manaType)).toBe(true); } }); it('no fire, water, air, light, dark, death, stellar, or void gear recipes', async () => { const { FABRICATOR_RECIPES } = await import('@/lib/game/data/fabricator-recipes'); const invalidTypes = new Set(['fire', 'water', 'air', 'light', 'dark', 'death', 'stellar', 'void']); for (const recipe of Object.values(FABRICATOR_RECIPES)) { expect(invalidTypes.has(recipe.manaType)).toBe(false); } }); it('getRecipesByManaType filters correctly', async () => { const { getRecipesByManaType, FABRICATOR_RECIPES } = await import('@/lib/game/data/fabricator-recipes'); const earthRecipes = getRecipesByManaType('earth'); expect(earthRecipes.length).toBeGreaterThan(0); for (const r of earthRecipes) { expect(r.manaType).toBe('earth'); } const empty = getRecipesByManaType('nonexistent'); expect(empty).toEqual([]); }); it('getRecipeById returns correct recipe', async () => { const { getRecipeById, FABRICATOR_RECIPES } = await import('@/lib/game/data/fabricator-recipes'); const firstId = Object.values(FABRICATOR_RECIPES)[0].id; const recipe = getRecipeById(firstId); expect(recipe).toBeDefined(); expect(recipe!.id).toBe(firstId); const missing = getRecipeById('nonexistent'); expect(missing).toBeUndefined(); }); it('canCraftRecipe returns correct availability', async () => { const { canCraftRecipe, FABRICATOR_RECIPES } = await import('@/lib/game/data/fabricator-recipes'); const recipe = Object.values(FABRICATOR_RECIPES)[0]; // Empty materials => cannot craft const result1 = canCraftRecipe(recipe, {}, 0); expect(result1.canCraft).toBe(false); expect(Object.keys(result1.missingMaterials).length).toBeGreaterThan(0); expect(result1.missingMana).toBeGreaterThan(0); // Sufficient materials and mana => can craft const sufficientMats: Record = {}; for (const [matId, amount] of Object.entries(recipe.materials)) { sufficientMats[matId] = amount; } const result2 = canCraftRecipe(recipe, sufficientMats, recipe.manaCost); expect(result2.canCraft).toBe(true); expect(Object.keys(result2.missingMaterials)).toHaveLength(0); expect(result2.missingMana).toBe(0); }); }); // ─── Test: File size limits ──────────────────────────────────────────────────── describe('File size limits (400 lines max)', () => { it('CraftingTab.tsx is under 400 lines', async () => { const fs = await import('fs'); const path = await import('path'); const content = fs.readFileSync( path.join(__dirname, 'CraftingTab.tsx'), 'utf-8', ); const lines = content.split('\n').length; expect(lines).toBeLessThan(400); }); it('FabricatorSubTab.tsx is under 400 lines', async () => { const fs = await import('fs'); const path = await import('path'); const content = fs.readFileSync( path.join(__dirname, 'CraftingTab', 'FabricatorSubTab.tsx'), 'utf-8', ); const lines = content.split('\n').length; expect(lines).toBeLessThan(400); }); it('EnchanterSubTab.tsx is under 400 lines', async () => { const fs = await import('fs'); const path = await import('path'); const content = fs.readFileSync( path.join(__dirname, 'CraftingTab', 'EnchanterSubTab.tsx'), 'utf-8', ); const lines = content.split('\n').length; expect(lines).toBeLessThan(400); }); });