5c316fc680
将 SFX Prompt 首尾规范化改为 ECMAScript String.trim 语义并同步 Rust 等值实现 更新共享边界 fixture、前后端与 Worker 回归测试 同步权威设计、实施计划、决策日志和 External OpenAPI 描述
277 lines
9.2 KiB
TypeScript
277 lines
9.2 KiB
TypeScript
import { describe, expect, it } from 'vitest';
|
||
|
||
import {
|
||
appendSoundEffectPromptPreset,
|
||
SOUND_EFFECT_PROMPT_PRESET_GROUPS,
|
||
SOUND_EFFECT_PROMPT_PRESETS,
|
||
} from './ImageCanvasSoundEffectPresetModel';
|
||
|
||
describe('ImageCanvasSoundEffectPresetModel', () => {
|
||
it('freezes 40 event presets and 12 requirements with unique identities', () => {
|
||
expect(SOUND_EFFECT_PROMPT_PRESETS).toHaveLength(52);
|
||
expect(
|
||
SOUND_EFFECT_PROMPT_PRESETS.filter(
|
||
(preset) => preset.category === 'event',
|
||
),
|
||
).toHaveLength(40);
|
||
expect(
|
||
SOUND_EFFECT_PROMPT_PRESETS.filter(
|
||
(preset) => preset.category === 'requirement',
|
||
),
|
||
).toHaveLength(12);
|
||
expect(new Set(SOUND_EFFECT_PROMPT_PRESETS.map(({ id }) => id)).size).toBe(
|
||
52,
|
||
);
|
||
expect(SOUND_EFFECT_PROMPT_PRESETS.map(({ id }) => id)).toEqual([
|
||
'button-tap',
|
||
'operation-confirm',
|
||
'back-cancel',
|
||
'page-transition',
|
||
'notification',
|
||
'operation-error',
|
||
'coin-pickup',
|
||
'item-pickup',
|
||
'reward-received',
|
||
'chest-open',
|
||
'content-unlock',
|
||
'rare-drop',
|
||
'item-craft',
|
||
'character-level-up',
|
||
'quest-complete',
|
||
'achievement-unlocked',
|
||
'challenge-victory',
|
||
'challenge-defeat',
|
||
'character-jump',
|
||
'character-land',
|
||
'light-hit',
|
||
'heavy-hit',
|
||
'attack-swing',
|
||
'attack-hit',
|
||
'block-success',
|
||
'object-break',
|
||
'skill-charge',
|
||
'magic-cast',
|
||
'healing',
|
||
'shield-create',
|
||
'teleport',
|
||
'ice-skill',
|
||
'fire-skill',
|
||
'status-buff',
|
||
'door-open',
|
||
'mechanism-start',
|
||
'lever-trigger',
|
||
'stone-move',
|
||
'portal-open',
|
||
'countdown-warning',
|
||
'casual-cute',
|
||
'retro-arcade',
|
||
'sci-fi-electronic',
|
||
'fantasy-magic',
|
||
'realistic-natural',
|
||
'cartoon-exaggerated',
|
||
'gentle-feedback',
|
||
'strong-feedback',
|
||
'short-feedback',
|
||
'two-stage-rise',
|
||
'clean-prominent',
|
||
'soft-not-harsh',
|
||
]);
|
||
expect(
|
||
new Set(SOUND_EFFECT_PROMPT_PRESETS.map(({ label }) => label)).size,
|
||
).toBe(52);
|
||
expect(
|
||
new Set(SOUND_EFFECT_PROMPT_PRESETS.map(({ group }) => group)),
|
||
).toEqual(new Set(SOUND_EFFECT_PROMPT_PRESET_GROUPS));
|
||
});
|
||
|
||
it('locks the visible labels and prompt text in authoritative order', () => {
|
||
expect(
|
||
SOUND_EFFECT_PROMPT_PRESETS.map(({ category, group, label, prompt }) => [
|
||
category,
|
||
group,
|
||
label,
|
||
prompt,
|
||
]),
|
||
).toEqual([
|
||
['event', 'ui-operation', '轻触按钮', '柔和的按钮点击声'],
|
||
['event', 'ui-operation', '确认操作', '明亮的确认提示音'],
|
||
['event', 'ui-operation', '返回取消', '轻微下降的取消提示音'],
|
||
['event', 'ui-operation', '页面切换', '快速掠过的界面切换声'],
|
||
['event', 'ui-operation', '通知提醒', '清晰柔和的通知提示音'],
|
||
['event', 'ui-operation', '操作错误', '短促克制的错误提示音'],
|
||
['event', 'pickup-reward', '金币拾取', '金币拾取时清脆的金属叮当声'],
|
||
['event', 'pickup-reward', '道具拾取', '拾取道具时轻快的提示音'],
|
||
['event', 'pickup-reward', '获得奖励', '奖励出现时明亮的提示音'],
|
||
[
|
||
'event',
|
||
'pickup-reward',
|
||
'宝箱开启',
|
||
'金属锁扣弹开,随后响起明亮的奖励提示音',
|
||
],
|
||
[
|
||
'event',
|
||
'pickup-reward',
|
||
'解锁内容',
|
||
'锁定状态解除,随后响起解锁提示音',
|
||
],
|
||
['event', 'pickup-reward', '稀有掉落', '稀有物品出现时闪耀的奖励提示音'],
|
||
[
|
||
'event',
|
||
'growth-result',
|
||
'物品合成',
|
||
'两件物品融合,随后响起明亮的完成提示音',
|
||
],
|
||
[
|
||
'event',
|
||
'growth-result',
|
||
'角色升级',
|
||
'能量快速上升,随后响起明亮的升级提示音',
|
||
],
|
||
[
|
||
'event',
|
||
'growth-result',
|
||
'任务完成',
|
||
'任务完成提示音,随后响起简短的奖励音符',
|
||
],
|
||
[
|
||
'event',
|
||
'growth-result',
|
||
'成就达成',
|
||
'明亮的成就提示音,随后响起简短的庆祝音符',
|
||
],
|
||
[
|
||
'event',
|
||
'growth-result',
|
||
'挑战胜利',
|
||
'明亮的胜利提示音,随后响起短暂的庆祝音符',
|
||
],
|
||
['event', 'growth-result', '挑战失败', '低沉的失败提示音'],
|
||
['event', 'character-combat', '角色跳跃', '角色轻盈跳起的声音'],
|
||
['event', 'character-combat', '角色落地', '角色落地时轻微的撞击声'],
|
||
['event', 'character-combat', '轻度受击', '轻微撞击的受击声'],
|
||
['event', 'character-combat', '重度受击', '沉重有力的撞击声'],
|
||
['event', 'character-combat', '攻击挥动', '武器快速挥过空气的呼啸声'],
|
||
['event', 'character-combat', '攻击命中', '武器击中目标的清晰撞击声'],
|
||
['event', 'character-combat', '格挡成功', '武器碰撞,随后被挡开的金属声'],
|
||
['event', 'character-combat', '物体破碎', '物体撞击地面后快速破碎的声音'],
|
||
['event', 'skill-status', '技能蓄力', '能量逐渐聚集的低沉嗡鸣声'],
|
||
[
|
||
'event',
|
||
'skill-status',
|
||
'魔法释放',
|
||
'柔和的魔法能量扩散,带有圆润空灵的闪光声',
|
||
],
|
||
[
|
||
'event',
|
||
'skill-status',
|
||
'治疗恢复',
|
||
'柔和能量扩散,带有温暖圆润的提示音',
|
||
],
|
||
['event', 'skill-status', '护盾生成', '能量向外展开,形成稳定的护盾声'],
|
||
[
|
||
'event',
|
||
'skill-status',
|
||
'瞬间移动',
|
||
'能量快速收缩,随后以短促的空气抽离声消失',
|
||
],
|
||
[
|
||
'event',
|
||
'skill-status',
|
||
'冰冻技能',
|
||
'冰霜能量扩散,随后响起清脆的冻结声',
|
||
],
|
||
['event', 'skill-status', '火焰技能', '火焰迅速喷发,带有短促的燃烧声'],
|
||
[
|
||
'event',
|
||
'skill-status',
|
||
'状态强化',
|
||
'能量逐渐上升,形成稳定明亮的提示音',
|
||
],
|
||
[
|
||
'event',
|
||
'mechanism-scene-interaction',
|
||
'门开启',
|
||
'门锁解除,随后厚重的木门缓慢打开',
|
||
],
|
||
[
|
||
'event',
|
||
'mechanism-scene-interaction',
|
||
'机关启动',
|
||
'机关解锁,随后齿轮开始转动',
|
||
],
|
||
[
|
||
'event',
|
||
'mechanism-scene-interaction',
|
||
'拉杆触发',
|
||
'拉杆被扳动,随后远处机关启动',
|
||
],
|
||
[
|
||
'event',
|
||
'mechanism-scene-interaction',
|
||
'石块移动',
|
||
'大型石块缓慢移动时低沉的摩擦声',
|
||
],
|
||
[
|
||
'event',
|
||
'mechanism-scene-interaction',
|
||
'传送门开启',
|
||
'能量旋转聚集,随后响起持续、空灵的传送门展开声',
|
||
],
|
||
[
|
||
'event',
|
||
'mechanism-scene-interaction',
|
||
'倒计时警告',
|
||
'逐渐加快的倒计时提示音',
|
||
],
|
||
['requirement', 'style-direction', '休闲可爱', '轻快可爱的卡通风格'],
|
||
['requirement', 'style-direction', '复古街机', '复古街机风格'],
|
||
['requirement', 'style-direction', '科幻电子', '干净的科幻电子音色'],
|
||
['requirement', 'style-direction', '奇幻魔法', '柔和梦幻的魔法音色'],
|
||
['requirement', 'style-direction', '写实自然', '自然真实的声音质感'],
|
||
['requirement', 'style-direction', '卡通夸张', '夸张鲜明的卡通风格'],
|
||
['requirement', 'feedback-requirement', '轻柔反馈', '轻柔克制'],
|
||
['requirement', 'feedback-requirement', '有力反馈', '更有力的撞击感'],
|
||
['requirement', 'feedback-requirement', '短促反馈', '短促的单次声音'],
|
||
['requirement', 'feedback-requirement', '两段递进', '由弱到强的两段变化'],
|
||
[
|
||
'requirement',
|
||
'feedback-requirement',
|
||
'干净突出',
|
||
'主体声音清晰,减少杂音',
|
||
],
|
||
[
|
||
'requirement',
|
||
'feedback-requirement',
|
||
'柔和不刺耳',
|
||
'圆润柔和,避免尖锐高频',
|
||
],
|
||
]);
|
||
});
|
||
|
||
it('canonicalizes and appends with the frozen ECMAScript trim rule', () => {
|
||
const preset = SOUND_EFFECT_PROMPT_PRESETS[40];
|
||
expect(appendSoundEffectPromptPreset('\uFEFF\u2003', preset)).toBe(
|
||
preset.prompt,
|
||
);
|
||
expect(appendSoundEffectPromptPreset('金币落地', preset)).toBe(
|
||
`金币落地,${preset.prompt}`,
|
||
);
|
||
expect(appendSoundEffectPromptPreset('金币落地!\uFEFF', preset)).toBe(
|
||
`金币落地!${preset.prompt}`,
|
||
);
|
||
});
|
||
|
||
it('allows duplicates and preserves overlong text without truncation', () => {
|
||
const preset = SOUND_EFFECT_PROMPT_PRESETS[0];
|
||
const once = appendSoundEffectPromptPreset('按钮', preset);
|
||
expect(appendSoundEffectPromptPreset(once, preset)).toBe(
|
||
`按钮,${preset.prompt},${preset.prompt}`,
|
||
);
|
||
|
||
const overlong = '声'.repeat(2048);
|
||
const appended = appendSoundEffectPromptPreset(overlong, preset);
|
||
expect(appended).toBe(`${overlong},${preset.prompt}`);
|
||
expect(Array.from(appended).length).toBeGreaterThan(2048);
|
||
});
|
||
});
|