transit-core-taf 1.0.21 → 1.0.22
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/dist/global-setup.js +0 -61
- package/dist/index.d.ts +1 -2
- package/dist/index.js +3 -2
- package/dist/reporters/testrail-reporter.d.ts +2 -6
- package/dist/reporters/testrail-reporter.js +14 -32
- package/dist/utils/testrail/client.d.ts +2 -1
- package/dist/utils/testrail/client.js +12 -9
- package/dist/utils/testrail-importer.d.ts +4 -5
- package/dist/utils/testrail-importer.js +51 -8
- package/package.json +5 -3
package/dist/global-setup.js
CHANGED
|
@@ -1,67 +1,6 @@
|
|
|
1
1
|
"use strict";
|
|
2
|
-
var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
|
|
3
|
-
if (k2 === undefined) k2 = k;
|
|
4
|
-
var desc = Object.getOwnPropertyDescriptor(m, k);
|
|
5
|
-
if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
|
|
6
|
-
desc = { enumerable: true, get: function() { return m[k]; } };
|
|
7
|
-
}
|
|
8
|
-
Object.defineProperty(o, k2, desc);
|
|
9
|
-
}) : (function(o, m, k, k2) {
|
|
10
|
-
if (k2 === undefined) k2 = k;
|
|
11
|
-
o[k2] = m[k];
|
|
12
|
-
}));
|
|
13
|
-
var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) {
|
|
14
|
-
Object.defineProperty(o, "default", { enumerable: true, value: v });
|
|
15
|
-
}) : function(o, v) {
|
|
16
|
-
o["default"] = v;
|
|
17
|
-
});
|
|
18
|
-
var __importStar = (this && this.__importStar) || (function () {
|
|
19
|
-
var ownKeys = function(o) {
|
|
20
|
-
ownKeys = Object.getOwnPropertyNames || function (o) {
|
|
21
|
-
var ar = [];
|
|
22
|
-
for (var k in o) if (Object.prototype.hasOwnProperty.call(o, k)) ar[ar.length] = k;
|
|
23
|
-
return ar;
|
|
24
|
-
};
|
|
25
|
-
return ownKeys(o);
|
|
26
|
-
};
|
|
27
|
-
return function (mod) {
|
|
28
|
-
if (mod && mod.__esModule) return mod;
|
|
29
|
-
var result = {};
|
|
30
|
-
if (mod != null) for (var k = ownKeys(mod), i = 0; i < k.length; i++) if (k[i] !== "default") __createBinding(result, mod, k[i]);
|
|
31
|
-
__setModuleDefault(result, mod);
|
|
32
|
-
return result;
|
|
33
|
-
};
|
|
34
|
-
})();
|
|
35
|
-
var __importDefault = (this && this.__importDefault) || function (mod) {
|
|
36
|
-
return (mod && mod.__esModule) ? mod : { "default": mod };
|
|
37
|
-
};
|
|
38
2
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
39
|
-
const dotenv = __importStar(require("dotenv"));
|
|
40
|
-
const path_1 = __importDefault(require("path"));
|
|
41
|
-
const fs = __importStar(require("fs"));
|
|
42
|
-
// Function to find the project root
|
|
43
|
-
const findProjectRoot = (startPath) => {
|
|
44
|
-
let currentPath = startPath;
|
|
45
|
-
while (currentPath !== path_1.default.parse(currentPath).root) {
|
|
46
|
-
if (fs.existsSync(path_1.default.join(currentPath, 'package.json'))) {
|
|
47
|
-
return currentPath;
|
|
48
|
-
}
|
|
49
|
-
currentPath = path_1.default.dirname(currentPath);
|
|
50
|
-
}
|
|
51
|
-
return startPath; // Fallback to the original directory if not found
|
|
52
|
-
};
|
|
53
3
|
async function globalSetup() {
|
|
54
|
-
const env = process.env.ENV || 'stage';
|
|
55
|
-
const projectRoot = path_1.default.resolve(__dirname, '..');
|
|
56
|
-
const envPath = path_1.default.join(projectRoot, `.env.${env}`);
|
|
57
|
-
// Load env file
|
|
58
|
-
if (fs.existsSync(envPath)) {
|
|
59
|
-
dotenv.config({ path: envPath, override: true });
|
|
60
|
-
console.log(`✅ Loaded ${envPath} from project root ${projectRoot} ✅`);
|
|
61
|
-
}
|
|
62
|
-
else {
|
|
63
|
-
throw new Error(`❌ Environment file .env.${env} not found in project root ${projectRoot} ❌`);
|
|
64
|
-
}
|
|
65
4
|
const argv = process.argv;
|
|
66
5
|
// Find all arguments related to project selection
|
|
67
6
|
const projectArgs = argv.map((arg, i) => {
|
package/dist/index.d.ts
CHANGED
|
@@ -9,7 +9,6 @@ export * from './utils/Utils';
|
|
|
9
9
|
export * from './baseapi/baseapihelpers';
|
|
10
10
|
export * from './baseapi/apiutils';
|
|
11
11
|
export * from './constants/test-tags';
|
|
12
|
-
export
|
|
12
|
+
export { TestRailClient, TestRailClientOptions, TestRailResult, } from './utils/testrail/client';
|
|
13
13
|
export * from './utils/testrail-importer';
|
|
14
14
|
export { default as TestRailReporter } from './reporters/testrail-reporter';
|
|
15
|
-
export type { TestRailReporterOptions } from './reporters/testrail-reporter';
|
package/dist/index.js
CHANGED
|
@@ -17,7 +17,7 @@ var __importDefault = (this && this.__importDefault) || function (mod) {
|
|
|
17
17
|
return (mod && mod.__esModule) ? mod : { "default": mod };
|
|
18
18
|
};
|
|
19
19
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
20
|
-
exports.TestRailReporter = void 0;
|
|
20
|
+
exports.TestRailReporter = exports.TestRailClient = void 0;
|
|
21
21
|
__exportStar(require("./baseui/basepagevalidations"), exports);
|
|
22
22
|
__exportStar(require("./baseui/basepageactions"), exports);
|
|
23
23
|
__exportStar(require("./baseui/basepagewaits"), exports);
|
|
@@ -29,7 +29,8 @@ __exportStar(require("./utils/Utils"), exports);
|
|
|
29
29
|
__exportStar(require("./baseapi/baseapihelpers"), exports);
|
|
30
30
|
__exportStar(require("./baseapi/apiutils"), exports);
|
|
31
31
|
__exportStar(require("./constants/test-tags"), exports);
|
|
32
|
-
|
|
32
|
+
var client_1 = require("./utils/testrail/client");
|
|
33
|
+
Object.defineProperty(exports, "TestRailClient", { enumerable: true, get: function () { return client_1.TestRailClient; } });
|
|
33
34
|
__exportStar(require("./utils/testrail-importer"), exports);
|
|
34
35
|
var testrail_reporter_1 = require("./reporters/testrail-reporter");
|
|
35
36
|
Object.defineProperty(exports, "TestRailReporter", { enumerable: true, get: function () { return __importDefault(testrail_reporter_1).default; } });
|
|
@@ -1,14 +1,10 @@
|
|
|
1
1
|
import { Reporter, FullConfig, Suite, FullResult } from '@playwright/test/reporter';
|
|
2
2
|
import { TestRailJunitImporterOptions } from '../utils/testrail-importer';
|
|
3
|
-
export interface TestRailReporterOptions extends Omit<TestRailJunitImporterOptions, 'junitPath' | 'onstart' | 'onend'> {
|
|
4
|
-
outputFile?: string;
|
|
5
|
-
}
|
|
6
3
|
declare class TestRailReporter implements Reporter {
|
|
7
4
|
private options;
|
|
8
|
-
private
|
|
9
|
-
constructor(options:
|
|
5
|
+
private runId;
|
|
6
|
+
constructor(options: TestRailJunitImporterOptions);
|
|
10
7
|
onBegin(config: FullConfig, suite: Suite): void;
|
|
11
8
|
onEnd(result: FullResult): Promise<void>;
|
|
12
|
-
private getJunitReporter;
|
|
13
9
|
}
|
|
14
10
|
export default TestRailReporter;
|
|
@@ -3,51 +3,33 @@ Object.defineProperty(exports, "__esModule", { value: true });
|
|
|
3
3
|
const testrail_importer_1 = require("../utils/testrail-importer");
|
|
4
4
|
class TestRailReporter {
|
|
5
5
|
options;
|
|
6
|
-
|
|
6
|
+
runId;
|
|
7
7
|
constructor(options) {
|
|
8
8
|
if (!options.runId) {
|
|
9
9
|
throw new Error('TestRail Reporter requires a `runId` to be specified.');
|
|
10
10
|
}
|
|
11
11
|
this.options = options;
|
|
12
|
+
this.runId = options.runId;
|
|
12
13
|
console.log('Initialized TestRail Reporter.');
|
|
13
14
|
}
|
|
14
15
|
onBegin(config, suite) {
|
|
15
|
-
this.config = config;
|
|
16
16
|
console.log(`Starting the run with ${suite.allTests().length} tests`);
|
|
17
17
|
}
|
|
18
18
|
async onEnd(result) {
|
|
19
19
|
console.log(`Run finished with status: ${result.status}`);
|
|
20
|
-
if (
|
|
21
|
-
|
|
22
|
-
|
|
20
|
+
if (this.options.junitPath) {
|
|
21
|
+
try {
|
|
22
|
+
await (0, testrail_importer_1.uploadJunitToTestRail)({
|
|
23
|
+
...this.options,
|
|
24
|
+
runId: this.runId,
|
|
25
|
+
junitPath: this.options.junitPath,
|
|
26
|
+
});
|
|
27
|
+
console.log('Successfully uploaded test results to TestRail.');
|
|
28
|
+
}
|
|
29
|
+
catch (error) {
|
|
30
|
+
console.error('Failed to upload results to TestRail:', error);
|
|
31
|
+
}
|
|
23
32
|
}
|
|
24
|
-
// Find the JUnit reporter's output file path from the Playwright config
|
|
25
|
-
const junitReporter = this.getJunitReporter(this.config);
|
|
26
|
-
if (!junitReporter) {
|
|
27
|
-
console.error('Error: JUnit reporter not found in Playwright config. The TestRail reporter depends on the output of the JUnit reporter.');
|
|
28
|
-
return;
|
|
29
|
-
}
|
|
30
|
-
const junitPath = junitReporter.outputFile || junitReporter._outputFile;
|
|
31
|
-
if (!junitPath) {
|
|
32
|
-
console.error('Error: Could not determine the output file path for the JUnit reporter.');
|
|
33
|
-
return;
|
|
34
|
-
}
|
|
35
|
-
console.log(`Using JUnit report from: ${junitPath}`);
|
|
36
|
-
try {
|
|
37
|
-
await (0, testrail_importer_1.uploadJunitToTestRail)({
|
|
38
|
-
...this.options,
|
|
39
|
-
junitPath,
|
|
40
|
-
});
|
|
41
|
-
console.log('Successfully uploaded test results to TestRail.');
|
|
42
|
-
}
|
|
43
|
-
catch (error) {
|
|
44
|
-
console.error('Failed to upload results to TestRail:', error);
|
|
45
|
-
}
|
|
46
|
-
}
|
|
47
|
-
getJunitReporter(config) {
|
|
48
|
-
// Playwright wraps reporters in an array, e.g., ['junit', { outputFile: 'results.xml' }]
|
|
49
|
-
const reporter = config.reporter.find((r) => r[0] === 'junit');
|
|
50
|
-
return reporter ? reporter[1] : undefined;
|
|
51
33
|
}
|
|
52
34
|
}
|
|
53
35
|
exports.default = TestRailReporter;
|
|
@@ -6,6 +6,7 @@ export interface TestRailClientOptions {
|
|
|
6
6
|
password?: string;
|
|
7
7
|
}
|
|
8
8
|
export interface TestRailResult {
|
|
9
|
+
case_id: number;
|
|
9
10
|
status_id: number;
|
|
10
11
|
comment?: string;
|
|
11
12
|
version?: string;
|
|
@@ -22,6 +23,6 @@ export declare class TestRailClient {
|
|
|
22
23
|
constructor(options: TestRailClientOptions);
|
|
23
24
|
private apiPost;
|
|
24
25
|
createTestRun(suiteId: number, name: string, description: string): Promise<any>;
|
|
25
|
-
|
|
26
|
+
addResultsForCases(runId: number, results: TestRailResult[]): Promise<any>;
|
|
26
27
|
addResultForCase(runId: number, caseId: number, result: TestRailResult): Promise<any>;
|
|
27
28
|
}
|
|
@@ -61,15 +61,18 @@ class TestRailClient {
|
|
|
61
61
|
console.log(`Successfully created Test Run with ID: ${run.id}. View at: ${run.url}`);
|
|
62
62
|
return run;
|
|
63
63
|
}
|
|
64
|
-
async
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
64
|
+
async addResultsForCases(runId, results) {
|
|
65
|
+
const endpoint = `add_results_for_cases/${runId}`;
|
|
66
|
+
console.log(`Adding ${results.length} results to Test Run ID: ${runId}`);
|
|
67
|
+
try {
|
|
68
|
+
const response = await this.apiPost(endpoint, { results });
|
|
69
|
+
console.log(`Successfully added ${results.length} results.`);
|
|
70
|
+
return response;
|
|
71
|
+
}
|
|
72
|
+
catch (error) {
|
|
73
|
+
console.error(`Failed to add results for Test Run ID: ${runId}.`, error);
|
|
74
|
+
throw error;
|
|
75
|
+
}
|
|
73
76
|
}
|
|
74
77
|
async addResultForCase(runId, caseId, result) {
|
|
75
78
|
const endpoint = `add_result_for_case/${runId}/${caseId}`;
|
|
@@ -4,13 +4,12 @@ export interface TestRailJunitImporterOptions extends TestRailClientOptions {
|
|
|
4
4
|
junitPath: string;
|
|
5
5
|
onstart?: () => void;
|
|
6
6
|
onend?: () => void;
|
|
7
|
+
statusMap?: {
|
|
8
|
+
[key: string]: number;
|
|
9
|
+
};
|
|
7
10
|
}
|
|
8
11
|
/**
|
|
9
|
-
*
|
|
10
|
-
*
|
|
11
|
-
* IMPORTANT: For this to work correctly, your test names must include the TestRail Case ID.
|
|
12
|
-
* The TestRail JUnit parser uses the test name to map results to cases.
|
|
13
|
-
* Example: test('C12345 My test description', async ({ page }) => { ... });
|
|
12
|
+
* Parses a JUnit XML report, extracts test results, and uploads them to a TestRail test run.
|
|
14
13
|
*
|
|
15
14
|
* @param options - The configuration options for the TestRail client and the JUnit import.
|
|
16
15
|
*/
|
|
@@ -36,17 +36,20 @@ Object.defineProperty(exports, "__esModule", { value: true });
|
|
|
36
36
|
exports.uploadJunitToTestRail = uploadJunitToTestRail;
|
|
37
37
|
const fs = __importStar(require("fs"));
|
|
38
38
|
const client_1 = require("./testrail/client");
|
|
39
|
+
const xmlJs = __importStar(require("xml-js"));
|
|
40
|
+
const defaultStatusMap = {
|
|
41
|
+
passed: 1,
|
|
42
|
+
failed: 5,
|
|
43
|
+
skipped: 2, // Mapped to 'Blocked'
|
|
44
|
+
};
|
|
45
|
+
const caseIdRegex = /C(\d+)/g;
|
|
39
46
|
/**
|
|
40
|
-
*
|
|
41
|
-
*
|
|
42
|
-
* IMPORTANT: For this to work correctly, your test names must include the TestRail Case ID.
|
|
43
|
-
* The TestRail JUnit parser uses the test name to map results to cases.
|
|
44
|
-
* Example: test('C12345 My test description', async ({ page }) => { ... });
|
|
47
|
+
* Parses a JUnit XML report, extracts test results, and uploads them to a TestRail test run.
|
|
45
48
|
*
|
|
46
49
|
* @param options - The configuration options for the TestRail client and the JUnit import.
|
|
47
50
|
*/
|
|
48
51
|
async function uploadJunitToTestRail(options) {
|
|
49
|
-
const { host, user, projectId, token, password, runId, junitPath, onstart, onend } = options;
|
|
52
|
+
const { host, user, projectId, token, password, runId, junitPath, onstart, onend, statusMap = defaultStatusMap, } = options;
|
|
50
53
|
onstart?.();
|
|
51
54
|
if (!fs.existsSync(junitPath)) {
|
|
52
55
|
throw new Error(`JUnit report not found at path: ${junitPath}`);
|
|
@@ -55,8 +58,48 @@ async function uploadJunitToTestRail(options) {
|
|
|
55
58
|
try {
|
|
56
59
|
console.log(`Reading JUnit report from: ${junitPath}`);
|
|
57
60
|
const xmlContent = fs.readFileSync(junitPath, 'utf-8');
|
|
58
|
-
|
|
59
|
-
|
|
61
|
+
const report = xmlJs.xml2js(xmlContent, { compact: true });
|
|
62
|
+
const results = [];
|
|
63
|
+
const testsuites = Array.isArray(report.testsuites.testsuite)
|
|
64
|
+
? report.testsuites.testsuite
|
|
65
|
+
: [report.testsuites.testsuite];
|
|
66
|
+
for (const testsuite of testsuites) {
|
|
67
|
+
if (!testsuite.testcase)
|
|
68
|
+
continue;
|
|
69
|
+
const testcases = Array.isArray(testsuite.testcase)
|
|
70
|
+
? testsuite.testcase
|
|
71
|
+
: [testsuite.testcase];
|
|
72
|
+
for (const testcase of testcases) {
|
|
73
|
+
const caseIds = testcase._attributes.name.match(caseIdRegex);
|
|
74
|
+
if (!caseIds)
|
|
75
|
+
continue;
|
|
76
|
+
const statusName = testcase.failure
|
|
77
|
+
? 'failed'
|
|
78
|
+
: testcase.skipped
|
|
79
|
+
? 'skipped'
|
|
80
|
+
: 'passed';
|
|
81
|
+
const statusId = statusMap[statusName];
|
|
82
|
+
if (statusId === undefined)
|
|
83
|
+
continue;
|
|
84
|
+
const comment = testcase.failure
|
|
85
|
+
? `Test failed: ${testcase.failure._attributes.message}`
|
|
86
|
+
: `Test ${statusName}`;
|
|
87
|
+
for (const caseId of caseIds) {
|
|
88
|
+
results.push({
|
|
89
|
+
case_id: parseInt(caseId.substring(1), 10),
|
|
90
|
+
status_id: statusId,
|
|
91
|
+
comment,
|
|
92
|
+
});
|
|
93
|
+
}
|
|
94
|
+
}
|
|
95
|
+
}
|
|
96
|
+
if (results.length > 0) {
|
|
97
|
+
await client.addResultsForCases(runId, results);
|
|
98
|
+
console.log('Successfully uploaded test results to TestRail.');
|
|
99
|
+
}
|
|
100
|
+
else {
|
|
101
|
+
console.log('No test results with case IDs found in the JUnit report.');
|
|
102
|
+
}
|
|
60
103
|
}
|
|
61
104
|
catch (error) {
|
|
62
105
|
console.error('Failed to upload JUnit report to TestRail.', error);
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "transit-core-taf",
|
|
3
|
-
"version": "1.0.
|
|
3
|
+
"version": "1.0.22",
|
|
4
4
|
"description": "Transit Core Automation Framework",
|
|
5
5
|
"main": "dist/index.js",
|
|
6
6
|
"types": "dist/index.d.ts",
|
|
@@ -24,7 +24,9 @@
|
|
|
24
24
|
"xlsx": "^0.18.5"
|
|
25
25
|
},
|
|
26
26
|
"dependencies": {
|
|
27
|
-
"
|
|
27
|
+
"@types/xml-js": "^0.9.0",
|
|
28
|
+
"axios": "^1.7.2",
|
|
29
|
+
"xml-js": "^1.6.11"
|
|
28
30
|
},
|
|
29
31
|
"peerDependencies": {
|
|
30
32
|
"playwright": "^1.54.1"
|
|
@@ -35,4 +37,4 @@
|
|
|
35
37
|
},
|
|
36
38
|
"author": "Transit Core",
|
|
37
39
|
"license": "ISC"
|
|
38
|
-
}
|
|
40
|
+
}
|