Skip to content

Commit

Permalink
test: Add unit tests for useMetricsChart and testDefinition.store.ee
Browse files Browse the repository at this point in the history
  • Loading branch information
OlegIvaniv committed Jan 6, 2025
1 parent 14b2851 commit 969cb49
Show file tree
Hide file tree
Showing 2 changed files with 256 additions and 0 deletions.
Original file line number Diff line number Diff line change
@@ -0,0 +1,127 @@
import { describe, it, expect } from 'vitest';
import { useMetricsChart } from '../composables/useMetricsChart';
import type { TestRunRecord } from '@/api/testDefinition.ee';

describe('useMetricsChart', () => {
const mockRuns: TestRunRecord[] = [
{
id: '1',
testDefinitionId: 'test1',
status: 'completed',
createdAt: '2025-01-06T10:00:00Z',
updatedAt: '2025-01-06T10:00:00Z',
completedAt: '2025-01-06T10:00:00Z',
runAt: '2025-01-06T10:00:00Z',
metrics: { responseTime: 100, successRate: 95 },
},
{
id: '2',
testDefinitionId: 'test1',
status: 'completed',
createdAt: '2025-01-06T10:00:00Z',
updatedAt: '2025-01-06T10:00:00Z',
completedAt: '2025-01-06T10:00:00Z',
runAt: '2025-01-06T10:00:00Z',
metrics: { responseTime: 150, successRate: 98 },
},
] as TestRunRecord[];

describe('generateChartData', () => {
it('should generate correct chart data structure', () => {
const { generateChartData } = useMetricsChart('light');
const result = generateChartData(mockRuns, 'responseTime');

expect(result.labels).toHaveLength(2);
expect(result.datasets).toHaveLength(1);
expect(result.datasets[0].data).toEqual([100, 150]);
});

it('should sort runs by date', () => {
const unsortedRuns = [
{
id: '1',
testDefinitionId: 'test1',
status: 'completed',
createdAt: '2025-01-06T10:05:00Z',
updatedAt: '2025-01-06T10:05:00Z',
completedAt: '2025-01-06T10:05:00Z',
runAt: '2025-01-06T10:05:00Z',
metrics: { responseTime: 150 },
},
{
id: '2',
testDefinitionId: 'test1',
status: 'completed',
createdAt: '2025-01-06T10:00:00Z',
updatedAt: '2025-01-06T10:00:00Z',
completedAt: '2025-01-06T10:00:00Z',
runAt: '2025-01-06T10:00:00Z',
metrics: { responseTime: 100 },
},
] as TestRunRecord[];

const { generateChartData } = useMetricsChart('light');
const result = generateChartData(unsortedRuns, 'responseTime');

expect(result.datasets[0].data).toEqual([100, 150]);
});

it('should filter out runs without specified metric', () => {
const runsWithMissingMetrics = [
{
id: '1',
testDefinitionId: 'test1',
status: 'completed',
createdAt: '2025-01-06T10:00:00Z',
updatedAt: '2025-01-06T10:00:00Z',
completedAt: '2025-01-06T10:00:00Z',
runAt: '2025-01-06T10:00:00Z',
metrics: { responseTime: 100 },
},
{
id: '2',
testDefinitionId: 'test1',
status: 'completed',
createdAt: '2025-01-06T10:00:00Z',
updatedAt: '2025-01-06T10:00:00Z',
completedAt: '2025-01-06T10:00:00Z',
runAt: '2025-01-06T10:00:00Z',
metrics: {},
},
] as TestRunRecord[];

const { generateChartData } = useMetricsChart('light');
const result = generateChartData(runsWithMissingMetrics, 'responseTime');

expect(result.labels).toHaveLength(1);
expect(result.datasets[0].data).toEqual([100]);
});

it('should handle dark theme colors', () => {
const { generateChartData } = useMetricsChart('dark');
const result = generateChartData(mockRuns, 'responseTime');

expect(result.datasets[0].pointHoverBackgroundColor).toBe('rgb(32, 32, 32)');
});
});

describe('generateChartOptions', () => {
it('should generate correct chart options structure', () => {
const { generateChartOptions } = useMetricsChart('light');
const result = generateChartOptions({ metric: 'responseTime', xTitle: 'Time' });

expect(result.scales?.y?.title?.text).toBe('responseTime');
expect(result.scales?.x?.title?.text).toBe('Time');
expect(result.responsive).toBe(true);
expect(result.maintainAspectRatio).toBe(false);
});

it('should apply correct theme colors', () => {
const { generateChartOptions } = useMetricsChart('dark');
const result = generateChartOptions({ metric: 'responseTime', xTitle: 'Time' });

expect(result.scales?.y?.ticks?.color).toBe('rgb(255, 255, 255)');
expect(result.plugins?.tooltip?.backgroundColor).toBe('rgb(32, 32, 32)');
});
});
});
129 changes: 129 additions & 0 deletions packages/editor-ui/src/stores/testDefinition.store.ee.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -370,6 +370,54 @@ describe('testDefinition.store.ee', () => {

expect(store.isFeatureEnabled).toBe(true);
});

test('allTestDefinitionsByWorkflowId', () => {
store.testDefinitionsById = {
'1': { ...TEST_DEF_A, workflowId: 'workflow1' },
'2': { ...TEST_DEF_B, workflowId: 'workflow1' },
'3': { ...TEST_DEF_NEW, workflowId: 'workflow2' },
};

expect(store.allTestDefinitionsByWorkflowId).toEqual({
workflow1: [
{ ...TEST_DEF_A, workflowId: 'workflow1' },
{ ...TEST_DEF_B, workflowId: 'workflow1' },
],
workflow2: [{ ...TEST_DEF_NEW, workflowId: 'workflow2' }],
});
});

test('lastRunByTestId', () => {
const olderRun = {
...TEST_RUN,
id: 'run2',
testDefinitionId: '1',
updatedAt: '2023-12-31',
};

const newerRun = {
...TEST_RUN,
id: 'run3',
testDefinitionId: '2',
updatedAt: '2024-01-02',
};

store.testRunsById = {
run1: { ...TEST_RUN, testDefinitionId: '1' },
run2: olderRun,
run3: newerRun,
};

expect(store.lastRunByTestId).toEqual({
'1': TEST_RUN,
'2': newerRun,
});
});

test('lastRunByTestId with no runs', () => {
store.testRunsById = {};
expect(store.lastRunByTestId).toEqual({});
});
});

describe('Error Handling', () => {
Expand Down Expand Up @@ -449,4 +497,85 @@ describe('testDefinition.store.ee', () => {
expect(runs).toEqual([TEST_RUN]);
});
});

describe('Polling Mechanism', () => {
beforeEach(() => {
vi.useFakeTimers();
});

afterEach(() => {
vi.useRealTimers();
});

test('should start polling for running test runs', async () => {
const runningTestRun = {
...TEST_RUN,
status: 'running',
};

getTestRuns.mockResolvedValueOnce([runningTestRun]);

// First call returns running status
getTestRun.mockResolvedValueOnce({
...runningTestRun,
status: 'running',
});

// Second call returns completed status
getTestRun.mockResolvedValueOnce({
...runningTestRun,
status: 'completed',
});

await store.fetchTestRuns('1');

expect(store.testRunsById).toEqual({
run1: runningTestRun,
});

// Advance timer to trigger the first poll
await vi.advanceTimersByTimeAsync(1000);

// Verify first poll happened
expect(getTestRun).toHaveBeenCalledWith(rootStoreMock.restApiContext, {
testDefinitionId: '1',
runId: 'run1',
});

// Advance timer again
await vi.advanceTimersByTimeAsync(1000);

// Verify polling stopped after status changed to completed
expect(getTestRun).toHaveBeenCalledTimes(2);
});

test('should cleanup polling timeouts', async () => {
const runningTestRun = {
...TEST_RUN,
status: 'running',
};

getTestRuns.mockResolvedValueOnce([runningTestRun]);
getTestRun.mockResolvedValue({
...runningTestRun,
status: 'running',
});

await store.fetchTestRuns('1');

// Wait for the first poll to complete
await vi.runOnlyPendingTimersAsync();

// Clear mock calls from initial setup
getTestRun.mockClear();

store.cleanupPolling();

// Advance timer
await vi.advanceTimersByTimeAsync(1000);

// Verify no more polling happened after cleanup
expect(getTestRun).not.toHaveBeenCalled();
});
});
});

0 comments on commit 969cb49

Please sign in to comment.