224 lines
6.3 KiB
TypeScript
224 lines
6.3 KiB
TypeScript
import React, { act } from 'react';
|
|
import { createRoot } from 'react-dom/client';
|
|
import { afterEach, describe, expect, it, vi } from 'vitest';
|
|
|
|
import { GraphProvisioningHud } from '@features/agent-graph/renderer/ui/GraphProvisioningHud';
|
|
|
|
const hoisted = vi.hoisted(() => ({
|
|
stepperProps: [] as { active?: boolean }[],
|
|
}));
|
|
|
|
const hookState = {
|
|
presentation: null as {
|
|
isActive: boolean;
|
|
isFailed: boolean;
|
|
hasMembersStillJoining: boolean;
|
|
failedSpawnCount: number;
|
|
compactTone: 'default' | 'warning' | 'error' | 'success';
|
|
compactTitle: string;
|
|
compactDetail?: string | null;
|
|
currentStepIndex: number;
|
|
progress: { runId: string };
|
|
} | null,
|
|
runInstanceKey: 'team:run-1:2026-04-13T10:00:00.000Z',
|
|
};
|
|
|
|
vi.mock('@renderer/components/team/useTeamProvisioningPresentation', () => ({
|
|
useTeamProvisioningPresentation: () => hookState,
|
|
}));
|
|
|
|
vi.mock('@renderer/components/ui/badge', () => ({
|
|
Badge: ({ children }: { children: React.ReactNode }) =>
|
|
React.createElement('span', null, children),
|
|
}));
|
|
|
|
vi.mock('@renderer/components/team/StepProgressBar', () => ({
|
|
StepProgressBar: (props: { active?: boolean }) => {
|
|
hoisted.stepperProps.push(props);
|
|
return React.createElement(
|
|
'div',
|
|
{
|
|
'data-testid': 'stepper',
|
|
'data-stepper-active': props.active ? 'true' : 'false',
|
|
},
|
|
'stepper'
|
|
);
|
|
},
|
|
}));
|
|
|
|
vi.mock('@renderer/components/team/TeamProvisioningPanel', () => ({
|
|
TeamProvisioningPanel: ({ defaultLogsOpen }: { defaultLogsOpen?: boolean }) =>
|
|
React.createElement(
|
|
'div',
|
|
{ 'data-testid': 'panel', 'data-default-logs-open': defaultLogsOpen ? 'true' : 'false' },
|
|
'provisioning-panel'
|
|
),
|
|
}));
|
|
|
|
describe('GraphProvisioningHud', () => {
|
|
afterEach(() => {
|
|
document.body.innerHTML = '';
|
|
hookState.presentation = null;
|
|
hookState.runInstanceKey = 'team:run-1:2026-04-13T10:00:00.000Z';
|
|
hoisted.stepperProps = [];
|
|
});
|
|
|
|
it('hides the graph launch hud once provisioning is ready', async () => {
|
|
vi.stubGlobal('IS_REACT_ACT_ENVIRONMENT', true);
|
|
hookState.presentation = {
|
|
isActive: false,
|
|
isFailed: false,
|
|
hasMembersStillJoining: false,
|
|
failedSpawnCount: 0,
|
|
compactTone: 'success',
|
|
compactTitle: 'Team launched',
|
|
compactDetail: 'All 3 teammates joined',
|
|
currentStepIndex: 4,
|
|
progress: { runId: 'run-1' },
|
|
};
|
|
|
|
const host = document.createElement('div');
|
|
document.body.appendChild(host);
|
|
const root = createRoot(host);
|
|
|
|
await act(async () => {
|
|
root.render(
|
|
React.createElement(GraphProvisioningHud, {
|
|
teamName: 'northstar-core',
|
|
})
|
|
);
|
|
await Promise.resolve();
|
|
});
|
|
|
|
expect(host.textContent).toBe('');
|
|
expect(host.querySelector('[data-testid="stepper"]')).toBeNull();
|
|
expect(document.body.textContent).not.toContain('provisioning-panel');
|
|
|
|
await act(async () => {
|
|
root.unmount();
|
|
await Promise.resolve();
|
|
});
|
|
});
|
|
|
|
it('opens launch details in a separate dialog when the stepper is clicked', async () => {
|
|
vi.stubGlobal('IS_REACT_ACT_ENVIRONMENT', true);
|
|
hookState.presentation = {
|
|
isActive: true,
|
|
isFailed: false,
|
|
hasMembersStillJoining: true,
|
|
failedSpawnCount: 0,
|
|
compactTone: 'default',
|
|
compactTitle: 'Launching team',
|
|
compactDetail: '1 teammate still joining',
|
|
currentStepIndex: 2,
|
|
progress: { runId: 'run-3' },
|
|
};
|
|
|
|
const host = document.createElement('div');
|
|
document.body.appendChild(host);
|
|
const root = createRoot(host);
|
|
|
|
await act(async () => {
|
|
root.render(
|
|
React.createElement(GraphProvisioningHud, {
|
|
teamName: 'northstar-core',
|
|
})
|
|
);
|
|
await Promise.resolve();
|
|
});
|
|
|
|
const openButton = host.querySelector('button[aria-label]');
|
|
expect(openButton).not.toBeNull();
|
|
expect(host.querySelector('[data-testid="stepper"]')?.getAttribute('data-stepper-active')).toBe(
|
|
'true'
|
|
);
|
|
|
|
await act(async () => {
|
|
openButton?.dispatchEvent(new MouseEvent('click', { bubbles: true }));
|
|
await Promise.resolve();
|
|
});
|
|
|
|
expect(document.body.textContent).toContain('provisioning-panel');
|
|
expect(
|
|
document.body.querySelector('[data-testid="panel"]')?.getAttribute('data-default-logs-open')
|
|
).toBe('true');
|
|
|
|
await act(async () => {
|
|
root.unmount();
|
|
await Promise.resolve();
|
|
});
|
|
});
|
|
|
|
it('renders the failed graph hud without active stepper animation', async () => {
|
|
vi.stubGlobal('IS_REACT_ACT_ENVIRONMENT', true);
|
|
hookState.presentation = {
|
|
isActive: false,
|
|
isFailed: true,
|
|
hasMembersStillJoining: false,
|
|
failedSpawnCount: 1,
|
|
compactTone: 'error',
|
|
compactTitle: 'Launch failed',
|
|
compactDetail: 'alice failed to start',
|
|
currentStepIndex: 2,
|
|
progress: { runId: 'run-4' },
|
|
};
|
|
|
|
const host = document.createElement('div');
|
|
document.body.appendChild(host);
|
|
const root = createRoot(host);
|
|
|
|
await act(async () => {
|
|
root.render(
|
|
React.createElement(GraphProvisioningHud, {
|
|
teamName: 'northstar-core',
|
|
})
|
|
);
|
|
await Promise.resolve();
|
|
});
|
|
|
|
expect(host.querySelector('[data-testid="stepper"]')?.getAttribute('data-stepper-active')).toBe(
|
|
'false'
|
|
);
|
|
|
|
await act(async () => {
|
|
root.unmount();
|
|
await Promise.resolve();
|
|
});
|
|
});
|
|
|
|
it('does not render or animate when disabled for an inactive graph tab', async () => {
|
|
vi.stubGlobal('IS_REACT_ACT_ENVIRONMENT', true);
|
|
hookState.presentation = {
|
|
isActive: true,
|
|
isFailed: false,
|
|
hasMembersStillJoining: false,
|
|
failedSpawnCount: 0,
|
|
compactTone: 'default',
|
|
compactTitle: 'Launching team',
|
|
compactDetail: 'Waiting for members',
|
|
currentStepIndex: 1,
|
|
progress: { runId: 'run-2' },
|
|
};
|
|
|
|
const host = document.createElement('div');
|
|
document.body.appendChild(host);
|
|
const root = createRoot(host);
|
|
|
|
await act(async () => {
|
|
root.render(
|
|
React.createElement(GraphProvisioningHud, {
|
|
teamName: 'northstar-core',
|
|
enabled: false,
|
|
})
|
|
);
|
|
await Promise.resolve();
|
|
});
|
|
|
|
expect(host.textContent).toBe('');
|
|
|
|
await act(async () => {
|
|
root.unmount();
|
|
await Promise.resolve();
|
|
});
|
|
});
|
|
});
|