Files
what-to-eat/test/recipe.test.ts
T

134 lines
5.3 KiB
TypeScript

import type { RecipeItem } from '../apps/web/app/types'
import { createPinia, setActivePinia } from 'pinia'
import { beforeEach, describe, expect, it, vi } from 'vitest'
import { useRecipeStore } from '../apps/web/app/composables/store/recipe'
import { db } from '../apps/web/app/utils/db'
const fixtures: RecipeItem[] = [
{ name: '土豆', stuff: ['土豆'], tools: ['一口大锅'] },
{ name: '腊肠饭', stuff: ['腊肠', '米'], tools: ['电饭煲'] },
{ name: '土豆腊肠饭', stuff: ['土豆', '腊肠', '米'], tools: ['电饭煲'] },
{ name: '盐煎蛋', stuff: ['鸡蛋', '盐'], tools: ['一口大锅'] },
]
beforeEach(async () => {
setActivePinia(createPinia())
await db.recipes.clear()
await db.recipes.bulkAdd(fixtures)
})
describe('recipe interaction', () => {
it('lists recipes for a tool before any ingredient is chosen, then switches to matches', async () => {
const store = useRecipeStore()
await db.recipes.add({ name: '缺三种的土豆杂烩', stuff: ['土豆', '米', '鸡蛋', '牛肉'], tools: ['电饭煲'] })
await store.loadRecipes()
expect(store.resultCount).toBe(0)
store.curTool = '电饭煲'
expect(store.toolRecipes.map(r => r.name)).toEqual(['腊肠饭', '土豆腊肠饭', '缺三种的土豆杂烩'])
expect(store.resultCount).toBe(3)
store.keyword = '土豆'
expect(store.toolRecipes.map(r => r.name)).toEqual(['土豆腊肠饭', '缺三种的土豆杂烩'])
store.keyword = ''
store.addStuff('土豆')
expect(store.toolRecipes).toEqual([])
// Recipes missing more than two ingredients are never recommended.
expect(store.recipeMatches.map(m => m.recipe.name)).toEqual(['土豆腊肠饭'])
expect(store.resultCount).toBe(1)
})
it('suggests the missing ingredient that completes the most recipes', async () => {
const store = useRecipeStore()
await db.recipes.bulkAdd([
{ name: '腊肠焖饭', stuff: ['腊肠', '米'], tools: ['电饭煲'] },
{ name: '土豆焖饭', stuff: ['土豆', '米'], tools: ['电饭煲'] },
])
await store.loadRecipes()
store.addStuff('土豆')
store.addStuff('腊肠')
// 腊肠饭、土豆腊肠饭、腊肠焖饭、土豆焖饭 all wait only for 米.
expect(store.unlockSuggestions).toEqual([{ name: '米', count: 4 }])
store.addStuff('米')
expect(store.unlockSuggestions).toEqual([])
})
it('clears ingredients, tool and filters together on reset', () => {
const store = useRecipeStore()
store.addStuff('土豆')
store.curTool = '电饭煲'
store.curMode = 'strict'
store.keyword = '腊肠'
store.reset()
expect(store.selectedStuff).toEqual([])
expect(store.curTool).toBe('')
expect(store.curMode).toBe('loose')
expect(store.keyword).toBe('')
})
it('normalizes selection, ignores duplicates and toggles canonical names', () => {
const store = useRecipeStore()
store.addStuff(' 西红柿 ')
store.addStuff('番茄')
store.addStuff(' ')
expect(store.selectedStuff).toEqual(['番茄'])
store.toggleStuff('西红柿')
expect(store.selectedStuff).toEqual([])
store.toggleTools('电饭煲')
expect(store.curTool).toBe('电饭煲')
store.toggleTools('电饭煲')
expect(store.curTool).toBe('')
})
it('loads actual results and reacts immediately to latest filters', async () => {
const store = useRecipeStore()
store.addStuff('土豆')
store.addStuff('腊肠')
await store.loadRecipes()
expect(store.recipeMatches.map(m => m.recipe.name)).toEqual(['土豆', '土豆腊肠饭', '腊肠饭'])
store.curTool = '电饭煲'
expect(store.recipeMatches.map(m => m.recipe.name)).toEqual(['土豆腊肠饭', '腊肠饭'])
store.setMode('strict')
expect(store.recipeMatches.map(m => m.recipe.name)).toEqual(['土豆腊肠饭'])
store.setMode('survival')
expect(store.recipeMatches).toEqual([])
store.addStuff('米')
expect(store.recipeMatches).toHaveLength(2)
store.keyword = '没有这道菜'
expect(store.recipeMatches).toEqual([])
store.clearFilters()
expect(store.selectedStuff).toEqual(['土豆', '腊肠', '米'])
expect(store.recipeMatches).toHaveLength(3)
})
it('updates missing ingredients when pantry changes and preserves pantry on basket reset', async () => {
const store = useRecipeStore()
store.addStuff('鸡蛋')
await store.loadRecipes()
expect(store.recipeMatches[0]?.missingStuff).toEqual([])
store.togglePantry('盐')
expect(store.recipeMatches[0]?.missingStuff).toEqual(['盐'])
store.togglePantry('蒜')
store.reset()
expect(store.recipeMatches).toEqual([])
expect(store.selectedPantry).toEqual(['油', '蒜'])
store.clearPantry()
expect(store.selectedPantry).toEqual([])
store.resetPantry()
expect(store.selectedPantry).toEqual(['油', '盐'])
})
it('shows load failure, ends loading and can retry', async () => {
const store = useRecipeStore()
const read = vi.spyOn(db.recipes, 'toArray').mockRejectedValueOnce(new Error('unavailable'))
await store.loadRecipes()
expect(store.loadError).toBeTruthy()
expect(store.isSearching).toBe(false)
store.addStuff('土豆')
await store.loadRecipes()
expect(store.loadError).toBe('')
expect(store.recipeMatches).toHaveLength(2)
read.mockRestore()
})
})