import { describe, it, expect } from 'vitest' // Replicates the fixed fmtCostWithRetail logic: retail shown whenever any ingredient // has a retail price stored (even when it equals the member price). function fmtCostWithRetail(ingredients, oilsMeta) { const cost = ingredients.reduce((s, i) => { const m = oilsMeta[i.oil] return s + (m ? (m.bottlePrice / m.dropCount) * i.drops : 0) }, 0) const retail = ingredients.reduce((s, i) => { const m = oilsMeta[i.oil] if (m && m.retailPrice && m.dropCount) return s + (m.retailPrice / m.dropCount) * i.drops return s + (m ? (m.bottlePrice / m.dropCount) * i.drops : 0) }, 0) const anyRetail = ingredients.some(i => { const m = oilsMeta[i.oil] return m && m.retailPrice && m.dropCount }) if (anyRetail && retail > 0) { return { cost: '¥ ' + cost.toFixed(2), retail: '¥ ' + retail.toFixed(2), hasRetail: true } } return { cost: '¥ ' + cost.toFixed(2), retail: null, hasRetail: false } } describe('fmtCostWithRetail — retail price display', () => { it('shows retail when retail > member', () => { const meta = { '玫瑰': { bottlePrice: 100, retailPrice: 150, dropCount: 10 } } const r = fmtCostWithRetail([{ oil: '玫瑰', drops: 5 }], meta) expect(r.hasRetail).toBe(true) expect(r.retail).toBe('¥ 75.00') }) it('still shows retail when retail === member (regression: 带玫瑰护手霜 case)', () => { const meta = { '玫瑰护手霜': { bottlePrice: 300, retailPrice: 300, dropCount: 50 } } const r = fmtCostWithRetail([{ oil: '玫瑰护手霜', drops: 5 }], meta) expect(r.hasRetail).toBe(true) expect(r.cost).toBe('¥ 30.00') expect(r.retail).toBe('¥ 30.00') }) it('no retail when ingredient has no retail price', () => { const meta = { '薰衣草': { bottlePrice: 100, retailPrice: null, dropCount: 10 } } const r = fmtCostWithRetail([{ oil: '薰衣草', drops: 5 }], meta) expect(r.hasRetail).toBe(false) expect(r.retail).toBeNull() }) }) // getEnglishName priority fix — DB en_name must beat static card override. function getEnglishName(name, oilsMeta, cards, aliases, oilEnFn) { const meta = oilsMeta[name] if (meta?.enName) return meta.enName if (cards[name]?.en) return cards[name].en if (aliases[name] && cards[aliases[name]]?.en) return cards[aliases[name]].en const base = name.replace(/呵护$/, '') if (base !== name && cards[base]?.en) return cards[base].en return oilEnFn ? oilEnFn(name) : '' } describe('getEnglishName — DB wins over static card', () => { const cards = { '温柔呵护': { en: 'Soft Talk' }, '椒样薄荷': { en: 'Peppermint' }, '西班牙牛至': { en: 'Oregano' }, } const aliases = { '仕女呵护': '温柔呵护', '薄荷呵护': '椒样薄荷', '牛至呵护': '西班牙牛至' } it('uses DB en_name over static card en (温柔呵护 regression)', () => { const meta = { '温柔呵护': { enName: 'Clary Calm' } } expect(getEnglishName('温柔呵护', meta, cards, aliases)).toBe('Clary Calm') }) it('uses DB en_name over aliased card en (仕女呵护 regression)', () => { const meta = { '仕女呵护': { enName: 'Soft Talk Touch' } } expect(getEnglishName('仕女呵护', meta, cards, aliases)).toBe('Soft Talk Touch') }) it('falls back to static card when DB en_name is empty', () => { const meta = { '温柔呵护': { enName: '' } } expect(getEnglishName('温柔呵护', meta, cards, aliases)).toBe('Soft Talk') }) it('alias still works as fallback', () => { const meta = { '牛至呵护': {} } expect(getEnglishName('牛至呵护', meta, cards, aliases)).toBe('Oregano') }) })