diff --git a/packages/react-native/src/private/webapis/performance/__tests__/Performance-test.js b/packages/react-native/src/private/webapis/performance/__tests__/Performance-test.js deleted file mode 100644 index 2b7a3108952..00000000000 --- a/packages/react-native/src/private/webapis/performance/__tests__/Performance-test.js +++ /dev/null @@ -1,292 +0,0 @@ -/** - * Copyright (c) Meta Platforms, Inc. and affiliates. - * - * This source code is licensed under the MIT license found in the - * LICENSE file in the root directory of this source tree. - * - * @flow strict-local - * @format - */ - -// eslint-disable-next-line @react-native/monorepo/sort-imports -import type Performance from '../Performance'; - -import {performanceEntryTypeToRaw} from '../internals/RawPerformanceEntry'; -import {reportEntry} from '../specs/__mocks__/NativePerformanceMock'; - -jest.mock('../specs/NativePerformance', () => - require('../specs/__mocks__/NativePerformanceMock'), -); - -declare var performance: Performance; - -const NativePerformanceMock = - require('../specs/__mocks__/NativePerformanceMock').default; - -describe('Performance', () => { - beforeEach(() => { - jest.resetModules(); - - const PerformanceClass = require('../Performance').default; - // $FlowExpectedError[cannot-write] - global.performance = new PerformanceClass(); - }); - - it('reports marks and measures', () => { - NativePerformanceMock.setCurrentTime(25); - - performance.mark('mark-now'); - performance.mark('mark-in-the-past', { - startTime: 10, - }); - performance.mark('mark-in-the-future', { - startTime: 50, - }); - performance.measure('measure-with-specific-time', { - start: 30, - duration: 4, - }); - performance.measure('measure-now-with-start-mark', 'mark-in-the-past'); - performance.measure( - 'measure-with-start-and-end-mark', - 'mark-in-the-past', - 'mark-in-the-future', - ); - - const entries = performance.getEntries(); - expect(entries.length).toBe(6); - expect(entries.map(entry => entry.toJSON())).toEqual([ - { - duration: 0, - entryType: 'mark', - name: 'mark-in-the-past', - startTime: 10, - }, - { - duration: 15, - entryType: 'measure', - name: 'measure-now-with-start-mark', - startTime: 10, - }, - { - duration: 40, - entryType: 'measure', - name: 'measure-with-start-and-end-mark', - startTime: 10, - }, - { - duration: 0, - entryType: 'mark', - name: 'mark-now', - startTime: 25, - }, - { - duration: 4, - entryType: 'measure', - name: 'measure-with-specific-time', - startTime: 30, - }, - { - duration: 0, - entryType: 'mark', - name: 'mark-in-the-future', - startTime: 50, - }, - ]); - }); - - it('clearMarks and clearMeasures remove correct entry types', async () => { - performance.mark('entry1', {startTime: 0}); - performance.mark('mark2', {startTime: 0}); - - performance.measure('entry1', {start: 0, duration: 0}); - performance.measure('measure2', {start: 0, duration: 0}); - - performance.clearMarks(); - - expect(performance.getEntries().map(e => e.name)).toStrictEqual([ - 'entry1', - 'measure2', - ]); - - performance.mark('entry2', {startTime: 0}); - performance.mark('mark3', {startTime: 0}); - - performance.clearMeasures(); - - expect(performance.getEntries().map(e => e.name)).toStrictEqual([ - 'entry2', - 'mark3', - ]); - - performance.clearMarks(); - - expect(performance.getEntries().map(e => e.name)).toStrictEqual([]); - }); - - it('getEntries only works with allowed entry types', async () => { - performance.clearMarks(); - performance.clearMeasures(); - - performance.mark('entry1', {startTime: 0}); - performance.mark('mark2', {startTime: 0}); - - jest.spyOn(console, 'warn').mockImplementation(() => {}); - - performance.getEntriesByType('mark'); - expect(console.warn).not.toHaveBeenCalled(); - - performance.getEntriesByType('measure'); - expect(console.warn).not.toHaveBeenCalled(); - - performance.getEntriesByName('entry1'); - expect(console.warn).not.toHaveBeenCalled(); - - performance.getEntriesByName('entry1', 'event'); - expect(console.warn).toHaveBeenCalled(); - - performance.getEntriesByName('entry1', 'mark'); - expect(console.warn).toHaveBeenCalled(); - - performance.getEntriesByType('event'); - expect(console.warn).toHaveBeenCalled(); - }); - - it('getEntries works with marks and measures', async () => { - performance.clearMarks(); - performance.clearMeasures(); - - performance.mark('entry1', {startTime: 0}); - performance.mark('mark2', {startTime: 0}); - - performance.measure('entry1', {start: 0, duration: 0}); - performance.measure('measure2', {start: 0, duration: 0}); - - expect(performance.getEntries().map(e => e.name)).toStrictEqual([ - 'entry1', - 'mark2', - 'entry1', - 'measure2', - ]); - - expect(performance.getEntriesByType('mark').map(e => e.name)).toStrictEqual( - ['entry1', 'mark2'], - ); - - expect( - performance.getEntriesByType('measure').map(e => e.name), - ).toStrictEqual(['entry1', 'measure2']); - - expect( - performance.getEntriesByName('entry1').map(e => e.entryType), - ).toStrictEqual(['mark', 'measure']); - - expect( - performance.getEntriesByName('entry1', 'measure').map(e => e.entryType), - ).toStrictEqual(['measure']); - }); - - it('defines EventCounts for Performance', () => { - expect(performance.eventCounts).not.toBeUndefined(); - }); - - it('consistently implements the API for EventCounts', async () => { - let interactionId = 0; - const eventDefaultValues = { - entryType: performanceEntryTypeToRaw('event'), - startTime: 0, // startTime - duration: 100, // duration - processingStart: 0, // processing start - processingEnd: 100, // processingEnd - }; - - reportEntry({ - name: 'click', - ...eventDefaultValues, - interactionId: interactionId++, - }); - reportEntry({ - name: 'input', - ...eventDefaultValues, - interactionId: interactionId++, - }); - reportEntry({ - name: 'input', - ...eventDefaultValues, - interactionId: interactionId++, - }); - reportEntry({ - name: 'keyup', - ...eventDefaultValues, - interactionId: interactionId++, - }); - reportEntry({ - name: 'keyup', - ...eventDefaultValues, - interactionId: interactionId++, - }); - reportEntry({ - name: 'keyup', - ...eventDefaultValues, - interactionId: interactionId++, - }); - - const eventCounts = performance.eventCounts; - expect(eventCounts.size).toBe(3); - expect(Array.from(eventCounts.entries())).toStrictEqual([ - ['click', 1], - ['input', 2], - ['keyup', 3], - ]); - - expect(eventCounts.get('click')).toEqual(1); - expect(eventCounts.get('input')).toEqual(2); - expect(eventCounts.get('keyup')).toEqual(3); - - expect(eventCounts.has('click')).toEqual(true); - expect(eventCounts.has('input')).toEqual(true); - expect(eventCounts.has('keyup')).toEqual(true); - - expect(Array.from(eventCounts.keys())).toStrictEqual([ - 'click', - 'input', - 'keyup', - ]); - expect(Array.from(eventCounts.values())).toStrictEqual([1, 2, 3]); - - await jest.runAllTicks(); - reportEntry({ - name: 'input', - ...eventDefaultValues, - interactionId: interactionId++, - }); - reportEntry({ - name: 'keyup', - ...eventDefaultValues, - interactionId: interactionId++, - }); - reportEntry({ - name: 'keyup', - ...eventDefaultValues, - interactionId: interactionId++, - }); - expect(Array.from(eventCounts.values())).toStrictEqual([1, 3, 5]); - - await jest.runAllTicks(); - reportEntry({ - name: 'click', - ...eventDefaultValues, - interactionId: interactionId++, - }); - - await jest.runAllTicks(); - - reportEntry({ - name: 'keyup', - ...eventDefaultValues, - interactionId: interactionId++, - }); - - expect(Array.from(eventCounts.values())).toStrictEqual([2, 3, 6]); - }); -}); diff --git a/packages/react-native/src/private/webapis/performance/__tests__/PerformanceObserver-test.js b/packages/react-native/src/private/webapis/performance/__tests__/PerformanceObserver-test.js deleted file mode 100644 index 9e96798378c..00000000000 --- a/packages/react-native/src/private/webapis/performance/__tests__/PerformanceObserver-test.js +++ /dev/null @@ -1,58 +0,0 @@ -/** - * Copyright (c) Meta Platforms, Inc. and affiliates. - * - * This source code is licensed under the MIT license found in the - * LICENSE file in the root directory of this source tree. - * - * @flow strict-local - * @format - */ - -import type Performance from '../Performance'; -import type {PerformanceEntryList} from '../PerformanceEntry'; - -jest.mock( - '../specs/NativePerformance', - () => require('../specs/__mocks__/NativePerformanceMock').default, -); - -declare var performance: Performance; - -describe('PerformanceObserver', () => { - let PerformanceObserver; - - beforeEach(() => { - jest.resetModules(); - - // $FlowExpectedError[cannot-write] - global.performance = new (require('../Performance').default)(); - PerformanceObserver = require('../PerformanceObserver').PerformanceObserver; - }); - - it('prevents durationThreshold to be used together with entryTypes', async () => { - const observer = new PerformanceObserver((list, _observer) => {}); - - expect(() => - observer.observe({entryTypes: ['event', 'mark'], durationThreshold: 100}), - ).toThrow(); - }); - - it('ignores durationThreshold when used with marks or measures', async () => { - let entries: PerformanceEntryList = []; - - const observer = new PerformanceObserver((list, _observer) => { - entries = [...entries, ...list.getEntries()]; - }); - - observer.observe({type: 'measure', durationThreshold: 100}); - - performance.measure('measure1', { - start: 0, - duration: 10, - }); - - await jest.runAllTicks(); - expect(entries).toHaveLength(1); - expect(entries.map(e => e.name)).toStrictEqual(['measure1']); - }); -}); diff --git a/packages/react-native/src/private/webapis/performance/specs/__mocks__/NativePerformanceMock.js b/packages/react-native/src/private/webapis/performance/specs/__mocks__/NativePerformanceMock.js deleted file mode 100644 index 518ca5e61e9..00000000000 --- a/packages/react-native/src/private/webapis/performance/specs/__mocks__/NativePerformanceMock.js +++ /dev/null @@ -1,269 +0,0 @@ -/** - * Copyright (c) Meta Platforms, Inc. and affiliates. - * - * This source code is licensed under the MIT license found in the - * LICENSE file in the root directory of this source tree. - * - * @flow strict - * @format - */ - -import type { - NativeBatchedObserverCallback, - NativeMemoryInfo, - NativePerformanceMarkResult, - NativePerformanceMeasureResult, - OpaqueNativeObserverHandle, - PerformanceObserverInit, - RawPerformanceEntry, - RawPerformanceEntryType, - ReactNativeStartupTiming, -} from '../NativePerformance'; -import typeof NativePerformance from '../NativePerformance'; - -import {RawPerformanceEntryTypeValues} from '../../internals/RawPerformanceEntry'; - -type MockObserver = { - handleEntry: (entry: RawPerformanceEntry) => void, - callback: NativeBatchedObserverCallback, - didScheduleFlushBuffer: boolean, - entries: Array, - options: PerformanceObserverInit, - droppedEntriesCount: number, -}; - -const eventCounts: Map = new Map(); -const observers: Set = new Set(); -const marks: Map = new Map(); -let entries: Array = []; - -function getMockObserver( - opaqueNativeObserverHandle: OpaqueNativeObserverHandle, -): MockObserver { - return opaqueNativeObserverHandle as $FlowFixMe as MockObserver; -} - -function createMockObserver(callback: NativeBatchedObserverCallback) { - const observer: MockObserver = { - callback, - didScheduleFlushBuffer: false, - entries: [], - options: {}, - droppedEntriesCount: 0, - handleEntry: (entry: RawPerformanceEntry) => { - if ( - observer.options.type !== entry.entryType && - !observer.options.entryTypes?.includes(entry.entryType) - ) { - return; - } - - if ( - entry.entryType === RawPerformanceEntryTypeValues.EVENT && - entry.duration < (observer.options?.durationThreshold ?? 0) - ) { - return; - } - - observer.entries.push(entry); - - if (!observer.didScheduleFlushBuffer) { - observer.didScheduleFlushBuffer = true; - // $FlowFixMe[incompatible-call] - global.queueMicrotask(() => { - observer.didScheduleFlushBuffer = false; - // We want to emulate the way it's done in native (i.e. async/batched) - observer.callback(); - }); - } - }, - }; - - return observer; -} - -export function reportEntry(entry: RawPerformanceEntry) { - entries.push(entry); - - switch (entry.entryType) { - case RawPerformanceEntryTypeValues.MARK: - marks.set(entry.name, entry.startTime); - break; - case RawPerformanceEntryTypeValues.MEASURE: - break; - case RawPerformanceEntryTypeValues.EVENT: - eventCounts.set(entry.name, (eventCounts.get(entry.name) ?? 0) + 1); - break; - } - - for (const observer of observers) { - observer.handleEntry(entry); - } -} - -let currentTime: number = 12; - -const NativePerformanceMock = { - setCurrentTime: (time: number): void => { - currentTime = time; - }, - - now: (): number => currentTime, - - markWithResult: ( - name: string, - startTime?: number, - ): NativePerformanceMarkResult => { - const computedStartTime = startTime ?? performance.now(); - - marks.set(name, computedStartTime); - reportEntry({ - entryType: RawPerformanceEntryTypeValues.MARK, - name, - startTime: computedStartTime, - duration: 0, - }); - - return computedStartTime; - }, - - measure: ( - name: string, - startTime?: number, - endTime?: number, - duration?: number, - startMark?: string, - endMark?: string, - ): NativePerformanceMeasureResult => { - const start = startMark != null ? marks.get(startMark) : startTime ?? 0; - const end = - endMark != null ? marks.get(endMark) : endTime ?? performance.now(); - - if (start === undefined) { - throw new Error('startMark does not exist'); - } - - if (end === undefined) { - throw new Error('endMark does not exist'); - } - - const computedDuration = duration ?? end - start; - reportEntry({ - entryType: RawPerformanceEntryTypeValues.MEASURE, - name, - startTime: start, - duration: computedDuration, - }); - - return [start, computedDuration]; - }, - - getSimpleMemoryInfo: (): NativeMemoryInfo => { - return {}; - }, - - getReactNativeStartupTiming: (): ReactNativeStartupTiming => { - return { - startTime: 0, - endTime: 0, - executeJavaScriptBundleEntryPointStart: 0, - executeJavaScriptBundleEntryPointEnd: 0, - initializeRuntimeStart: 0, - initializeRuntimeEnd: 0, - }; - }, - - getEventCounts: (): $ReadOnlyArray<[string, number]> => { - return Array.from(eventCounts.entries()); - }, - - createObserver: ( - callback: NativeBatchedObserverCallback, - ): OpaqueNativeObserverHandle => { - // $FlowExpectedError[incompatible-return] - return createMockObserver(callback); - }, - - getDroppedEntriesCount: (observer: OpaqueNativeObserverHandle): number => { - return getMockObserver(observer).droppedEntriesCount; - }, - - observe: ( - observer: OpaqueNativeObserverHandle, - options: PerformanceObserverInit, - ): void => { - const mockObserver = getMockObserver(observer); - mockObserver.options = options; - observers.add(mockObserver); - }, - - disconnect: (observer: OpaqueNativeObserverHandle): void => { - const mockObserver = getMockObserver(observer); - observers.delete(mockObserver); - }, - - takeRecords: ( - observer: OpaqueNativeObserverHandle, - ): $ReadOnlyArray => { - const mockObserver = getMockObserver(observer); - const observerEntries = mockObserver.entries; - mockObserver.entries = []; - return observerEntries.sort((a, b) => a.startTime - b.startTime); - }, - - clearMarks: (entryName?: string) => { - if (entryName != null) { - marks.delete(entryName); - } else { - marks.clear(); - } - - entries = entries.filter( - entry => - entry.entryType !== RawPerformanceEntryTypeValues.MARK || - (entryName != null && entry.name !== entryName), - ); - }, - - clearMeasures: (entryName?: string) => { - entries = entries.filter( - entry => - entry.entryType !== RawPerformanceEntryTypeValues.MEASURE || - (entryName != null && entry.name !== entryName), - ); - }, - - getEntries: (): $ReadOnlyArray => { - return [...entries].sort((a, b) => a.startTime - b.startTime); - }, - - getEntriesByName: ( - entryName: string, - entryType?: ?RawPerformanceEntryType, - ): $ReadOnlyArray => { - return NativePerformanceMock.getEntries().filter( - entry => - (entryType == null || entry.entryType === entryType) && - entry.name === entryName, - ); - }, - - getEntriesByType: ( - entryType: RawPerformanceEntryType, - ): $ReadOnlyArray => { - return entries.filter(entry => entry.entryType === entryType); - }, - - getSupportedPerformanceEntryTypes: - (): $ReadOnlyArray => { - return [ - RawPerformanceEntryTypeValues.MARK, - RawPerformanceEntryTypeValues.MEASURE, - RawPerformanceEntryTypeValues.EVENT, - ]; - }, -}; - -(NativePerformanceMock: NativePerformance); - -export default NativePerformanceMock;