From f5f6a9a11b3606bd6afb6836aefad1e88bd61b82 Mon Sep 17 00:00:00 2001 From: Joao Victor Vasconcelos Date: Thu, 8 Oct 2026 11:22:35 -0300 Subject: [PATCH] fix(diagnostics): avoid duplicate child stat updates --- src/stats/stats-provider.test.ts | 30 ++++++++++++++++++++++++++++++ src/stats/stats-provider.ts | 10 ++++++---- 2 files changed, 36 insertions(+), 4 deletions(-) diff --git a/src/stats/stats-provider.test.ts b/src/stats/stats-provider.test.ts index 82a5be32..5f2820ca 100644 --- a/src/stats/stats-provider.test.ts +++ b/src/stats/stats-provider.test.ts @@ -2,6 +2,36 @@ import { describe, it, expect } from 'vitest'; import { StatData, StatDataModel, StatsProvider } from './stats-provider'; describe('StatsProvider', () => { + it('emits each child statistic once to each listener', () => { + const provider = new StatsProvider('test', 'test'); + const firstListenerStats: StatData[] = []; + const secondListenerStats: StatData[] = []; + + provider.addStatListener({ + onStatUpdated: (stat: StatData) => firstListenerStats.push(stat), + }); + provider.addStatListener({ + onStatUpdated: (stat: StatData) => secondListenerStats.push(stat), + }); + + provider.setStats({ + tick: 1, + type: 'stats', + stats: [{ + name: 'parent', + should_aggregate: false, + children: [{ + name: 'child', + should_aggregate: false, + values: [1], + }], + }], + }); + + expect(firstListenerStats.map((stat: StatData) => stat.name)).toEqual(['parent', 'child']); + expect(secondListenerStats.map((stat: StatData) => stat.name)).toEqual(['parent', 'child']); + }); + it('aggregateData successful', async () => { const childDataA: StatDataModel = { name: 'childA', diff --git a/src/stats/stats-provider.ts b/src/stats/stats-provider.ts index ab0a6fcb..670569f0 100644 --- a/src/stats/stats-provider.ts +++ b/src/stats/stats-provider.ts @@ -168,11 +168,13 @@ export class StatsProvider { if (aggregateChildData !== undefined) { listener.onStatUpdated?.(aggregateChildData); - } else if (stat.children) { - stat.children.forEach((child: StatDataModel) => { - this._fireStatUpdated(child, tick, statData); - }); } }); + + if (aggregateChildData === undefined && stat.children) { + stat.children.forEach((child: StatDataModel) => { + this._fireStatUpdated(child, tick, statData); + }); + } } }