@samitouri / QOS-React-2 / commits / e4aa3c5b33

Update profiling-supported status each time roots change (and added tests)

Brian Vaughn committed May 23, 2019 at 09:09 UTC e4aa3c5b3375154037674f56624e6619bb889274
4 files changed +65 -8
src/__tests__/profilerContext-test.js
+35
@@ -65,6 +65,41 @@ describe('ProfilerContext', () => {
65 </BridgeContext.Provider>
66 );
67
68 + it('updates updates profiling support based on the attached roots', async done => {
69 + const Component = () => null;
70 +
71 + let context: Context = ((null: any): Context);
72 +
73 + function ContextReader() {
74 + context = React.useContext(ProfilerContext);
75 + return null;
76 + }
77 + await utils.actAsync(() => {
78 + TestRenderer.create(
79 + <Contexts>
80 + <ContextReader />
81 + </Contexts>
82 + );
83 + });
84 +
85 + expect(context.supportsProfiling).toBe(false);
86 +
87 + const containerA = document.createElement('div');
88 + const containerB = document.createElement('div');
89 +
90 + await utils.actAsync(() => ReactDOM.render(<Component />, containerA));
91 + expect(context.supportsProfiling).toBe(true);
92 +
93 + await utils.actAsync(() => ReactDOM.render(<Component />, containerB));
94 + await utils.actAsync(() => ReactDOM.unmountComponentAtNode(containerA));
95 + expect(context.supportsProfiling).toBe(true);
96 +
97 + await utils.actAsync(() => ReactDOM.unmountComponentAtNode(containerB));
98 + expect(context.supportsProfiling).toBe(false);
99 +
100 + done();
101 + });
102 +
103 it('should gracefully handle an empty profiling session (with no recorded commits)', async done => {
104 const Example = () => null;
105
src/__tests__/store-test.js
+19
@@ -778,4 +778,23 @@ describe('Store', () => {
778 }
779 });
780 });
781 +
782 + it('detects and updates profiling support based on the attached roots', () => {
783 + const Component = () => null;
784 +
785 + const containerA = document.createElement('div');
786 + const containerB = document.createElement('div');
787 +
788 + expect(store.supportsProfiling).toBe(false);
789 +
790 + act(() => ReactDOM.render(<Component />, containerA));
791 + expect(store.supportsProfiling).toBe(true);
792 +
793 + act(() => ReactDOM.render(<Component />, containerB));
794 + act(() => ReactDOM.unmountComponentAtNode(containerA));
795 + expect(store.supportsProfiling).toBe(true);
796 +
797 + act(() => ReactDOM.unmountComponentAtNode(containerB));
798 + expect(store.supportsProfiling).toBe(false);
799 + });
800 });
src/devtools/store.js
+8 -2
@@ -859,20 +859,26 @@ export default class Store extends EventEmitter {
859 this._revision++;
860
861 if (haveRootsChanged) {
862 + const prevSupportsProfiling = this._supportsProfiling;
863 +
864 this._hasOwnerMetadata = false;
865 + this._supportsProfiling = false;
866 this._rootIDToCapabilities.forEach(
867 ({ hasOwnerMetadata, supportsProfiling }) => {
868 if (hasOwnerMetadata) {
869 this._hasOwnerMetadata = true;
870 }
868 - if (!this._supportsProfiling && supportsProfiling) {
871 + if (supportsProfiling) {
872 this._supportsProfiling = true;
870 - this.emit('supportsProfiling');
873 }
874 }
875 );
876
877 this.emit('roots');
878 +
879 + if (this._supportsProfiling !== prevSupportsProfiling) {
880 + this.emit('supportsProfiling');
881 + }
882 }
883
884 if (__DEBUG__) {
src/devtools/views/Profiler/ProfilerContext.js
+3 -6
@@ -21,16 +21,12 @@ import type { ProfilingDataFrontend } from './types';
21 export type TabID = 'flame-chart' | 'ranked-chart' | 'interactions';
22
23 export type Context = {|
24 - // Does the Store support profiling?
25 - supportsProfiling: boolean,
26 -
24 // Which tab is selexted in the Profiler UI?
25 selectedTabID: TabID,
26 selectTab(id: TabID): void,
27
31 - // Have we recorded any profiling data?
32 - // Are we currently profiling?
33 - // This value may be modified by the record button in the Profiler toolbar,
28 + // Store subscription based values.
29 + // The isProfiling value may be modified by the record button in the Profiler toolbar,
30 // or from the backend itself (after a reload-and-profile action).
31 // It is synced between the backend and frontend via a Store subscription.
32 didRecordCommits: boolean,
@@ -39,6 +35,7 @@ export type Context = {|
35 profilingData: ProfilingDataFrontend | null,
36 startProfiling(value: boolean): void,
37 stopProfiling(value: boolean): void,
38 + supportsProfiling: boolean,
39
40 // Which root should profiling data be shown for?
41 // This value should be initialized to either: