diff --git a/packages/process-explorer-worker/package.json b/packages/process-explorer-worker/package.json index 188186e..d5cdbe3 100644 --- a/packages/process-explorer-worker/package.json +++ b/packages/process-explorer-worker/package.json @@ -33,6 +33,14 @@ "testMatch": [ "**/test/**" ], + "testPathIgnorePatterns": [ + "/node_modules/", + "/test/fixtures/" + ], + "coveragePathIgnorePatterns": [ + "/node_modules/", + "/test/fixtures/" + ], "collectCoverage": true, "coverageThreshold": { "global": { diff --git a/packages/process-explorer-worker/test/ApplyRender.test.ts b/packages/process-explorer-worker/test/ApplyRender.test.ts index 23f2038..2519ad9 100644 --- a/packages/process-explorer-worker/test/ApplyRender.test.ts +++ b/packages/process-explorer-worker/test/ApplyRender.test.ts @@ -1,26 +1,27 @@ import { expect, test } from '@jest/globals' import { ViewletCommand } from '@lvce-editor/constants' import * as ApplyRender from '../src/parts/ApplyRender/ApplyRender.ts' -import { createDefaultState } from '../src/parts/CreateDefaultState/CreateDefaultState.ts' import * as DiffType from '../src/parts/DiffType/DiffType.ts' +import { createProcessState } from './fixtures/ProcessExplorerFixtures.ts' -test('applyRender - filters empty render commands', () => { - const state = createDefaultState() - - expect(ApplyRender.applyRender(state, state, [DiffType.RenderFocus])).toEqual( - [], - ) -}) - -test('applyRender - returns render commands', () => { - const oldState = createDefaultState() - const newState = { - ...oldState, +test('applyRender ignores empty render results', () => { + const state = createProcessState({ focused: true, focusedIndex: 0, - } + }) + const commands = ApplyRender.applyRender(state, state, [DiffType.RenderFocus]) + expect(commands).toEqual([]) +}) - expect( - ApplyRender.applyRender(oldState, newState, [DiffType.RenderFocus]), - ).toEqual([[ViewletCommand.FocusSelector, '[data-index="0"]']]) +test('applyRender returns non-empty render results', () => { + const oldState = createProcessState() + const newState = createProcessState({ + initial: false, + }) + const commands = ApplyRender.applyRender(oldState, newState, [ + DiffType.RenderFocus, + DiffType.RenderItems, + ]) + expect(commands).toHaveLength(1) + expect(commands[0][0]).toBe(ViewletCommand.SetDom2) }) diff --git a/packages/process-explorer-worker/test/CollapseAll.test.ts b/packages/process-explorer-worker/test/CollapseAll.test.ts new file mode 100644 index 0000000..2e5211c --- /dev/null +++ b/packages/process-explorer-worker/test/CollapseAll.test.ts @@ -0,0 +1,27 @@ +import { expect, test } from '@jest/globals' +import * as CollapseAll from '../src/parts/CollapseAll/CollapseAll.ts' +import { createDefaultState } from '../src/parts/CreateDefaultState/CreateDefaultState.ts' +import { + createProcessState, + processes, +} from './fixtures/ProcessExplorerFixtures.ts' + +test('collapseAll collapses every parent process', () => { + const state = createProcessState() + const result = CollapseAll.collapseAll(state) + expect(result.collapsedPids).toEqual([1, 2]) + expect(result.focusedIndex).toBe(0) + expect(result.visibleProcesses.map((process) => process.pid)).toEqual([1]) +}) + +test('collapseAll focuses nothing when no process is visible', () => { + const state = { + ...createDefaultState(), + processes, + rootPid: 99, + } + const result = CollapseAll.collapseAll(state) + expect(result.collapsedPids).toEqual([1, 2]) + expect(result.focusedIndex).toBe(-1) + expect(result.visibleProcesses).toEqual([]) +}) diff --git a/packages/process-explorer-worker/test/Create.test.ts b/packages/process-explorer-worker/test/Create.test.ts index 8c76ef9..d8a8462 100644 --- a/packages/process-explorer-worker/test/Create.test.ts +++ b/packages/process-explorer-worker/test/Create.test.ts @@ -19,28 +19,9 @@ test('create', () => { expect(ProcessExplorerStates.get(7).newState).toBe(state) }) -test('create - defaults and include frontend memory usage', () => { +test('create uses default asset dir', () => { ProcessExplorerStates.clear() - const state = create( - 8, - '', - 1, - 2, - 300, - 400, - { includeFrontendMemoryUsage: true }, - 5, - ) - expect(state).toMatchObject({ - assetDir: '', - includeFrontendMemoryUsage: true, - platform: 0, - }) - expect(ProcessExplorerStates.get(8).newState).toBe(state) -}) - -test('create - missing args', () => { - ProcessExplorerStates.clear() - const state = create(9, '', 1, 2, 300, 400, undefined, 5) - expect(state.includeFrontendMemoryUsage).toBe(false) + const state = create(8, '', 1, 2, 300, 400, [], 5) + expect(state.assetDir).toBe('') + expect(state.uid).toBe(8) }) diff --git a/packages/process-explorer-worker/test/FocusFirst.test.ts b/packages/process-explorer-worker/test/FocusFirst.test.ts new file mode 100644 index 0000000..866eb3d --- /dev/null +++ b/packages/process-explorer-worker/test/FocusFirst.test.ts @@ -0,0 +1,17 @@ +import { expect, test } from '@jest/globals' +import * as FocusFirst from '../src/parts/FocusFirst/FocusFirst.ts' +import { createProcessState } from './fixtures/ProcessExplorerFixtures.ts' + +test('focusFirst focuses first visible process', () => { + const state = createProcessState({ + focusedIndex: 2, + }) + expect(FocusFirst.focusFirst(state).focusedIndex).toBe(0) +}) + +test('focusFirst returns state for empty visible processes', () => { + const state = createProcessState({ + visibleProcesses: [], + }) + expect(FocusFirst.focusFirst(state)).toBe(state) +}) diff --git a/packages/process-explorer-worker/test/FocusIndex.test.ts b/packages/process-explorer-worker/test/FocusIndex.test.ts new file mode 100644 index 0000000..f44184d --- /dev/null +++ b/packages/process-explorer-worker/test/FocusIndex.test.ts @@ -0,0 +1,25 @@ +import { expect, test } from '@jest/globals' +import * as FocusIndex from '../src/parts/FocusIndex/FocusIndex.ts' +import { createProcessState } from './fixtures/ProcessExplorerFixtures.ts' + +test('focusIndex focuses valid index', () => { + const state = createProcessState() + expect(FocusIndex.focusIndex(state, 1)).toMatchObject({ + focusedIndex: 1, + }) +}) + +test('focusIndex allows -1', () => { + const state = createProcessState({ + focusedIndex: 1, + }) + expect(FocusIndex.focusIndex(state, -1).focusedIndex).toBe(-1) +}) + +test('focusIndex ignores invalid indexes', () => { + const state = createProcessState() + expect(FocusIndex.focusIndex(state, -2)).toBe(state) + expect(FocusIndex.focusIndex(state, state.visibleProcesses.length)).toBe( + state, + ) +}) diff --git a/packages/process-explorer-worker/test/FocusLast.test.ts b/packages/process-explorer-worker/test/FocusLast.test.ts new file mode 100644 index 0000000..5b0a7ce --- /dev/null +++ b/packages/process-explorer-worker/test/FocusLast.test.ts @@ -0,0 +1,15 @@ +import { expect, test } from '@jest/globals' +import * as FocusLast from '../src/parts/FocusLast/FocusLast.ts' +import { createProcessState } from './fixtures/ProcessExplorerFixtures.ts' + +test('focusLast focuses last visible process', () => { + const state = createProcessState() + expect(FocusLast.focusLast(state).focusedIndex).toBe(2) +}) + +test('focusLast returns state for empty visible processes', () => { + const state = createProcessState({ + visibleProcesses: [], + }) + expect(FocusLast.focusLast(state)).toBe(state) +}) diff --git a/packages/process-explorer-worker/test/FocusPrevious.test.ts b/packages/process-explorer-worker/test/FocusPrevious.test.ts index 931ee70..a3a693e 100644 --- a/packages/process-explorer-worker/test/FocusPrevious.test.ts +++ b/packages/process-explorer-worker/test/FocusPrevious.test.ts @@ -1,44 +1,30 @@ import { expect, test } from '@jest/globals' -import { createDefaultState } from '../src/parts/CreateDefaultState/CreateDefaultState.ts' import * as FocusPrevious from '../src/parts/FocusPrevious/FocusPrevious.ts' -import * as GetVisibleProcesses from '../src/parts/GetVisibleProcesses/GetVisibleProcesses.ts' - -const processes = [ - { - cmd: 'main', - memory: 1, - name: 'main', - pid: 1, - ppid: 0, - }, - { - cmd: 'node child.js', - memory: 1500, - name: 'child', - pid: 2, - ppid: 1, - }, - { - cmd: 'leaf', - memory: 2_500_000, - name: 'leaf', - pid: 3, - ppid: 2, - }, - { - cmd: 'orphan', - memory: 1, - name: 'orphan', - pid: 4, - ppid: 999, - }, -] +import { createProcessState } from './fixtures/ProcessExplorerFixtures.ts' test('focusPrevious', () => { - const state = { - ...createDefaultState(), + const state = createProcessState({ focusedIndex: 1, - visibleProcesses: GetVisibleProcesses.getVisibleProcesses(processes, [], 1), - } + }) expect(FocusPrevious.focusPrevious(state).focusedIndex).toBe(0) }) + +test('focusPrevious focuses last item from -1', () => { + const state = createProcessState({ + focusedIndex: -1, + }) + expect(FocusPrevious.focusPrevious(state).focusedIndex).toBe(2) +}) + +test('focusPrevious returns state at beginning or empty list', () => { + const state = createProcessState({ + focusedIndex: 0, + }) + expect(FocusPrevious.focusPrevious(state)).toBe(state) + + const emptyState = createProcessState({ + focusedIndex: -1, + visibleProcesses: [], + }) + expect(FocusPrevious.focusPrevious(emptyState)).toBe(emptyState) +}) diff --git a/packages/process-explorer-worker/test/GetRenderer.test.ts b/packages/process-explorer-worker/test/GetRenderer.test.ts index 7db3b9b..82030b6 100644 --- a/packages/process-explorer-worker/test/GetRenderer.test.ts +++ b/packages/process-explorer-worker/test/GetRenderer.test.ts @@ -3,24 +3,20 @@ import * as DiffType from '../src/parts/DiffType/DiffType.ts' import * as GetRenderer from '../src/parts/GetRenderer/GetRenderer.ts' import * as RenderFocus from '../src/parts/RenderFocus/RenderFocus.ts' import * as RenderFocusContext from '../src/parts/RenderFocusContext/RenderFocusContext.ts' -import { renderIncremental } from '../src/parts/RenderIncremental/RenderIncremental.ts' import * as RenderItems from '../src/parts/RenderItems/RenderItems.ts' -test('getRenderer', () => { +test('getRenderer returns renderer for diff type', () => { expect(GetRenderer.getRenderer(DiffType.RenderFocus)).toBe( RenderFocus.renderFocus, ) expect(GetRenderer.getRenderer(DiffType.RenderFocusContext)).toBe( RenderFocusContext.renderFocusContext, ) - expect(GetRenderer.getRenderer(DiffType.RenderIncremental)).toBe( - renderIncremental, - ) expect(GetRenderer.getRenderer(DiffType.RenderItems)).toBe( RenderItems.renderItems, ) }) -test('getRenderer - unknown renderer', () => { +test('getRenderer throws for unknown diff type', () => { expect(() => GetRenderer.getRenderer(999)).toThrow('unknown renderer 999') }) diff --git a/packages/process-explorer-worker/test/GetVisibleProcesses.test.ts b/packages/process-explorer-worker/test/GetVisibleProcesses.test.ts index 8320818..576f866 100644 --- a/packages/process-explorer-worker/test/GetVisibleProcesses.test.ts +++ b/packages/process-explorer-worker/test/GetVisibleProcesses.test.ts @@ -51,12 +51,7 @@ test('getVisibleProcesses', () => { }) }) -test('getVisibleProcesses - uses first process when root pid is missing', () => { +test('getVisibleProcesses uses first process when root pid is zero', () => { const visible = GetVisibleProcesses.getVisibleProcesses(processes, [], 0) - expect(visible.map((process) => process.pid)).toEqual([1, 2, 3]) }) - -test('getVisibleProcesses - missing root process', () => { - expect(GetVisibleProcesses.getVisibleProcesses(processes, [], 99)).toEqual([]) -}) diff --git a/packages/process-explorer-worker/test/HandleArrowLeft.test.ts b/packages/process-explorer-worker/test/HandleArrowLeft.test.ts index f3a8d55..ed80815 100644 --- a/packages/process-explorer-worker/test/HandleArrowLeft.test.ts +++ b/packages/process-explorer-worker/test/HandleArrowLeft.test.ts @@ -1,88 +1,43 @@ import { expect, test } from '@jest/globals' -import { createDefaultState } from '../src/parts/CreateDefaultState/CreateDefaultState.ts' -import * as GetVisibleProcesses from '../src/parts/GetVisibleProcesses/GetVisibleProcesses.ts' import * as HandleArrowLeft from '../src/parts/HandleArrowLeft/HandleArrowLeft.ts' - -const processes = [ - { - cmd: 'main', - memory: 1, - name: 'main', - pid: 1, - ppid: 0, - }, - { - cmd: 'node child.js', - memory: 1500, - name: 'child', - pid: 2, - ppid: 1, - }, - { - cmd: 'leaf', - memory: 2_500_000, - name: 'leaf', - pid: 3, - ppid: 2, - }, - { - cmd: 'orphan', - memory: 1, - name: 'orphan', - pid: 4, - ppid: 999, - }, -] +import { createProcessState } from './fixtures/ProcessExplorerFixtures.ts' test('handleArrowLeft collapses expanded process', () => { - const state = { - ...createDefaultState(), + const state = createProcessState({ focusedIndex: 1, - processes, - rootPid: 1, - visibleProcesses: GetVisibleProcesses.getVisibleProcesses(processes, [], 1), - } + }) const result = HandleArrowLeft.handleArrowLeft(state) expect(result.collapsedPids).toEqual([2]) expect(result.visibleProcesses.map((process) => process.pid)).toEqual([1, 2]) }) test('handleArrowLeft focuses parent for leaf', () => { - const state = { - ...createDefaultState(), + const state = createProcessState({ focusedIndex: 2, - processes, - rootPid: 1, - visibleProcesses: GetVisibleProcesses.getVisibleProcesses(processes, [], 1), - } + }) expect(HandleArrowLeft.handleArrowLeft(state).focusedIndex).toBe(1) }) -test('handleArrowLeft - missing focused process', () => { - const state = { - ...createDefaultState(), +test('handleArrowLeft returns state without focused process', () => { + const state = createProcessState({ focusedIndex: 99, - processes, - rootPid: 1, - visibleProcesses: GetVisibleProcesses.getVisibleProcesses(processes, [], 1), - } - + }) expect(HandleArrowLeft.handleArrowLeft(state)).toBe(state) }) -test('handleArrowLeft - no parent', () => { - const singleProcess = [processes[0]] - const state = { - ...createDefaultState(), +test('handleArrowLeft returns state when focused process has no parent', () => { + const processes = [ + { + cmd: 'main', + memory: 1, + name: 'main', + pid: 1, + ppid: 0, + }, + ] + const state = createProcessState({ focusedIndex: 0, - processes: singleProcess, - rootPid: 1, - visibleProcesses: GetVisibleProcesses.getVisibleProcesses( - singleProcess, - [], - 1, - ), - } - + processes, + }) expect(HandleArrowLeft.handleArrowLeft(state)).toBe(state) }) diff --git a/packages/process-explorer-worker/test/HandleArrowRight.test.ts b/packages/process-explorer-worker/test/HandleArrowRight.test.ts index cfa1f7d..8fd9cd4 100644 --- a/packages/process-explorer-worker/test/HandleArrowRight.test.ts +++ b/packages/process-explorer-worker/test/HandleArrowRight.test.ts @@ -1,52 +1,12 @@ import { expect, test } from '@jest/globals' -import { createDefaultState } from '../src/parts/CreateDefaultState/CreateDefaultState.ts' -import * as GetVisibleProcesses from '../src/parts/GetVisibleProcesses/GetVisibleProcesses.ts' import * as HandleArrowRight from '../src/parts/HandleArrowRight/HandleArrowRight.ts' - -const processes = [ - { - cmd: 'main', - memory: 1, - name: 'main', - pid: 1, - ppid: 0, - }, - { - cmd: 'node child.js', - memory: 1500, - name: 'child', - pid: 2, - ppid: 1, - }, - { - cmd: 'leaf', - memory: 2_500_000, - name: 'leaf', - pid: 3, - ppid: 2, - }, - { - cmd: 'orphan', - memory: 1, - name: 'orphan', - pid: 4, - ppid: 999, - }, -] +import { createProcessState } from './fixtures/ProcessExplorerFixtures.ts' test('handleArrowRight expands collapsed process', () => { - const state = { - ...createDefaultState(), + const state = createProcessState({ collapsedPids: [2], focusedIndex: 1, - processes, - rootPid: 1, - visibleProcesses: GetVisibleProcesses.getVisibleProcesses( - processes, - [2], - 1, - ), - } + }) const result = HandleArrowRight.handleArrowRight(state) expect(result.collapsedPids).toEqual([]) expect(result.visibleProcesses.map((process) => process.pid)).toEqual([ @@ -55,36 +15,22 @@ test('handleArrowRight expands collapsed process', () => { }) test('handleArrowRight focuses first child for expanded process', () => { - const state = { - ...createDefaultState(), + const state = createProcessState({ focusedIndex: 0, - processes, - rootPid: 1, - visibleProcesses: GetVisibleProcesses.getVisibleProcesses(processes, [], 1), - } + }) expect(HandleArrowRight.handleArrowRight(state).focusedIndex).toBe(1) }) -test('handleArrowRight - missing focused process', () => { - const state = { - ...createDefaultState(), +test('handleArrowRight returns state without focused process', () => { + const state = createProcessState({ focusedIndex: 99, - processes, - rootPid: 1, - visibleProcesses: GetVisibleProcesses.getVisibleProcesses(processes, [], 1), - } - + }) expect(HandleArrowRight.handleArrowRight(state)).toBe(state) }) -test('handleArrowRight - leaf process', () => { - const state = { - ...createDefaultState(), +test('handleArrowRight returns state for leaf process', () => { + const state = createProcessState({ focusedIndex: 2, - processes, - rootPid: 1, - visibleProcesses: GetVisibleProcesses.getVisibleProcesses(processes, [], 1), - } - + }) expect(HandleArrowRight.handleArrowRight(state)).toBe(state) }) diff --git a/packages/process-explorer-worker/test/HandleBlur.test.ts b/packages/process-explorer-worker/test/HandleBlur.test.ts new file mode 100644 index 0000000..1a9c202 --- /dev/null +++ b/packages/process-explorer-worker/test/HandleBlur.test.ts @@ -0,0 +1,12 @@ +import { expect, test } from '@jest/globals' +import * as HandleBlur from '../src/parts/HandleBlur/HandleBlur.ts' +import { createProcessState } from './fixtures/ProcessExplorerFixtures.ts' + +test('handleBlur clears focused state', () => { + const state = createProcessState({ + focused: true, + }) + expect(HandleBlur.handleBlur(state)).toMatchObject({ + focused: false, + }) +}) diff --git a/packages/process-explorer-worker/test/HandleClickAt.test.ts b/packages/process-explorer-worker/test/HandleClickAt.test.ts new file mode 100644 index 0000000..89291f1 --- /dev/null +++ b/packages/process-explorer-worker/test/HandleClickAt.test.ts @@ -0,0 +1,13 @@ +import { expect, test } from '@jest/globals' +import * as HandleClickAt from '../src/parts/HandleClickAt/HandleClickAt.ts' +import { createProcessState } from './fixtures/ProcessExplorerFixtures.ts' + +test('handleClickAt focuses clicked index', () => { + const state = createProcessState() + expect(HandleClickAt.handleClickAt(state, 1).focusedIndex).toBe(1) +}) + +test('handleClickAt ignores invalid clicked index', () => { + const state = createProcessState() + expect(HandleClickAt.handleClickAt(state, 10)).toBe(state) +}) diff --git a/packages/process-explorer-worker/test/HandleContextMenu.test.ts b/packages/process-explorer-worker/test/HandleContextMenu.test.ts index 17ad086..86308c1 100644 --- a/packages/process-explorer-worker/test/HandleContextMenu.test.ts +++ b/packages/process-explorer-worker/test/HandleContextMenu.test.ts @@ -4,37 +4,7 @@ import { createDefaultState } from '../src/parts/CreateDefaultState/CreateDefaul import * as GetVisibleProcesses from '../src/parts/GetVisibleProcesses/GetVisibleProcesses.ts' import * as HandleContextMenu from '../src/parts/HandleContextMenu/HandleContextMenu.ts' import * as MenuEntryId from '../src/parts/MenuEntryId/MenuEntryId.ts' - -const processes = [ - { - cmd: 'main', - memory: 1, - name: 'main', - pid: 1, - ppid: 0, - }, - { - cmd: 'node child.js', - memory: 1500, - name: 'child', - pid: 2, - ppid: 1, - }, - { - cmd: 'leaf', - memory: 2_500_000, - name: 'leaf', - pid: 3, - ppid: 2, - }, - { - cmd: 'orphan', - memory: 1, - name: 'orphan', - pid: 4, - ppid: 999, - }, -] +import { processes } from './fixtures/ProcessExplorerFixtures.ts' test('handleContextMenu', async () => { using mockRpc = RendererWorker.registerMockRpc({ @@ -89,7 +59,6 @@ test('handleContextMenu - defaults', async () => { visibleProcesses: GetVisibleProcesses.getVisibleProcesses(processes, [], 1), } const result = await HandleContextMenu.handleContextMenu(state) - expect(result).toEqual({ ...state, focused: false, diff --git a/packages/process-explorer-worker/test/HandleDoubleClick.test.ts b/packages/process-explorer-worker/test/HandleDoubleClick.test.ts index decc59b..3490dd6 100644 --- a/packages/process-explorer-worker/test/HandleDoubleClick.test.ts +++ b/packages/process-explorer-worker/test/HandleDoubleClick.test.ts @@ -47,14 +47,13 @@ test('handleDoubleClick toggles process', () => { ]) }) -test('handleDoubleClick - default index', () => { +test('handleDoubleClick uses focused index by default', () => { const state = { ...createDefaultState(), - focusedIndex: 0, + focusedIndex: 1, processes, rootPid: 1, visibleProcesses: GetVisibleProcesses.getVisibleProcesses(processes, [], 1), } - - expect(HandleDoubleClick.handleDoubleClick(state).collapsedPids).toEqual([1]) + expect(HandleDoubleClick.handleDoubleClick(state).collapsedPids).toEqual([2]) }) diff --git a/packages/process-explorer-worker/test/HandleFocus.test.ts b/packages/process-explorer-worker/test/HandleFocus.test.ts new file mode 100644 index 0000000..d7dd085 --- /dev/null +++ b/packages/process-explorer-worker/test/HandleFocus.test.ts @@ -0,0 +1,12 @@ +import { expect, test } from '@jest/globals' +import * as HandleFocus from '../src/parts/HandleFocus/HandleFocus.ts' +import { createProcessState } from './fixtures/ProcessExplorerFixtures.ts' + +test('handleFocus sets focused state', () => { + const state = createProcessState({ + focused: false, + }) + expect(HandleFocus.handleFocus(state)).toMatchObject({ + focused: true, + }) +}) diff --git a/packages/process-explorer-worker/test/LoadContent.test.ts b/packages/process-explorer-worker/test/LoadContent.test.ts index 97c90a7..a3bd652 100644 --- a/packages/process-explorer-worker/test/LoadContent.test.ts +++ b/packages/process-explorer-worker/test/LoadContent.test.ts @@ -1,109 +1,40 @@ -import { afterEach, expect, jest, test } from '@jest/globals' +import { expect, jest, test } from '@jest/globals' import { createMockRpc } from '@lvce-editor/rpc' -import { ErrorWorker, RendererWorker } from '@lvce-editor/rpc-registry' -import * as AutoRefresh from '../src/parts/AutoRefresh/AutoRefresh.ts' import { createDefaultState } from '../src/parts/CreateDefaultState/CreateDefaultState.ts' import * as LoadContent from '../src/parts/LoadContent/LoadContent.ts' -import * as ProcessExplorerModule from '../src/parts/ProcessExplorer/ProcessExplorer.ts' -import * as ProcessExplorerStates from '../src/parts/ProcessExplorerStates/ProcessExplorerStates.ts' +import { processes } from './fixtures/ProcessExplorerFixtures.ts' -afterEach(() => { - AutoRefresh.clear() - ErrorWorker.set(createMockRpc({ commandMap: {} })) - ProcessExplorerModule.clear() - ProcessExplorerStates.clear() - jest.useRealTimers() -}) - -test('loadContent - refreshes and starts auto refresh', async () => { - jest.useFakeTimers() - const update = jest.fn() - using _mockRendererRpc = RendererWorker.registerMockRpc({ - 'ProcessExplorer.update': update, - }) - const listProcessesWithMemoryUsage = jest.fn( - (_rootPid: number, _includeElectronData: boolean) => [ - { - cmd: 'main', - memory: 1, - name: 'main', - pid: 1, - ppid: 0, - }, - ], - ) - const getMainProcessId = jest.fn(() => 1) - ProcessExplorerModule.set( - createMockRpc({ - commandMap: { - 'ListProcessesWithMemoryUsage.listProcessesWithMemoryUsage': - listProcessesWithMemoryUsage, - 'ProcessId.getMainProcessId': getMainProcessId, - }, - }), - ) - const state = { - ...createDefaultState(), - uid: 7, - } - ProcessExplorerStates.set(7, state, state) +const ProcessExplorerModule = + await import('../src/parts/ProcessExplorer/ProcessExplorer.ts') - const result = await LoadContent.loadContent(state) - await jest.advanceTimersByTimeAsync(1000) +interface DisposableMockRpc { + [Symbol.dispose](): void +} - expect(getMainProcessId).toHaveBeenCalledTimes(1) - expect(listProcessesWithMemoryUsage).toHaveBeenCalledWith(1, false) - expect(update).toHaveBeenCalledTimes(1) - expect(result.error).toBeUndefined() - expect(result.state).toMatchObject({ - initial: false, - rootPid: 1, - }) -}) - -test('loadContent - does not start auto refresh after load error', async () => { - jest.useFakeTimers() - const update = jest.fn() - using _mockRendererRpc = RendererWorker.registerMockRpc({ - 'ProcessExplorer.update': update, - }) - const prepare = jest.fn((_error: unknown) => ({ - codeFrame: '1 | throw new Error()', - message: 'Pretty no pid', - stack: 'Pretty stack', - })) - ErrorWorker.set( - createMockRpc({ - commandMap: { - 'Errors.prepare': prepare, - }, - }), - ) - ProcessExplorerModule.set( - createMockRpc({ - commandMap: { - 'ProcessId.getMainProcessId': jest.fn(() => { - throw new Error('no pid') - }), - }, - }), - ) - const state = { - ...createDefaultState(), - uid: 7, +const registerProcessExplorerMock = ( + commandMap: Record, +): DisposableMockRpc => { + ProcessExplorerModule.set(createMockRpc({ commandMap })) + return { + [Symbol.dispose](): void { + ProcessExplorerModule.clear() + }, } - ProcessExplorerStates.set(7, state, state) +} - const result = await LoadContent.loadContent(state) - await jest.advanceTimersByTimeAsync(1000) - - expect(prepare).toHaveBeenCalledTimes(1) - expect(update).not.toHaveBeenCalled() +test('loadContent refreshes process explorer state', async () => { + using _mockRpc = registerProcessExplorerMock({ + 'ListProcessesWithMemoryUsage.listProcessesWithMemoryUsage': jest.fn( + () => processes, + ), + 'ProcessId.getMainProcessId': jest.fn(() => 1), + }) + const result = await LoadContent.loadContent(createDefaultState()) expect(result.error).toBeUndefined() expect(result.state).toMatchObject({ - errorCodeFrame: '1 | throw new Error()', - errorMessage: 'Pretty no pid', - errorStack: 'Pretty stack', + errorMessage: '', + focusedIndex: 0, initial: false, + rootPid: 1, }) }) diff --git a/packages/process-explorer-worker/test/Refresh.test.ts b/packages/process-explorer-worker/test/Refresh.test.ts index 9afafb8..648d402 100644 --- a/packages/process-explorer-worker/test/Refresh.test.ts +++ b/packages/process-explorer-worker/test/Refresh.test.ts @@ -2,6 +2,7 @@ import { afterEach, beforeEach, expect, jest, test } from '@jest/globals' import { PlatformType } from '@lvce-editor/constants' import { createMockRpc } from '@lvce-editor/rpc' import { ErrorWorker } from '@lvce-editor/rpc-registry' +import { processes } from './fixtures/ProcessExplorerFixtures.ts' const initializeProcessExplorer = jest.fn( async (..._args: readonly unknown[]) => {}, @@ -56,37 +57,6 @@ const registerProcessExplorerMock = ( } } -const processes = [ - { - cmd: 'main', - memory: 1, - name: 'main', - pid: 1, - ppid: 0, - }, - { - cmd: 'node child.js', - memory: 1500, - name: 'child', - pid: 2, - ppid: 1, - }, - { - cmd: 'leaf', - memory: 2_500_000, - name: 'leaf', - pid: 3, - ppid: 2, - }, - { - cmd: 'orphan', - memory: 1, - name: 'orphan', - pid: 4, - ppid: 999, - }, -] - beforeEach(() => { initializeProcessExplorer.mockClear() }) diff --git a/packages/process-explorer-worker/test/RenderFocus.test.ts b/packages/process-explorer-worker/test/RenderFocus.test.ts index 0218d76..8dd7ee1 100644 --- a/packages/process-explorer-worker/test/RenderFocus.test.ts +++ b/packages/process-explorer-worker/test/RenderFocus.test.ts @@ -1,60 +1,47 @@ import { expect, test } from '@jest/globals' import { ViewletCommand } from '@lvce-editor/constants' -import { createDefaultState } from '../src/parts/CreateDefaultState/CreateDefaultState.ts' import * as RenderFocus from '../src/parts/RenderFocus/RenderFocus.ts' +import { createProcessState } from './fixtures/ProcessExplorerFixtures.ts' -test('renderFocus - not focused', () => { - const oldState = createDefaultState() - const newState = { - ...oldState, - focused: false, +test('renderFocus returns no commands when not focused', () => { + const oldState = createProcessState({ focusedIndex: 0, - } - + }) + const newState = createProcessState({ + focused: false, + focusedIndex: 1, + }) expect(RenderFocus.renderFocus(oldState, newState)).toEqual([]) }) -test('renderFocus - focused index unchanged', () => { - const oldState = { - ...createDefaultState(), - focusedIndex: 1, - } - const newState = { - ...oldState, +test('renderFocus returns no commands when focused index is unchanged', () => { + const state = createProcessState({ focused: true, - } - - expect(RenderFocus.renderFocus(oldState, newState)).toEqual([]) + focusedIndex: 0, + }) + expect(RenderFocus.renderFocus(state, state)).toEqual([]) }) -test('renderFocus - focus table', () => { - const oldState = { - ...createDefaultState(), - focusedIndex: 0, - } - const newState = { - ...oldState, - focused: true, +test('renderFocus focuses table for negative index', () => { + const oldState = createProcessState({ + focusedIndex: 1, + }) + const newState = createProcessState({ focusedIndex: -1, - } - + }) expect(RenderFocus.renderFocus(oldState, newState)).toEqual([ ViewletCommand.FocusSelector, '.ProcessExplorerTable', ]) }) -test('renderFocus - focus row', () => { - const oldState = { - ...createDefaultState(), - focusedIndex: -1, - } - const newState = { - ...oldState, - focused: true, +test('renderFocus focuses row selector for valid index', () => { + const oldState = createProcessState({ + focusedIndex: 0, + }) + const newState = createProcessState({ focusedIndex: 2, - } - + }) expect(RenderFocus.renderFocus(oldState, newState)).toEqual([ ViewletCommand.FocusSelector, '[data-index="2"]', diff --git a/packages/process-explorer-worker/test/RenderFocusContext.test.ts b/packages/process-explorer-worker/test/RenderFocusContext.test.ts index 8ed272d..e64eb41 100644 --- a/packages/process-explorer-worker/test/RenderFocusContext.test.ts +++ b/packages/process-explorer-worker/test/RenderFocusContext.test.ts @@ -1,49 +1,43 @@ import { expect, test } from '@jest/globals' import { ViewletCommand, WhenExpression } from '@lvce-editor/constants' -import { createDefaultState } from '../src/parts/CreateDefaultState/CreateDefaultState.ts' import * as RenderFocusContext from '../src/parts/RenderFocusContext/RenderFocusContext.ts' +import { createProcessState } from './fixtures/ProcessExplorerFixtures.ts' -test('renderFocusContext - unchanged', () => { - const oldState = createDefaultState() - const newState = { - ...oldState, - } - - expect(RenderFocusContext.renderFocusContext(oldState, newState)).toEqual([]) +test('renderFocusContext returns no commands when focus is unchanged', () => { + const state = createProcessState({ + focused: true, + }) + expect(RenderFocusContext.renderFocusContext(state, state)).toEqual([]) }) -test('renderFocusContext - focused', () => { - const oldState = { - ...createDefaultState(), +test('renderFocusContext sets explorer focus context', () => { + const oldState = createProcessState({ focused: false, - } - const newState = { - ...oldState, + uid: 7, + }) + const newState = createProcessState({ focused: true, - uid: 9, - } - + uid: 7, + }) expect(RenderFocusContext.renderFocusContext(oldState, newState)).toEqual([ ViewletCommand.SetFocusContext, - 9, + 7, WhenExpression.FocusExplorer, ]) }) -test('renderFocusContext - blurred', () => { - const oldState = { - ...createDefaultState(), +test('renderFocusContext clears explorer focus context', () => { + const oldState = createProcessState({ focused: true, - } - const newState = { - ...oldState, + uid: 7, + }) + const newState = createProcessState({ focused: false, - uid: 9, - } - + uid: 7, + }) expect(RenderFocusContext.renderFocusContext(oldState, newState)).toEqual([ ViewletCommand.SetFocusContext, - 9, + 7, WhenExpression.Empty, ]) }) diff --git a/packages/process-explorer-worker/test/RenderItems.test.ts b/packages/process-explorer-worker/test/RenderItems.test.ts index 1fea87d..a748026 100644 --- a/packages/process-explorer-worker/test/RenderItems.test.ts +++ b/packages/process-explorer-worker/test/RenderItems.test.ts @@ -1,48 +1,17 @@ import { expect, test } from '@jest/globals' import { ViewletCommand } from '@lvce-editor/constants' -import { VirtualDomElements } from '@lvce-editor/virtual-dom-worker' import { createDefaultState } from '../src/parts/CreateDefaultState/CreateDefaultState.ts' -import * as GetVisibleProcesses from '../src/parts/GetVisibleProcesses/GetVisibleProcesses.ts' import * as RenderItems from '../src/parts/RenderItems/RenderItems.ts' - -const processes = [ - { - cmd: 'main', - memory: 1, - name: 'main', - pid: 1, - ppid: 0, - }, - { - cmd: 'node child.js', - memory: 1500, - name: 'child', - pid: 2, - ppid: 1, - }, - { - cmd: 'leaf', - memory: 2_500_000, - name: 'leaf', - pid: 3, - ppid: 2, - }, - { - cmd: 'orphan', - memory: 1, - name: 'orphan', - pid: 4, - ppid: 999, - }, -] +import { + createProcessState, + createVisibleProcesses, +} from './fixtures/ProcessExplorerFixtures.ts' test('renderItems - populated table', () => { - const state = { - ...createDefaultState(), + const state = createProcessState({ focusedIndex: 1, initial: false, - visibleProcesses: GetVisibleProcesses.getVisibleProcesses(processes, [], 1), - } + }) const result = RenderItems.renderItems(createDefaultState(), state) expect(result[0]).toBe(ViewletCommand.SetDom2) expect(result[2]).toContainEqual( @@ -70,19 +39,27 @@ test('renderItems - populated table', () => { title: 'node child.js', }), ) + expect(result[2]).toContainEqual( + expect.objectContaining({ + ariaLevel: 3, + title: 'leaf', + }), + ) + expect(result[2]).toContainEqual( + expect.objectContaining({ + className: 'ProcessExplorerCell ProcessExplorerNameCell', + paddingLeft: 'calc(3ch + 17px)', + }), + ) }) -test('renderItems - collapsed row', () => { - const state = { - ...createDefaultState(), +test('renderItems - collapsed row with fixture state', () => { + const state = createProcessState({ + collapsedPids: [2], focusedIndex: 1, initial: false, - visibleProcesses: GetVisibleProcesses.getVisibleProcesses( - processes, - [2], - 1, - ), - } + visibleProcesses: createVisibleProcesses([2]), + }) const result = RenderItems.renderItems(createDefaultState(), state) expect(result[2]).toContainEqual( @@ -107,73 +84,44 @@ test('renderItems - initial is empty', () => { ]) }) -test('renderItems - error only', () => { - const state = { - ...createDefaultState(), - errorCodeFrame: '1 | throw new Error()', - errorMessage: 'Pretty no pid', - errorStack: 'Pretty stack', +test('renderItems - error message', () => { + const state = createProcessState({ + errorMessage: 'boom', initial: false, - visibleProcesses: GetVisibleProcesses.getVisibleProcesses(processes, [], 1), - } + visibleProcesses: [], + }) const result = RenderItems.renderItems(createDefaultState(), state) - expect(result[0]).toBe(ViewletCommand.SetDom2) expect(result[2]).toContainEqual( expect.objectContaining({ + childCount: 1, className: 'ProcessExplorerError', - type: VirtualDomElements.Div, - }), - ) - expect(result[2]).toContainEqual( - expect.objectContaining({ - text: 'Pretty no pid', - type: VirtualDomElements.Text, - }), - ) - expect(result[2]).toContainEqual( - expect.objectContaining({ - text: '1 | throw new Error()', - type: VirtualDomElements.Text, - }), - ) - expect(result[2]).toContainEqual( - expect.objectContaining({ - text: 'Pretty stack', - type: VirtualDomElements.Text, }), ) expect(result[2]).toContainEqual( expect.objectContaining({ - childCount: 1, - type: VirtualDomElements.Pre, - }), - ) - expect(result[2]).not.toContainEqual( - expect.objectContaining({ - className: 'ProcessExplorerTable', + text: 'boom', }), ) }) -test('renderItems - error message only', () => { - const state = { - ...createDefaultState(), - errorMessage: 'Pretty no pid', +test('renderItems - collapsed row', () => { + const state = createProcessState({ + collapsedPids: [2], initial: false, - } + visibleProcesses: createVisibleProcesses([2]), + }) const result = RenderItems.renderItems(createDefaultState(), state) - expect(result[2]).toContainEqual( expect.objectContaining({ - childCount: 1, - className: 'ProcessExplorerError', - type: VirtualDomElements.Div, + ariaExpanded: false, + ariaLevel: 2, + title: 'node child.js', }), ) expect(result[2]).toContainEqual( expect.objectContaining({ - text: 'Pretty no pid', - type: VirtualDomElements.Text, + className: 'ProcessExplorerCell ProcessExplorerNameCell', + paddingLeft: '1.5ch', }), ) }) diff --git a/packages/process-explorer-worker/test/SendMessagePortToFileSystemWorker.test.ts b/packages/process-explorer-worker/test/SendMessagePortToFileSystemWorker.test.ts new file mode 100644 index 0000000..adad585 --- /dev/null +++ b/packages/process-explorer-worker/test/SendMessagePortToFileSystemWorker.test.ts @@ -0,0 +1,20 @@ +import { expect, jest, test } from '@jest/globals' +import { RendererWorker } from '@lvce-editor/rpc-registry' +import * as SendMessagePortToFileSystemWorker from '../src/parts/SendMessagePortToFileSystemWorker/SendMessagePortToFileSystemWorker.ts' + +test('sendMessagePortToFileSystemWorker forwards port to renderer worker', async () => { + const sendMessagePortToFileSystemWorker = jest.fn() + using _mockRpc = RendererWorker.registerMockRpc({ + 'SendMessagePortToExtensionHostWorker.sendMessagePortToFileSystemWorker': + sendMessagePortToFileSystemWorker, + }) + const port = {} + await SendMessagePortToFileSystemWorker.sendMessagePortToFileSystemWorker( + port, + ) + expect(sendMessagePortToFileSystemWorker).toHaveBeenCalledWith( + port, + 'FileSystem.handleMessagePort', + 0, + ) +}) diff --git a/packages/process-explorer-worker/test/ToggleIndex.test.ts b/packages/process-explorer-worker/test/ToggleIndex.test.ts new file mode 100644 index 0000000..9195edd --- /dev/null +++ b/packages/process-explorer-worker/test/ToggleIndex.test.ts @@ -0,0 +1,39 @@ +import { expect, test } from '@jest/globals' +import * as ToggleIndex from '../src/parts/ToggleIndex/ToggleIndex.ts' +import { createProcessState } from './fixtures/ProcessExplorerFixtures.ts' + +test('toggleIndex collapses expanded process', () => { + const state = createProcessState({ + focusedIndex: 1, + }) + const result = ToggleIndex.toggleIndex(state, 1) + expect(result.collapsedPids).toEqual([2]) + expect(result.visibleProcesses.map((process) => process.pid)).toEqual([1, 2]) +}) + +test('toggleIndex expands collapsed process', () => { + const state = createProcessState({ + collapsedPids: [2], + focusedIndex: 1, + }) + const result = ToggleIndex.toggleIndex(state, 1) + expect(result.collapsedPids).toEqual([]) + expect(result.visibleProcesses.map((process) => process.pid)).toEqual([ + 1, 2, 3, + ]) +}) + +test('toggleIndex returns state for invalid or leaf indexes', () => { + const state = createProcessState() + expect(ToggleIndex.toggleIndex(state, 10)).toBe(state) + expect(ToggleIndex.toggleIndex(state, 2)).toBe(state) +}) + +test('toggleIndex clamps focus when visible processes shrink', () => { + const state = createProcessState({ + focusedIndex: 2, + }) + const result = ToggleIndex.toggleIndex(state, 0) + expect(result.focusedIndex).toBe(0) + expect(result.visibleProcesses.map((process) => process.pid)).toEqual([1]) +}) diff --git a/packages/process-explorer-worker/test/fixtures/ProcessExplorerFixtures.ts b/packages/process-explorer-worker/test/fixtures/ProcessExplorerFixtures.ts new file mode 100644 index 0000000..a67b0f1 --- /dev/null +++ b/packages/process-explorer-worker/test/fixtures/ProcessExplorerFixtures.ts @@ -0,0 +1,59 @@ +import { createDefaultState } from '../../src/parts/CreateDefaultState/CreateDefaultState.ts' +import * as GetVisibleProcesses from '../../src/parts/GetVisibleProcesses/GetVisibleProcesses.ts' +import type { ProcessExplorerState } from '../../src/parts/ProcessExplorerState/ProcessExplorerState.ts' +import type { ProcessInfo } from '../../src/parts/ProcessInfo/ProcessInfo.ts' + +export const processes: readonly ProcessInfo[] = [ + { + cmd: 'main', + memory: 1, + name: 'main', + pid: 1, + ppid: 0, + }, + { + cmd: 'node child.js', + memory: 1500, + name: 'child', + pid: 2, + ppid: 1, + }, + { + cmd: 'leaf', + memory: 2_500_000, + name: 'leaf', + pid: 3, + ppid: 2, + }, + { + cmd: 'orphan', + memory: 1, + name: 'orphan', + pid: 4, + ppid: 999, + }, +] + +export const createVisibleProcesses = ( + collapsedPids: readonly number[] = [], + rootPid: number = 1, + items: readonly ProcessInfo[] = processes, +) => { + return GetVisibleProcesses.getVisibleProcesses(items, collapsedPids, rootPid) +} + +export const createProcessState = ( + overrides: Partial = {}, +): ProcessExplorerState => { + const collapsedPids = overrides.collapsedPids ?? [] + const rootPid = overrides.rootPid ?? 1 + const items = overrides.processes ?? processes + return { + ...createDefaultState(), + collapsedPids, + processes: items, + rootPid, + visibleProcesses: createVisibleProcesses(collapsedPids, rootPid, items), + ...overrides, + } +}