Change:
); }); <ins> it('does not report work done on a sibling', () => { const callback = jest.fn(); const DoesNotUpdate = React.memo(function DoesNotUpdateInner() { Scheduler.unstable_advanceTime(10); return null; }, () => true); let updateProfilerSibling; function ProfilerSibling() { const [count, setCount] = React.useState(0); updateProfilerSibling = () => setCount(count + 1); return null; } function App() { return ( <React.Fragment> <React.Profiler id="test" onRender={callback}> <DoesNotUpdate /> </React.Profiler> <ProfilerSibling /> </React.Fragment> ); } const renderer = ReactTestRenderer.create(<App />); expect(callback).toHaveBeenCalledTimes(1); let call = callback.mock.calls[0]; expect(call).toHaveLength(enableSchedulerTracing ? 7 : 6); expect(call[0]).toBe('test'); expect(call[1]).toBe('mount'); expect(call[2]).toBe(10); // actual time expect(call[3]).toBe(10); // base time expect(call[4]).toBe(0); // start time expect(call[5]).toBe(10); // commit time expect(call[6]).toEqual(enableSchedulerTracing ? new Set() : undefined); // interaction events callback.mockReset(); Scheduler.unstable_advanceTime(20); // 10 -> 30 // Updating a parent should report a re-render, // since React technically did a little bit of work between the Profiler and the bailed out subtree. renderer.update(<App />); expect(callback).toHaveBeenCalledTimes(1); call = callback.mock.calls[0]; expect(call).toHaveLength(enableSchedulerTracing ? 7 : 6); expect(call[0]).toBe('test'); expect(call[1]).toBe('update'); expect(call[2]).toBe(0); // actual time expect(call[3]).toBe(10); // base time expect(call[4]).toBe(30); // start time expect(call[5]).toBe(30); // commit time expect(call[6]).toEqual(enableSchedulerTracing ? new Set() : undefined); // interaction events callback.mockReset(); Scheduler.unstable_advanceTime(20); // 30 -> 50 // Updating a sibling should not report a re-render. ReactTestRenderer.act(updateProfilerSibling); expect(callback).not.toHaveBeenCalled(); }); </ins> it('logs render times for both mount and update', () => { const callback = jest.fn();

Discussion:
: However, given: I'm getting a log when I click on the unprofiled counter. Reproduction: Am I misunderstanding this API, or is this a bug?
As the state is being updated by Counter function which is being called on both the profiled and unprofiled counter, is causing re render and is being called both the times.
Thanks but I'm pretty sure that the way it's documented (and what would be sensible) it shouldn't be operating like that. Also, I tried making a separate component instead of using the same one and I got the same result.
At a quick glance it does look unexpected. Don't have time to dig in further at the moment though.
It seems that this occurs for elements which have same type with greater or equal depth in same tree. See:
I don't think it has anything to do with the element type, but where they are declared relative to where the tags are defined. It looks like for a subtree that belongs to a single owner- rendering further down in the subtree will cause the Profiler higher up to call . Given the above example:
This does not look to be hooks-specific, nor is it a recent regression. (Same behavior is exhibited for class components in the earliest release of the Profiler component- v16.5.)
It seems that the is always marked as in phase.
Thanks