-
Notifications
You must be signed in to change notification settings - Fork 24.3k
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Reference implementation (mock) for NativePerformanceObserver (#36116)
Summary: Pull Request resolved: #36116 [Changelog][Internal] Add a minimal/reference JavaScript implementation for NativePerformanceObserver - the purpose is both unit testing (JS and native sides separately) and potentially shimming the part of functionality that is not dependent on native side. This is both a setup for adding general unit tests for the Performance* APIs, but also to be able to do non-trivial changes on JS side for WebPerformance (such as in (D43154319). Reviewed By: rubennorte Differential Revision: D43167392 fbshipit-source-id: 213d9534d810dece1dd464f910e92e08dbf39508
- Loading branch information
1 parent
96fb708
commit f76d4de
Showing
8 changed files
with
261 additions
and
71 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,87 @@ | ||
/** | ||
* 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. | ||
* | ||
* @format | ||
* @flow strict | ||
*/ | ||
|
||
import type { | ||
RawPerformanceEntry, | ||
RawPerformanceEntryType, | ||
} from './NativePerformanceObserver'; | ||
import type {PerformanceEntryType} from './PerformanceEntry'; | ||
|
||
import {PerformanceEntry} from './PerformanceEntry'; | ||
import {PerformanceEventTiming} from './PerformanceEventTiming'; | ||
|
||
export const RawPerformanceEntryTypeValues = { | ||
UNDEFINED: 0, | ||
MARK: 1, | ||
MEASURE: 2, | ||
EVENT: 3, | ||
}; | ||
|
||
export function rawToPerformanceEntry( | ||
entry: RawPerformanceEntry, | ||
): PerformanceEntry { | ||
if (entry.entryType === RawPerformanceEntryTypeValues.EVENT) { | ||
return new PerformanceEventTiming({ | ||
name: entry.name, | ||
startTime: entry.startTime, | ||
duration: entry.duration, | ||
processingStart: entry.processingStart, | ||
processingEnd: entry.processingEnd, | ||
interactionId: entry.interactionId, | ||
}); | ||
} else { | ||
return new PerformanceEntry({ | ||
name: entry.name, | ||
entryType: rawToPerformanceEntryType(entry.entryType), | ||
startTime: entry.startTime, | ||
duration: entry.duration, | ||
}); | ||
} | ||
} | ||
|
||
export function rawToPerformanceEntryType( | ||
type: RawPerformanceEntryType, | ||
): PerformanceEntryType { | ||
switch (type) { | ||
case RawPerformanceEntryTypeValues.MARK: | ||
return 'mark'; | ||
case RawPerformanceEntryTypeValues.MEASURE: | ||
return 'measure'; | ||
case RawPerformanceEntryTypeValues.EVENT: | ||
return 'event'; | ||
case RawPerformanceEntryTypeValues.UNDEFINED: | ||
throw new TypeError( | ||
"rawToPerformanceEntryType: UNDEFINED can't be cast to PerformanceEntryType", | ||
); | ||
default: | ||
throw new TypeError( | ||
`rawToPerformanceEntryType: unexpected performance entry type received: ${type}`, | ||
); | ||
} | ||
} | ||
|
||
export function performanceEntryTypeToRaw( | ||
type: PerformanceEntryType, | ||
): RawPerformanceEntryType { | ||
switch (type) { | ||
case 'mark': | ||
return RawPerformanceEntryTypeValues.MARK; | ||
case 'measure': | ||
return RawPerformanceEntryTypeValues.MEASURE; | ||
case 'event': | ||
return RawPerformanceEntryTypeValues.EVENT; | ||
default: | ||
// Verify exhaustive check with Flow | ||
(type: empty); | ||
throw new TypeError( | ||
`performanceEntryTypeToRaw: unexpected performance entry type received: ${type}`, | ||
); | ||
} | ||
} |
56 changes: 56 additions & 0 deletions
56
Libraries/WebPerformance/__mocks__/NativePerformanceObserver.js
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,56 @@ | ||
/** | ||
* 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 { | ||
GetPendingEntriesResult, | ||
RawPerformanceEntry, | ||
RawPerformanceEntryType, | ||
Spec as NativePerformanceObserver, | ||
} from '../NativePerformanceObserver'; | ||
|
||
const reportingType: Set<RawPerformanceEntryType> = new Set(); | ||
let entries: Array<RawPerformanceEntry> = []; | ||
let onPerformanceEntryCallback: ?() => void; | ||
|
||
const NativePerformanceObserverMock: NativePerformanceObserver = { | ||
startReporting: (entryType: RawPerformanceEntryType) => { | ||
reportingType.add(entryType); | ||
}, | ||
|
||
stopReporting: (entryType: RawPerformanceEntryType) => { | ||
reportingType.delete(entryType); | ||
}, | ||
|
||
popPendingEntries: (): GetPendingEntriesResult => { | ||
const res = entries; | ||
entries = []; | ||
return { | ||
droppedEntriesCount: 0, | ||
entries: res, | ||
}; | ||
}, | ||
|
||
setOnPerformanceEntryCallback: (callback?: () => void) => { | ||
onPerformanceEntryCallback = callback; | ||
}, | ||
|
||
logRawEntry: (entry: RawPerformanceEntry) => { | ||
if (reportingType.has(entry.entryType)) { | ||
entries.push(entry); | ||
// $FlowFixMe[incompatible-call] | ||
global.queueMicrotask(() => { | ||
// We want to emulate the way it's done in native (i.e. async/batched) | ||
onPerformanceEntryCallback?.(); | ||
}); | ||
} | ||
}, | ||
}; | ||
|
||
export default NativePerformanceObserverMock; |
56 changes: 56 additions & 0 deletions
56
Libraries/WebPerformance/__tests__/NativePerformanceObserverMock-test.js
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,56 @@ | ||
/** | ||
* 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. | ||
* | ||
* @format | ||
* @oncall react_native | ||
*/ | ||
|
||
import NativePerformanceObserverMock from '../__mocks__/NativePerformanceObserver'; | ||
import {RawPerformanceEntryTypeValues} from '../RawPerformanceEntry'; | ||
|
||
describe('NativePerformanceObserver', () => { | ||
it('correctly starts and stops listening to entries in a nominal scenario', async () => { | ||
NativePerformanceObserverMock.startReporting( | ||
RawPerformanceEntryTypeValues.MARK, | ||
); | ||
|
||
NativePerformanceObserverMock.logRawEntry({ | ||
name: 'mark1', | ||
entryType: RawPerformanceEntryTypeValues.MARK, | ||
startTime: 0, | ||
duration: 10, | ||
}); | ||
|
||
NativePerformanceObserverMock.logRawEntry({ | ||
name: 'mark2', | ||
entryType: RawPerformanceEntryTypeValues.MARK, | ||
startTime: 0, | ||
duration: 20, | ||
}); | ||
|
||
NativePerformanceObserverMock.logRawEntry({ | ||
name: 'event1', | ||
entryType: RawPerformanceEntryTypeValues.EVENT, | ||
startTime: 0, | ||
duration: 20, | ||
}); | ||
|
||
const entriesResult = NativePerformanceObserverMock.popPendingEntries(); | ||
expect(entriesResult).not.toBe(undefined); | ||
const entries = entriesResult.entries; | ||
|
||
expect(entries.length).toBe(2); | ||
expect(entries[0].name).toBe('mark1'); | ||
expect(entries[1].name).toBe('mark2'); | ||
|
||
const entriesResult1 = NativePerformanceObserverMock.popPendingEntries(); | ||
expect(entriesResult1).not.toBe(undefined); | ||
const entries1 = entriesResult1.entries; | ||
expect(entries1.length).toBe(0); | ||
|
||
NativePerformanceObserverMock.stopReporting('mark'); | ||
}); | ||
}); |
49 changes: 49 additions & 0 deletions
49
Libraries/WebPerformance/__tests__/PerformanceObserver-test.js
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,49 @@ | ||
/** | ||
* 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. | ||
* | ||
* @format | ||
* @oncall react_native | ||
*/ | ||
|
||
import {RawPerformanceEntryTypeValues} from '../RawPerformanceEntry'; | ||
|
||
// NOTE: Jest mocks of transitive dependencies don't appear to work with | ||
// ES6 module imports, therefore forced to use commonjs style imports here. | ||
const NativePerformanceObserver = require('../NativePerformanceObserver'); | ||
const PerformanceObserver = require('../PerformanceObserver').default; | ||
|
||
jest.mock( | ||
'../NativePerformanceObserver', | ||
() => require('../__mocks__/NativePerformanceObserver').default, | ||
); | ||
|
||
describe('PerformanceObserver', () => { | ||
it('can be mocked by a reference NativePerformanceObserver implementation', async () => { | ||
expect(NativePerformanceObserver).not.toBe(undefined); | ||
|
||
let totalEntries = 0; | ||
const observer = new PerformanceObserver((list, _observer) => { | ||
const entries = list.getEntries(); | ||
expect(entries).toHaveLength(1); | ||
const entry = entries[0]; | ||
expect(entry.name).toBe('mark1'); | ||
expect(entry.entryType).toBe('mark'); | ||
totalEntries += entries.length; | ||
}); | ||
expect(() => observer.observe({entryTypes: ['mark']})).not.toThrow(); | ||
|
||
NativePerformanceObserver.logRawEntry({ | ||
name: 'mark1', | ||
entryType: RawPerformanceEntryTypeValues.MARK, | ||
startTime: 0, | ||
duration: 0, | ||
}); | ||
|
||
await jest.runAllTicks(); | ||
expect(totalEntries).toBe(1); | ||
observer.disconnect(); | ||
}); | ||
}); |