diff --git a/packages/kit/src/runtime/registry.ts b/packages/kit/src/runtime/registry.ts index db42bc89b..95db07259 100644 --- a/packages/kit/src/runtime/registry.ts +++ b/packages/kit/src/runtime/registry.ts @@ -462,7 +462,7 @@ function readAppName(app: object): string | undefined { return component ? readStringProperty(component, 'name') : undefined } -function readComponentName(instance: object): string { +export function readComponentName(instance: object): string { const type = readObjectProperty(instance, 'type') if (type) { const name = diff --git a/packages/kit/src/runtime/timeline.ts b/packages/kit/src/runtime/timeline.ts index 8d4a797b9..a0b521058 100644 --- a/packages/kit/src/runtime/timeline.ts +++ b/packages/kit/src/runtime/timeline.ts @@ -2,6 +2,7 @@ import type { EncodedValue, ValueHandleRegistry } from '../codec' import type { AppId, InstanceRef } from './types' import type { DevtoolsRuntime } from './runtime' import { encodeValue } from '../codec' +import { readComponentName } from './registry' interface PerformanceStartEvent { type: 'perf:start' @@ -148,7 +149,7 @@ export function createRuntimeTimeline( const componentRecord = component ? runtime.registry.getComponent(component, event.appId) : undefined - const componentName = componentRecord?.name ?? 'Unknown Component' + const componentName = componentRecord?.name ?? readComponentName(event.instance) dispatchTimelineEvent(runtime, handles, state, { appId: event.appId, @@ -236,7 +237,7 @@ function addPerformanceStart( const componentRecord = componentId ? runtime.registry.getComponent(componentId, event.appId) : undefined - const componentName = componentRecord?.name ?? 'Unknown Component' + const componentName = componentRecord?.name ?? readComponentName(event.instance) const groupId = state.groupSeed++ // The registry ID can change from undefined to an ID between start and end. const groupKey = `${event.appId}:${event.phase}` @@ -286,7 +287,7 @@ function addPerformanceEnd( const componentRecord = componentId ? runtime.registry.getComponent(componentId, event.appId) : undefined - const componentName = componentRecord?.name ?? 'Unknown Component' + const componentName = componentRecord?.name ?? readComponentName(event.instance) const duration = Math.max(0, event.timestamp - group.startTime) groups!.delete(groupKey) diff --git a/tests/unit/runtime/timeline-rate-limit.test.ts b/tests/unit/runtime/timeline-rate-limit.test.ts index a6ce06a33..596221ae4 100644 --- a/tests/unit/runtime/timeline-rate-limit.test.ts +++ b/tests/unit/runtime/timeline-rate-limit.test.ts @@ -5,6 +5,53 @@ import * as codec from '../../../packages/kit/src/codec' afterEach(() => vi.useRealTimers()) +it('names component events before component registration', async () => { + const runtime = createDevtoolsRuntime() + try { + const fixture = createComponentTreeFixture(2) + runtime.dispatch({ + type: 'app:init', + app: fixture.app, + version: '3.5.0', + vueTypes: {}, + time: 1, + }) + const instance = fixture.instances[1]! + expect(runtime.registry.getComponentId(instance)).toBeUndefined() + const events = vi.fn() + runtime.subscribe('timeline:eventAdded', events) + runtime.dispatch({ + type: 'component:emit', + appId: 'app:0', + instance, + event: 'update', + args: [], + time: 2, + }) + await runtime.scheduler.flush() + expect(events).toHaveBeenCalledExactlyOnceWith( + expect.objectContaining({ + layerId: 'component-event', + title: 'update', + subtitle: 'by FixtureComponent1', + data: expect.objectContaining({ + preview: expect.arrayContaining([ + expect.objectContaining({ + key: 'component', + value: expect.objectContaining({ + kind: 'custom', + display: 'FixtureComponent1', + }), + }), + ]), + }), + }), + ) + } finally { + runtime.dispose() + } +}) + it('pairs performance events across component registration', async () => { const runtime = createDevtoolsRuntime() try { @@ -17,6 +64,7 @@ it('pairs performance events across component registration', async () => { time: 1, }) const instance = fixture.instances[1]! + expect(runtime.registry.getComponentId(instance)).toBeUndefined() const events = vi.fn() runtime.subscribe('timeline:eventAdded', events) runtime.dispatch({ @@ -39,6 +87,14 @@ it('pairs performance events across component registration', async () => { await runtime.scheduler.flush() expect(events).toHaveBeenCalledTimes(2) expect(events.mock.calls[1]![0].groupId).toBe(events.mock.calls[0]![0].groupId) + for (const [event] of events.mock.calls) { + expect(event.title).toBe('FixtureComponent1') + expect(event.data).toMatchObject({ + preview: expect.arrayContaining([ + { key: 'component', value: { kind: 'string', value: 'FixtureComponent1' } }, + ]), + }) + } } finally { runtime.dispose() }