cucumber-dressing 0.1.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.
- package/CHANGELOG.md +91 -0
- package/LICENSE +21 -0
- package/README.md +421 -0
- package/dist/cli.d.ts +6 -0
- package/dist/cli.js +154 -0
- package/dist/index.d.ts +15 -0
- package/dist/index.js +13 -0
- package/dist/parser.d.ts +39 -0
- package/dist/parser.js +140 -0
- package/dist/reporter.d.ts +74 -0
- package/dist/reporter.js +235 -0
- package/dist/statistics.d.ts +96 -0
- package/dist/statistics.js +256 -0
- package/dist/template-generator.d.ts +101 -0
- package/dist/template-generator.js +528 -0
- package/dist/templates/scripts.js.template.d.ts +3 -0
- package/dist/templates/scripts.js.template.js +297 -0
- package/dist/templates/styles.css.template.d.ts +3 -0
- package/dist/templates/styles.css.template.js +621 -0
- package/dist/types.d.ts +207 -0
- package/dist/types.js +5 -0
- package/dist/utils.d.ts +112 -0
- package/dist/utils.js +250 -0
- package/package.json +92 -0
package/dist/types.d.ts
ADDED
|
@@ -0,0 +1,207 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Core data models for DRESSING reporter
|
|
3
|
+
*/
|
|
4
|
+
/**
|
|
5
|
+
* Represents a Cucumber/Gherkin feature
|
|
6
|
+
*/
|
|
7
|
+
export interface GherkinFeature {
|
|
8
|
+
id: string;
|
|
9
|
+
uri: string;
|
|
10
|
+
keyword: string;
|
|
11
|
+
name: string;
|
|
12
|
+
description?: string;
|
|
13
|
+
line: number;
|
|
14
|
+
tags?: GherkinTag[];
|
|
15
|
+
elements: GherkinScenario[];
|
|
16
|
+
}
|
|
17
|
+
/**
|
|
18
|
+
* Represents a scenario or background in a Gherkin feature
|
|
19
|
+
*/
|
|
20
|
+
export interface GherkinScenario {
|
|
21
|
+
id: string;
|
|
22
|
+
keyword: string;
|
|
23
|
+
name: string;
|
|
24
|
+
description?: string;
|
|
25
|
+
line: number;
|
|
26
|
+
type: 'scenario' | 'background';
|
|
27
|
+
tags?: GherkinTag[];
|
|
28
|
+
steps: GherkinStep[];
|
|
29
|
+
before?: GherkinHook[];
|
|
30
|
+
after?: GherkinHook[];
|
|
31
|
+
}
|
|
32
|
+
/**
|
|
33
|
+
* Represents a step in a Gherkin scenario
|
|
34
|
+
*/
|
|
35
|
+
export interface GherkinStep {
|
|
36
|
+
keyword: string;
|
|
37
|
+
name: string;
|
|
38
|
+
line: number;
|
|
39
|
+
result: StepResult;
|
|
40
|
+
match?: {
|
|
41
|
+
location?: string;
|
|
42
|
+
};
|
|
43
|
+
embeddings?: Embedding[];
|
|
44
|
+
output?: string[];
|
|
45
|
+
doc_string?: {
|
|
46
|
+
value: string;
|
|
47
|
+
line: number;
|
|
48
|
+
content_type?: string;
|
|
49
|
+
};
|
|
50
|
+
rows?: DataTableRow[];
|
|
51
|
+
}
|
|
52
|
+
/**
|
|
53
|
+
* Represents a row in a Gherkin data table
|
|
54
|
+
*/
|
|
55
|
+
export interface DataTableRow {
|
|
56
|
+
cells: string[];
|
|
57
|
+
}
|
|
58
|
+
/**
|
|
59
|
+
* Represents a before/after hook in a Gherkin scenario
|
|
60
|
+
*/
|
|
61
|
+
export interface GherkinHook {
|
|
62
|
+
match: {
|
|
63
|
+
location: string;
|
|
64
|
+
};
|
|
65
|
+
result: StepResult;
|
|
66
|
+
}
|
|
67
|
+
/**
|
|
68
|
+
* Represents a tag annotation in Gherkin
|
|
69
|
+
*/
|
|
70
|
+
export interface GherkinTag {
|
|
71
|
+
name: string;
|
|
72
|
+
line?: number;
|
|
73
|
+
}
|
|
74
|
+
/**
|
|
75
|
+
* Represents the execution result of a step
|
|
76
|
+
*/
|
|
77
|
+
export interface StepResult {
|
|
78
|
+
status: 'passed' | 'failed' | 'skipped' | 'pending' | 'undefined' | 'ambiguous';
|
|
79
|
+
duration?: number;
|
|
80
|
+
error_message?: string;
|
|
81
|
+
}
|
|
82
|
+
/**
|
|
83
|
+
* Represents an embedded asset (screenshot, text, etc.) in a step
|
|
84
|
+
*/
|
|
85
|
+
export interface Embedding {
|
|
86
|
+
data: string;
|
|
87
|
+
mime_type: string;
|
|
88
|
+
name?: string;
|
|
89
|
+
}
|
|
90
|
+
/**
|
|
91
|
+
* Color customization options for report theming
|
|
92
|
+
*/
|
|
93
|
+
export interface ColorCustomization {
|
|
94
|
+
primary?: string;
|
|
95
|
+
success?: string;
|
|
96
|
+
danger?: string;
|
|
97
|
+
warning?: string;
|
|
98
|
+
info?: string;
|
|
99
|
+
muted?: string;
|
|
100
|
+
background?: string;
|
|
101
|
+
backgroundSecondary?: string;
|
|
102
|
+
border?: string;
|
|
103
|
+
text?: string;
|
|
104
|
+
textSecondary?: string;
|
|
105
|
+
}
|
|
106
|
+
/**
|
|
107
|
+
* Configuration options for report generation
|
|
108
|
+
*/
|
|
109
|
+
export interface ReportOptions {
|
|
110
|
+
jsonDir?: string;
|
|
111
|
+
jsonFile?: string;
|
|
112
|
+
output: string;
|
|
113
|
+
reportTitle?: string;
|
|
114
|
+
reportName?: string;
|
|
115
|
+
metadata?: ReportMetadata;
|
|
116
|
+
customData?: CustomData;
|
|
117
|
+
theme?: 'modern' | 'classic' | 'dark';
|
|
118
|
+
colors?: ColorCustomization;
|
|
119
|
+
displayDuration?: boolean;
|
|
120
|
+
durationInMS?: boolean;
|
|
121
|
+
openReportInBrowser?: boolean;
|
|
122
|
+
screenshotsDirectory?: string;
|
|
123
|
+
noInlineScreenshots?: boolean;
|
|
124
|
+
columnLayout?: 1 | 2;
|
|
125
|
+
brandTitle?: string;
|
|
126
|
+
scenarioTimestamp?: boolean;
|
|
127
|
+
disableLog?: boolean;
|
|
128
|
+
customStyle?: string;
|
|
129
|
+
}
|
|
130
|
+
/**
|
|
131
|
+
* Metadata about the test execution environment
|
|
132
|
+
*/
|
|
133
|
+
export interface ReportMetadata {
|
|
134
|
+
browser?: {
|
|
135
|
+
name: string;
|
|
136
|
+
version: string;
|
|
137
|
+
};
|
|
138
|
+
device?: string;
|
|
139
|
+
platform?: {
|
|
140
|
+
name: string;
|
|
141
|
+
version: string;
|
|
142
|
+
};
|
|
143
|
+
app?: {
|
|
144
|
+
name: string;
|
|
145
|
+
version: string;
|
|
146
|
+
};
|
|
147
|
+
}
|
|
148
|
+
/**
|
|
149
|
+
* Custom data section for additional report information
|
|
150
|
+
*/
|
|
151
|
+
export interface CustomData {
|
|
152
|
+
title?: string;
|
|
153
|
+
data: {
|
|
154
|
+
label: string;
|
|
155
|
+
value: string;
|
|
156
|
+
}[];
|
|
157
|
+
}
|
|
158
|
+
/**
|
|
159
|
+
* Computed statistics for the test execution
|
|
160
|
+
*/
|
|
161
|
+
export interface ReportStatistics {
|
|
162
|
+
features: number;
|
|
163
|
+
scenarios: number;
|
|
164
|
+
steps: number;
|
|
165
|
+
passed: number;
|
|
166
|
+
failed: number;
|
|
167
|
+
skipped: number;
|
|
168
|
+
pending: number;
|
|
169
|
+
undefined: number;
|
|
170
|
+
ambiguous: number;
|
|
171
|
+
duration: number;
|
|
172
|
+
passRate: number;
|
|
173
|
+
startTime?: string;
|
|
174
|
+
endTime?: string;
|
|
175
|
+
}
|
|
176
|
+
/**
|
|
177
|
+
* Feature with computed status, duration, and processed scenarios
|
|
178
|
+
*/
|
|
179
|
+
export interface ProcessedFeature extends GherkinFeature {
|
|
180
|
+
status: 'passed' | 'failed' | 'skipped' | 'pending';
|
|
181
|
+
duration: number;
|
|
182
|
+
scenarios: ProcessedScenario[];
|
|
183
|
+
metadata?: ReportMetadata;
|
|
184
|
+
}
|
|
185
|
+
/**
|
|
186
|
+
* Scenario with computed status, duration, and feature references
|
|
187
|
+
*/
|
|
188
|
+
export interface ProcessedScenario extends GherkinScenario {
|
|
189
|
+
status: 'passed' | 'failed' | 'skipped' | 'pending' | 'undefined';
|
|
190
|
+
duration: number;
|
|
191
|
+
featureName: string;
|
|
192
|
+
featureId: string;
|
|
193
|
+
}
|
|
194
|
+
/**
|
|
195
|
+
* Chart.js compatible data structure for visualizations
|
|
196
|
+
*/
|
|
197
|
+
export interface ChartData {
|
|
198
|
+
labels: string[];
|
|
199
|
+
datasets: {
|
|
200
|
+
label: string;
|
|
201
|
+
data: number[];
|
|
202
|
+
backgroundColor?: string[];
|
|
203
|
+
borderColor?: string[];
|
|
204
|
+
borderWidth?: number;
|
|
205
|
+
}[];
|
|
206
|
+
}
|
|
207
|
+
//# sourceMappingURL=types.d.ts.map
|
package/dist/types.js
ADDED
package/dist/utils.d.ts
ADDED
|
@@ -0,0 +1,112 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Utility functions for DRESSING reporter
|
|
3
|
+
*/
|
|
4
|
+
import { GherkinFeature, GherkinScenario, GherkinStep, StepResult } from './types.js';
|
|
5
|
+
/**
|
|
6
|
+
* Calculate duration in a human-readable format
|
|
7
|
+
* @param nanoseconds - Duration in nanoseconds (or milliseconds if inMS is true)
|
|
8
|
+
* @param inMS - If true, treats input as milliseconds instead of nanoseconds
|
|
9
|
+
* @returns Formatted duration string (e.g., "1.50s", "2m 30s")
|
|
10
|
+
*/
|
|
11
|
+
export declare function formatDuration(nanoseconds: number, inMS?: boolean): string;
|
|
12
|
+
/**
|
|
13
|
+
* Get the worst status from a list of statuses (failed > ambiguous > undefined > pending > skipped > passed)
|
|
14
|
+
* @param statuses - Array of status strings
|
|
15
|
+
* @returns The worst status from the hierarchy
|
|
16
|
+
*/
|
|
17
|
+
export declare function getWorstStatus(statuses: ('passed' | 'failed' | 'skipped' | 'pending' | 'undefined' | 'ambiguous')[]): 'passed' | 'failed' | 'skipped' | 'pending' | 'undefined' | 'ambiguous';
|
|
18
|
+
/**
|
|
19
|
+
* Calculate scenario status based on steps
|
|
20
|
+
* @param steps - Array of Gherkin steps
|
|
21
|
+
* @returns The worst status among all steps, or 'pending' if no steps
|
|
22
|
+
*/
|
|
23
|
+
export declare function calculateScenarioStatus(steps: GherkinStep[]): 'passed' | 'failed' | 'skipped' | 'pending' | 'undefined';
|
|
24
|
+
/**
|
|
25
|
+
* Calculate feature status based on scenarios
|
|
26
|
+
* @param scenarios - Array of Gherkin scenarios
|
|
27
|
+
* @returns 'failed' if any scenario failed, 'skipped' if all skipped, otherwise 'passed'
|
|
28
|
+
*/
|
|
29
|
+
export declare function calculateFeatureStatus(scenarios: GherkinScenario[]): 'passed' | 'failed' | 'skipped' | 'pending';
|
|
30
|
+
/**
|
|
31
|
+
* Calculate total duration from steps
|
|
32
|
+
* @param steps - Array of Gherkin steps
|
|
33
|
+
* @returns Total duration in nanoseconds
|
|
34
|
+
*/
|
|
35
|
+
export declare function calculateDuration(steps: GherkinStep[]): number;
|
|
36
|
+
/**
|
|
37
|
+
* Calculate scenario duration including hooks (before/after)
|
|
38
|
+
* @param scenario - Gherkin scenario object
|
|
39
|
+
* @returns Total duration including steps and hooks in nanoseconds
|
|
40
|
+
*/
|
|
41
|
+
export declare function calculateScenarioDuration(scenario: GherkinScenario): number;
|
|
42
|
+
/**
|
|
43
|
+
* Format timestamp to human-readable string
|
|
44
|
+
* @param timestamp - Unix timestamp (number) or ISO date string
|
|
45
|
+
* @returns Formatted date string or 'N/A' if no timestamp provided
|
|
46
|
+
*/
|
|
47
|
+
export declare function formatTimestamp(timestamp?: number | string): string;
|
|
48
|
+
/**
|
|
49
|
+
* Get status icon character for display
|
|
50
|
+
* @param status - Test status
|
|
51
|
+
* @returns Unicode character representing the status (✓, ✗, ⊘, ⧗, ?, ≈)
|
|
52
|
+
*/
|
|
53
|
+
export declare function getStatusIcon(status: 'passed' | 'failed' | 'skipped' | 'pending' | 'undefined' | 'ambiguous'): string;
|
|
54
|
+
/**
|
|
55
|
+
* Get CSS class name for status styling
|
|
56
|
+
* @param status - Test status
|
|
57
|
+
* @returns CSS class name (e.g., 'status-passed', 'status-failed')
|
|
58
|
+
*/
|
|
59
|
+
export declare function getStatusClass(status: 'passed' | 'failed' | 'skipped' | 'pending' | 'undefined' | 'ambiguous'): string;
|
|
60
|
+
/**
|
|
61
|
+
* Sanitize HTML by escaping special characters
|
|
62
|
+
* @param text - Raw text that may contain HTML characters
|
|
63
|
+
* @returns Escaped text safe for HTML rendering
|
|
64
|
+
*/
|
|
65
|
+
export declare function sanitizeHtml(text: string): string;
|
|
66
|
+
/**
|
|
67
|
+
* Generate unique ID with timestamp and random component
|
|
68
|
+
* @param prefix - Prefix for the ID
|
|
69
|
+
* @returns Unique ID string (e.g., 'feature-1234567890-abc123xyz')
|
|
70
|
+
*/
|
|
71
|
+
export declare function generateId(prefix: string): string;
|
|
72
|
+
/**
|
|
73
|
+
* Parse tags from Gherkin tags, removing @ prefix
|
|
74
|
+
* @param tags - Array of Gherkin tag objects
|
|
75
|
+
* @returns Array of tag names without @ prefix
|
|
76
|
+
*/
|
|
77
|
+
export declare function parseTags(tags?: {
|
|
78
|
+
name: string;
|
|
79
|
+
}[]): string[];
|
|
80
|
+
/**
|
|
81
|
+
* Group features by their directory path
|
|
82
|
+
* @param features - Array of Gherkin features
|
|
83
|
+
* @returns Map of directory paths to features in that directory
|
|
84
|
+
*/
|
|
85
|
+
export declare function groupFeaturesByDirectory(features: GherkinFeature[]): Map<string, GherkinFeature[]>;
|
|
86
|
+
/**
|
|
87
|
+
* Calculate pass rate percentage with 2 decimal precision
|
|
88
|
+
* @param passed - Number of passed tests
|
|
89
|
+
* @param total - Total number of tests
|
|
90
|
+
* @returns Pass rate as percentage (0-100) with 2 decimal places
|
|
91
|
+
*/
|
|
92
|
+
export declare function calculatePassRate(passed: number, total: number): number;
|
|
93
|
+
/**
|
|
94
|
+
* Extract error message from step result (first line only)
|
|
95
|
+
* @param result - Step result object
|
|
96
|
+
* @returns First line of error message, or empty string if no error
|
|
97
|
+
*/
|
|
98
|
+
export declare function extractErrorMessage(result: StepResult): string;
|
|
99
|
+
/**
|
|
100
|
+
* Get file name from URI or path
|
|
101
|
+
* @param uri - File URI or path
|
|
102
|
+
* @returns File name (last part of the path)
|
|
103
|
+
*/
|
|
104
|
+
export declare function getFileName(uri: string): string;
|
|
105
|
+
/**
|
|
106
|
+
* Convert markdown to HTML (basic conversion)
|
|
107
|
+
* Supports headers (#, ##, ###), bold (**text**), italic (*text*), and line breaks
|
|
108
|
+
* @param markdown - Markdown formatted text
|
|
109
|
+
* @returns HTML string
|
|
110
|
+
*/
|
|
111
|
+
export declare function markdownToHtml(markdown: string): string;
|
|
112
|
+
//# sourceMappingURL=utils.d.ts.map
|
package/dist/utils.js
ADDED
|
@@ -0,0 +1,250 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Utility functions for DRESSING reporter
|
|
3
|
+
*/
|
|
4
|
+
/**
|
|
5
|
+
* Calculate duration in a human-readable format
|
|
6
|
+
* @param nanoseconds - Duration in nanoseconds (or milliseconds if inMS is true)
|
|
7
|
+
* @param inMS - If true, treats input as milliseconds instead of nanoseconds
|
|
8
|
+
* @returns Formatted duration string (e.g., "1.50s", "2m 30s")
|
|
9
|
+
*/
|
|
10
|
+
export function formatDuration(nanoseconds, inMS = false) {
|
|
11
|
+
const milliseconds = inMS ? nanoseconds : nanoseconds / 1000000;
|
|
12
|
+
if (milliseconds < 1000) {
|
|
13
|
+
return `${Math.round(milliseconds)}ms`;
|
|
14
|
+
}
|
|
15
|
+
const seconds = milliseconds / 1000;
|
|
16
|
+
if (seconds < 60) {
|
|
17
|
+
return `${seconds.toFixed(2)}s`;
|
|
18
|
+
}
|
|
19
|
+
const minutes = Math.floor(seconds / 60);
|
|
20
|
+
const remainingSeconds = seconds % 60;
|
|
21
|
+
return `${minutes}m ${remainingSeconds.toFixed(0)}s`;
|
|
22
|
+
}
|
|
23
|
+
/**
|
|
24
|
+
* Get the worst status from a list of statuses (failed > ambiguous > undefined > pending > skipped > passed)
|
|
25
|
+
* @param statuses - Array of status strings
|
|
26
|
+
* @returns The worst status from the hierarchy
|
|
27
|
+
*/
|
|
28
|
+
export function getWorstStatus(statuses) {
|
|
29
|
+
if (statuses.includes('failed')) {
|
|
30
|
+
return 'failed';
|
|
31
|
+
}
|
|
32
|
+
if (statuses.includes('ambiguous')) {
|
|
33
|
+
return 'ambiguous';
|
|
34
|
+
}
|
|
35
|
+
if (statuses.includes('undefined')) {
|
|
36
|
+
return 'undefined';
|
|
37
|
+
}
|
|
38
|
+
if (statuses.includes('pending')) {
|
|
39
|
+
return 'pending';
|
|
40
|
+
}
|
|
41
|
+
if (statuses.includes('skipped')) {
|
|
42
|
+
return 'skipped';
|
|
43
|
+
}
|
|
44
|
+
return 'passed';
|
|
45
|
+
}
|
|
46
|
+
/**
|
|
47
|
+
* Calculate scenario status based on steps
|
|
48
|
+
* @param steps - Array of Gherkin steps
|
|
49
|
+
* @returns The worst status among all steps, or 'pending' if no steps
|
|
50
|
+
*/
|
|
51
|
+
export function calculateScenarioStatus(steps) {
|
|
52
|
+
if (steps.length === 0) {
|
|
53
|
+
return 'pending';
|
|
54
|
+
}
|
|
55
|
+
const statuses = steps.map(step => step.result.status);
|
|
56
|
+
return getWorstStatus(statuses);
|
|
57
|
+
}
|
|
58
|
+
/**
|
|
59
|
+
* Calculate feature status based on scenarios
|
|
60
|
+
* @param scenarios - Array of Gherkin scenarios
|
|
61
|
+
* @returns 'failed' if any scenario failed, 'skipped' if all skipped, otherwise 'passed'
|
|
62
|
+
*/
|
|
63
|
+
export function calculateFeatureStatus(scenarios) {
|
|
64
|
+
if (scenarios.length === 0) {
|
|
65
|
+
return 'pending';
|
|
66
|
+
}
|
|
67
|
+
const hasFailedScenario = scenarios.some(scenario => {
|
|
68
|
+
const scenarioStatus = calculateScenarioStatus(scenario.steps);
|
|
69
|
+
return scenarioStatus === 'failed' || scenarioStatus === 'undefined';
|
|
70
|
+
});
|
|
71
|
+
if (hasFailedScenario) {
|
|
72
|
+
return 'failed';
|
|
73
|
+
}
|
|
74
|
+
const allSkipped = scenarios.every(scenario => {
|
|
75
|
+
const scenarioStatus = calculateScenarioStatus(scenario.steps);
|
|
76
|
+
return scenarioStatus === 'skipped';
|
|
77
|
+
});
|
|
78
|
+
if (allSkipped) {
|
|
79
|
+
return 'skipped';
|
|
80
|
+
}
|
|
81
|
+
return 'passed';
|
|
82
|
+
}
|
|
83
|
+
/**
|
|
84
|
+
* Calculate total duration from steps
|
|
85
|
+
* @param steps - Array of Gherkin steps
|
|
86
|
+
* @returns Total duration in nanoseconds
|
|
87
|
+
*/
|
|
88
|
+
export function calculateDuration(steps) {
|
|
89
|
+
return steps.reduce((total, step) => {
|
|
90
|
+
return total + (step.result.duration ?? 0);
|
|
91
|
+
}, 0);
|
|
92
|
+
}
|
|
93
|
+
/**
|
|
94
|
+
* Calculate scenario duration including hooks (before/after)
|
|
95
|
+
* @param scenario - Gherkin scenario object
|
|
96
|
+
* @returns Total duration including steps and hooks in nanoseconds
|
|
97
|
+
*/
|
|
98
|
+
export function calculateScenarioDuration(scenario) {
|
|
99
|
+
const stepsDuration = calculateDuration(scenario.steps);
|
|
100
|
+
const beforeDuration = scenario.before
|
|
101
|
+
? scenario.before.reduce((sum, hook) => sum + (hook.result.duration ?? 0), 0)
|
|
102
|
+
: 0;
|
|
103
|
+
const afterDuration = scenario.after
|
|
104
|
+
? scenario.after.reduce((sum, hook) => sum + (hook.result.duration ?? 0), 0)
|
|
105
|
+
: 0;
|
|
106
|
+
return stepsDuration + beforeDuration + afterDuration;
|
|
107
|
+
}
|
|
108
|
+
/**
|
|
109
|
+
* Format timestamp to human-readable string
|
|
110
|
+
* @param timestamp - Unix timestamp (number) or ISO date string
|
|
111
|
+
* @returns Formatted date string or 'N/A' if no timestamp provided
|
|
112
|
+
*/
|
|
113
|
+
export function formatTimestamp(timestamp) {
|
|
114
|
+
if (!timestamp) {
|
|
115
|
+
return 'N/A';
|
|
116
|
+
}
|
|
117
|
+
const date = typeof timestamp === 'string' ? new Date(timestamp) : new Date(timestamp);
|
|
118
|
+
return date.toLocaleString('en-US', {
|
|
119
|
+
year: 'numeric',
|
|
120
|
+
month: 'short',
|
|
121
|
+
day: 'numeric',
|
|
122
|
+
hour: '2-digit',
|
|
123
|
+
minute: '2-digit',
|
|
124
|
+
second: '2-digit',
|
|
125
|
+
});
|
|
126
|
+
}
|
|
127
|
+
/**
|
|
128
|
+
* Get status icon character for display
|
|
129
|
+
* @param status - Test status
|
|
130
|
+
* @returns Unicode character representing the status (✓, ✗, ⊘, ⧗, ?, ≈)
|
|
131
|
+
*/
|
|
132
|
+
export function getStatusIcon(status) {
|
|
133
|
+
const icons = {
|
|
134
|
+
passed: '✓',
|
|
135
|
+
failed: '✗',
|
|
136
|
+
skipped: '⊘',
|
|
137
|
+
pending: '⧗',
|
|
138
|
+
undefined: '?',
|
|
139
|
+
ambiguous: '≈',
|
|
140
|
+
};
|
|
141
|
+
return icons[status] || '?';
|
|
142
|
+
}
|
|
143
|
+
/**
|
|
144
|
+
* Get CSS class name for status styling
|
|
145
|
+
* @param status - Test status
|
|
146
|
+
* @returns CSS class name (e.g., 'status-passed', 'status-failed')
|
|
147
|
+
*/
|
|
148
|
+
export function getStatusClass(status) {
|
|
149
|
+
return `status-${status}`;
|
|
150
|
+
}
|
|
151
|
+
/**
|
|
152
|
+
* Sanitize HTML by escaping special characters
|
|
153
|
+
* @param text - Raw text that may contain HTML characters
|
|
154
|
+
* @returns Escaped text safe for HTML rendering
|
|
155
|
+
*/
|
|
156
|
+
export function sanitizeHtml(text) {
|
|
157
|
+
const map = {
|
|
158
|
+
'&': '&',
|
|
159
|
+
'<': '<',
|
|
160
|
+
'>': '>',
|
|
161
|
+
'"': '"',
|
|
162
|
+
"'": ''',
|
|
163
|
+
};
|
|
164
|
+
return text.replace(/[&<>"']/g, m => map[m]);
|
|
165
|
+
}
|
|
166
|
+
/**
|
|
167
|
+
* Generate unique ID with timestamp and random component
|
|
168
|
+
* @param prefix - Prefix for the ID
|
|
169
|
+
* @returns Unique ID string (e.g., 'feature-1234567890-abc123xyz')
|
|
170
|
+
*/
|
|
171
|
+
export function generateId(prefix) {
|
|
172
|
+
return `${prefix}-${Date.now()}-${Math.random().toString(36).substr(2, 9)}`;
|
|
173
|
+
}
|
|
174
|
+
/**
|
|
175
|
+
* Parse tags from Gherkin tags, removing @ prefix
|
|
176
|
+
* @param tags - Array of Gherkin tag objects
|
|
177
|
+
* @returns Array of tag names without @ prefix
|
|
178
|
+
*/
|
|
179
|
+
export function parseTags(tags) {
|
|
180
|
+
if (!tags || tags.length === 0) {
|
|
181
|
+
return [];
|
|
182
|
+
}
|
|
183
|
+
return tags.map(tag => tag.name.replace('@', ''));
|
|
184
|
+
}
|
|
185
|
+
/**
|
|
186
|
+
* Group features by their directory path
|
|
187
|
+
* @param features - Array of Gherkin features
|
|
188
|
+
* @returns Map of directory paths to features in that directory
|
|
189
|
+
*/
|
|
190
|
+
export function groupFeaturesByDirectory(features) {
|
|
191
|
+
const grouped = new Map();
|
|
192
|
+
features.forEach(feature => {
|
|
193
|
+
const dir = feature.uri.split('/').slice(0, -1).join('/') || 'root';
|
|
194
|
+
if (!grouped.has(dir)) {
|
|
195
|
+
grouped.set(dir, []);
|
|
196
|
+
}
|
|
197
|
+
grouped.get(dir).push(feature);
|
|
198
|
+
});
|
|
199
|
+
return grouped;
|
|
200
|
+
}
|
|
201
|
+
/**
|
|
202
|
+
* Calculate pass rate percentage with 2 decimal precision
|
|
203
|
+
* @param passed - Number of passed tests
|
|
204
|
+
* @param total - Total number of tests
|
|
205
|
+
* @returns Pass rate as percentage (0-100) with 2 decimal places
|
|
206
|
+
*/
|
|
207
|
+
export function calculatePassRate(passed, total) {
|
|
208
|
+
if (total === 0) {
|
|
209
|
+
return 0;
|
|
210
|
+
}
|
|
211
|
+
return Math.round((passed / total) * 100 * 100) / 100;
|
|
212
|
+
}
|
|
213
|
+
/**
|
|
214
|
+
* Extract error message from step result (first line only)
|
|
215
|
+
* @param result - Step result object
|
|
216
|
+
* @returns First line of error message, or empty string if no error
|
|
217
|
+
*/
|
|
218
|
+
export function extractErrorMessage(result) {
|
|
219
|
+
if (!result.error_message) {
|
|
220
|
+
return '';
|
|
221
|
+
}
|
|
222
|
+
// Try to extract just the meaningful part of the error
|
|
223
|
+
const lines = result.error_message.split('\n');
|
|
224
|
+
return lines[0] || result.error_message;
|
|
225
|
+
}
|
|
226
|
+
/**
|
|
227
|
+
* Get file name from URI or path
|
|
228
|
+
* @param uri - File URI or path
|
|
229
|
+
* @returns File name (last part of the path)
|
|
230
|
+
*/
|
|
231
|
+
export function getFileName(uri) {
|
|
232
|
+
const parts = uri.split('/');
|
|
233
|
+
return parts[parts.length - 1];
|
|
234
|
+
}
|
|
235
|
+
/**
|
|
236
|
+
* Convert markdown to HTML (basic conversion)
|
|
237
|
+
* Supports headers (#, ##, ###), bold (**text**), italic (*text*), and line breaks
|
|
238
|
+
* @param markdown - Markdown formatted text
|
|
239
|
+
* @returns HTML string
|
|
240
|
+
*/
|
|
241
|
+
export function markdownToHtml(markdown) {
|
|
242
|
+
return markdown
|
|
243
|
+
.replace(/^### (.*$)/gim, '<h3>$1</h3>')
|
|
244
|
+
.replace(/^## (.*$)/gim, '<h2>$1</h2>')
|
|
245
|
+
.replace(/^# (.*$)/gim, '<h1>$1</h1>')
|
|
246
|
+
.replace(/\*\*(.*)\*\*/gim, '<strong>$1</strong>')
|
|
247
|
+
.replace(/\*(.*)\*/gim, '<em>$1</em>')
|
|
248
|
+
.replace(/\n/gim, '<br>');
|
|
249
|
+
}
|
|
250
|
+
//# sourceMappingURL=utils.js.map
|
package/package.json
ADDED
|
@@ -0,0 +1,92 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "cucumber-dressing",
|
|
3
|
+
"version": "0.1.0",
|
|
4
|
+
"type": "module",
|
|
5
|
+
"description": "Detailed Report of Executed Scenarios, Steps and INsights for Gherkin - A comprehensive test automation reporter for Gherkin-based test results",
|
|
6
|
+
"main": "dist/index.js",
|
|
7
|
+
"types": "dist/index.d.ts",
|
|
8
|
+
"bin": {
|
|
9
|
+
"dressing": "dist/cli.js"
|
|
10
|
+
},
|
|
11
|
+
"scripts": {
|
|
12
|
+
"build": "tsc",
|
|
13
|
+
"build:watch": "tsc --watch",
|
|
14
|
+
"test": "cross-env NODE_OPTIONS=--experimental-vm-modules jest",
|
|
15
|
+
"test:watch": "cross-env NODE_OPTIONS=--experimental-vm-modules jest --watch",
|
|
16
|
+
"test:coverage": "cross-env NODE_OPTIONS=--experimental-vm-modules jest --coverage",
|
|
17
|
+
"lint": "eslint .",
|
|
18
|
+
"lint:fix": "eslint . --fix",
|
|
19
|
+
"format": "prettier --write \"src/**/*.ts\"",
|
|
20
|
+
"prepublishOnly": "npm run lint && npm run build && npm test",
|
|
21
|
+
"preversion": "npm run lint && npm test",
|
|
22
|
+
"version": "npm run format && git add -A src",
|
|
23
|
+
"postversion": "git push && git push --tags",
|
|
24
|
+
"example": "node dist/example.js",
|
|
25
|
+
"clean": "rm -rf dist coverage"
|
|
26
|
+
},
|
|
27
|
+
"keywords": [
|
|
28
|
+
"cucumber",
|
|
29
|
+
"gherkin",
|
|
30
|
+
"test",
|
|
31
|
+
"reporter",
|
|
32
|
+
"html",
|
|
33
|
+
"report",
|
|
34
|
+
"automation",
|
|
35
|
+
"testing",
|
|
36
|
+
"bdd",
|
|
37
|
+
"behavior-driven-development",
|
|
38
|
+
"test-results",
|
|
39
|
+
"json-to-html",
|
|
40
|
+
"test-automation",
|
|
41
|
+
"test-reporting",
|
|
42
|
+
"cucumber-report",
|
|
43
|
+
"html-reporter",
|
|
44
|
+
"test-report-generator"
|
|
45
|
+
],
|
|
46
|
+
"author": "Jed Aureus Gonzales",
|
|
47
|
+
"license": "MIT",
|
|
48
|
+
"repository": {
|
|
49
|
+
"type": "git",
|
|
50
|
+
"url": "https://github.com/jedau/cucumber-dressing.git"
|
|
51
|
+
},
|
|
52
|
+
"bugs": {
|
|
53
|
+
"url": "https://github.com/jedau/cucumber-dressing/issues"
|
|
54
|
+
},
|
|
55
|
+
"homepage": "https://github.com/jedau/cucumber-dressing#readme",
|
|
56
|
+
"files": [
|
|
57
|
+
"dist",
|
|
58
|
+
"!dist/**/*.map",
|
|
59
|
+
"!dist/__tests__",
|
|
60
|
+
"!dist/example.*",
|
|
61
|
+
"README.md",
|
|
62
|
+
"LICENSE",
|
|
63
|
+
"CHANGELOG.md"
|
|
64
|
+
],
|
|
65
|
+
"engines": {
|
|
66
|
+
"node": ">=18.0.0",
|
|
67
|
+
"npm": ">=8.0.0"
|
|
68
|
+
},
|
|
69
|
+
"devDependencies": {
|
|
70
|
+
"@eslint/js": "^9.0.0",
|
|
71
|
+
"@types/fs-extra": "^11.0.0",
|
|
72
|
+
"@types/jest": "^29.5.0",
|
|
73
|
+
"@types/node": "^20.0.0",
|
|
74
|
+
"cross-env": "^10.1.0",
|
|
75
|
+
"eslint": "^9.0.0",
|
|
76
|
+
"eslint-config-prettier": "^9.0.0",
|
|
77
|
+
"jest": "^29.5.0",
|
|
78
|
+
"prettier": "^3.0.0",
|
|
79
|
+
"ts-jest": "^29.1.0",
|
|
80
|
+
"typescript": "^5.0.0",
|
|
81
|
+
"typescript-eslint": "^8.0.0"
|
|
82
|
+
},
|
|
83
|
+
"dependencies": {
|
|
84
|
+
"chart.js": "^4.4.0",
|
|
85
|
+
"commander": "^11.0.0",
|
|
86
|
+
"fs-extra": "^11.1.0",
|
|
87
|
+
"glob": "^10.3.0",
|
|
88
|
+
"handlebars": "^4.7.8",
|
|
89
|
+
"markdown-it": "^14.0.0",
|
|
90
|
+
"open": "^10.0.0"
|
|
91
|
+
}
|
|
92
|
+
}
|