1
0
mirror of https://github.com/Unleash/unleash.git synced 2025-01-11 00:08:30 +01:00

feat: insights project filtering hooks with tests (#6403)

Hooks to filter and aggregate insights data on frontend
This commit is contained in:
Tymoteusz Czech 2024-03-01 11:15:16 +01:00 committed by GitHub
parent 446b2b2a2d
commit ae077558c0
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
4 changed files with 297 additions and 0 deletions

View File

@ -0,0 +1,122 @@
import { renderHook } from '@testing-library/react-hooks';
import { useFilteredFlagsSummary } from './useFilteredFlagsSummary';
describe('useFilteredFlagTrends', () => {
it('should summarize only last week of project flag trends', () => {
const { result } = renderHook(() =>
useFilteredFlagsSummary([
{
week: '2024-01',
project: 'project1',
total: 1,
active: 1,
stale: 0,
potentiallyStale: 0,
users: 1,
date: '',
},
{
week: '2024-01',
project: 'project2',
total: 2,
active: 2,
stale: 0,
potentiallyStale: 0,
users: 2,
date: '',
},
{
week: '2024-02',
project: 'project1',
total: 4,
active: 3,
stale: 0,
potentiallyStale: 1,
users: 1,
date: '',
},
{
week: '2024-02',
project: 'project3',
total: 10,
active: 8,
stale: 2,
potentiallyStale: 0,
users: 3,
date: '',
},
]),
);
expect(result.current).toEqual({
total: 14,
active: 11,
stale: 2,
potentiallyStale: 1,
averageUsers: '2.00',
averageHealth: '79',
});
});
it('should work with project with zero users', () => {
const { result, rerender } = renderHook(() =>
useFilteredFlagsSummary([
{
week: '2024-01',
project: 'project1',
total: 5,
active: 5,
stale: 0,
potentiallyStale: 0,
users: 0,
date: '',
},
]),
);
expect(result.current).toEqual({
total: 5,
active: 5,
stale: 0,
potentiallyStale: 0,
averageUsers: '0.00',
averageHealth: '100',
});
});
it('should work with projects where some have with zero users', () => {
const { result } = renderHook(() =>
useFilteredFlagsSummary([
{
week: '2024-01',
project: 'project1',
total: 5,
active: 5,
stale: 0,
potentiallyStale: 0,
users: 0,
date: '',
},
{
week: '2024-01',
project: 'project2',
total: 5,
active: 5,
stale: 0,
potentiallyStale: 0,
users: 2,
date: '',
},
]),
);
expect(result.current).toEqual({
total: 10,
active: 10,
stale: 0,
potentiallyStale: 0,
averageUsers: '1.00',
averageHealth: '100',
});
});
});

View File

@ -0,0 +1,46 @@
import { useMemo } from 'react';
import { ExecutiveSummarySchemaProjectFlagTrendsItem } from 'openapi';
export const useFilteredFlagsSummary = (
filteredProjectFlagTrends: ExecutiveSummarySchemaProjectFlagTrendsItem[],
) =>
useMemo(() => {
const lastWeekId = filteredProjectFlagTrends.reduce((prev, current) => {
if (current.week > prev) return current.week;
return prev;
}, '');
const lastWeekSummary = filteredProjectFlagTrends.filter(
(summary) => summary.week === lastWeekId,
);
const averageUsers = (
lastWeekSummary.reduce(
(acc, current) => acc + (current.users || 0),
0,
) / lastWeekSummary.length
).toFixed(2);
const sum = lastWeekSummary.reduce(
(acc, current) => ({
total: acc.total + current.total,
active: acc.active + current.active,
stale: acc.stale + current.stale,
potentiallyStale:
acc.potentiallyStale + current.potentiallyStale,
averageUsers,
}),
{
total: 0,
active: 0,
stale: 0,
potentiallyStale: 0,
},
);
return {
...sum,
averageUsers,
averageHealth: ((sum.active / (sum.total || 1)) * 100).toFixed(0),
};
}, [filteredProjectFlagTrends]);

View File

@ -0,0 +1,107 @@
import { renderHook } from '@testing-library/react-hooks';
import { useFilteredTrends } from './useFilteredTrends';
const mockProjectFlagTrends = [
{
week: '2024-01',
project: 'project1',
},
{
week: '2024-01',
project: 'project2',
},
{
week: '2024-02',
project: 'project1',
},
{
week: '2024-02',
project: 'project3',
},
];
describe('useFilteredFlagTrends', () => {
it('should return all project flag trends when all projects option is selected', () => {
const projects = ['*'];
const { result } = renderHook(() =>
useFilteredTrends(mockProjectFlagTrends, projects),
);
expect(result.current).toEqual(mockProjectFlagTrends);
});
it('should return all project flag trends project selection is empty', () => {
const projects: string[] = [];
const { result } = renderHook(() =>
useFilteredTrends(mockProjectFlagTrends, projects),
);
expect(result.current).toEqual(mockProjectFlagTrends);
});
it('should return filtered project when specific project is selected', () => {
const projects = ['project1'];
const { result } = renderHook(() =>
useFilteredTrends(mockProjectFlagTrends, projects),
);
expect(result.current).toEqual([
{
week: '2024-01',
project: 'project1',
},
{
week: '2024-02',
project: 'project1',
},
]);
});
it('should return filtered project flag trends when specific projects are selected', () => {
const projects = ['project1', 'project2'];
const { result } = renderHook(() =>
useFilteredTrends(mockProjectFlagTrends, projects),
);
expect(result.current).toEqual([
{
week: '2024-01',
project: 'project1',
},
{
week: '2024-01',
project: 'project2',
},
{
week: '2024-02',
project: 'project1',
},
]);
});
it('should re-render if input has changed', () => {
const projects = ['project1'];
const { result, rerender } = renderHook(
({ input, projects }) => useFilteredTrends(input, projects),
{
initialProps: {
input: mockProjectFlagTrends,
projects,
},
},
);
rerender({
input: [
{
week: '2024-01',
project: 'project1',
},
],
projects,
});
expect(result.current).toEqual([
{
week: '2024-01',
project: 'project1',
},
]);
});
});

View File

@ -0,0 +1,22 @@
import { useMemo } from 'react';
import { allOption } from '../ProjectSelect/ProjectSelect';
export const useFilteredTrends = <
T extends {
project: string;
},
>(
input: T[],
projects: string[],
) =>
useMemo<T[]>(() => {
if (projects.length < 1 || projects[0] === allOption.id) {
return input;
}
const output = input.filter((trend) =>
projects.includes(trend.project),
) as T[];
return output;
}, [input, projects]);