feat: wire bark battle platform loop
Some checks are pending
CI / verify (pull_request) Waiting to run

This commit is contained in:
2026-05-14 18:20:46 +08:00
parent 8c6ec9e6e4
commit 1d7ef7e4b6
73 changed files with 7933 additions and 107 deletions

View File

@@ -0,0 +1,130 @@
import { describe, expect, test } from 'vitest';
import {
BARK_BATTLE_DIFFICULTY_PRESETS,
type BarkBattleDraftConfig,
type BarkBattleFinishResponse,
type BarkBattlePersonalBestSummary,
type BarkBattleWorkStats,
} from './barkBattle';
describe('Bark Battle shared contracts', () => {
test('default draft config fixture uses normal difficulty and camelCase fields', () => {
const draft: BarkBattleDraftConfig = {
draftId: 'draft-bark-1',
title: '汪汪声浪挑战',
description: '轻配置草稿',
themePreset: 'city-park',
playerDogSkinPreset: 'corgi',
opponentDogSkinPreset: 'husky',
difficultyPreset: 'normal',
leaderboardEnabled: true,
updatedAt: '2026-05-13T03:00:00.000Z',
};
expect(BARK_BATTLE_DIFFICULTY_PRESETS).toEqual(['easy', 'normal', 'hard']);
expect(draft.difficultyPreset).toBe('normal');
expect(Object.keys(draft)).toEqual([
'draftId',
'title',
'description',
'themePreset',
'playerDogSkinPreset',
'opponentDogSkinPreset',
'difficultyPreset',
'leaderboardEnabled',
'updatedAt',
]);
});
test('finish accepted player_win fixture exposes backend adjudication result', () => {
const response: BarkBattleFinishResponse = {
status: 'accepted',
runId: 'run-bark-1',
workId: 'work-bark-1',
configVersion: 3,
rulesetVersion: 'bark-battle-ruleset-v1',
difficultyPreset: 'hard',
serverResult: 'player_win',
scoreSummary: {
finalEnergy: 87,
triggerCount: 42,
maxVolume: 0.96,
averageVolume: 0.61,
comboMax: 9,
durationMs: 30000,
},
leaderboardScore: 870429630,
antiCheatFlags: [],
updatedAt: '2026-05-13T03:00:30.000Z',
};
expect(response.status).toBe('accepted');
expect(response.serverResult).toBe('player_win');
expect(response.scoreSummary.finalEnergy).toBe(87);
expect(response.antiCheatFlags).toEqual([]);
});
test('work stats fixture tracks starts, finishes, result counts, flags and energy summary', () => {
const stats: BarkBattleWorkStats = {
workId: 'work-bark-1',
configVersion: 3,
rulesetVersion: 'bark-battle-ruleset-v1',
difficultyPreset: 'normal',
playStartCount: 18,
finishCount: 15,
winCount: 8,
drawCount: 2,
lossCount: 5,
flaggedCount: 1,
leaderboardEntryCount: 7,
bestLeaderboardScore: 930389410,
bestFinalEnergy: 93,
averageFinalEnergy: 41.25,
updatedAt: '2026-05-13T04:00:00.000Z',
};
expect(stats.playStartCount).toBe(18);
expect(stats.finishCount).toBe(15);
expect(stats.winCount + stats.drawCount + stats.lossCount).toBe(15);
expect(stats.flaggedCount).toBe(1);
expect(stats.bestFinalEnergy).toBeGreaterThan(stats.averageFinalEnergy);
});
test('optional score fields may be omitted instead of serialized as null', () => {
const finishWithoutLeaderboard: BarkBattleFinishResponse = {
status: 'accepted',
runId: 'run-bark-no-rank',
workId: 'work-bark-1',
configVersion: 3,
rulesetVersion: 'bark-battle-ruleset-v1',
difficultyPreset: 'normal',
serverResult: 'draw',
scoreSummary: {
finalEnergy: 50,
triggerCount: 12,
maxVolume: 0.7,
averageVolume: 0.5,
comboMax: 3,
durationMs: 30000,
},
antiCheatFlags: [],
updatedAt: '2026-05-13T03:00:30.000Z',
};
const personalBestWithoutWin: BarkBattlePersonalBestSummary = {
workId: 'work-bark-1',
rulesetVersion: 'bark-battle-ruleset-v1',
difficultyPreset: 'normal',
winCount: 0,
drawCount: 1,
lossCount: 2,
finishCount: 3,
updatedAt: '2026-05-13T04:00:00.000Z',
};
expect('leaderboardScore' in finishWithoutLeaderboard).toBe(false);
expect('bestLeaderboardScore' in personalBestWithoutWin).toBe(false);
expect('bestFinalEnergy' in personalBestWithoutWin).toBe(false);
});
});