From e6bff3f1fec7db9dbffa454948b994be27ec0db5 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Rub=C3=A9n=20Norte?= Date: Mon, 7 Jul 2025 06:42:23 -0700 Subject: [PATCH] Add tests for performance.eventCounts (#52463) Summary: Pull Request resolved: https://github.com/facebook/react-native/pull/52463 Changelog: [internal] This adds Fantom tests for `performance.eventCounts`. Reviewed By: huntie Differential Revision: D77860881 fbshipit-source-id: 26b9ef56b9c610cbad7011bc0adde27251fda909 --- .../webperformance/NativePerformance.cpp | 4 ++ .../webperformance/NativePerformance.h | 1 + .../timeline/PerformanceEntryReporter.cpp | 4 ++ .../timeline/PerformanceEntryReporter.h | 2 + .../__tests__/EventTimingAPI-itest.js | 61 +++++++++++++++++++ .../performance/specs/NativePerformance.js | 1 + 6 files changed, 73 insertions(+) diff --git a/packages/react-native/ReactCommon/react/nativemodule/webperformance/NativePerformance.cpp b/packages/react-native/ReactCommon/react/nativemodule/webperformance/NativePerformance.cpp index 7c8be7f36d2..34b2cc21e84 100644 --- a/packages/react-native/ReactCommon/react/nativemodule/webperformance/NativePerformance.cpp +++ b/packages/react-native/ReactCommon/react/nativemodule/webperformance/NativePerformance.cpp @@ -464,4 +464,8 @@ void NativePerformance::setCurrentTimeStampForTesting( forcedCurrentTimeStamp_ = ts; } +void NativePerformance::clearEventCountsForTesting(jsi::Runtime& /*rt*/) { + PerformanceEntryReporter::getInstance()->clearEventCounts(); +} + } // namespace facebook::react diff --git a/packages/react-native/ReactCommon/react/nativemodule/webperformance/NativePerformance.h b/packages/react-native/ReactCommon/react/nativemodule/webperformance/NativePerformance.h index d713171e14c..a1e05cf66c3 100644 --- a/packages/react-native/ReactCommon/react/nativemodule/webperformance/NativePerformance.h +++ b/packages/react-native/ReactCommon/react/nativemodule/webperformance/NativePerformance.h @@ -199,6 +199,7 @@ class NativePerformance : public NativePerformanceCxxSpec { #pragma mark - Testing void setCurrentTimeStampForTesting(jsi::Runtime& rt, HighResTimeStamp ts); + void clearEventCountsForTesting(jsi::Runtime& rt); private: std::optional forcedCurrentTimeStamp_; diff --git a/packages/react-native/ReactCommon/react/performance/timeline/PerformanceEntryReporter.cpp b/packages/react-native/ReactCommon/react/performance/timeline/PerformanceEntryReporter.cpp index 01a7591ccef..4bb9f8e44d2 100644 --- a/packages/react-native/ReactCommon/react/performance/timeline/PerformanceEntryReporter.cpp +++ b/packages/react-native/ReactCommon/react/performance/timeline/PerformanceEntryReporter.cpp @@ -213,6 +213,10 @@ PerformanceMeasure PerformanceEntryReporter::reportMeasure( return entry; } +void PerformanceEntryReporter::clearEventCounts() { + eventCounts_.clear(); +} + std::optional PerformanceEntryReporter::getMarkTime( const std::string& markName) const { std::shared_lock lock(buffersMutex_); diff --git a/packages/react-native/ReactCommon/react/performance/timeline/PerformanceEntryReporter.h b/packages/react-native/ReactCommon/react/performance/timeline/PerformanceEntryReporter.h index 2eb67ceca03..1bacd16e1d9 100644 --- a/packages/react-native/ReactCommon/react/performance/timeline/PerformanceEntryReporter.h +++ b/packages/react-native/ReactCommon/react/performance/timeline/PerformanceEntryReporter.h @@ -81,6 +81,8 @@ class PerformanceEntryReporter { return eventCounts_; } + void clearEventCounts(); + std::optional getMarkTime( const std::string& markName) const; diff --git a/packages/react-native/src/private/webapis/performance/__tests__/EventTimingAPI-itest.js b/packages/react-native/src/private/webapis/performance/__tests__/EventTimingAPI-itest.js index 41df7c609a9..4139eaaa29d 100644 --- a/packages/react-native/src/private/webapis/performance/__tests__/EventTimingAPI-itest.js +++ b/packages/react-native/src/private/webapis/performance/__tests__/EventTimingAPI-itest.js @@ -10,8 +10,10 @@ import '@react-native/fantom/src/setUpDefaultReactNativeEnvironment'; +import type Performance from 'react-native/src/private/webapis/performance/Performance'; import type {PerformanceObserverEntryList} from 'react-native/src/private/webapis/performance/PerformanceObserver'; +import NativePerformance from '../specs/NativePerformance'; import * as Fantom from '@react-native/fantom'; import nullthrows from 'nullthrows'; import {useState} from 'react'; @@ -22,6 +24,8 @@ import {PerformanceObserver} from 'react-native/src/private/webapis/performance/ setUpPerformanceObserver(); +declare var performance: Performance; + function sleep(ms: number) { const end = performance.now() + ms; while (performance.now() < end) {} @@ -187,4 +191,61 @@ describe('Event Timing API', () => { expect(entry.interactionId).toBeGreaterThanOrEqual(0); }); + + it('reports number of dispatched events via performance.eventCounts', () => { + NativePerformance?.clearEventCountsForTesting?.(); + + const root = Fantom.createRoot(); + Fantom.runTask(() => { + root.render(); + }); + + const element = nullthrows(root.document.documentElement.firstElementChild); + + expect(performance.eventCounts).not.toBeInstanceOf(Map); + + // FIXME: this isn't spec compliant, as the map should be prepopulated with + // all the supported event names mapped to 0. + expect(performance.eventCounts.size).toBe(0); + expect([...performance.eventCounts.entries()]).toEqual([]); + const initialForEachCallback = jest.fn(); + performance.eventCounts.forEach(initialForEachCallback); + expect(initialForEachCallback.mock.calls).toEqual([]); + expect([...performance.eventCounts.keys()]).toEqual([]); + expect([...performance.eventCounts.values()]).toEqual([]); + + Fantom.dispatchNativeEvent(element, 'click'); + Fantom.dispatchNativeEvent(element, 'click'); + Fantom.dispatchNativeEvent(element, 'click'); + + Fantom.dispatchNativeEvent(element, 'pointerDown'); + Fantom.dispatchNativeEvent(element, 'pointerUp'); + + expect(performance.eventCounts.size).toBe(3); + expect(performance.eventCounts.get('click')).toBe(3); + expect(performance.eventCounts.get('pointerdown')).toBe(1); + expect(performance.eventCounts.get('pointerup')).toBe(1); + + expect([...performance.eventCounts.entries()]).toEqual([ + ['pointerup', 1], + ['pointerdown', 1], + ['click', 3], + ]); + + const forEachCallback = jest.fn(); + performance.eventCounts.forEach(forEachCallback); + expect(forEachCallback.mock.calls).toEqual([ + [1, 'pointerup', performance.eventCounts], + [1, 'pointerdown', performance.eventCounts], + [3, 'click', performance.eventCounts], + ]); + + expect([...performance.eventCounts.keys()]).toEqual([ + 'pointerup', + 'pointerdown', + 'click', + ]); + + expect([...performance.eventCounts.values()]).toEqual([1, 1, 3]); + }); }); diff --git a/packages/react-native/src/private/webapis/performance/specs/NativePerformance.js b/packages/react-native/src/private/webapis/performance/specs/NativePerformance.js index 6ce038f9395..39014040cf0 100644 --- a/packages/react-native/src/private/webapis/performance/specs/NativePerformance.js +++ b/packages/react-native/src/private/webapis/performance/specs/NativePerformance.js @@ -107,6 +107,7 @@ export interface Spec extends TurboModule { +getSupportedPerformanceEntryTypes?: () => $ReadOnlyArray; +setCurrentTimeStampForTesting?: (timeStamp: number) => void; + +clearEventCountsForTesting?: () => void; } export default (TurboModuleRegistry.get('NativePerformanceCxx'): ?Spec);