@allurereport/web-awesome
Version:
The static files for Allure Awesome Report
172 lines (146 loc) • 4.98 kB
text/typescript
import type { Comparator, DefaultTreeGroup, Statistic, TestStatus, TreeLeaf } from "@allurereport/core-api";
import {
alphabetically,
andThen,
byStatistic,
byStatus,
compareBy,
emptyStatistic,
incrementStatistic,
mergeStatistic,
ordinal,
reverse,
} from "@allurereport/core-api";
import type { SortBy } from "@/stores/treeSort";
import type { AwesomeRecursiveTree, AwesomeTree, AwesomeTreeGroup, AwesomeTreeLeaf } from "../../types";
const leafComparatorByTreeSortBy = (sortBy: SortBy = "status,asc"): Comparator<TreeLeaf<AwesomeTreeLeaf>> => {
const typedCompareBy = compareBy<TreeLeaf<AwesomeTreeLeaf>>;
switch (sortBy) {
case "order,asc":
case "order,desc":
return typedCompareBy("groupOrder", ordinal());
case "duration,asc":
case "duration,desc":
return typedCompareBy("duration", ordinal());
case "name,asc":
case "name,desc":
return typedCompareBy("name", alphabetically());
case "status,asc":
case "status,desc":
return typedCompareBy("status", byStatus());
default:
// eslint-disable-next-line no-console
console.warn(`unsupported comparator ${sortBy as string}`);
return () => 0;
}
};
const groupComparatorByTreeSortBy = (sortBy: SortBy = "status,asc"): Comparator<DefaultTreeGroup> => {
const typedCompareBy = compareBy<DefaultTreeGroup>;
switch (sortBy) {
case "name,desc":
case "name,asc":
return typedCompareBy("name", alphabetically());
case "order,desc":
case "order,asc":
case "duration,desc":
case "duration,asc":
case "status,desc":
case "status,asc":
return typedCompareBy("statistic", byStatistic());
default:
// eslint-disable-next-line no-console
console.warn(`unsupported comparator ${sortBy as string}`);
return () => 0;
}
};
const withDirection = <T extends { name: string }>(cmp: Comparator<T>, sortBy: SortBy): Comparator<T> => {
const sortParams = sortBy.split(",");
const isStatusSort = sortParams.includes("status");
const isDescending = sortParams.includes("desc");
const nameComparator = compareBy<T>("name", alphabetically());
return andThen([
isDescending && !isStatusSort ? reverse(cmp) : cmp,
isDescending && isStatusSort ? reverse(nameComparator) : nameComparator,
]);
};
export const leafComparator = (sortBy: SortBy = "status,asc"): Comparator<TreeLeaf<AwesomeTreeLeaf>> => {
const cmp = leafComparatorByTreeSortBy(sortBy);
return withDirection(cmp, sortBy);
};
export const groupComparator = (sortBy: SortBy = "status,asc"): Comparator<DefaultTreeGroup> => {
const cmp = groupComparatorByTreeSortBy(sortBy);
return withDirection(cmp, sortBy);
};
export const filterLeaves = (
leafIds: string[] = [],
leavesById: AwesomeTree["leavesById"],
filterPredicate: (item: AwesomeTreeLeaf) => boolean,
sortBy: SortBy = "status,asc",
) => {
let leaves = [...leafIds].map((leafId) => leavesById[leafId]);
if (filterPredicate) {
leaves = leaves.filter(filterPredicate);
}
const comparator = leafComparator(sortBy);
return leaves.sort(comparator);
};
/**
* Fills the given tree from generator and returns recursive tree which includes leaves data instead of their IDs
* Filters leaves when `filterOptions` property is provided
* @param payload
*/
export const createRecursiveTree = (payload: {
group: AwesomeTreeGroup;
groupsById: AwesomeTree["groupsById"];
leavesById: AwesomeTree["leavesById"];
filterPredicate: (item: AwesomeTreeLeaf) => boolean;
sortBy: SortBy;
}): AwesomeRecursiveTree => {
const { group, groupsById, leavesById, filterPredicate, sortBy } = payload;
const groupLeaves: string[] = group.leaves ?? [];
const leaves = filterLeaves(groupLeaves, leavesById, filterPredicate, sortBy);
const trees =
group.groups
?.flatMap((groupId) => {
const nestedGroup = groupsById[groupId];
if (!nestedGroup) {
return [];
}
return [
createRecursiveTree({
group: nestedGroup,
groupsById,
leavesById,
filterPredicate,
sortBy,
}),
];
})
?.filter((rt) => !isRecursiveTreeEmpty(rt)) ?? [];
const statistic: Statistic = emptyStatistic();
trees.forEach((rt: AwesomeRecursiveTree) => {
if (rt.statistic) {
const additional: Statistic = rt.statistic;
mergeStatistic(statistic, additional);
}
});
leaves.forEach((leaf) => {
const status: TestStatus = leaf.status;
incrementStatistic(statistic, status);
});
return {
...group,
statistic,
leaves,
trees: trees.sort(groupComparator(sortBy)),
};
};
export const isRecursiveTreeEmpty = (tree: AwesomeRecursiveTree): boolean => {
if (!tree.trees?.length && !tree.leaves?.length) {
return true;
}
if (tree.leaves?.length) {
return false;
}
return tree.trees?.every((subTree) => isRecursiveTreeEmpty(subTree));
};