mirror of
https://github.com/Unleash/unleash.git
synced 2025-11-10 01:19:53 +01:00
Vitest Pros: * Automated failing test comments on github PRs * A nice local UI with incremental testing when changing files (`yarn test:ui`) * Also nicely supported in all major IDEs, click to run test works (so we won't miss what we had with jest). * Works well with ESM Vitest Cons: * The ESBuild transformer vitest uses takes a little longer to transform than our current SWC/jest setup, however, it is possible to setup SWC as the transformer for vitest as well (though it only does one transform, so we're paying ~7-10 seconds instead of ~ 2-3 seconds in transform phase). * Exposes how slow our tests are (tongue in cheek here)
379 lines
12 KiB
TypeScript
379 lines
12 KiB
TypeScript
import { createTestConfig } from '../../../test/config/test-config.js';
|
|
import { BadDataError } from '../../error/index.js';
|
|
import {
|
|
type IFlagResolver,
|
|
type ProjectCreated,
|
|
RoleName,
|
|
TEST_AUDIT_USER,
|
|
} from '../../types/index.js';
|
|
import { createFakeProjectService } from './createProjectService.js';
|
|
|
|
import { vi } from 'vitest';
|
|
|
|
describe('enterprise extension: enable change requests', () => {
|
|
const createService = (mode: 'oss' | 'enterprise' = 'enterprise') => {
|
|
const config = createTestConfig();
|
|
config.isEnterprise = mode === 'enterprise';
|
|
const alwaysOnFlagResolver = {
|
|
isEnabled() {
|
|
return true;
|
|
},
|
|
} as unknown as IFlagResolver;
|
|
config.flagResolver = alwaysOnFlagResolver;
|
|
const {
|
|
projectService,
|
|
accessService,
|
|
environmentStore,
|
|
eventService,
|
|
projectStore,
|
|
} = createFakeProjectService(config);
|
|
|
|
accessService.createRole(
|
|
{
|
|
name: RoleName.OWNER,
|
|
description: 'Project owner',
|
|
createdByUserId: -1,
|
|
},
|
|
TEST_AUDIT_USER,
|
|
);
|
|
|
|
return {
|
|
service: projectService,
|
|
environmentStore,
|
|
eventService,
|
|
projectStore,
|
|
};
|
|
};
|
|
|
|
test('it calls the change request enablement function on enterprise after creating the project', async () => {
|
|
expect.assertions(1);
|
|
const { service, projectStore } = createService();
|
|
|
|
const projectId = 'fake-project-id';
|
|
await service.createProject(
|
|
{
|
|
id: projectId,
|
|
name: 'fake-project-name',
|
|
changeRequestEnvironments: [],
|
|
},
|
|
{
|
|
id: 5,
|
|
permissions: [],
|
|
isAPI: false,
|
|
},
|
|
TEST_AUDIT_USER,
|
|
async () => {
|
|
const project = await projectStore.get(projectId);
|
|
|
|
expect(project).toBeTruthy();
|
|
|
|
return [];
|
|
},
|
|
);
|
|
});
|
|
|
|
test("it does not call the change request enablement function if we're not enterprise", async () => {
|
|
const { service } = createService('oss');
|
|
|
|
const fn = vi.fn() as () => Promise<
|
|
{ name: string; requiredApprovals: number }[] | undefined
|
|
>;
|
|
|
|
const projectId = 'fake-project-id';
|
|
await service.createProject(
|
|
{
|
|
id: projectId,
|
|
name: 'fake-project-name',
|
|
},
|
|
{
|
|
id: 5,
|
|
permissions: [],
|
|
isAPI: false,
|
|
},
|
|
TEST_AUDIT_USER,
|
|
fn,
|
|
);
|
|
|
|
expect(fn).not.toHaveBeenCalled();
|
|
});
|
|
|
|
test('the emitted event contains an empty list of changeRequestEnvironments if the input had none', async () => {
|
|
expect.assertions(1);
|
|
const { service, eventService } = createService();
|
|
|
|
const projectId = 'fake-project-id';
|
|
await service.createProject(
|
|
{
|
|
id: projectId,
|
|
name: 'fake-project-name',
|
|
},
|
|
{
|
|
id: 5,
|
|
permissions: [],
|
|
isAPI: false,
|
|
},
|
|
TEST_AUDIT_USER,
|
|
);
|
|
|
|
const { events } = await eventService.getEvents();
|
|
expect(events).toMatchObject([
|
|
{
|
|
type: 'project-created',
|
|
data: { changeRequestEnvironments: [] },
|
|
},
|
|
]);
|
|
});
|
|
|
|
test('the emitted event contains no changeRequestEnvironments if we are not on enterprise', async () => {
|
|
const { service, eventService } = createService('oss');
|
|
|
|
const projectId = 'fake-project-id';
|
|
await service.createProject(
|
|
{
|
|
id: projectId,
|
|
name: 'fake-project-name',
|
|
},
|
|
{
|
|
id: 5,
|
|
permissions: [],
|
|
isAPI: false,
|
|
},
|
|
TEST_AUDIT_USER,
|
|
async () => [],
|
|
);
|
|
|
|
const { events } = await eventService.getEvents();
|
|
expect(events[0].data.changeRequestEnvironments).toBeUndefined();
|
|
});
|
|
|
|
test('the emitted event contains the list of change request envs returned from the extension function, *not* what was passed in', async () => {
|
|
const { service, environmentStore, eventService } = createService();
|
|
await environmentStore.create({
|
|
name: 'dev',
|
|
type: 'production',
|
|
enabled: true,
|
|
protected: false,
|
|
sortOrder: 0,
|
|
});
|
|
|
|
const crEnvs = [{ name: 'prod', requiredApprovals: 10 }];
|
|
|
|
const projectId = 'fake-project-id';
|
|
await service.createProject(
|
|
{
|
|
id: projectId,
|
|
name: 'fake-project-name',
|
|
changeRequestEnvironments: [
|
|
{ name: 'dev', requiredApprovals: 1 },
|
|
],
|
|
},
|
|
{
|
|
id: 5,
|
|
permissions: [],
|
|
isAPI: false,
|
|
},
|
|
TEST_AUDIT_USER,
|
|
async () => crEnvs,
|
|
);
|
|
|
|
const { events } = await eventService.getEvents();
|
|
expect(events).toMatchObject([
|
|
{
|
|
type: 'project-created',
|
|
data: {
|
|
changeRequestEnvironments: [
|
|
{ name: 'prod', requiredApprovals: 10 },
|
|
],
|
|
},
|
|
},
|
|
]);
|
|
});
|
|
|
|
test('prefer env approval settings over explicit user approvals', async () => {
|
|
const { service, environmentStore, eventService } = createService();
|
|
await environmentStore.create({
|
|
name: 'dev',
|
|
type: 'production',
|
|
enabled: true,
|
|
protected: false,
|
|
sortOrder: 0,
|
|
});
|
|
await environmentStore.create({
|
|
name: 'stage',
|
|
type: 'production',
|
|
enabled: true,
|
|
protected: false,
|
|
sortOrder: 0,
|
|
requiredApprovals: 2,
|
|
});
|
|
await environmentStore.create({
|
|
name: 'prod',
|
|
type: 'production',
|
|
enabled: true,
|
|
protected: false,
|
|
sortOrder: 0,
|
|
requiredApprovals: 3,
|
|
});
|
|
|
|
const projectId = 'fake-project-id';
|
|
await service.createProject(
|
|
{
|
|
id: projectId,
|
|
name: 'fake-project-name',
|
|
environments: ['prod', 'stage'], // stage selected but no approvals set by user
|
|
changeRequestEnvironments: [
|
|
{ name: 'dev', requiredApprovals: 1 },
|
|
{ name: 'prod', requiredApprovals: 10 }, // ignored in favor of env config
|
|
],
|
|
},
|
|
{
|
|
id: 5,
|
|
permissions: [],
|
|
isAPI: false,
|
|
},
|
|
TEST_AUDIT_USER,
|
|
async (envs) => envs as ProjectCreated['changeRequestEnvironments'],
|
|
);
|
|
|
|
const { events } = await eventService.getEvents();
|
|
expect(events).toMatchObject([
|
|
{
|
|
type: 'project-created',
|
|
data: {
|
|
changeRequestEnvironments: [
|
|
{ name: 'dev', requiredApprovals: 1 },
|
|
{ name: 'stage', requiredApprovals: 2 },
|
|
{ name: 'prod', requiredApprovals: 3 },
|
|
],
|
|
},
|
|
},
|
|
]);
|
|
});
|
|
|
|
test('the create project function returns the list of change request envs returned from the extension function, *not* what was passed in', async () => {
|
|
const { service, environmentStore } = createService();
|
|
await environmentStore.create({
|
|
name: 'dev',
|
|
type: 'production',
|
|
enabled: true,
|
|
protected: false,
|
|
sortOrder: 0,
|
|
});
|
|
|
|
const crEnvs = [{ name: 'prod', requiredApprovals: 10 }];
|
|
|
|
const projectId = 'fake-project-id';
|
|
const result = await service.createProject(
|
|
{
|
|
id: projectId,
|
|
name: 'fake-project-name',
|
|
changeRequestEnvironments: [
|
|
{ name: 'dev', requiredApprovals: 1 },
|
|
],
|
|
},
|
|
{
|
|
id: 5,
|
|
permissions: [],
|
|
isAPI: false,
|
|
},
|
|
TEST_AUDIT_USER,
|
|
async () => crEnvs,
|
|
);
|
|
|
|
expect(result.changeRequestEnvironments).toStrictEqual(crEnvs);
|
|
});
|
|
|
|
test('the create project function defaults to returning an empty list if the input had no cr envs', async () => {
|
|
const { service } = createService();
|
|
|
|
const projectId = 'fake-project-id';
|
|
const result = await service.createProject(
|
|
{
|
|
id: projectId,
|
|
name: 'fake-project-name',
|
|
},
|
|
{
|
|
id: 5,
|
|
permissions: [],
|
|
isAPI: false,
|
|
},
|
|
TEST_AUDIT_USER,
|
|
async () => [],
|
|
);
|
|
|
|
expect(result.changeRequestEnvironments).toStrictEqual([]);
|
|
});
|
|
|
|
test('the create project function does not return a list of change request envs if we are not on enterprise', async () => {
|
|
const { service } = createService('oss');
|
|
|
|
const crEnvs = [{ name: 'prod', requiredApprovals: 10 }];
|
|
|
|
const projectId = 'fake-project-id';
|
|
const result = await service.createProject(
|
|
{
|
|
id: projectId,
|
|
name: 'fake-project-name',
|
|
changeRequestEnvironments: [
|
|
{ name: 'dev', requiredApprovals: 1 },
|
|
],
|
|
},
|
|
{
|
|
id: 5,
|
|
permissions: [],
|
|
isAPI: false,
|
|
},
|
|
TEST_AUDIT_USER,
|
|
async () => crEnvs,
|
|
);
|
|
|
|
expect('changeRequestEnvironments' in result).toBeFalsy();
|
|
});
|
|
|
|
test("it throws an error if you provide it with environments that don't exist", async () => {
|
|
const { service } = createService();
|
|
|
|
const projectId = 'fake-project-id';
|
|
await expect(
|
|
service.createProject(
|
|
{
|
|
id: projectId,
|
|
name: 'fake-project-name',
|
|
changeRequestEnvironments: [
|
|
{ name: 'dev', requiredApprovals: 1 },
|
|
],
|
|
},
|
|
{
|
|
id: 5,
|
|
permissions: [],
|
|
isAPI: false,
|
|
},
|
|
TEST_AUDIT_USER,
|
|
),
|
|
).rejects.toThrow(BadDataError);
|
|
});
|
|
|
|
test("it does not throw if an error if you provide it with environments that don't exist but aren't on enterprise", async () => {
|
|
const { service } = createService('oss');
|
|
|
|
const projectId = 'fake-project-id';
|
|
await expect(
|
|
service.createProject(
|
|
{
|
|
id: projectId,
|
|
name: 'fake-project-name',
|
|
changeRequestEnvironments: [
|
|
{ name: 'dev', requiredApprovals: 1 },
|
|
],
|
|
},
|
|
{
|
|
id: 5,
|
|
permissions: [],
|
|
isAPI: false,
|
|
},
|
|
TEST_AUDIT_USER,
|
|
),
|
|
).resolves.toBeTruthy();
|
|
});
|
|
});
|