1
0
mirror of https://github.com/Unleash/unleash.git synced 2025-04-10 01:16:39 +02:00
unleash.unleash/src/lib/features/feature-search/feature.search.e2e.test.ts
2023-10-27 14:16:29 +02:00

251 lines
7.4 KiB
TypeScript

import dbInit, { ITestDb } from '../../../test/e2e/helpers/database-init';
import {
IUnleashTest,
setupAppWithCustomConfig,
} from '../../../test/e2e/helpers/test-helper';
import getLogger from '../../../test/fixtures/no-logger';
import { FeatureSearchQueryParameters } from '../../openapi/spec/feature-search-query-parameters';
let app: IUnleashTest;
let db: ITestDb;
beforeAll(async () => {
db = await dbInit('feature_search', getLogger);
app = await setupAppWithCustomConfig(
db.stores,
{
experimental: {
flags: {
strictSchemaValidation: true,
featureSearchAPI: true,
},
},
},
db.rawDatabase,
);
});
afterAll(async () => {
await app.destroy();
await db.destroy();
});
beforeEach(async () => {
await db.stores.featureToggleStore.deleteAll();
});
const searchFeatures = async (
{ query = '', projectId = 'default' }: FeatureSearchQueryParameters,
expectedCode = 200,
) => {
return app.request
.get(`/api/admin/search/features?query=${query}&projectId=${projectId}`)
.expect(expectedCode);
};
const searchFeaturesWithCursor = async (
{
query = '',
projectId = 'default',
cursor = '',
limit = 10,
}: FeatureSearchQueryParameters,
expectedCode = 200,
) => {
return app.request
.get(
`/api/admin/search/features?query=${query}&projectId=${projectId}&cursor=${cursor}&limit=${limit}`,
)
.expect(expectedCode);
};
const filterFeaturesByType = async (types: string[], expectedCode = 200) => {
const typeParams = types.map((type) => `type[]=${type}`).join('&');
return app.request
.get(`/api/admin/search/features?${typeParams}`)
.expect(expectedCode);
};
const filterFeaturesByTag = async (tags: string[], expectedCode = 200) => {
const tagParams = tags.map((tag) => `tag[]=${tag}`).join('&');
return app.request
.get(`/api/admin/search/features?${tagParams}`)
.expect(expectedCode);
};
const filterFeaturesByEnvironmentStatus = async (
environmentStatuses: string[],
expectedCode = 200,
) => {
const statuses = environmentStatuses
.map((status) => `status[]=${status}`)
.join('&');
return app.request
.get(`/api/admin/search/features?${statuses}`)
.expect(expectedCode);
};
const searchFeaturesWithoutQueryParams = async (expectedCode = 200) => {
return app.request.get(`/api/admin/search/features`).expect(expectedCode);
};
test('should search matching features by name', async () => {
await app.createFeature('my_feature_a');
await app.createFeature('my_feature_b');
await app.createFeature('my_feat_c');
const { body } = await searchFeatures({ query: 'feature' });
expect(body).toMatchObject({
features: [{ name: 'my_feature_a' }, { name: 'my_feature_b' }],
});
});
test('should paginate with cursor', async () => {
await app.createFeature('my_feature_a');
await app.createFeature('my_feature_b');
await app.createFeature('my_feature_c');
await app.createFeature('my_feature_d');
const { body: firstPage } = await searchFeaturesWithCursor({
query: 'feature',
cursor: '',
limit: 2,
});
const nextCursor =
firstPage.features[firstPage.features.length - 1].createdAt;
expect(firstPage).toMatchObject({
features: [{ name: 'my_feature_a' }, { name: 'my_feature_b' }],
});
const { body: secondPage } = await searchFeaturesWithCursor({
query: 'feature',
cursor: nextCursor,
limit: 2,
});
expect(secondPage).toMatchObject({
features: [{ name: 'my_feature_c' }, { name: 'my_feature_d' }],
});
const lastCursor =
secondPage.features[secondPage.features.length - 1].createdAt;
const { body: lastPage } = await searchFeaturesWithCursor({
query: 'feature',
cursor: lastCursor,
limit: 2,
});
expect(lastPage).toMatchObject({
features: [],
});
});
test('should filter features by type', async () => {
await app.createFeature({ name: 'my_feature_a', type: 'release' });
await app.createFeature({ name: 'my_feature_b', type: 'experimental' });
const { body } = await filterFeaturesByType([
'experimental',
'kill-switch',
]);
expect(body).toMatchObject({
features: [{ name: 'my_feature_b' }],
});
});
test('should filter features by tag', async () => {
await app.createFeature('my_feature_a');
await app.createFeature('my_feature_b');
await app.addTag('my_feature_a', { type: 'simple', value: 'my_tag' });
const { body } = await filterFeaturesByTag(['simple:my_tag']);
expect(body).toMatchObject({
features: [{ name: 'my_feature_a' }],
});
});
test('should filter features by environment status', async () => {
await app.createFeature('my_feature_a');
await app.createFeature('my_feature_b');
await app.enableFeature('my_feature_a', 'default');
const { body } = await filterFeaturesByEnvironmentStatus([
'default:enabled',
'nonexistentEnv:disabled',
'default:wrongStatus',
]);
expect(body).toMatchObject({
features: [{ name: 'my_feature_a' }],
});
});
test('filter with invalid tag should ignore filter', async () => {
await app.createFeature('my_feature_a');
await app.createFeature('my_feature_b');
await app.addTag('my_feature_a', { type: 'simple', value: 'my_tag' });
const { body } = await filterFeaturesByTag(['simple']);
expect(body).toMatchObject({
features: [{ name: 'my_feature_a' }, { name: 'my_feature_b' }],
});
});
test('should search matching features by tag', async () => {
await app.createFeature('my_feature_a');
await app.createFeature('my_feature_b');
await app.addTag('my_feature_a', { type: 'simple', value: 'my_tag' });
const { body: fullMatch } = await searchFeatures({
query: 'simple:my_tag',
});
const { body: tagTypeMatch } = await searchFeatures({ query: 'simple' });
const { body: tagValueMatch } = await searchFeatures({ query: 'my_tag' });
const { body: partialTagMatch } = await searchFeatures({ query: 'e:m' });
expect(fullMatch).toMatchObject({
features: [{ name: 'my_feature_a' }],
});
expect(tagTypeMatch).toMatchObject({
features: [{ name: 'my_feature_a' }],
});
expect(tagValueMatch).toMatchObject({
features: [{ name: 'my_feature_a' }],
});
expect(partialTagMatch).toMatchObject({
features: [{ name: 'my_feature_a' }],
});
});
test('should return empty features', async () => {
const { body } = await searchFeatures({ query: '' });
expect(body).toMatchObject({ features: [] });
});
test('should not search features from another project', async () => {
await app.createFeature('my_feature_a');
await app.createFeature('my_feature_b');
const { body } = await searchFeatures({
query: '',
projectId: 'another_project',
});
expect(body).toMatchObject({ features: [] });
});
test('should return features without query', async () => {
await app.createFeature('my_feature_a');
await app.createFeature('my_feature_b');
const { body } = await searchFeaturesWithoutQueryParams();
expect(body).toMatchObject({
features: [{ name: 'my_feature_a' }, { name: 'my_feature_b' }],
});
});