Some checks failed
Test / unit-test (push) Successful in 6s
Test / build-check (push) Successful in 4s
PR Preview / teardown-preview (pull_request) Has been skipped
Test / e2e-test (push) Failing after 25s
PR Preview / test (pull_request) Successful in 6s
PR Preview / deploy-preview (pull_request) Successful in 15s
1. 编辑配方的滴数输入框从 42px 加宽到 58px,确保 50.5 不被 spinner 遮挡 2. 配方卡片在零售价==会员价时也显示零售价(之前因 retail>cost 过滤掉) 3. 精油价目英文名保存后被静态 OIL_CARDS 覆盖,把 getEnglishName 的优先级改 为先用 DB meta.enName,解决温柔呵护/仕女呵护等显示不更新的问题 4. 再次审核 tag 的配方被非管理员修改时,给管理员发通知,内容含前后 diff 5. 对应 vitest + cypress 测试各一组 Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
88 lines
3.6 KiB
JavaScript
88 lines
3.6 KiB
JavaScript
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')
|
|
})
|
|
})
|