qase-report 1.0.0

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.
@@ -0,0 +1,43 @@
1
+ import { z } from 'zod';
2
+ /**
3
+ * Schema for attachment files referenced in test results and steps.
4
+ * Attachments can be screenshots, videos, logs, or other files
5
+ * generated during test execution.
6
+ */
7
+ export const AttachmentSchema = z
8
+ .object({
9
+ /**
10
+ * Unique identifier for the attachment
11
+ */
12
+ id: z.string(),
13
+ /**
14
+ * Original filename (e.g., "screenshot.png").
15
+ * Optional — derived from file_path when not provided by reporter.
16
+ */
17
+ file_name: z.string().optional(),
18
+ /**
19
+ * Relative path to the attachment file
20
+ * (e.g., "./build/qase-report/attachments/abc-123.png")
21
+ */
22
+ file_path: z.string(),
23
+ /**
24
+ * MIME type of the attachment (e.g., "image/png", "video/mp4")
25
+ */
26
+ mime_type: z.string().optional(),
27
+ /**
28
+ * File size in bytes (optional)
29
+ */
30
+ size: z.number().optional(),
31
+ /**
32
+ * Base64-encoded content for inline attachments (optional, nullable)
33
+ */
34
+ content: z.string().nullable().optional(),
35
+ /**
36
+ * Whether this is a temporary attachment (optional)
37
+ */
38
+ temporary: z.boolean().optional(),
39
+ })
40
+ .transform(att => ({
41
+ ...att,
42
+ file_name: att.file_name ?? att.file_path.split('/').pop() ?? 'unknown',
43
+ }));
@@ -0,0 +1,147 @@
1
+ import { z } from 'zod';
2
+ /**
3
+ * Enum for test execution status in historical data.
4
+ * Matches TestStatusEnum from QaseTestResult.schema.ts
5
+ */
6
+ const TestStatusEnum = z.enum(['passed', 'failed', 'skipped', 'broken', 'blocked', 'invalid', 'muted']);
7
+ /**
8
+ * Statistical summary of test run results.
9
+ * Simplified version for historical data storage.
10
+ */
11
+ const HistoricalRunStatsSchema = z.object({
12
+ /**
13
+ * Total number of tests
14
+ */
15
+ total: z.number(),
16
+ /**
17
+ * Number of passed tests
18
+ */
19
+ passed: z.number(),
20
+ /**
21
+ * Number of failed tests
22
+ */
23
+ failed: z.number(),
24
+ /**
25
+ * Number of skipped tests
26
+ */
27
+ skipped: z.number(),
28
+ /**
29
+ * Number of blocked tests (optional)
30
+ */
31
+ blocked: z.number().optional(),
32
+ /**
33
+ * Number of invalid tests (optional)
34
+ */
35
+ invalid: z.number().optional(),
36
+ /**
37
+ * Number of muted tests (optional)
38
+ */
39
+ muted: z.number().optional(),
40
+ });
41
+ /**
42
+ * Summary data for each historical test run.
43
+ * Contains run-level metadata and statistics for tiered loading.
44
+ */
45
+ export const HistoricalRunSchema = z.object({
46
+ /**
47
+ * Unique identifier for this run (can be timestamp or UUID)
48
+ */
49
+ run_id: z.string(),
50
+ /**
51
+ * Run title (optional, nullable)
52
+ */
53
+ title: z.string().nullable().optional(),
54
+ /**
55
+ * Environment where tests ran (optional, nullable)
56
+ */
57
+ environment: z.string().nullable().optional(),
58
+ /**
59
+ * Unix timestamp when run started (milliseconds)
60
+ */
61
+ start_time: z.number(),
62
+ /**
63
+ * Unix timestamp when run ended (milliseconds)
64
+ */
65
+ end_time: z.number().nullable(),
66
+ /**
67
+ * Total duration of the run in milliseconds
68
+ */
69
+ duration: z.number(),
70
+ /**
71
+ * Statistical summary of run results
72
+ */
73
+ stats: HistoricalRunStatsSchema,
74
+ });
75
+ /**
76
+ * Per-test run data for historical tracking.
77
+ * Contains status and timing for a single test execution in a specific run.
78
+ */
79
+ export const HistoricalTestRunDataSchema = z.object({
80
+ /**
81
+ * Reference to HistoricalRunSchema.run_id
82
+ */
83
+ run_id: z.string(),
84
+ /**
85
+ * Test execution status
86
+ */
87
+ status: TestStatusEnum,
88
+ /**
89
+ * Test duration in milliseconds
90
+ */
91
+ duration: z.number(),
92
+ /**
93
+ * Unix timestamp when test started (milliseconds)
94
+ */
95
+ start_time: z.number(),
96
+ /**
97
+ * First line of error message or stacktrace (nullable).
98
+ * Used for flakiness detection - consistent errors vs random failures.
99
+ */
100
+ error_message: z.string().nullable(),
101
+ });
102
+ /**
103
+ * Per-test historical summary across runs.
104
+ * Uses signature-based identity for stable tracking across runs.
105
+ */
106
+ export const HistoricalTestResultSchema = z.object({
107
+ /**
108
+ * Test signature (stable identifier, not run-specific UUID).
109
+ * Matches signature field from QaseTestResult.
110
+ */
111
+ signature: z.string(),
112
+ /**
113
+ * Test case title
114
+ */
115
+ title: z.string(),
116
+ /**
117
+ * Array of run data for this test.
118
+ * Each entry represents one execution of this test in a historical run.
119
+ */
120
+ runs: z.array(HistoricalTestRunDataSchema),
121
+ });
122
+ /**
123
+ * Root schema for test-history.json file.
124
+ * Contains versioned history data with run summaries and per-test results.
125
+ *
126
+ * Schema versioning uses SchemaVer format (MODEL-REVISION-ADDITION):
127
+ * - MODEL: Breaking changes requiring migration
128
+ * - REVISION: Backward-compatible additions
129
+ * - ADDITION: Minor fixes or metadata updates
130
+ */
131
+ export const QaseHistorySchema = z.object({
132
+ /**
133
+ * Schema version for future migration support.
134
+ * Format: SchemaVer (MODEL-REVISION-ADDITION), e.g., "1.0.0"
135
+ */
136
+ schema_version: z.string().default('1.0.0'),
137
+ /**
138
+ * Array of historical run summaries.
139
+ * Contains high-level metadata and stats for tiered loading.
140
+ */
141
+ runs: z.array(HistoricalRunSchema),
142
+ /**
143
+ * Array of per-test historical results.
144
+ * Contains detailed run history for each test by signature.
145
+ */
146
+ tests: z.array(HistoricalTestResultSchema),
147
+ });
@@ -0,0 +1,146 @@
1
+ import { z } from 'zod';
2
+ /**
3
+ * Execution timing information for the test run.
4
+ */
5
+ const RunExecutionSchema = z.object({
6
+ /**
7
+ * Unix timestamp when run started (milliseconds)
8
+ */
9
+ start_time: z.number(),
10
+ /**
11
+ * Unix timestamp when run ended (milliseconds)
12
+ */
13
+ end_time: z.number().nullable(),
14
+ /**
15
+ * Total duration of the run in milliseconds
16
+ */
17
+ duration: z.number(),
18
+ /**
19
+ * Cumulative duration of all test executions in milliseconds
20
+ */
21
+ cumulative_duration: z.number(),
22
+ });
23
+ /**
24
+ * Statistical summary of test run results.
25
+ */
26
+ const RunStatsSchema = z.object({
27
+ /**
28
+ * Total number of tests
29
+ */
30
+ total: z.number(),
31
+ /**
32
+ * Number of passed tests
33
+ */
34
+ passed: z.number(),
35
+ /**
36
+ * Number of failed tests
37
+ */
38
+ failed: z.number(),
39
+ /**
40
+ * Number of skipped tests
41
+ */
42
+ skipped: z.number(),
43
+ /**
44
+ * Number of broken tests
45
+ */
46
+ broken: z.number().optional(),
47
+ /**
48
+ * Number of blocked tests
49
+ */
50
+ blocked: z.number().optional(),
51
+ /**
52
+ * Number of invalid tests
53
+ */
54
+ invalid: z.number().optional(),
55
+ /**
56
+ * Number of muted tests
57
+ */
58
+ muted: z.number().optional(),
59
+ });
60
+ /**
61
+ * Summary information for individual test results.
62
+ */
63
+ const ResultSummarySchema = z.object({
64
+ /**
65
+ * Test result ID (matches filename in results/ directory)
66
+ */
67
+ id: z.string(),
68
+ /**
69
+ * Test title
70
+ */
71
+ title: z.string(),
72
+ /**
73
+ * Test execution status
74
+ */
75
+ status: z.string(),
76
+ /**
77
+ * Test duration in milliseconds
78
+ */
79
+ duration: z.number(),
80
+ /**
81
+ * Thread where test ran (nullable)
82
+ */
83
+ thread: z.string().nullable(),
84
+ });
85
+ /**
86
+ * Host system information where tests were executed.
87
+ * Fields vary depending on the reporter (Python vs JavaScript).
88
+ */
89
+ const HostDataSchema = z
90
+ .object({
91
+ node: z.string().optional(),
92
+ system: z.string().optional(),
93
+ release: z.string().optional(),
94
+ version: z.string().optional(),
95
+ machine: z.string().optional(),
96
+ arch: z.string().optional(),
97
+ machineName: z.string().optional(),
98
+ python: z.string().optional(),
99
+ pip: z.string().optional(),
100
+ npm: z.string().optional(),
101
+ framework: z.string().optional(),
102
+ reporter: z.string().optional(),
103
+ commons: z.string().optional(),
104
+ apiClientV1: z.string().optional(),
105
+ apiClientV2: z.string().optional(),
106
+ })
107
+ .passthrough();
108
+ /**
109
+ * Schema for run.json file.
110
+ * Contains metadata about the test run, summary statistics,
111
+ * and references to individual test results.
112
+ */
113
+ export const QaseRunSchema = z.object({
114
+ /**
115
+ * Run title (optional - may not be present in all formats)
116
+ */
117
+ title: z.string().optional(),
118
+ /**
119
+ * Environment where tests ran (optional, nullable)
120
+ */
121
+ environment: z.string().nullable().optional(),
122
+ /**
123
+ * Execution timing information
124
+ */
125
+ execution: RunExecutionSchema,
126
+ /**
127
+ * Statistical summary of results
128
+ */
129
+ stats: RunStatsSchema,
130
+ /**
131
+ * Array of test result summaries
132
+ */
133
+ results: z.array(ResultSummarySchema),
134
+ /**
135
+ * List of threads used for execution
136
+ */
137
+ threads: z.array(z.string()).optional(),
138
+ /**
139
+ * List of test suites in this run
140
+ */
141
+ suites: z.array(z.string()).optional(),
142
+ /**
143
+ * Host system information
144
+ */
145
+ host_data: HostDataSchema.optional(),
146
+ });
@@ -0,0 +1,122 @@
1
+ import { z } from 'zod';
2
+ import { AttachmentSchema } from './Attachment.schema.js';
3
+ import { StepSchema } from './Step.schema.js';
4
+ /**
5
+ * Enum for test execution status.
6
+ * - passed: Test completed successfully
7
+ * - failed: Test failed with assertion errors
8
+ * - skipped: Test was skipped
9
+ * - broken: Test encountered errors preventing execution
10
+ * - blocked: Test blocked by external dependency
11
+ * - invalid: Test has invalid configuration
12
+ * - muted: Test failures are muted/ignored
13
+ */
14
+ const TestStatusEnum = z.enum(['passed', 'failed', 'skipped', 'broken', 'blocked', 'invalid', 'muted']);
15
+ /**
16
+ * Execution information for a test result.
17
+ */
18
+ const TestExecutionSchema = z.object({
19
+ /**
20
+ * Test execution status
21
+ */
22
+ status: TestStatusEnum,
23
+ /**
24
+ * Unix timestamp when test started (milliseconds)
25
+ */
26
+ start_time: z.number(),
27
+ /**
28
+ * Unix timestamp when test ended (milliseconds)
29
+ */
30
+ end_time: z.number().nullable(),
31
+ /**
32
+ * Duration in milliseconds
33
+ */
34
+ duration: z.number(),
35
+ /**
36
+ * Stack trace if test failed (nullable)
37
+ */
38
+ stacktrace: z.string().nullable().optional(),
39
+ /**
40
+ * Thread identifier where test ran (nullable)
41
+ */
42
+ thread: z.string().nullable(),
43
+ });
44
+ /**
45
+ * Relations metadata for test result.
46
+ * Contains suite hierarchy information.
47
+ */
48
+ const TestRelationsSchema = z
49
+ .object({
50
+ suite: z.object({
51
+ data: z.array(z.object({
52
+ /**
53
+ * Suite title
54
+ */
55
+ title: z.string(),
56
+ /**
57
+ * Public ID from Qase TMS (nullable)
58
+ */
59
+ public_id: z.number().nullable().optional(),
60
+ })),
61
+ }),
62
+ })
63
+ .nullable();
64
+ /**
65
+ * Schema for individual test result file (results/{uuid}.json).
66
+ * Contains complete test execution data including steps, attachments,
67
+ * parameters, and metadata.
68
+ */
69
+ export const TestResultSchema = z.object({
70
+ /**
71
+ * Unique identifier for this test result
72
+ */
73
+ id: z.string(),
74
+ /**
75
+ * Test case title
76
+ */
77
+ title: z.string(),
78
+ /**
79
+ * Test signature (unique identifier for test case)
80
+ */
81
+ signature: z.string(),
82
+ /**
83
+ * Whether test failures are muted/ignored
84
+ */
85
+ muted: z.boolean(),
86
+ /**
87
+ * Execution information (status, timing, stack trace)
88
+ */
89
+ execution: TestExecutionSchema,
90
+ /**
91
+ * Test result message (nullable)
92
+ */
93
+ message: z.string().nullable().optional(),
94
+ /**
95
+ * Relations to suite hierarchy (nullable)
96
+ */
97
+ relations: TestRelationsSchema,
98
+ /**
99
+ * Array of test steps (can be nested)
100
+ */
101
+ steps: z.array(StepSchema),
102
+ /**
103
+ * Attachments for this test
104
+ */
105
+ attachments: z.array(AttachmentSchema),
106
+ /**
107
+ * Test parameters (key-value pairs)
108
+ */
109
+ params: z.record(z.string(), z.string()),
110
+ /**
111
+ * Parameter groups for parameterized tests
112
+ */
113
+ param_groups: z.array(z.array(z.string())),
114
+ /**
115
+ * Custom fields (key-value pairs, values can be null)
116
+ */
117
+ fields: z.record(z.string(), z.string().nullable()),
118
+ /**
119
+ * Qase TMS test case IDs (optional, nullable)
120
+ */
121
+ testops_ids: z.array(z.number()).nullable().optional(),
122
+ });
@@ -0,0 +1,87 @@
1
+ import { z } from 'zod';
2
+ import { AttachmentSchema } from './Attachment.schema.js';
3
+ /**
4
+ * Step type - flexible to handle various step types from different reporters.
5
+ * Common values: text, request, assertion, gherkin, action
6
+ */
7
+ const StepTypeSchema = z.string();
8
+ /**
9
+ * Step execution status - flexible to handle various statuses.
10
+ * Common values: passed, failed, skipped, broken, pending
11
+ */
12
+ const StepStatusSchema = z.string();
13
+ /**
14
+ * Data associated with a test step.
15
+ * All fields are optional to handle various reporter formats.
16
+ */
17
+ const StepDataSchema = z.object({
18
+ /**
19
+ * Action performed in this step (optional)
20
+ */
21
+ action: z.string().optional(),
22
+ /**
23
+ * Expected result for this step (optional, nullable)
24
+ */
25
+ expected_result: z.string().nullable().optional(),
26
+ /**
27
+ * Input data used in this step (optional, nullable)
28
+ */
29
+ input_data: z.string().nullable().optional(),
30
+ });
31
+ /**
32
+ * Execution information for a step.
33
+ */
34
+ const StepExecutionSchema = z.object({
35
+ /**
36
+ * Execution status (passed, failed, skipped, broken, etc.)
37
+ */
38
+ status: StepStatusSchema,
39
+ /**
40
+ * Unix timestamp when step started (milliseconds)
41
+ */
42
+ start_time: z.number(),
43
+ /**
44
+ * Unix timestamp when step ended (milliseconds)
45
+ */
46
+ end_time: z.number().nullable(),
47
+ /**
48
+ * Duration in milliseconds
49
+ */
50
+ duration: z.number(),
51
+ /**
52
+ * Attachments created during this step
53
+ */
54
+ attachments: z.array(AttachmentSchema),
55
+ });
56
+ /**
57
+ * Recursive schema for test steps.
58
+ * Steps can contain nested steps, allowing hierarchical test structure.
59
+ *
60
+ * Uses z.lazy() to enable recursive type definition.
61
+ */
62
+ export const StepSchema = z.lazy(() => z.object({
63
+ /**
64
+ * Unique identifier for this step
65
+ */
66
+ id: z.string(),
67
+ /**
68
+ * Type of step (text, request, assertion, gherkin, etc.)
69
+ */
70
+ step_type: StepTypeSchema,
71
+ /**
72
+ * ID of parent step (nullable for top-level steps)
73
+ */
74
+ parent_id: z.string().nullable().optional(),
75
+ /**
76
+ * Step data (action, expected result, input data)
77
+ */
78
+ data: StepDataSchema,
79
+ /**
80
+ * Execution information for this step
81
+ */
82
+ execution: StepExecutionSchema,
83
+ /**
84
+ * Nested steps (recursive array)
85
+ */
86
+ steps: z.array(StepSchema),
87
+ }));
package/package.json ADDED
@@ -0,0 +1,92 @@
1
+ {
2
+ "name": "qase-report",
3
+ "private": false,
4
+ "version": "1.0.0",
5
+ "type": "module",
6
+ "description": "CLI tool for visualizing Qase TMS test reports with interactive UI",
7
+ "keywords": [
8
+ "qase",
9
+ "testing",
10
+ "test-report",
11
+ "visualization",
12
+ "tms",
13
+ "cli",
14
+ "reporter"
15
+ ],
16
+ "author": "Qase TMS",
17
+ "license": "MIT",
18
+ "repository": {
19
+ "type": "git",
20
+ "url": "git+https://github.com/qase-tms/qase-report.git"
21
+ },
22
+ "homepage": "https://github.com/qase-tms/qase-report#readme",
23
+ "bugs": {
24
+ "url": "https://github.com/qase-tms/qase-report/issues"
25
+ },
26
+ "engines": {
27
+ "node": ">=18.0.0"
28
+ },
29
+ "bin": {
30
+ "qase-report": "./dist/cli/index.js"
31
+ },
32
+ "files": [
33
+ "dist/cli/",
34
+ "dist/schemas/",
35
+ "dist/index.html"
36
+ ],
37
+ "scripts": {
38
+ "dev": "vite",
39
+ "build": "tsc && vite build && npm run build:cli",
40
+ "build:cli": "tsc -p tsconfig.cli.json && chmod +x dist/cli/index.js",
41
+ "preview": "vite preview",
42
+ "prepublishOnly": "npm run build"
43
+ },
44
+ "dependencies": {
45
+ "@tailwindcss/vite": "^4.1.18",
46
+ "@tanstack/match-sorter-utils": "^8.19.4",
47
+ "@tanstack/react-table": "^8.21.3",
48
+ "@tanstack/react-virtual": "^3.13.18",
49
+ "archiver": "^7.0.1",
50
+ "class-variance-authority": "^0.7.1",
51
+ "clsx": "^2.1.1",
52
+ "cmdk": "^1.1.1",
53
+ "commander": "^14.0.3",
54
+ "express": "^5.2.1",
55
+ "lucide-react": "^0.563.0",
56
+ "mobx": "^6.9.0",
57
+ "mobx-react-lite": "^3.4.3",
58
+ "open": "^11.0.0",
59
+ "prism-react-renderer": "^2.4.1",
60
+ "radix-ui": "^1.4.3",
61
+ "react": "^18.2.0",
62
+ "react-dom": "^18.2.0",
63
+ "react-hotkeys-hook": "^5.2.4",
64
+ "react-window": "^1.8.11",
65
+ "recharts": "^2.15.4",
66
+ "tailwind-merge": "^3.4.0",
67
+ "tailwindcss": "^4.1.18",
68
+ "tailwindcss-animate": "^1.0.7",
69
+ "yet-another-react-lightbox": "^3.28.0",
70
+ "zod": "^4.3.6"
71
+ },
72
+ "devDependencies": {
73
+ "@types/archiver": "^7.0.0",
74
+ "@types/express": "^5.0.6",
75
+ "@types/node": "^25.2.3",
76
+ "@types/react": "^18.0.28",
77
+ "@types/react-dom": "^18.0.11",
78
+ "@types/react-window": "^1.8.8",
79
+ "@vitejs/plugin-legacy": "^5.4.3",
80
+ "@vitejs/plugin-react": "^4.7.0",
81
+ "prettier": "2.8.7",
82
+ "shadcn": "^3.8.4",
83
+ "terser": "^5.46.0",
84
+ "tw-animate-css": "^1.4.0",
85
+ "typescript": "^5.9.3",
86
+ "vite": "^5.4.21",
87
+ "vite-plugin-singlefile": "^2.3.0"
88
+ },
89
+ "optionalDependencies": {
90
+ "playwright-core": "^1.58.0"
91
+ }
92
+ }