transit-core-taf 1.0.5 → 1.0.7

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.
@@ -51,4 +51,21 @@ export declare class BasePageWaits {
51
51
  * @param timeout - Optional timeout in milliseconds (default: 5000).
52
52
  */
53
53
  waitForElementToBeVisible(element: Locator, timeout?: number): Promise<void>;
54
+ /**
55
+ * Waits for a given element to be invisible on the page.
56
+ * @param element - The Playwright Locator of the element to wait for to be invisible.
57
+ * @param timeout - Optional timeout in milliseconds (default: 10000).
58
+ */
59
+ waitForElementToBeInvisible(element: Locator, timeout?: number): Promise<void>;
60
+ /**
61
+ * A generic wait function for a given element.
62
+ * @param element - The Playwright Locator of the element to wait for.
63
+ * @param options - Optional parameters for state and timeout.
64
+ * @param {('attached' | 'detached' | 'visible' | 'hidden')} [options.state='visible'] - The state to wait for.
65
+ * @param {number} [options.timeout=10000] - Optional timeout in milliseconds.
66
+ */
67
+ waitFor(element: Locator, options?: {
68
+ state?: 'attached' | 'detached' | 'visible' | 'hidden';
69
+ timeout?: number;
70
+ }): Promise<void>;
54
71
  }
@@ -165,5 +165,38 @@ class BasePageWaits {
165
165
  throw error;
166
166
  }
167
167
  }
168
+ /**
169
+ * Waits for a given element to be invisible on the page.
170
+ * @param element - The Playwright Locator of the element to wait for to be invisible.
171
+ * @param timeout - Optional timeout in milliseconds (default: 10000).
172
+ */
173
+ async waitForElementToBeInvisible(element, timeout = 10000) {
174
+ try {
175
+ this.logger.info(`🔍 Waiting for element to be invisible: ${element.toString()} (timeout: ${timeout}ms)`);
176
+ await element.waitFor({ state: 'hidden', timeout });
177
+ }
178
+ catch (error) {
179
+ this.logger.error(`❌ Element did not become invisible: ${element.toString()} within ${timeout}ms`);
180
+ throw error;
181
+ }
182
+ }
183
+ /**
184
+ * A generic wait function for a given element.
185
+ * @param element - The Playwright Locator of the element to wait for.
186
+ * @param options - Optional parameters for state and timeout.
187
+ * @param {('attached' | 'detached' | 'visible' | 'hidden')} [options.state='visible'] - The state to wait for.
188
+ * @param {number} [options.timeout=10000] - Optional timeout in milliseconds.
189
+ */
190
+ async waitFor(element, options) {
191
+ const { state = 'visible', timeout = 10000 } = options || {};
192
+ try {
193
+ this.logger.info(`🔍 Waiting for element ${element.toString()} to be ${state} (timeout: ${timeout}ms)`);
194
+ await element.waitFor({ state, timeout });
195
+ }
196
+ catch (error) {
197
+ this.logger.error(`❌ Element ${element.toString()} did not reach state ${state} within ${timeout}ms`);
198
+ throw error;
199
+ }
200
+ }
168
201
  }
169
202
  exports.BasePageWaits = BasePageWaits;
@@ -9,3 +9,5 @@ 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 * from './reporters/testrail-reporter';
13
+ export * from './utils/testrail/client';
@@ -25,3 +25,5 @@ __exportStar(require("./utils/Utils"), exports);
25
25
  __exportStar(require("./baseapi/baseapihelpers"), exports);
26
26
  __exportStar(require("./baseapi/apiutils"), exports);
27
27
  __exportStar(require("./constants/test-tags"), exports);
28
+ __exportStar(require("./reporters/testrail-reporter"), exports);
29
+ __exportStar(require("./utils/testrail/client"), exports);
@@ -0,0 +1,11 @@
1
+ import { Reporter, FullConfig, Suite, TestCase, TestResult } from '@playwright/test/reporter';
2
+ declare class TestRailReporter implements Reporter {
3
+ private client;
4
+ private runId;
5
+ private suiteId;
6
+ private enabled;
7
+ constructor();
8
+ onBegin(config: FullConfig, suite: Suite): Promise<void>;
9
+ onTestEnd(test: TestCase, result: TestResult): Promise<void>;
10
+ }
11
+ export default TestRailReporter;
@@ -0,0 +1,79 @@
1
+ "use strict";
2
+ var __importDefault = (this && this.__importDefault) || function (mod) {
3
+ return (mod && mod.__esModule) ? mod : { "default": mod };
4
+ };
5
+ Object.defineProperty(exports, "__esModule", { value: true });
6
+ const client_1 = require("@/utils/testrail/client");
7
+ const dotenv_1 = __importDefault(require("dotenv"));
8
+ dotenv_1.default.config();
9
+ class TestRailReporter {
10
+ client = null;
11
+ runId = null;
12
+ suiteId = null;
13
+ enabled = false;
14
+ constructor() {
15
+ if (process.env.TESTRAIL_REPORTER_ENABLED === 'true') {
16
+ this.enabled = true;
17
+ try {
18
+ const host = process.env.TESTRAIL_HOST;
19
+ const user = process.env.TESTRAIL_USER;
20
+ const token = process.env.TESTRAIL_PASSWORD;
21
+ const projectId = process.env.TESTRAIL_PROJECT_ID;
22
+ if (!host || !user || !token || !projectId) {
23
+ throw new Error('TestRail credentials are not fully set in environment variables.');
24
+ }
25
+ this.client = new client_1.TestRailClient(host, user, token, projectId);
26
+ const suiteIdEnv = process.env.TESTRAIL_SUITE_ID;
27
+ if (!suiteIdEnv) {
28
+ throw new Error('TESTRAIL_SUITE_ID environment variable is not set.');
29
+ }
30
+ this.suiteId = parseInt(suiteIdEnv, 10);
31
+ if (isNaN(this.suiteId)) {
32
+ throw new Error('TESTRAIL_SUITE_ID is not a valid number.');
33
+ }
34
+ }
35
+ catch (error) {
36
+ console.error('Failed to initialize TestRail reporter:', error);
37
+ this.enabled = false;
38
+ }
39
+ }
40
+ else {
41
+ console.log("TestRail reporter is disabled. Set TESTRAIL_REPORTER_ENABLED to 'true' to enable.");
42
+ }
43
+ }
44
+ async onBegin(config, suite) {
45
+ if (!this.enabled || !this.client || !this.suiteId)
46
+ return;
47
+ const timestamp = new Date().toLocaleString();
48
+ const runName = `Automated Test Run - ${timestamp}`;
49
+ const runDescription = `Playwright test run executed on ${timestamp}`;
50
+ try {
51
+ const run = await this.client.createTestRun(this.suiteId, runName, runDescription);
52
+ this.runId = run.id;
53
+ }
54
+ catch (error) {
55
+ console.error('Failed to create TestRail test run. Disabling reporter.');
56
+ this.enabled = false;
57
+ }
58
+ }
59
+ async onTestEnd(test, result) {
60
+ if (!this.enabled || !this.client || !this.runId)
61
+ return;
62
+ const caseIdRegex = /C(\d+)/;
63
+ const match = test.title.match(caseIdRegex);
64
+ if (match) {
65
+ const caseId = parseInt(match[1], 10);
66
+ const comment = result.status === 'failed' || result.status === 'timedOut'
67
+ ? `Test failed with error: ${result.error?.message}`
68
+ : `Test completed with status: ${result.status}`;
69
+ try {
70
+ await this.client.addResultForCase(this.runId, caseId, result.status, comment);
71
+ console.log(`Successfully reported result for Case C${caseId} to TestRail.`);
72
+ }
73
+ catch (error) {
74
+ console.error(`Failed to report result for Case C${caseId}.`);
75
+ }
76
+ }
77
+ }
78
+ }
79
+ exports.default = TestRailReporter;
@@ -0,0 +1,15 @@
1
+ declare const statusMap: {
2
+ [key: string]: number;
3
+ };
4
+ export declare class TestRailClient {
5
+ private host;
6
+ private user;
7
+ private token;
8
+ private projectId;
9
+ private auth;
10
+ constructor(host: string, user: string, token: string, projectId: string);
11
+ private apiPost;
12
+ createTestRun(suiteId: number, name: string, description: string): Promise<any>;
13
+ addResultForCase(runId: number, caseId: number, status: keyof typeof statusMap, comment?: string): Promise<any>;
14
+ }
15
+ export {};
@@ -0,0 +1,71 @@
1
+ "use strict";
2
+ var __importDefault = (this && this.__importDefault) || function (mod) {
3
+ return (mod && mod.__esModule) ? mod : { "default": mod };
4
+ };
5
+ Object.defineProperty(exports, "__esModule", { value: true });
6
+ exports.TestRailClient = void 0;
7
+ const axios_1 = __importDefault(require("axios"));
8
+ const statusMap = {
9
+ passed: 1,
10
+ failed: 5,
11
+ timedOut: 5,
12
+ skipped: 2, // Mapped to 'Blocked'
13
+ };
14
+ class TestRailClient {
15
+ host;
16
+ user;
17
+ token;
18
+ projectId;
19
+ auth;
20
+ constructor(host, user, token, projectId) {
21
+ if (!host || !user || !token || !projectId) {
22
+ throw new Error('TestRail host, user, token, or project ID is missing.');
23
+ }
24
+ this.host = host;
25
+ this.user = user;
26
+ this.token = token;
27
+ this.projectId = projectId;
28
+ this.auth = `Basic ${Buffer.from(`${this.user}:${this.token}`).toString('base64')}`;
29
+ }
30
+ async apiPost(endpoint, data) {
31
+ const url = `${this.host}index.php?/api/v2/${endpoint}`;
32
+ try {
33
+ const response = await axios_1.default.post(url, data, {
34
+ headers: {
35
+ 'Content-Type': 'application/json',
36
+ Authorization: this.auth,
37
+ },
38
+ });
39
+ return response.data;
40
+ }
41
+ catch (error) {
42
+ console.error(`TestRail API Error: Failed to post to ${endpoint}.`, error.response ? error.response.data : error.message);
43
+ throw error;
44
+ }
45
+ }
46
+ async createTestRun(suiteId, name, description) {
47
+ console.log(`Creating TestRail Test Run for project ID: ${this.projectId}...`);
48
+ const data = {
49
+ suite_id: suiteId,
50
+ name,
51
+ description,
52
+ include_all: true,
53
+ };
54
+ const run = await this.apiPost(`add_run/${this.projectId}`, data);
55
+ console.log(`Successfully created Test Run with ID: ${run.id}`);
56
+ return run;
57
+ }
58
+ async addResultForCase(runId, caseId, status, comment) {
59
+ const status_id = statusMap[status];
60
+ if (status_id === undefined) {
61
+ console.warn(`Unknown test status: ${status}. Skipping TestRail update.`);
62
+ return;
63
+ }
64
+ const data = { status_id };
65
+ if (comment) {
66
+ data.comment = comment;
67
+ }
68
+ return this.apiPost(`add_result_for_case/${runId}/${caseId}`, data);
69
+ }
70
+ }
71
+ exports.TestRailClient = TestRailClient;
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "transit-core-taf",
3
- "version": "1.0.5",
3
+ "version": "1.0.7",
4
4
  "description": "Transit Core Automation Framework",
5
5
  "main": "dist/transit-core-taf/index.js",
6
6
  "types": "dist/transit-core-taf/index.d.ts",
@@ -20,6 +20,9 @@
20
20
  "typescript": "^5.0.0",
21
21
  "xlsx": "^0.18.5"
22
22
  },
23
+ "dependencies": {
24
+ "axios": "^1.7.2"
25
+ },
23
26
  "peerDependencies": {
24
27
  "playwright": "^1.54.1"
25
28
  },