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: