@allurereport/web-classic
Version:
The static files for Allure Classic Report
140 lines (124 loc) • 4.79 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 { TreeFiltersState, TreeSortBy } from "@/stores/tree";
import type { AwesomeRecursiveTree, AwesomeTree, AwesomeTreeGroup, AwesomeTreeLeaf } from "../../types";
export const isIncluded = (leaf: TreeLeaf<AwesomeTreeLeaf>, filterOptions: TreeFiltersState) => {
const queryMatched = !filterOptions?.query || leaf.name.toLowerCase().includes(filterOptions.query.toLowerCase());
const statusMatched =
!filterOptions?.status || filterOptions?.status === "total" || leaf.status === filterOptions.status;
const flakyMatched = !filterOptions?.filter?.flaky || leaf.flaky;
const retryMatched = !filterOptions?.filter?.retry || leaf.retry;
// TODO: at this moment we don't have a new field implementation even in the generator
// const newMatched = !filterOptions?.filter?.new || leaf.new;
return [queryMatched, statusMatched, flakyMatched, retryMatched].every(Boolean);
};
const leafComparatorByTreeSortBy = (sortBy: TreeSortBy): Comparator<TreeLeaf<AwesomeTreeLeaf>> => {
const typedCompareBy = compareBy<TreeLeaf<AwesomeTreeLeaf>>;
switch (sortBy) {
case "order":
return typedCompareBy("groupOrder", ordinal());
case "duration":
return typedCompareBy("duration", ordinal());
case "alphabet":
return typedCompareBy("name", alphabetically());
case "status":
return typedCompareBy("status", byStatus());
}
};
const groupComparatorByTreeSortBy = (sortBy: TreeSortBy): Comparator<DefaultTreeGroup> => {
const typedCompareBy = compareBy<DefaultTreeGroup>;
switch (sortBy) {
case "alphabet":
return typedCompareBy("name", alphabetically());
case "order":
case "duration":
case "status":
return typedCompareBy("statistic", byStatistic());
}
};
export const leafComparator = (filterOptions: TreeFiltersState): Comparator<TreeLeaf<AwesomeTreeLeaf>> => {
const cmp = leafComparatorByTreeSortBy(filterOptions.sortBy);
const directional = filterOptions.direction === "asc" ? cmp : reverse(cmp);
// apply fallback sorting by name
return andThen([directional, compareBy("name", alphabetically())]);
};
export const groupComparator = (filterOptions: TreeFiltersState): Comparator<DefaultTreeGroup> => {
const cmp = groupComparatorByTreeSortBy(filterOptions.sortBy);
const directional = filterOptions.direction === "asc" ? cmp : reverse(cmp);
// apply fallback sorting by name
return andThen([directional, compareBy("name", alphabetically())]);
};
export const filterLeaves = (
leaves: string[] = [],
leavesById: AwesomeTree["leavesById"],
filterOptions: TreeFiltersState,
) => {
const filteredLeaves = [...leaves]
.map((leafId) => leavesById[leafId])
.filter((leaf: TreeLeaf<AwesomeTreeLeaf>) => isIncluded(leaf, filterOptions));
const comparator = leafComparator(filterOptions);
return filteredLeaves.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"];
filterOptions?: TreeFiltersState;
}): AwesomeRecursiveTree => {
const { group, groupsById, leavesById, filterOptions } = payload;
const groupLeaves: string[] = group.leaves ?? [];
const leaves = filterLeaves(groupLeaves, leavesById, filterOptions);
const trees =
group.groups
?.map((groupId) =>
createRecursiveTree({
group: groupsById[groupId],
groupsById,
leavesById,
filterOptions,
}),
)
?.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(filterOptions)),
};
};
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));
};