diff --git a/src/lib/features/project-status/project-stale-flags-read-model/project-stale-flags-read-model.ts b/src/lib/features/project-status/project-stale-flags-read-model/project-stale-flags-read-model.ts index bc0a4c56123a..11b9c7616bfb 100644 --- a/src/lib/features/project-status/project-stale-flags-read-model/project-stale-flags-read-model.ts +++ b/src/lib/features/project-status/project-stale-flags-read-model/project-stale-flags-read-model.ts @@ -7,7 +7,8 @@ export class ProjectStaleFlagsReadModel implements IProjectStaleFlagsReadModel { async getStaleFlagCountForProject(projectId: string): Promise { const result = await this.db('features') .count() - .where({ project: projectId, archived: false }) + .whereNull('archived_at') + .where({ project: projectId }) .where((builder) => builder .orWhere({ stale: true }) diff --git a/src/lib/features/project-status/projects-status.e2e.test.ts b/src/lib/features/project-status/projects-status.e2e.test.ts index 73966d7dab15..dc681c528f52 100644 --- a/src/lib/features/project-status/projects-status.e2e.test.ts +++ b/src/lib/features/project-status/projects-status.e2e.test.ts @@ -264,36 +264,46 @@ test('project status includes stale flags', async () => { {} as IUser, {} as IAuditUser, ); - const createFlagInState = async ( - name: string, - state?: Object, - projectId?: string, - ) => { - await app.createFeature(name, projectId); - if (state) { - await db.rawDatabase('features').update(state).where({ name }); - } - }; - await createFlagInState('stale-flag', { stale: true }); - await createFlagInState('potentially-stale-flag', { - potentially_stale: true, - }); - await createFlagInState('potentially-stale-and-stale-flag', { - potentially_stale: true, - stale: true, - }); - await createFlagInState('non-stale-flag'); - await createFlagInState('archived-stale-flag', { - archived: true, - stale: true, - }); - await createFlagInState( - 'stale-other-project', - { stale: true }, - otherProject.id, + function cartesianProduct(...arrays: any[][]): any[][] { + return arrays.reduce( + (acc, array) => { + return acc.flatMap((accItem) => + array.map((item) => [...accItem, item]), + ); + }, + [[]] as any[][], + ); + } + + // of all 16 (2^4) permutations, only 3 are unhealthy flags in a given project. + const combinations = cartesianProduct( + [false, true], // stale + [false, true], // potentially stale + [false, true], // archived + ['default', otherProject.id], // project ); + for (const [stale, potentiallyStale, archived, project] of combinations) { + const name = `flag-${project}-stale-${stale}-potentially-stale-${potentiallyStale}-archived-${archived}`; + await app.createFeature( + { + name, + stale, + }, + project, + ); + if (potentiallyStale) { + await db + .rawDatabase('features') + .update('potentially_stale', true) + .where({ name }); + } + if (archived) { + await app.archiveFeature(name, project); + } + } + const { body } = await app.request .get('/api/admin/projects/default/status') .expect('Content-Type', /json/)