Files
umami/tests/api/segments.spec.ts

210 lines
7.0 KiB
TypeScript

import { expect, test } from './fixtures';
import { UNKNOWN_UUID } from './helpers/constants';
import { dateRange } from './helpers/dates';
import { createWebsite, deleteWebsite, uniqueName } from './helpers/entities';
test.describe('Segments', () => {
test.describe.configure({ mode: 'serial' });
const parameters = {
filters: [{ name: 'path', operator: 'eq', value: '/pricing' }],
match: 'all',
};
let websiteId = '';
let segmentId = '';
let cohortId = '';
let seedSegmentId = '';
let base = '';
test.beforeAll(async ({ admin }) => {
websiteId = (await createWebsite(admin)).id;
base = `/api/websites/${websiteId}/segments`;
});
test.afterAll(async ({ admin, seed }) => {
if (seedSegmentId) {
await admin.del(`/api/websites/${seed.website.id}/segments/${seedSegmentId}`);
}
if (websiteId) {
await deleteWebsite(admin, websiteId);
}
});
test('POST /api/websites/{websiteId}/segments creates a segment', async ({ admin }) => {
const name = uniqueName('segment');
const response = await admin.post(base, { type: 'segment', name, parameters });
expect(response.status).toBe(200);
expect(response.body).toMatchObject({
id: expect.any(String),
websiteId,
type: 'segment',
name,
parameters,
createdAt: expect.any(String),
});
segmentId = response.body.id;
});
test('POST /api/websites/{websiteId}/segments creates a cohort', async ({ admin }) => {
const name = uniqueName('cohort');
const response = await admin.post(base, {
type: 'cohort',
name,
parameters: { ...parameters, dateRange: '30d', action: { type: 'event', value: 'signup' } },
});
expect(response.status).toBe(200);
expect(response.body).toMatchObject({ websiteId, type: 'cohort', name });
cohortId = response.body.id;
});
test('POST /api/websites/{websiteId}/segments validates and requires permission', async ({
admin,
user,
viewer,
api,
}) => {
const badType = await admin.post(base, { type: 'nope', name: 'x', parameters });
const missingParams = await admin.post(base, { type: 'segment', name: 'x' });
const badOperator = await admin.post(base, {
type: 'segment',
name: 'x',
parameters: { filters: [{ name: 'path', operator: 'nope', value: '/' }] },
});
const tooLong = await admin.post(base, { type: 'segment', name: 'x'.repeat(201), parameters });
const notOwner = await user.post(base, { type: 'segment', name: 'x', parameters });
const denied = await viewer.post(base, { type: 'segment', name: 'x', parameters });
const anonymous = await api.post(base, { type: 'segment', name: 'x', parameters });
expect(badType.status).toBe(400);
expect(missingParams.status).toBe(400);
expect(badOperator.status).toBe(400);
expect(tooLong.status).toBe(400);
expect(notOwner.status).toBe(401);
expect(denied.status).toBe(401);
expect(anonymous.status).toBe(401);
});
test('GET /api/websites/{websiteId}/segments lists segments by type', async ({
admin,
viewer,
share,
seed,
}) => {
const segments = await admin.get(base, { params: { type: 'segment' } });
const cohorts = await admin.get(base, { params: { type: 'cohort' } });
const search = await admin.get(base, {
params: { type: 'segment', search: 'zzz-no-such-segment' },
});
const missingType = await admin.get(base);
const badType = await admin.get(base, { params: { type: 'nope' } });
const denied = await viewer.get(base, { params: { type: 'segment' } });
const shared = await (await share()).get(`/api/websites/${seed.website.id}/segments`, {
params: { type: 'segment' },
});
expect(segments.status).toBe(200);
expect(segments.body).toMatchObject({
data: expect.any(Array),
count: 1,
page: 1,
pageSize: expect.any(Number),
});
expect(segments.body.data[0]).toMatchObject({ id: segmentId, type: 'segment', parameters });
expect(cohorts.body.data.map((s: any) => s.id)).toEqual([cohortId]);
expect(search.body.data).toHaveLength(0);
expect(missingType.status).toBe(400);
expect(badType.status).toBe(400);
expect(denied.status).toBe(401);
expect(shared.status).toBe(200);
});
test('GET /api/websites/{websiteId}/segments/{segmentId} returns a segment', async ({
admin,
viewer,
}) => {
const response = await admin.get(`${base}/${segmentId}`);
const denied = await viewer.get(`${base}/${segmentId}`);
const unknown = await admin.get(`${base}/${UNKNOWN_UUID}`);
expect(response.status).toBe(200);
expect(response.body).toMatchObject({ id: segmentId, websiteId, type: 'segment', parameters });
expect(denied.status).toBe(401);
expect(unknown.status).toBe(404);
});
test('POST /api/websites/{websiteId}/segments/{segmentId} updates a segment', async ({
admin,
user,
}) => {
const name = uniqueName('renamed');
const updated = { filters: [{ name: 'path', operator: 'c', value: '/docs' }], match: 'any' };
const response = await admin.post(`${base}/${segmentId}`, {
type: 'segment',
name,
parameters: updated,
});
const invalid = await admin.post(`${base}/${segmentId}`, { name });
const unknown = await admin.post(`${base}/${UNKNOWN_UUID}`, {
type: 'segment',
name,
parameters: updated,
});
const denied = await user.post(`${base}/${segmentId}`, {
type: 'segment',
name,
parameters: updated,
});
expect(response.status).toBe(200);
expect(response.body).toMatchObject({ id: segmentId, name, parameters: updated });
expect(invalid.status).toBe(400);
expect(unknown.status).toBe(404);
expect(denied.status).toBe(401);
});
test('GET /api/websites/{websiteId}/stats accepts a segment filter', async ({ admin, seed }) => {
const created = await admin.post(`/api/websites/${seed.website.id}/segments`, {
type: 'segment',
name: uniqueName('segment'),
parameters,
});
expect(created.status).toBe(200);
seedSegmentId = created.body.id;
const stats = await admin.get(`/api/websites/${seed.website.id}/stats`, {
params: dateRange(seed, { segment: seedSegmentId }),
});
expect(stats.status).toBe(200);
expect(stats.body).toMatchObject({ pageviews: expect.anything(), visitors: expect.anything() });
});
test('DELETE /api/websites/{websiteId}/segments/{segmentId} deletes a segment', async ({
admin,
user,
}) => {
const denied = await user.del(`${base}/${segmentId}`);
const response = await admin.del(`${base}/${segmentId}`);
const cohort = await admin.del(`${base}/${cohortId}`);
const gone = await admin.get(`${base}/${segmentId}`);
const unknown = await admin.del(`${base}/${UNKNOWN_UUID}`);
expect(denied.status).toBe(401);
expect(response.status).toBe(200);
expect(response.body).toEqual({ ok: true });
expect(cohort.status).toBe(200);
expect(gone.status).toBe(404);
expect(unknown.status).toBe(404);
segmentId = '';
cohortId = '';
});
});