feat: 套装方案对比与导出功能 #32
@@ -251,3 +251,80 @@ describe('Recipe Matching', () => {
|
||||
expect(canMakeRecipe(kit, recipe)).toBe(false)
|
||||
})
|
||||
})
|
||||
|
||||
// ---------------------------------------------------------------------------
|
||||
// Accessory Values — PR32
|
||||
// ---------------------------------------------------------------------------
|
||||
describe('Accessory Values', () => {
|
||||
it('芳香调理 has no accessories', () => {
|
||||
const kit = KITS.find(k => k.id === 'aroma')
|
||||
expect(kit.accessoryValue).toBeUndefined()
|
||||
})
|
||||
|
||||
it('家庭医生 accessories = 475 (香薰机375 + 木盒100)', () => {
|
||||
const kit = KITS.find(k => k.id === 'family')
|
||||
expect(kit.accessoryValue).toBe(475)
|
||||
})
|
||||
|
||||
it('居家呵护 accessories = 585 (香薰机375 + 竹木架210)', () => {
|
||||
const kit = KITS.find(k => k.id === 'home3988')
|
||||
expect(kit.accessoryValue).toBe(585)
|
||||
})
|
||||
|
||||
it('全精油 accessories = 795 (香薰机375 + 竹木架210×2)', () => {
|
||||
const kit = KITS.find(k => k.id === 'full')
|
||||
expect(kit.accessoryValue).toBe(795)
|
||||
})
|
||||
})
|
||||
|
||||
// ---------------------------------------------------------------------------
|
||||
// Discount Rate Calculation — PR32
|
||||
// ---------------------------------------------------------------------------
|
||||
describe('Discount Rate', () => {
|
||||
function calcDiscountRate(kit) {
|
||||
const resolved = kit.oils.map(resolveOilName)
|
||||
const bc = kit.bottleCount || {}
|
||||
let totalBP = 0
|
||||
for (const name of resolved) {
|
||||
const meta = oils[name]
|
||||
totalBP += meta ? meta.bottlePrice * (bc[name] || 1) : 0
|
||||
}
|
||||
const totalValue = totalBP + (kit.accessoryValue || 0)
|
||||
return totalValue > 0 ? Math.min(kit.price / totalValue, 1) : 1
|
||||
}
|
||||
|
||||
it('all kits have discount rate < 1 (套装比单买便宜)', () => {
|
||||
for (const kit of KITS) {
|
||||
const rate = calcDiscountRate(kit)
|
||||
expect(rate).toBeLessThan(1)
|
||||
expect(rate).toBeGreaterThan(0)
|
||||
}
|
||||
})
|
||||
|
||||
it('全精油 discount rate ≈ 0.69', () => {
|
||||
const kit = KITS.find(k => k.id === 'full')
|
||||
const rate = calcDiscountRate(kit)
|
||||
expect(rate).toBeGreaterThan(0.65)
|
||||
expect(rate).toBeLessThan(0.75)
|
||||
})
|
||||
|
||||
it('larger kits have better discounts', () => {
|
||||
const rates = KITS.map(k => ({ id: k.id, rate: calcDiscountRate(k), count: k.oils.length }))
|
||||
rates.sort((a, b) => a.count - b.count)
|
||||
// Generally larger kits should have lower discount rate (better deal)
|
||||
// At minimum, the largest kit should have a lower rate than the smallest
|
||||
expect(rates[rates.length - 1].rate).toBeLessThanOrEqual(rates[0].rate)
|
||||
})
|
||||
|
||||
it('kit cost per recipe should be less than original cost', () => {
|
||||
for (const kit of KITS) {
|
||||
const perDrop = calcKitPerDrop(kit)
|
||||
const recipes = prodData.recipes.filter(r => canMakeRecipe(kit, r))
|
||||
for (const r of recipes.slice(0, 5)) {
|
||||
const kitCost = calcRecipeCostWithKit(perDrop, r)
|
||||
const originalCost = calcOriginalCost(r)
|
||||
expect(kitCost).toBeLessThanOrEqual(originalCost + 0.01)
|
||||
}
|
||||
}
|
||||
})
|
||||
})
|
||||
|
||||
Reference in New Issue
Block a user