2022-02-04 07:17:40 -05:00
|
|
|
import metricsData from 'test_fixtures/projects/analytics/value_stream_analytics/summary.json';
|
2021-10-08 11:12:51 -04:00
|
|
|
import {
|
|
|
|
filterBySearchTerm,
|
|
|
|
extractFilterQueryParameters,
|
|
|
|
extractPaginationQueryParameters,
|
2021-10-11 11:13:01 -04:00
|
|
|
getDataZoomOption,
|
2022-02-04 07:17:40 -05:00
|
|
|
prepareTimeMetricsData,
|
2021-10-08 11:12:51 -04:00
|
|
|
} from '~/analytics/shared/utils';
|
2022-02-04 07:17:40 -05:00
|
|
|
import { slugify } from '~/lib/utils/text_utility';
|
2021-10-08 11:12:51 -04:00
|
|
|
import { objectToQuery } from '~/lib/utils/url_utility';
|
2021-07-05 17:07:32 -04:00
|
|
|
|
|
|
|
describe('filterBySearchTerm', () => {
|
|
|
|
const data = [
|
|
|
|
{ name: 'eins', title: 'one' },
|
|
|
|
{ name: 'zwei', title: 'two' },
|
|
|
|
{ name: 'drei', title: 'three' },
|
|
|
|
];
|
|
|
|
const searchTerm = 'rei';
|
|
|
|
|
|
|
|
it('filters data by `name` for the provided search term', () => {
|
|
|
|
expect(filterBySearchTerm(data, searchTerm)).toEqual([data[2]]);
|
|
|
|
});
|
|
|
|
|
|
|
|
it('with no search term returns the data', () => {
|
|
|
|
['', null].forEach((search) => {
|
|
|
|
expect(filterBySearchTerm(data, search)).toEqual(data);
|
|
|
|
});
|
|
|
|
});
|
|
|
|
|
|
|
|
it('with a key, filters by the provided key', () => {
|
|
|
|
expect(filterBySearchTerm(data, 'ne', 'title')).toEqual([data[0]]);
|
|
|
|
});
|
|
|
|
});
|
2021-10-08 11:12:51 -04:00
|
|
|
|
|
|
|
describe('extractFilterQueryParameters', () => {
|
|
|
|
const selectedAuthor = 'Author 1';
|
|
|
|
const selectedMilestone = 'Milestone 1.0';
|
|
|
|
const selectedSourceBranch = 'main';
|
|
|
|
const selectedTargetBranch = 'feature-1';
|
|
|
|
const selectedAssigneeList = ['Alice', 'Bob'];
|
|
|
|
const selectedLabelList = ['Label 1', 'Label 2'];
|
|
|
|
|
|
|
|
const queryParamsString = objectToQuery({
|
|
|
|
source_branch_name: selectedSourceBranch,
|
|
|
|
target_branch_name: selectedTargetBranch,
|
|
|
|
author_username: selectedAuthor,
|
|
|
|
milestone_title: selectedMilestone,
|
|
|
|
assignee_username: selectedAssigneeList,
|
|
|
|
label_name: selectedLabelList,
|
|
|
|
});
|
|
|
|
|
|
|
|
it('extracts the correct filter parameters from a url', () => {
|
|
|
|
const result = extractFilterQueryParameters(queryParamsString);
|
|
|
|
const operator = '=';
|
|
|
|
const expectedFilters = {
|
|
|
|
selectedAssigneeList: { operator, value: selectedAssigneeList.join(',') },
|
|
|
|
selectedLabelList: { operator, value: selectedLabelList.join(',') },
|
|
|
|
selectedAuthor: { operator, value: selectedAuthor },
|
|
|
|
selectedMilestone: { operator, value: selectedMilestone },
|
|
|
|
selectedSourceBranch: { operator, value: selectedSourceBranch },
|
|
|
|
selectedTargetBranch: { operator, value: selectedTargetBranch },
|
|
|
|
};
|
|
|
|
expect(result).toMatchObject(expectedFilters);
|
|
|
|
});
|
|
|
|
|
|
|
|
it('returns null for missing parameters', () => {
|
|
|
|
const result = extractFilterQueryParameters('');
|
|
|
|
const expectedFilters = {
|
|
|
|
selectedAuthor: null,
|
|
|
|
selectedMilestone: null,
|
|
|
|
selectedSourceBranch: null,
|
|
|
|
selectedTargetBranch: null,
|
|
|
|
};
|
|
|
|
expect(result).toMatchObject(expectedFilters);
|
|
|
|
});
|
|
|
|
|
|
|
|
it('only returns the parameters we expect', () => {
|
|
|
|
const result = extractFilterQueryParameters('foo="one"&bar="two"');
|
|
|
|
const resultKeys = Object.keys(result);
|
|
|
|
['foo', 'bar'].forEach((key) => {
|
|
|
|
expect(resultKeys).not.toContain(key);
|
|
|
|
});
|
|
|
|
|
|
|
|
[
|
|
|
|
'selectedAuthor',
|
|
|
|
'selectedMilestone',
|
|
|
|
'selectedSourceBranch',
|
|
|
|
'selectedTargetBranch',
|
|
|
|
'selectedAssigneeList',
|
|
|
|
'selectedLabelList',
|
|
|
|
].forEach((key) => {
|
|
|
|
expect(resultKeys).toContain(key);
|
|
|
|
});
|
|
|
|
});
|
|
|
|
|
|
|
|
it('returns an empty array for missing list parameters', () => {
|
|
|
|
const result = extractFilterQueryParameters('');
|
|
|
|
const expectedFilters = { selectedAssigneeList: [], selectedLabelList: [] };
|
|
|
|
expect(result).toMatchObject(expectedFilters);
|
|
|
|
});
|
|
|
|
});
|
|
|
|
|
|
|
|
describe('extractPaginationQueryParameters', () => {
|
|
|
|
const sort = 'title';
|
|
|
|
const direction = 'asc';
|
|
|
|
const page = '1';
|
|
|
|
const queryParamsString = objectToQuery({ sort, direction, page });
|
|
|
|
|
|
|
|
it('extracts the correct filter parameters from a url', () => {
|
|
|
|
const result = extractPaginationQueryParameters(queryParamsString);
|
|
|
|
const expectedFilters = { sort, page, direction };
|
|
|
|
expect(result).toMatchObject(expectedFilters);
|
|
|
|
});
|
|
|
|
|
|
|
|
it('returns null for missing parameters', () => {
|
|
|
|
const result = extractPaginationQueryParameters('');
|
|
|
|
const expectedFilters = { sort: null, direction: null, page: null };
|
|
|
|
expect(result).toMatchObject(expectedFilters);
|
|
|
|
});
|
|
|
|
|
|
|
|
it('only returns the parameters we expect', () => {
|
|
|
|
const result = extractPaginationQueryParameters('foo="one"&bar="two"&qux="three"');
|
|
|
|
const resultKeys = Object.keys(result);
|
|
|
|
['foo', 'bar', 'qux'].forEach((key) => {
|
|
|
|
expect(resultKeys).not.toContain(key);
|
|
|
|
});
|
|
|
|
|
|
|
|
['sort', 'page', 'direction'].forEach((key) => {
|
|
|
|
expect(resultKeys).toContain(key);
|
|
|
|
});
|
|
|
|
});
|
|
|
|
});
|
2021-10-11 11:13:01 -04:00
|
|
|
|
|
|
|
describe('getDataZoomOption', () => {
|
|
|
|
it('returns an empty object when totalItems <= maxItemsPerPage', () => {
|
|
|
|
const totalItems = 10;
|
|
|
|
const maxItemsPerPage = 20;
|
|
|
|
|
|
|
|
expect(getDataZoomOption({ totalItems, maxItemsPerPage })).toEqual({});
|
|
|
|
});
|
|
|
|
|
|
|
|
describe('when totalItems > maxItemsPerPage', () => {
|
|
|
|
const totalItems = 30;
|
|
|
|
const maxItemsPerPage = 20;
|
|
|
|
|
|
|
|
it('properly computes the end interval for the default datazoom config', () => {
|
|
|
|
const expected = [
|
|
|
|
{
|
|
|
|
type: 'slider',
|
|
|
|
bottom: 10,
|
|
|
|
start: 0,
|
|
|
|
end: 67,
|
|
|
|
},
|
|
|
|
];
|
|
|
|
|
|
|
|
expect(getDataZoomOption({ totalItems, maxItemsPerPage })).toEqual(expected);
|
|
|
|
});
|
|
|
|
|
|
|
|
it('properly computes the end interval for a custom datazoom config', () => {
|
|
|
|
const dataZoom = [
|
|
|
|
{ type: 'slider', bottom: 0, start: 0 },
|
|
|
|
{ type: 'inside', start: 0 },
|
|
|
|
];
|
|
|
|
const expected = [
|
|
|
|
{
|
|
|
|
type: 'slider',
|
|
|
|
bottom: 0,
|
|
|
|
start: 0,
|
|
|
|
end: 67,
|
|
|
|
},
|
|
|
|
{
|
|
|
|
type: 'inside',
|
|
|
|
start: 0,
|
|
|
|
end: 67,
|
|
|
|
},
|
|
|
|
];
|
|
|
|
|
|
|
|
expect(getDataZoomOption({ totalItems, maxItemsPerPage, dataZoom })).toEqual(expected);
|
|
|
|
});
|
|
|
|
});
|
|
|
|
});
|
2022-02-04 07:17:40 -05:00
|
|
|
|
|
|
|
describe('prepareTimeMetricsData', () => {
|
|
|
|
let prepared;
|
|
|
|
const [first, second] = metricsData;
|
|
|
|
delete second.identifier; // testing the case when identifier is missing
|
|
|
|
|
|
|
|
const firstIdentifier = first.identifier;
|
|
|
|
const secondIdentifier = slugify(second.title);
|
|
|
|
|
|
|
|
beforeEach(() => {
|
|
|
|
prepared = prepareTimeMetricsData([first, second], {
|
|
|
|
[firstIdentifier]: { description: 'Is a value that is good' },
|
|
|
|
});
|
|
|
|
});
|
|
|
|
|
|
|
|
it('will add a `identifier` based on the title', () => {
|
|
|
|
expect(prepared).toMatchObject([
|
|
|
|
{ identifier: firstIdentifier },
|
|
|
|
{ identifier: secondIdentifier },
|
|
|
|
]);
|
|
|
|
});
|
|
|
|
|
|
|
|
it('will add a `label` key', () => {
|
|
|
|
expect(prepared).toMatchObject([{ label: 'New Issues' }, { label: 'Commits' }]);
|
|
|
|
});
|
|
|
|
|
|
|
|
it('will add a popover description using the key if it is provided', () => {
|
|
|
|
expect(prepared).toMatchObject([
|
|
|
|
{ description: 'Is a value that is good' },
|
|
|
|
{ description: '' },
|
|
|
|
]);
|
|
|
|
});
|
|
|
|
});
|