artes 1.1.21 → 1.1.23
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 +6 -1
- package/cucumber.config.js +13 -0
- package/executer.js +19 -14
- package/package.json +1 -1
- package/src/helper/executers/helper.js +6 -0
- package/src/helper/executers/projectCreator.js +3 -0
- package/src/helper/executers/reportGenerator.js +1 -1
- package/src/hooks/hooks.js +121 -89
package/README.md
CHANGED
|
@@ -50,6 +50,8 @@ npx artes [options]
|
|
|
50
50
|
| ✅ `-y, --yes` | Skip the confirmation prompt when creating an example project | `artes -c -y` or `artes --create --yes` |
|
|
51
51
|
| 📊 `-r, --report` | Run tests and generate Allure report | `artes -r` or `artes --report` |
|
|
52
52
|
| `--reportSuccess` | Add screenshots and video records for also Success test cases | `artes --reportSuccess` |
|
|
53
|
+
| `--trace` | Enable tracing | `artes --trace ` |
|
|
54
|
+
| `-rwt, --reportWithTrace` | Add trace to the report | ` artes -rwt ` or `artes --reportWithTrace`|
|
|
53
55
|
| 📁 `--features` | Specify one or more feature files' relative paths to run (comma-separated) | `artes --features "tests/features/Alma,tests/features/Banan.feature"` |
|
|
54
56
|
| 📜 `--stepDef` | Specify one or more step definition files' relative paths to use (comma-separated) | `artes --stepDef "tests/steps/login.js,tests/steps/home.js"` |
|
|
55
57
|
| 🔖 `--tags` | Run tests with specified Cucumber tags | `artes --tags "@smoke or @wip"` |
|
|
@@ -295,7 +297,10 @@ You can configure Artes by editing the `artes.config.js` file. Below are the def
|
|
|
295
297
|
| `pomPath` | `moduleConfig.pomPath` | Path to Page Object Models. |
|
|
296
298
|
| `import` | `[]` | Support code paths. |
|
|
297
299
|
| `testPercentage` | `0` | Define test coverage percentage |
|
|
298
|
-
| `
|
|
300
|
+
| `report` | `false` | Generate report |
|
|
301
|
+
| `reportSuccess` | `false` | Add screenshots and video records for also success test cases |
|
|
302
|
+
| `trace` | `false` | Enable trace |
|
|
303
|
+
| `reportWithTrace` | `false` | Add trace to the report |
|
|
299
304
|
| `format` | `["rerun:@rerun.txt", "allure-cucumberjs/reporter"]` | Formatter names/paths. |
|
|
300
305
|
| `formatOptions` | `{ "resultsDir": "allure-result" }` | Formatter options. |
|
|
301
306
|
| `parallel` | `1` | Number of parallel workers. |
|
package/cucumber.config.js
CHANGED
|
@@ -58,10 +58,23 @@ module.exports = {
|
|
|
58
58
|
: moduleConfig.pomPath,
|
|
59
59
|
import: artesConfig.import || [], // Support code paths
|
|
60
60
|
|
|
61
|
+
report:
|
|
62
|
+
process.env.REPORT_WITH_TRACE ??
|
|
63
|
+
artesConfig.reportWithTrace ??
|
|
64
|
+
process.env.REPORT ??
|
|
65
|
+
artesConfig.report ??
|
|
66
|
+
false, // Generate report
|
|
61
67
|
// Formatting and output
|
|
62
68
|
successReport: process.env.REPORT_SUCCESS
|
|
63
69
|
? true
|
|
64
70
|
: artesConfig.reportSuccess || false, // Include successful tests in report
|
|
71
|
+
|
|
72
|
+
trace: process.env.TRACE ? process.env.TRACE : artesConfig.trace || false, // Enable tracing
|
|
73
|
+
|
|
74
|
+
reportWithTrace: process.env.REPORT_WITH_TRACE
|
|
75
|
+
? process.env.REPORT_WITH_TRACE
|
|
76
|
+
: artesConfig.reportWithTrace || false, // Include trace in report
|
|
77
|
+
|
|
65
78
|
format: finalFormats, // Formatter names/paths
|
|
66
79
|
formatOptions: artesConfig.formatOptions || {
|
|
67
80
|
resultsDir: `allure-result`,
|
package/executer.js
CHANGED
|
@@ -7,6 +7,7 @@ const {
|
|
|
7
7
|
generateReport,
|
|
8
8
|
cleanUp,
|
|
9
9
|
} = require("./src/helper/executers/exporter");
|
|
10
|
+
const artesConfig = require("../../artes.config");
|
|
10
11
|
const fs = require("fs");
|
|
11
12
|
const path = require("path");
|
|
12
13
|
|
|
@@ -20,6 +21,7 @@ const flags = {
|
|
|
20
21
|
report: args.includes("-r") || args.includes("--report"),
|
|
21
22
|
reportSuccess: args.includes("--reportSuccess"),
|
|
22
23
|
trace: args.includes("-t") || args.includes("--trace"),
|
|
24
|
+
reportWithTrace: args.includes("-rwt") || args.includes("--reportWithTrace"),
|
|
23
25
|
features: args.includes("--features"),
|
|
24
26
|
stepDef: args.includes("--stepDef"),
|
|
25
27
|
tags: args.includes("--tags"),
|
|
@@ -56,7 +58,10 @@ const slowMo = args[args.indexOf("--slowMo") + 1];
|
|
|
56
58
|
flags.env && console.log("Running env:", env);
|
|
57
59
|
flags.env ? (process.env.ENV = JSON.stringify(env)) : "";
|
|
58
60
|
|
|
59
|
-
flags.
|
|
61
|
+
flags.reportWithTrace ||
|
|
62
|
+
artesConfig.reportWithTrace ||
|
|
63
|
+
flags.report ||
|
|
64
|
+
artesConfig.report
|
|
60
65
|
? (process.env.REPORT_FORMAT = JSON.stringify([
|
|
61
66
|
"allure-cucumberjs/reporter:./allure-results",
|
|
62
67
|
]))
|
|
@@ -73,8 +78,12 @@ flags.features ? (process.env.FEATURES = features) : "";
|
|
|
73
78
|
flags.stepDef && console.log("Running step definitions:", flags.stepDef);
|
|
74
79
|
flags.stepDef ? (process.env.STEP_DEFINITIONS = stepDef) : "";
|
|
75
80
|
|
|
81
|
+
flags.report ? (process.env.REPORT = true) : "";
|
|
82
|
+
|
|
76
83
|
flags.trace ? (process.env.TRACE = true) : "";
|
|
77
84
|
|
|
85
|
+
flags.reportWithTrace ? (process.env.REPORT_WITH_TRACE = true) : "";
|
|
86
|
+
|
|
78
87
|
flags.headless &&
|
|
79
88
|
console.log("Running mode:", flags.headless ? "headless" : "headed");
|
|
80
89
|
flags.headless ? (process.env.MODE = JSON.stringify(true)) : false;
|
|
@@ -112,25 +121,21 @@ function main() {
|
|
|
112
121
|
if (flags.create) return createProject(flags.createYes);
|
|
113
122
|
|
|
114
123
|
runTests();
|
|
115
|
-
if (
|
|
124
|
+
if (
|
|
125
|
+
flags.reportWithTrace ||
|
|
126
|
+
artesConfig.reportWithTrace ||
|
|
127
|
+
flags.report ||
|
|
128
|
+
artesConfig.report
|
|
129
|
+
)
|
|
130
|
+
generateReport();
|
|
116
131
|
|
|
117
132
|
if (
|
|
118
133
|
fs.existsSync(
|
|
119
|
-
path.join(
|
|
120
|
-
process.cwd(),
|
|
121
|
-
"node_modules",
|
|
122
|
-
"artes",
|
|
123
|
-
"EXIT_CODE.txt",
|
|
124
|
-
),
|
|
134
|
+
path.join(process.cwd(), "node_modules", "artes", "EXIT_CODE.txt"),
|
|
125
135
|
)
|
|
126
136
|
) {
|
|
127
137
|
const data = fs.readFileSync(
|
|
128
|
-
path.join(
|
|
129
|
-
process.cwd(),
|
|
130
|
-
"node_modules",
|
|
131
|
-
"artes",
|
|
132
|
-
"EXIT_CODE.txt",
|
|
133
|
-
),
|
|
138
|
+
path.join(process.cwd(), "node_modules", "artes", "EXIT_CODE.txt"),
|
|
134
139
|
"utf8",
|
|
135
140
|
);
|
|
136
141
|
process.env.EXIT_CODE = parseInt(data, 10);
|
package/package.json
CHANGED
|
@@ -27,6 +27,12 @@ function showHelp() {
|
|
|
27
27
|
|
|
28
28
|
✅ --reportSuccess Generate screenshot and video record with also successful tests
|
|
29
29
|
Usage: artes --reportSuccess
|
|
30
|
+
|
|
31
|
+
--trace Enable tracing for all tests
|
|
32
|
+
Usage: artes --trace
|
|
33
|
+
|
|
34
|
+
-rwt, --reportWithTrace Include trace in the report
|
|
35
|
+
Usage: artes --reportWithTrace
|
|
30
36
|
|
|
31
37
|
📁 --features Specify one or more feature files' relative paths to run (comma-separated)
|
|
32
38
|
Usage: artes --features "tests/features/Alma, tests/features/Banan.feature"
|
|
@@ -48,7 +48,10 @@ function createProject(createYes) {
|
|
|
48
48
|
// timeout : 0, // number - Test timeout in seconds
|
|
49
49
|
// slowMo: 0, // number - Slow down test execution (Default: 0 seconds)
|
|
50
50
|
// parallel: 0, // number - Number of parallel workers
|
|
51
|
+
//report: true / boolean - Generate report
|
|
51
52
|
// reportSuccess: false, // boolean - Add screenshots and video records to report also for success test cases
|
|
53
|
+
// trace: false, // boolean - Enable tracing
|
|
54
|
+
// reportWithTrace: false, // boolean - Include trace in report
|
|
52
55
|
// format: [], // string[] - Formatter names/paths
|
|
53
56
|
// formatOptions: {}, // object - Formatter options
|
|
54
57
|
// retry: 0, // number - Retry attempts for failing tests
|
package/src/hooks/hooks.js
CHANGED
|
@@ -8,20 +8,47 @@ const {
|
|
|
8
8
|
BeforeStep,
|
|
9
9
|
AfterAll,
|
|
10
10
|
} = require("@cucumber/cucumber");
|
|
11
|
+
const { spawnSync } = require("child_process");
|
|
11
12
|
const { invokeBrowser } = require("../helper/contextManager/browserManager");
|
|
12
13
|
const { invokeRequest } = require("../helper/contextManager/requestManager");
|
|
13
14
|
const { pomCollector } = require("../helper/controller/pomCollector");
|
|
14
15
|
const cucumberConfig = require("../../cucumber.config");
|
|
15
16
|
const { context } = require("./context");
|
|
16
17
|
const fs = require("fs");
|
|
17
|
-
const { moduleConfig } = require("artes/src/helper/imports/commons");
|
|
18
18
|
const path = require("path");
|
|
19
|
+
const { moduleConfig } = require("artes/src/helper/imports/commons");
|
|
19
20
|
|
|
20
21
|
const statusDir = path.join(process.cwd(), "testsStatus");
|
|
22
|
+
const HTTP_METHODS = ["GET", "HEAD", "POST", "PUT", "PATCH", "DELETE"];
|
|
21
23
|
|
|
22
24
|
setDefaultTimeout(cucumberConfig.default.timeout);
|
|
23
25
|
|
|
24
|
-
|
|
26
|
+
/* ------------------- Helpers ------------------- */
|
|
27
|
+
|
|
28
|
+
async function attachResponse(attachFn) {
|
|
29
|
+
if (!context.response) return;
|
|
30
|
+
|
|
31
|
+
for (const [key, value] of Object.entries(context.response)) {
|
|
32
|
+
const text =
|
|
33
|
+
typeof value === "object"
|
|
34
|
+
? `${key}:\n${JSON.stringify(value, null, 2)}`
|
|
35
|
+
: `${key}:\n${value}`;
|
|
36
|
+
|
|
37
|
+
await attachFn(text, "text/plain");
|
|
38
|
+
}
|
|
39
|
+
}
|
|
40
|
+
|
|
41
|
+
function saveTestStatus(result, pickle) {
|
|
42
|
+
fs.mkdirSync(statusDir, { recursive: true });
|
|
43
|
+
fs.writeFileSync(
|
|
44
|
+
path.join(statusDir, `${result.status}-${pickle.id}.txt`),
|
|
45
|
+
"",
|
|
46
|
+
);
|
|
47
|
+
}
|
|
48
|
+
|
|
49
|
+
/* ------------------- Hooks ------------------- */
|
|
50
|
+
|
|
51
|
+
BeforeAll(() => {
|
|
25
52
|
pomCollector();
|
|
26
53
|
});
|
|
27
54
|
|
|
@@ -38,130 +65,135 @@ Before(async function () {
|
|
|
38
65
|
|
|
39
66
|
await context.page.setDefaultTimeout(cucumberConfig.default.timeout);
|
|
40
67
|
|
|
41
|
-
|
|
42
|
-
(
|
|
68
|
+
if (
|
|
69
|
+
(cucumberConfig.default.reportWithTrace || cucumberConfig.default.trace) &&
|
|
70
|
+
!context.response
|
|
71
|
+
) {
|
|
72
|
+
await browserContext.tracing.start({
|
|
43
73
|
sources: true,
|
|
44
74
|
screenshots: true,
|
|
45
75
|
snapshots: true,
|
|
46
|
-
})
|
|
76
|
+
});
|
|
77
|
+
}
|
|
47
78
|
});
|
|
48
79
|
|
|
49
|
-
BeforeStep(
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
const methods = ["GET", "HEAD", "POST", "PUT", "PATCH", "DELETE"];
|
|
53
|
-
|
|
54
|
-
if (methods.some((method) => stepText.includes(method))) {
|
|
80
|
+
BeforeStep(({ pickleStep }) => {
|
|
81
|
+
if (HTTP_METHODS.some((method) => pickleStep.text.includes(method))) {
|
|
55
82
|
context.response = {};
|
|
56
83
|
}
|
|
57
84
|
});
|
|
58
85
|
|
|
59
86
|
AfterStep(async function ({ pickleStep }) {
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
const methods = ["GET", "HEAD", "POST", "PUT", "PATCH", "DELETE"];
|
|
63
|
-
|
|
64
|
-
if (methods.some((method) => stepText.includes(method))) {
|
|
65
|
-
if (await context.response) {
|
|
66
|
-
for (const [key, value] of Object.entries(context.response)) {
|
|
67
|
-
let text = `${key}:\n`;
|
|
68
|
-
|
|
69
|
-
if (typeof value === "object") {
|
|
70
|
-
text += JSON.stringify(value, null, 2);
|
|
71
|
-
} else {
|
|
72
|
-
text += value;
|
|
73
|
-
}
|
|
74
|
-
|
|
75
|
-
await this.attach(text, "text/plain");
|
|
76
|
-
}
|
|
77
|
-
}
|
|
87
|
+
if (HTTP_METHODS.some((method) => pickleStep.text.includes(method))) {
|
|
88
|
+
await attachResponse(this.attach);
|
|
78
89
|
}
|
|
79
90
|
});
|
|
80
91
|
|
|
81
92
|
After(async function ({ pickle, result }) {
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
93
|
+
const shouldReport =
|
|
94
|
+
(cucumberConfig.default.successReport ||
|
|
95
|
+
result?.status !== Status.PASSED) &&
|
|
96
|
+
!context.response;
|
|
97
|
+
|
|
98
|
+
if (shouldReport) {
|
|
99
|
+
const screenshotPath = path.join(
|
|
100
|
+
"test-results",
|
|
101
|
+
"visualReport",
|
|
102
|
+
pickle.name,
|
|
103
|
+
`${pickle.name}.png`,
|
|
104
|
+
);
|
|
105
|
+
|
|
106
|
+
const img = await context.page.screenshot({
|
|
107
|
+
path: screenshotPath,
|
|
85
108
|
type: "png",
|
|
86
109
|
});
|
|
87
|
-
await this.attach(img,
|
|
110
|
+
await this.attach(img, {
|
|
111
|
+
mediaType: "image/png",
|
|
112
|
+
fileName: `${pickle.name.replaceAll(" ", "_")}.png`,
|
|
113
|
+
});
|
|
88
114
|
}
|
|
89
115
|
|
|
90
|
-
|
|
116
|
+
saveTestStatus(result, pickle);
|
|
91
117
|
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
"",
|
|
118
|
+
const tracePath = path.join(
|
|
119
|
+
moduleConfig.projectPath,
|
|
120
|
+
`./${pickle.name.replaceAll(" ", "_")}.zip`,
|
|
95
121
|
);
|
|
96
122
|
|
|
97
|
-
|
|
98
|
-
(
|
|
99
|
-
|
|
100
|
-
|
|
123
|
+
if (
|
|
124
|
+
(cucumberConfig.default.reportWithTrace || cucumberConfig.default.trace) &&
|
|
125
|
+
!context.response &&
|
|
126
|
+
shouldReport
|
|
127
|
+
) {
|
|
128
|
+
await context.browserContext.tracing.stop({
|
|
129
|
+
path: tracePath,
|
|
130
|
+
});
|
|
131
|
+
|
|
132
|
+
if (cucumberConfig.default.reportWithTrace) {
|
|
133
|
+
const trace = fs.readFileSync(tracePath);
|
|
101
134
|
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
|
|
135
|
+
await this.attach(trace, {
|
|
136
|
+
mediaType: "application/zip",
|
|
137
|
+
fileName: `${pickle.name.replace(/\s+/g, "_")}_trace.zip`,
|
|
138
|
+
});
|
|
105
139
|
|
|
106
|
-
if (
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
|
|
140
|
+
if (!cucumberConfig.default.trace) {
|
|
141
|
+
spawnSync("npx", ["rimraf", tracePath], {
|
|
142
|
+
cwd: moduleConfig.projectPath,
|
|
143
|
+
stdio: "inherit",
|
|
144
|
+
shell: true,
|
|
145
|
+
});
|
|
110
146
|
}
|
|
111
|
-
|
|
112
|
-
await this.attach(text, "text/plain");
|
|
113
147
|
}
|
|
114
148
|
}
|
|
115
149
|
|
|
116
|
-
await
|
|
150
|
+
await attachResponse(this.attach);
|
|
117
151
|
|
|
152
|
+
await context.page?.close();
|
|
118
153
|
await context.browserContext?.close();
|
|
119
|
-
|
|
120
154
|
await context.browser?.close();
|
|
121
|
-
|
|
122
155
|
await context.request?.dispose();
|
|
123
156
|
|
|
124
|
-
if (
|
|
125
|
-
|
|
126
|
-
|
|
127
|
-
|
|
128
|
-
|
|
129
|
-
|
|
157
|
+
if (shouldReport && context.page.video) {
|
|
158
|
+
const video = context.page.video();
|
|
159
|
+
if (video) {
|
|
160
|
+
const videoPath = await video.path();
|
|
161
|
+
|
|
162
|
+
await new Promise((resolve) => setTimeout(resolve, 1000));
|
|
130
163
|
|
|
131
|
-
|
|
132
|
-
|
|
133
|
-
|
|
164
|
+
if (fs.existsSync(videoPath)) {
|
|
165
|
+
const webmBuffer = fs.readFileSync(videoPath);
|
|
166
|
+
await this.attach(webmBuffer, {
|
|
167
|
+
mediaType: "video/webm",
|
|
168
|
+
fileName: `${pickle.name.replaceAll(" ", "_")}.webm`,
|
|
169
|
+
});
|
|
170
|
+
}
|
|
134
171
|
}
|
|
135
172
|
}
|
|
136
173
|
});
|
|
137
174
|
|
|
138
|
-
AfterAll(
|
|
139
|
-
if (fs.existsSync(statusDir))
|
|
140
|
-
|
|
141
|
-
|
|
142
|
-
|
|
143
|
-
|
|
144
|
-
|
|
145
|
-
|
|
146
|
-
|
|
147
|
-
const
|
|
148
|
-
successPercentage
|
|
149
|
-
|
|
150
|
-
if (
|
|
151
|
-
|
|
152
|
-
|
|
153
|
-
|
|
154
|
-
|
|
155
|
-
|
|
156
|
-
|
|
157
|
-
)
|
|
158
|
-
|
|
159
|
-
|
|
160
|
-
console.log(
|
|
161
|
-
`Tests failed at required ${cucumberConfig.default.testPercentage}% success rate with ${successPercentage.toFixed(2)}%!`,
|
|
162
|
-
);
|
|
163
|
-
fs.writeFileSync(path.join(process.cwd(), `EXIT_CODE.txt`), "1");
|
|
164
|
-
}
|
|
175
|
+
AfterAll(() => {
|
|
176
|
+
if (!fs.existsSync(statusDir)) return;
|
|
177
|
+
|
|
178
|
+
const files = fs.readdirSync(statusDir);
|
|
179
|
+
const passedCount = files.filter((f) => f.split("-")[0] === "PASSED").length;
|
|
180
|
+
const totalTests = files.length;
|
|
181
|
+
const successPercentage = (passedCount / totalTests) * 100;
|
|
182
|
+
|
|
183
|
+
if (cucumberConfig.default.testPercentage !== undefined) {
|
|
184
|
+
const meetsThreshold =
|
|
185
|
+
successPercentage >= cucumberConfig.default.testPercentage;
|
|
186
|
+
|
|
187
|
+
if (meetsThreshold) {
|
|
188
|
+
console.log(
|
|
189
|
+
`✅ Tests passed required ${cucumberConfig.default.testPercentage}% success rate with ${successPercentage.toFixed(2)}%!`,
|
|
190
|
+
);
|
|
191
|
+
fs.writeFileSync(path.join(process.cwd(), "EXIT_CODE.txt"), "0");
|
|
192
|
+
} else {
|
|
193
|
+
console.log(
|
|
194
|
+
`❌ Tests failed required ${cucumberConfig.default.testPercentage}% success rate with ${successPercentage.toFixed(2)}%!`,
|
|
195
|
+
);
|
|
196
|
+
fs.writeFileSync(path.join(process.cwd(), "EXIT_CODE.txt"), "1");
|
|
165
197
|
}
|
|
166
198
|
}
|
|
167
199
|
});
|