1
0
mirror of https://github.com/Unleash/unleash.git synced 2024-12-22 19:07:54 +01:00

tests: add more tests for the lifecycle avg calculation query (#8698)

This PR adds more tests to check a few more cases for the lifecycle
calculation query. Specifically, it tests that:
- If we don't have any data for a stage, we return `null`.
- We filter on projects
- It correctly takes `0` days into account when calculating averages.
This commit is contained in:
Thomas Heartman 2024-11-08 11:29:17 +01:00 committed by GitHub
parent 5733f91347
commit 0a250a7526
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
3 changed files with 118 additions and 24 deletions

View File

@ -1,4 +1,4 @@
import { addDays } from 'date-fns';
import { addDays, addMinutes } from 'date-fns';
import dbInit, { type ITestDb } from '../../../test/e2e/helpers/database-init';
import getLogger from '../../../test/fixtures/no-logger';
import { ProjectLifecycleSummaryReadModel } from './project-lifecycle-summary-read-model';
@ -17,6 +17,12 @@ afterAll(async () => {
}
});
afterEach(async () => {
await db.stores.projectStore.deleteAll();
await db.stores.featureToggleStore.deleteAll();
await db.stores.featureLifecycleStore.deleteAll();
});
const updateFeatureStageDate = async (
flagName: string,
stage: string,
@ -30,22 +36,22 @@ const updateFeatureStageDate = async (
describe('Average time calculation', () => {
test('it calculates the average time for each stage', async () => {
const project1 = await db.stores.projectStore.create({
name: 'project1',
id: 'project1',
const project = await db.stores.projectStore.create({
name: 'project',
id: randomId(),
});
const now = new Date();
const flags = [
{ name: randomId(), offsets: [2, 5, 6, 10] },
{ name: randomId(), offsets: [1, null, 4, 7] },
{ name: randomId(), offsets: [12, 25, 8, 9] },
{ name: randomId(), offsets: [12, 25, 0, 9] },
{ name: randomId(), offsets: [1, 2, 3, null] },
];
for (const { name, offsets } of flags) {
const created = await db.stores.featureToggleStore.create(
project1.id,
project.id,
{
name,
createdByUserId: 1,
@ -79,27 +85,115 @@ describe('Average time calculation', () => {
await updateFeatureStageDate(
created.name,
stage,
addDays(now, offsetFromInitial),
addMinutes(
addDays(now, offsetFromInitial),
1 * (index + 1),
),
);
}
}
const readModel = new ProjectLifecycleSummaryReadModel(db.rawDatabase);
const result = await readModel.getAverageTimeInEachStage(project1.id);
const result = await readModel.getAverageTimeInEachStage(project.id);
expect(result).toMatchObject({
initial: 4, // (2 + 1 + 12 + 1) / 4 = 4
'pre-live': 9, // (5 + 25 + 2 + 4) / 4 = 9
live: 6, // (6 + 8 + 3) / 3 ~= 5.67 ~= 6
'pre-live': 9, // (5 + 4 + 25 + 2) / 4 = 9
live: 3, // (6 + 0 + 3) / 3 = 3
completed: 9, // (10 + 7 + 9) / 3 ~= 8.67 ~= 9
});
});
test('it returns `null` if it has no data for something', async () => {});
test('it rounds to the nearest whole number', async () => {});
test('it ignores flags in other projects', async () => {});
test('it ignores flags in other projects', async () => {});
test('it returns `null` if it has no data for something', async () => {
const project = await db.stores.projectStore.create({
name: 'project',
id: randomId(),
});
const readModel = new ProjectLifecycleSummaryReadModel(db.rawDatabase);
test("it ignores rows that don't have a next stage", async () => {});
const result1 = await readModel.getAverageTimeInEachStage(project.id);
expect(result1).toMatchObject({
initial: null,
'pre-live': null,
live: null,
completed: null,
});
const flag = await db.stores.featureToggleStore.create(project.id, {
name: randomId(),
createdByUserId: 1,
});
await db.stores.featureLifecycleStore.insert([
{
feature: flag.name,
stage: 'initial',
},
]);
await db.stores.featureLifecycleStore.insert([
{
feature: flag.name,
stage: 'pre-live',
},
]);
await updateFeatureStageDate(
flag.name,
'pre-live',
addDays(new Date(), 5),
);
const result2 = await readModel.getAverageTimeInEachStage(project.id);
expect(result2).toMatchObject({
initial: 5,
'pre-live': null,
live: null,
completed: null,
});
});
test('it ignores flags in other projects', async () => {
const project = await db.stores.projectStore.create({
name: 'project',
id: randomId(),
});
const readModel = new ProjectLifecycleSummaryReadModel(db.rawDatabase);
const flag = await db.stores.featureToggleStore.create(project.id, {
name: randomId(),
createdByUserId: 1,
});
await db.stores.featureLifecycleStore.insert([
{
feature: flag.name,
stage: 'initial',
},
]);
await db.stores.featureLifecycleStore.insert([
{
feature: flag.name,
stage: 'pre-live',
},
]);
await updateFeatureStageDate(
flag.name,
'pre-live',
addDays(new Date(), 5),
);
const result =
await readModel.getAverageTimeInEachStage('some-other-project');
expect(result).toMatchObject({
initial: null,
'pre-live': null,
live: null,
completed: null,
});
});
});

View File

@ -38,10 +38,10 @@ export class ProjectLifecycleSummaryReadModel
}
async getAverageTimeInEachStage(projectId: string): Promise<{
initial: number;
'pre-live': number;
live: number;
completed: number;
initial: number | null;
'pre-live': number | null;
live: number | null;
completed: number | null;
}> {
const q = this.db
.with(
@ -80,10 +80,10 @@ export class ProjectLifecycleSummaryReadModel
return acc;
},
{
initial: 0,
'pre-live': 0,
live: 0,
completed: 0,
initial: null,
'pre-live': null,
live: null,
completed: null,
},
);
}

View File

@ -294,7 +294,7 @@ const config: Config = {
routeBasePath: '/',
remarkPlugins: [[pluginNpm2Yarn, { sync: true }]],
docItemComponent: '@theme/ApiItem',
sidebarPath: './sidebars.ts'
sidebarPath: './sidebars.ts',
},
theme: {
customCss: './src/css/custom.css',