@allurereport/core-api 3.0.0-beta.10

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/README.md ADDED
@@ -0,0 +1,25 @@
1
+ # Core API
2
+
3
+ [<img src="https://allurereport.org/public/img/allure-report.svg" height="85px" alt="Allure Report logo" align="right" />](https://allurereport.org "Allure Report")
4
+
5
+ - Learn more about Allure Report at https://allurereport.org
6
+ - 📚 [Documentation](https://allurereport.org/docs/) – discover official documentation for Allure Report
7
+ - ❓ [Questions and Support](https://github.com/orgs/allure-framework/discussions/categories/questions-support) – get help from the team and community
8
+ - 📢 [Official announcements](https://github.com/orgs/allure-framework/discussions/categories/announcements) – be in touch with the latest updates
9
+ - 💬 [General Discussion ](https://github.com/orgs/allure-framework/discussions/categories/general-discussion) – engage in casual conversations, share insights and ideas with the community
10
+
11
+ ---
12
+
13
+ ## Overview
14
+
15
+ The collection of interfaces describing the core Allure Report entities.
16
+
17
+ ## Install
18
+
19
+ Use your favorite package manager to install the package:
20
+
21
+ ```shell
22
+ npm add @allurereport/core-api
23
+ yarn add @allurereport/core-api
24
+ pnpm add @allurereport/core-api
25
+ ```
@@ -0,0 +1,8 @@
1
+ export type Statistic = {
2
+ failed?: number;
3
+ broken?: number;
4
+ passed?: number;
5
+ skipped?: number;
6
+ unknown?: number;
7
+ total: number;
8
+ };
@@ -0,0 +1 @@
1
+ export {};
@@ -0,0 +1 @@
1
+ export type DefaultLabelsConfig = Record<string, string | string[]>;
package/dist/config.js ADDED
@@ -0,0 +1 @@
1
+ export {};
@@ -0,0 +1,21 @@
1
+ import type { Statistic } from "./aggregate.js";
2
+ import type { TestStatus } from "./model.js";
3
+ export declare const statusesList: TestStatus[];
4
+ export declare const unsuccessfulStatuses: Set<TestStatus>;
5
+ export declare const successfulStatuses: Set<TestStatus>;
6
+ export declare const includedInSuccessRate: Set<TestStatus>;
7
+ export declare const filterByStatus: <T extends {
8
+ status: TestStatus;
9
+ }>(statuses: Iterable<TestStatus>) => (t: T) => boolean;
10
+ export declare const filterSuccessful: (t: {
11
+ status: TestStatus;
12
+ }) => boolean;
13
+ export declare const filterUnsuccessful: (t: {
14
+ status: TestStatus;
15
+ }) => boolean;
16
+ export declare const filterIncludedInSuccessRate: (t: {
17
+ status: TestStatus;
18
+ }) => boolean;
19
+ export declare const emptyStatistic: () => Statistic;
20
+ export declare const incrementStatistic: (statistic: Statistic, status: TestStatus, count?: number) => void;
21
+ export declare const mergeStatistic: (statistic: Statistic, additional: Statistic) => void;
@@ -0,0 +1,23 @@
1
+ export const statusesList = ["failed", "broken", "passed", "skipped", "unknown"];
2
+ export const unsuccessfulStatuses = new Set(["failed", "broken"]);
3
+ export const successfulStatuses = new Set(["passed"]);
4
+ export const includedInSuccessRate = new Set([...unsuccessfulStatuses, ...successfulStatuses]);
5
+ export const filterByStatus = (statuses) => {
6
+ const set = new Set(statuses);
7
+ return (t) => set.has(t.status);
8
+ };
9
+ export const filterSuccessful = filterByStatus(successfulStatuses);
10
+ export const filterUnsuccessful = filterByStatus(unsuccessfulStatuses);
11
+ export const filterIncludedInSuccessRate = filterByStatus(includedInSuccessRate);
12
+ export const emptyStatistic = () => ({ total: 0 });
13
+ export const incrementStatistic = (statistic, status, count = 1) => {
14
+ statistic[status] = (statistic[status] ?? 0) + count;
15
+ statistic.total += count;
16
+ };
17
+ export const mergeStatistic = (statistic, additional) => {
18
+ statusesList.forEach((status) => {
19
+ if (additional[status]) {
20
+ incrementStatistic(statistic, status, additional[status]);
21
+ }
22
+ });
23
+ };
@@ -0,0 +1,19 @@
1
+ import type { TestLabel } from "./metadata.js";
2
+ import type { TestResult } from "./model.js";
3
+ export interface EnvironmentItem {
4
+ name: string;
5
+ values: string[];
6
+ }
7
+ export type ReportVariables = Record<string, string>;
8
+ export type EnvironmentMatcherPayload = {
9
+ labels: TestLabel[];
10
+ };
11
+ export type EnvironmentDescriptor = {
12
+ variables?: ReportVariables;
13
+ matcher: (payload: EnvironmentMatcherPayload) => boolean;
14
+ };
15
+ export type EnvironmentsConfig = Record<string, EnvironmentDescriptor>;
16
+ export type EnvTestGroup = Pick<TestResult, "fullName" | "name" | "status"> & {
17
+ id: string;
18
+ testResultsByEnv: Record<string, TestResult>;
19
+ };
@@ -0,0 +1 @@
1
+ export {};
@@ -0,0 +1,19 @@
1
+ import type { TestError, TestStatus } from "./model.js";
2
+ export interface HistoryTestResult {
3
+ id: string;
4
+ name: string;
5
+ fullName?: string;
6
+ status: TestStatus;
7
+ error?: TestError;
8
+ start?: number;
9
+ stop?: number;
10
+ duration?: number;
11
+ }
12
+ export interface HistoryDataPoint {
13
+ uuid: string;
14
+ name: string;
15
+ timestamp: number;
16
+ knownTestCaseIds: string[];
17
+ testResults: Record<string, HistoryTestResult>;
18
+ metrics: Record<string, number>;
19
+ }
@@ -0,0 +1 @@
1
+ export {};
@@ -0,0 +1,19 @@
1
+ export type * from "./aggregate.js";
2
+ export * from "./constants.js";
3
+ export type * from "./environment.js";
4
+ export type * from "./history.js";
5
+ export type * from "./known.js";
6
+ export type * from "./metadata.js";
7
+ export type * from "./model.js";
8
+ export type * from "./testCase.js";
9
+ export type * from "./testPlan.js";
10
+ export type * from "./config.js";
11
+ export * from "./utils/step.js";
12
+ export type * from "./utils/tree.js";
13
+ export * from "./utils/time.js";
14
+ export * from "./utils/comparator.js";
15
+ export * from "./utils/predicate.js";
16
+ export * from "./utils/label.js";
17
+ export * from "./utils/testplan.js";
18
+ export * from "./utils/status.js";
19
+ export * from "./utils/environment.js";
package/dist/index.js ADDED
@@ -0,0 +1,9 @@
1
+ export * from "./constants.js";
2
+ export * from "./utils/step.js";
3
+ export * from "./utils/time.js";
4
+ export * from "./utils/comparator.js";
5
+ export * from "./utils/predicate.js";
6
+ export * from "./utils/label.js";
7
+ export * from "./utils/testplan.js";
8
+ export * from "./utils/status.js";
9
+ export * from "./utils/environment.js";
@@ -0,0 +1,8 @@
1
+ import type { TestLink } from "./metadata.js";
2
+ import type { TestError } from "./model.js";
3
+ export interface KnownTestFailure {
4
+ historyId: string;
5
+ issues?: TestLink[];
6
+ comment?: string;
7
+ error?: TestError;
8
+ }
package/dist/known.js ADDED
@@ -0,0 +1 @@
1
+ export {};
@@ -0,0 +1,16 @@
1
+ export interface TestLabel {
2
+ name: string;
3
+ value?: string;
4
+ }
5
+ export interface TestLink {
6
+ name?: string;
7
+ url: string;
8
+ type?: string;
9
+ }
10
+ export interface TestParameter {
11
+ name: string;
12
+ value: string;
13
+ hidden: boolean;
14
+ excluded: boolean;
15
+ masked: boolean;
16
+ }
@@ -0,0 +1 @@
1
+ export {};
@@ -0,0 +1,102 @@
1
+ import type { TestLabel, TestLink, TestParameter } from "./metadata.js";
2
+ import type { TestCase } from "./testCase.js";
3
+ export type TestStatus = "failed" | "broken" | "passed" | "skipped" | "unknown";
4
+ export interface SourceMetadata {
5
+ readerId: string;
6
+ metadata: {
7
+ [key: string]: any;
8
+ };
9
+ }
10
+ export interface TestError {
11
+ message?: string;
12
+ trace?: string;
13
+ actual?: string;
14
+ expected?: string;
15
+ }
16
+ export interface TestResult {
17
+ id: string;
18
+ name: string;
19
+ status: TestStatus;
20
+ error?: TestError;
21
+ testCase?: TestCase;
22
+ environment?: string;
23
+ fullName?: string;
24
+ historyId?: string;
25
+ description?: string;
26
+ descriptionHtml?: string;
27
+ precondition?: string;
28
+ preconditionHtml?: string;
29
+ expectedResult?: string;
30
+ expectedResultHtml?: string;
31
+ start?: number;
32
+ stop?: number;
33
+ duration?: number;
34
+ flaky: boolean;
35
+ muted: boolean;
36
+ known: boolean;
37
+ hidden: boolean;
38
+ hostId?: string;
39
+ threadId?: string;
40
+ labels: TestLabel[];
41
+ parameters: TestParameter[];
42
+ links: TestLink[];
43
+ steps: TestStepResult[];
44
+ sourceMetadata: SourceMetadata;
45
+ runSelector?: string;
46
+ retries?: TestResult[];
47
+ categories?: any;
48
+ }
49
+ export interface TestFixtureResult {
50
+ id: string;
51
+ testResultIds: string[];
52
+ type: "before" | "after";
53
+ name: string;
54
+ status: TestStatus;
55
+ error?: TestError;
56
+ start?: number;
57
+ stop?: number;
58
+ duration?: number;
59
+ steps: TestStepResult[];
60
+ sourceMetadata: SourceMetadata;
61
+ }
62
+ export type TestStepResult = DefaultTestStepResult | AttachmentTestStepResult;
63
+ export interface DefaultTestStepResult {
64
+ name: string;
65
+ parameters: TestParameter[];
66
+ status: TestStatus;
67
+ error?: TestError;
68
+ start?: number;
69
+ stop?: number;
70
+ duration?: number;
71
+ steps: TestStepResult[];
72
+ stepId?: string;
73
+ type: "step";
74
+ }
75
+ export interface AttachmentLinkFile {
76
+ id: string;
77
+ contentType?: string;
78
+ contentLength?: number;
79
+ originalFileName: string;
80
+ ext: string;
81
+ used: false;
82
+ missed: false;
83
+ }
84
+ export interface AttachmentLinkExpected {
85
+ id: string;
86
+ name: string;
87
+ contentType?: string;
88
+ originalFileName: string;
89
+ ext: string;
90
+ used: true;
91
+ missed: true;
92
+ }
93
+ export type AttachmentLinkLinked = Omit<AttachmentLinkFile, "used"> & Omit<AttachmentLinkExpected, "missed">;
94
+ export type AttachmentLinkInvalid = Omit<AttachmentLinkExpected, "originalFileName" | "ext"> & {
95
+ originalFileName: undefined;
96
+ ext: "";
97
+ };
98
+ export type AttachmentLink = AttachmentLinkFile | AttachmentLinkExpected | AttachmentLinkLinked | AttachmentLinkInvalid;
99
+ export interface AttachmentTestStepResult {
100
+ link: AttachmentLinkExpected | AttachmentLinkLinked | AttachmentLinkInvalid;
101
+ type: "attachment";
102
+ }
package/dist/model.js ADDED
@@ -0,0 +1 @@
1
+ export {};
@@ -0,0 +1,6 @@
1
+ export interface TestCase {
2
+ id: string;
3
+ allureId?: string;
4
+ name: string;
5
+ fullName?: string;
6
+ }
@@ -0,0 +1 @@
1
+ export {};
@@ -0,0 +1,8 @@
1
+ export interface TestPlanTest {
2
+ id?: string;
3
+ selector?: string;
4
+ }
5
+ export interface TestPlan {
6
+ version: "1.0";
7
+ tests: TestPlanTest[];
8
+ }
@@ -0,0 +1 @@
1
+ export {};
@@ -0,0 +1,19 @@
1
+ import type { Statistic } from "../aggregate.js";
2
+ import type { TestStatus } from "../model.js";
3
+ export type SortFunction<T> = () => Comparator<T>;
4
+ export type Comparator<T> = (a: T, b: T) => number;
5
+ type Value<T, P> = T extends any ? (P extends keyof T ? T[P] : P extends "" ? T : never) : never;
6
+ export declare const reverse: <T>(comparator: Comparator<T>) => Comparator<T>;
7
+ export declare const nullsLast: <T extends {}>(compare: Comparator<T>) => Comparator<T | undefined>;
8
+ export declare const nullsFirst: <T extends {}>(compare: Comparator<T>) => Comparator<T | undefined>;
9
+ export declare const nullsDefault: <T extends {}>(compare: Comparator<T>, defaultValue: T) => Comparator<T | undefined>;
10
+ export declare const compareBy: <T extends Record<string, any> = {}, P extends keyof T = keyof T>(property: P, compare: Comparator<Value<T, P>>, defaultValue?: T[P]) => Comparator<T>;
11
+ export declare const andThen: <T>(comparators: Comparator<T>[]) => Comparator<T>;
12
+ export declare const alphabetically: SortFunction<string | undefined>;
13
+ export declare const ordinal: SortFunction<number | undefined>;
14
+ export declare const byStatus: SortFunction<TestStatus | undefined>;
15
+ export declare const byStatistic: SortFunction<Statistic | undefined>;
16
+ export declare const byName: SortFunction<Partial<{
17
+ name: string;
18
+ }> | undefined>;
19
+ export {};
@@ -0,0 +1,47 @@
1
+ import { statusesList } from "../constants.js";
2
+ export const reverse = (comparator) => {
3
+ return (a, b) => comparator(b, a);
4
+ };
5
+ export const nullsLast = (compare) => {
6
+ return (a, b) => a === b ? 0 : a === undefined || a === null ? 1 : b === undefined || b === null ? -1 : compare(a, b);
7
+ };
8
+ export const nullsFirst = (compare) => {
9
+ return (a, b) => a === b ? 0 : a === undefined || a === null ? -1 : b === undefined || b === null ? 1 : compare(a, b);
10
+ };
11
+ export const nullsDefault = (compare, defaultValue) => {
12
+ return (a, b) => compare(a ?? defaultValue, b ?? defaultValue);
13
+ };
14
+ export const compareBy = (property, compare, defaultValue) => {
15
+ return nullsLast((a, b) => {
16
+ if (defaultValue !== undefined) {
17
+ return compare(a[property] ?? defaultValue, b[property] ?? defaultValue);
18
+ }
19
+ if (property in a && property in b) {
20
+ return compare(a[property], b[property]);
21
+ }
22
+ return 0;
23
+ });
24
+ };
25
+ export const andThen = (comparators) => {
26
+ return (a, b) => {
27
+ for (const compare of comparators) {
28
+ const res = compare(a, b);
29
+ if (res !== 0) {
30
+ return res;
31
+ }
32
+ }
33
+ return 0;
34
+ };
35
+ };
36
+ export const alphabetically = () => nullsLast((a, b) => a.localeCompare(b));
37
+ export const ordinal = () => nullsLast((a, b) => a - b);
38
+ export const byStatus = () => {
39
+ return nullsLast((a, b) => {
40
+ return statusesList.indexOf(a) - statusesList.indexOf(b);
41
+ });
42
+ };
43
+ export const byStatistic = () => {
44
+ const compares = statusesList.map((status) => compareBy(status, reverse(ordinal()), 0));
45
+ return nullsLast(andThen(compares));
46
+ };
47
+ export const byName = () => nullsLast(compareBy("name", alphabetically()));
@@ -0,0 +1,3 @@
1
+ import type { EnvironmentsConfig } from "../environment.js";
2
+ import type { TestResult } from "../model.js";
3
+ export declare const matchEnvironment: (envConfig: EnvironmentsConfig, tr: TestResult) => string;
@@ -0,0 +1,3 @@
1
+ export const matchEnvironment = (envConfig, tr) => {
2
+ return Object.entries(envConfig).find(([, { matcher }]) => matcher({ labels: tr.labels }))?.[0] ?? "default";
3
+ };
@@ -0,0 +1,2 @@
1
+ import type { TestLabel } from "../index.js";
2
+ export declare const findByLabelName: (labels: TestLabel[], name: string) => string | undefined;
@@ -0,0 +1,3 @@
1
+ export const findByLabelName = (labels, name) => {
2
+ return labels.find((label) => label.name === name)?.value;
3
+ };
@@ -0,0 +1 @@
1
+ export declare const notNull: <T>(value: T) => value is NonNullable<T>;
@@ -0,0 +1 @@
1
+ export const notNull = (value) => !!value;
@@ -0,0 +1,4 @@
1
+ import type { TestStatus } from "../model.js";
2
+ export declare const StatusByPriority: TestStatus[];
3
+ export declare const statusToPriority: (status: TestStatus | undefined) => number;
4
+ export declare const getWorstStatus: (items: TestStatus[]) => TestStatus | undefined;
@@ -0,0 +1,13 @@
1
+ export const StatusByPriority = ["failed", "broken", "passed", "skipped", "unknown"];
2
+ export const statusToPriority = (status) => {
3
+ if (!status) {
4
+ return -1;
5
+ }
6
+ return StatusByPriority.indexOf(status);
7
+ };
8
+ export const getWorstStatus = (items) => {
9
+ if (items.length === 0) {
10
+ return;
11
+ }
12
+ return items.sort((a, b) => statusToPriority(a) - statusToPriority(b))[0];
13
+ };
@@ -0,0 +1,3 @@
1
+ import type { AttachmentTestStepResult, DefaultTestStepResult, TestStepResult } from "../model.js";
2
+ export declare const isStep: (result: TestStepResult) => result is DefaultTestStepResult;
3
+ export declare const isAttachment: (result: TestStepResult) => result is AttachmentTestStepResult;
@@ -0,0 +1,6 @@
1
+ export const isStep = (result) => {
2
+ return result.type === "step";
3
+ };
4
+ export const isAttachment = (result) => {
5
+ return result.type === "attachment";
6
+ };
@@ -0,0 +1,2 @@
1
+ import type { TestPlan, TestResult } from "../index.js";
2
+ export declare const createTestPlan: (testResults: TestResult[]) => TestPlan;
@@ -0,0 +1,13 @@
1
+ import { findByLabelName } from "./label.js";
2
+ export const createTestPlan = (testResults) => {
3
+ const seenIds = new Set();
4
+ const seenSelectors = new Set();
5
+ const tests = testResults
6
+ .map((tr) => ({ selector: tr.runSelector ?? tr.fullName, id: findByLabelName(tr.labels, "ALLURE_ID") }))
7
+ .filter((value) => (value.selector && (seenSelectors.has(value.selector) ? false : !!seenSelectors.add(value.selector))) ||
8
+ (value.id && (seenIds.has(value.id) ? false : !!seenSelectors.add(value.id))));
9
+ return {
10
+ version: "1.0",
11
+ tests,
12
+ };
13
+ };
@@ -0,0 +1 @@
1
+ export declare const formatDuration: (duration?: number) => string;
@@ -0,0 +1,42 @@
1
+ const times = [
2
+ {
3
+ suffix: "d",
4
+ accessor: (duration) => Math.floor(duration / (24 * 3600 * 1000)),
5
+ },
6
+ {
7
+ suffix: "h",
8
+ accessor: (duration) => Math.floor(duration / (3600 * 1000)) % 24,
9
+ },
10
+ {
11
+ suffix: "m",
12
+ accessor: (duration) => Math.floor(duration / (60 * 1000)) % 60,
13
+ },
14
+ {
15
+ suffix: "s",
16
+ accessor: (duration) => Math.floor(duration / 1000) % 60,
17
+ },
18
+ {
19
+ suffix: "ms",
20
+ accessor: (duration) => Math.round(duration) % 1000,
21
+ },
22
+ ];
23
+ export const formatDuration = (duration) => {
24
+ if (duration === undefined) {
25
+ return "unknown";
26
+ }
27
+ if (duration < 0.5) {
28
+ return "0s";
29
+ }
30
+ const res = [];
31
+ for (const { accessor, suffix } of times) {
32
+ const value = accessor(duration);
33
+ if (res.length === 0 && !value) {
34
+ continue;
35
+ }
36
+ res.push(value + suffix);
37
+ if (res.length > 1) {
38
+ break;
39
+ }
40
+ }
41
+ return res.join(" ");
42
+ };
@@ -0,0 +1,22 @@
1
+ import type { Statistic } from "../aggregate.js";
2
+ import type { TestResult } from "../model.js";
3
+ type TreeNode<T> = Omit<T, "nodeId"> & {
4
+ nodeId: string;
5
+ };
6
+ export interface WithChildren {
7
+ groups?: string[];
8
+ leaves?: string[];
9
+ }
10
+ export type TreeGroup<T> = TreeNode<T> & WithChildren;
11
+ export type TreeLeaf<T> = TreeNode<T>;
12
+ export type TreeData<L, G> = {
13
+ root: WithChildren;
14
+ leavesById: Record<string, TreeLeaf<L>>;
15
+ groupsById: Record<string, TreeGroup<G>>;
16
+ };
17
+ export type DefaultTreeLeaf = Pick<TestResult, "name" | "status" | "duration">;
18
+ export type DefaultTreeGroup = {
19
+ name: string;
20
+ statistic: Statistic;
21
+ };
22
+ export {};
@@ -0,0 +1 @@
1
+ export {};
package/package.json ADDED
@@ -0,0 +1,48 @@
1
+ {
2
+ "name": "@allurereport/core-api",
3
+ "version": "3.0.0-beta.10",
4
+ "description": "Allure Core API",
5
+ "keywords": [
6
+ "allure"
7
+ ],
8
+ "repository": "https://github.com/allure-framework/allure3",
9
+ "license": "Apache-2.0",
10
+ "author": "Qameta Software",
11
+ "type": "module",
12
+ "exports": {
13
+ ".": "./dist/index.js"
14
+ },
15
+ "main": "./dist/index.js",
16
+ "module": "./dist/index.js",
17
+ "types": "./dist/index.d.ts",
18
+ "files": [
19
+ "dist"
20
+ ],
21
+ "scripts": {
22
+ "build": "run clean && tsc --project ./tsconfig.json",
23
+ "clean": "rimraf ./dist",
24
+ "eslint": "eslint ./src/**/*.{js,jsx,ts,tsx}",
25
+ "eslint:format": "eslint --fix ./src/**/*.{js,jsx,ts,tsx}",
26
+ "test": "rimraf ./out && vitest run"
27
+ },
28
+ "devDependencies": {
29
+ "@stylistic/eslint-plugin": "^2.6.1",
30
+ "@types/eslint": "^8.56.11",
31
+ "@types/node": "^20.17.9",
32
+ "@typescript-eslint/eslint-plugin": "^8.0.0",
33
+ "@typescript-eslint/parser": "^8.0.0",
34
+ "@vitest/runner": "^2.1.8",
35
+ "@vitest/snapshot": "^2.1.8",
36
+ "allure-vitest": "^3.0.9",
37
+ "eslint": "^8.57.0",
38
+ "eslint-config-prettier": "^9.1.0",
39
+ "eslint-plugin-import": "^2.29.1",
40
+ "eslint-plugin-jsdoc": "^50.0.0",
41
+ "eslint-plugin-n": "^17.10.1",
42
+ "eslint-plugin-no-null": "^1.0.2",
43
+ "eslint-plugin-prefer-arrow": "^1.2.3",
44
+ "rimraf": "^6.0.1",
45
+ "typescript": "^5.6.3",
46
+ "vitest": "^2.1.8"
47
+ }
48
+ }