bend_puzzle/test/v4785-cosmetics-shop-smoke-test.js

35 lines
6.1 KiB
JavaScript
Raw Normal View History

2026-08-01 16:06:14 +09:00
'use strict';
const {assert,app,css,read,functionSource,vm}=require('./helpers/app-source');
const catalog=JSON.parse(read('store-catalog.json')),generatedContext={};
vm.createContext(generatedContext);vm.runInContext(read('store-catalog.generated.js'),generatedContext);const generated=generatedContext.BendStoreCatalog;
assert(JSON.stringify(generated)===JSON.stringify(catalog),'Generated store catalog is not synchronized with store-catalog.json');
assert(catalog.length===380&&new Set(catalog.map(item=>item.id)).size===catalog.length,'Expanded store catalog count or IDs are invalid');
const colors=catalog.filter(item=>item.lineColor),lineEffects=catalog.filter(item=>item.lineEffect),reactionEffects=catalog.filter(item=>item.reactionStyle),cursors=catalog.filter(item=>item.cursorStyle),aurora=catalog.find(item=>item.id==='line-effect-aurora');
assert(colors.length===15&&lineEffects.length===0&&reactionEffects.length===5&&cursors.length===359&&aurora?.aurora===true,'The requested color, reaction-effect, or cursor inventory is incomplete');
assert(catalog.every(item=>[item.cursorStyle,item.scoreLens===true,item.lineColor,item.lineEffect,item.reactionStyle].filter(Boolean).length===1),'A catalog item mixes multiple cosmetic/tool contracts');
const retiredReactions=['fountain','shockwave','rain'];
assert(retiredReactions.every(style=>!reactionEffects.some(item=>item.reactionStyle===style)&&!read('realtime-server.js').includes(`'${style}'`)),`A retired emoji effect remains active`);
const retiredLineEffects=['neon','prism','comet','glow','pulse','dash','starlight'];
assert(retiredLineEffects.every(style=>!lineEffects.some(item=>item.lineEffect===style)),`A retired line effect remains active`);
const removed=['cursor-face-1f642-200d-2194-fe0f','cursor-face-1f642-200d-2195-fe0f','cursor-face-1fae9','cursor-face-1faea'];
assert(removed.every(id=>!catalog.some(item=>item.id===id)&&!app.includes(`'${id}'`)),`A removed glitchy/undisplayed cursor remains`);
const defaultData=functionSource('defaultData'),normalize=functionSource('normalizeSnapshot'),newPath=functionSource('startGate'),pathNormalization=functionSource('normalizePath'),appearance=functionSource('syncCosmeticAppearance'),migration=functionSource('migratedLineColorStyle');
assert(defaultData.includes('starterLineColor=randomStarterLineColorId()')&&defaultData.includes('lineColorStyle:starterLineColor'),'A first-access player is not granted and equipped a random starter line color');
assert(functionSource('validStarterLineColorId').includes('STARTER_LINE_COLOR_IDS.includes(value)')&&normalize.includes('validStarterLineColorId(raw.starterLineColor)'),'A premium shop color can be forged as a free starter color');
assert(normalize.includes('clean.lineColorStyle=migratedLineColorStyle(raw)||clean.starterLineColor')&&normalize.includes("clean.reactionStyle=REACTION_STYLE_IDS.has(raw.reactionStyle)")&&!normalize.includes('ownsSavedItem'),'Saved equipped cosmetics are incorrectly reset before purchase data hydrates');
assert(migration.includes("source?.lineEffectStyle==='aurora'")&&migration.includes('AURORA_LINE_COLOR_ITEM_ID'),'Legacy Aurora equipment is not migrated to the line-color contract');
assert(functionSource('starterColorGrantCount').includes('data.starterLineColor')&&functionSource('inventoryCount').includes('starterColorGrantCount')&&functionSource('ownsStoreItem').includes('inventoryCount(itemId)>0'),'The starter color is not represented as owned inventory');
assert(newPath.includes("activeLineColorItem()?.aurora?'aurora':null")&&newPath.includes('ownerId:currentPlayerId()')&&pathNormalization.includes('LINE_EFFECT_IDS.has(raw.lineEffect)'),'Aurora line presentation is not persisted on newly drawn paths or legacy paths');
assert(appearance.includes("activeColor?.aurora?'aurora':'none'")&&appearance.includes('--player-line-color'),'Equipped color and Aurora are not synchronized to the presentation layer');
assert(css.includes('.path.line-effect-aurora')&&css.includes('.gate-dot.line-effect-aurora'),'Aurora line and gate CSS presentation is missing');
assert(css.includes('@media (prefers-reduced-motion:reduce)')&&css.includes('body.lightweight-rendering'),'Cosmetic effects do not provide reduced/lightweight rendering fallbacks');
const reactionSource=functionSource('drawStyledReaction'),publishSource=functionSource('publishReactionAt'),realtime=read('realtime-server.js');
for(const style of reactionEffects.map(item=>item.reactionStyle)){assert(reactionSource.includes(`style==='${style}'`),`Missing canvas presentation for emoji effect ${style}`);assert(realtime.includes(`'${style}'`),`Realtime server does not accept emoji effect ${style}`)}
assert(publishSource.includes('style,x,y')&&publishSource.includes('sendOrQueueRealtimeReaction(reaction)')&&realtime.includes("REACTION_STYLES.has(message.style)?message.style:'classic'"),'Purchased emoji styles are not published and safely normalized');
assert(functionSource('publishReaction',realtime).includes("style!=='classic'")&&functionSource('publishReaction',realtime).includes('active.playerId===client.playerId'),'Realtime authority does not prevent overlapping special emoji effects');
const seeded=functionSource('seededStoreItemIds'),authoritative=functionSource('authoritativeStoreItemIds',read('server.js'));
assert(seeded.includes('.slice(0,6)')&&seeded.includes('6-fixedTools.length')&&seeded.includes('item.scoreLens'),'Client shops do not offer six cursors and six non-cursor items including the Score Lens');
assert(authoritative.includes('.slice(0,6)')&&authoritative.includes('6-fixedTools.length')&&authoritative.includes('item.scoreLens'),'Server shop authority does not match the twelve-item client inventory');
assert(functionSource('renderStorePanel').includes("compact:true")&&functionSource('renderStorePanel').includes('if(category.compact)card.append(icon,buy)')&&css.includes('.store-compact-list{grid-template-columns:repeat(6'),'New shop cosmetics are not displayed in the compact cursor-style grid');
assert(functionSource('starterLineColorForPlayer',read('server.js')).includes("createHash('sha256')"),'Server-backed players do not receive a stable starter color');
console.log('v47.87 starter colors, Aurora line color, emoji effects, and cursor cleanup passed');