Skip to content

Commit 4de1639

Browse files
Merge pull request #9 from prashanth-sams/upload
feat: Added automation api for bulk cucumber ouput upload
2 parents d00eea2 + 38cc0e2 commit 4de1639

File tree

7 files changed

+235
-9
lines changed

7 files changed

+235
-9
lines changed

Readme.md

Lines changed: 50 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -11,8 +11,11 @@ npm install --save-dev qmetry-cucumber
1111

1212
## How to use
1313

14-
#### qmetry.config.json
15-
Create `qmetry.config.json` file in the test project's root folder and add the below configurations.
14+
#### Case #1 Open API
15+
16+
> Create `qmetry.config.json` file in the test project's root folder and add the below configurations.
17+
18+
##### qmetry.config.json
1619
```
1720
{
1821
"baseUrl": "https://<your base url>",
@@ -26,6 +29,51 @@ Create `qmetry.config.json` file in the test project's root folder and add the b
2629
```
2730
Here, `testCycleId`, `summary` and `description` fields are optional.
2831

32+
#### Case #2 Automation API
33+
34+
> Submit the Cucumber test output in JSON format to QMetry using the Automation API. To achieve this, create a `qmetry.config.json` file in the root directory of your test project and add the following configurations.
35+
36+
##### qmetry.config.json
37+
```
38+
{
39+
"baseUrl": "https://<your base url>",
40+
"authorization": "<jira auth creds encoded by base64>",
41+
42+
"automationApiKey": "<automation api key>",
43+
"automation": {
44+
"format": "cucumber",
45+
"attachFile": true,
46+
"isZip":false,
47+
"build":"",
48+
"fields":{
49+
"testCycle":{
50+
"labels": ["<your label>"],
51+
"status":"Done",
52+
"summary": "<test cycle summary>",
53+
"description": "<test cycle description>",
54+
"customFields": [
55+
{
56+
"name": "<field name; say., Environment>",
57+
"value": "<field value; say., DEV>"
58+
}
59+
]
60+
},
61+
"testCase":{
62+
"labels": ["<your label>"],
63+
"description": "<test case description>",
64+
"customFields": [
65+
{
66+
"name": "<field name; say., Environment>",
67+
"value": "<field value; say., DEV>"
68+
}
69+
]
70+
}
71+
}
72+
}
73+
}
74+
```
75+
Here, `baseUrl`, `authorization`, `automationApiKey`, and `automation > format` are the only mandatory fields.
76+
2977
#### Feature
3078
```
3179
Scenario: [PRO-TC-1] [PRO-TC-2] User logs in with valid credentials

package.json

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
{
22
"name": "qmetry-cucumber",
3-
"version": "1.1.1",
3+
"version": "2.1.2",
44
"description": "Sync cucumber automation test results with Qmetry Test Cycle",
55
"main": "./dist/index.js",
66
"module": "./dist/index.mjs",
@@ -17,7 +17,7 @@
1717
"build": "rm -rf ./dist/* && tsup",
1818
"publish": "npm run build && npm publish",
1919
"lint": "prettier --check . && eslint .",
20-
"test": "jest"
20+
"test": "cd test && npm test"
2121
},
2222
"keywords": [
2323
"qmetry",

src/config.ts

Lines changed: 23 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -29,7 +29,29 @@ export const getConfig = async () => {
2929
projectId: data?.projectId,
3030
testCycleId: data?.testCycleId,
3131
summary: data?.summary || 'Test Cycle Summary',
32-
description: data?.description || 'Automated status update using qmetry-cucumber'
32+
description: data?.description || 'Automated status update using qmetry-cucumber',
33+
34+
automationApiKey: data?.automationApiKey,
35+
automation: {
36+
format: data?.automation?.format,
37+
attachFile: data?.automation?.attachFile,
38+
isZip: data?.automation?.isZip,
39+
build: data?.automation?.build,
40+
fields: {
41+
testCycle: {
42+
labels: data?.automation?.fields?.testCycle?.labels,
43+
status: data?.automation?.fields?.testCycle?.status,
44+
summary: data?.automation?.fields?.testCycle?.summary,
45+
description: data?.automation?.fields?.testCycle?.description,
46+
customFields: data?.automation?.fields?.testCycle?.customFields || [],
47+
},
48+
testCase: {
49+
labels: data?.automation?.fields?.testCase?.labels,
50+
description: data?.automation?.fields?.testCase?.description,
51+
customFields: data?.automation?.fields?.testCase?.customFields || [],
52+
},
53+
},
54+
}
3355
};
3456
} catch (error) {
3557
console.error('Error fetching configuration:', error);

src/qmetry-cucumber.ts

Lines changed: 67 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,9 @@
11
import axios, { AxiosResponse } from 'axios';
2-
import { TestStepResultStatus, ResponseData, ExecutionResultProps, ExecutionResult, ResultPair, TestCaseList, Keys } from './types';
2+
import { TestStepResultStatus, ResponseData, ExecutionResultProps, ExecutionResult, ResultPair, TestCaseList, importResultProps, Keys } from './types';
33
import { getConfig } from './config';
44
import { delay, checkStatusId } from './utils';
5+
import FormData from 'form-data';
6+
import fs from 'fs';
57

68
export async function updateQmetryStatus (name: string, status?: TestStepResultStatus) {
79
const config = await getConfig();
@@ -245,3 +247,67 @@ export async function validateTestCycleId(testCycleId: string): Promise<boolean>
245247

246248
return response;
247249
}
250+
251+
export async function sendTestResultToQmetry(jsonData: any) {
252+
const config = await getConfig();
253+
254+
const url = `${config.baseUrl}/rest/qtm4j/automation/latest/importresult`;
255+
256+
const headers = {
257+
'Content-Type': 'application/json',
258+
'apiKey': `${config.automationApiKey}`,
259+
'Authorization': `${config.authorization}`
260+
};
261+
262+
if (!config?.automation?.format) {
263+
throw new Error('Format is a required field but was not provided.');
264+
}
265+
266+
const body: importResultProps = {
267+
format: config.automation.format,
268+
attachFile: config?.automation.attachFile,
269+
isZip: config?.automation.isZip,
270+
build: config?.automation.build,
271+
fields: {
272+
testCycle: {
273+
labels: config?.automation?.fields?.testCycle?.labels,
274+
status: config?.automation?.fields?.testCycle?.status,
275+
summary: config?.automation?.fields?.testCycle?.summary,
276+
description: config?.automation?.fields?.testCycle?.description,
277+
customFields: config?.automation?.fields?.testCycle?.customFields || [],
278+
},
279+
testCase: {
280+
labels: config?.automation?.fields?.testCase?.labels,
281+
description: config?.automation?.fields?.testCase?.description,
282+
customFields: config?.automation?.fields?.testCase?.customFields || [],
283+
}
284+
}
285+
};
286+
287+
const response = await axios.post(url, body, { headers }).then((resp) => {
288+
return resp.data.url;
289+
});
290+
291+
submitFile(response, jsonData);
292+
}
293+
294+
export async function submitFile(url: string, jsonData: any) {
295+
296+
const config = await getConfig();
297+
const form = new FormData();
298+
299+
const headers = {
300+
'Content-Type': 'multipart/form-data',
301+
'apiKey': `${config.automationApiKey}`,
302+
'Authorization': `${config.authorization}`,
303+
};
304+
305+
form.append('file', fs.createReadStream(jsonData));
306+
307+
axios.post(url, form, { headers })
308+
.then((response) => {
309+
})
310+
.catch((error) => {
311+
console.error('Error submitting file:', error);
312+
});
313+
}

src/types.ts

Lines changed: 54 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -72,4 +72,58 @@ export interface QmetryConfig {
7272
testCycleId?: string;
7373
summary?: string;
7474
description?: string;
75+
automationApiKey?: string;
76+
automation?: Automation;
77+
}
78+
79+
export interface Automation {
80+
format: string;
81+
attachFile?: boolean;
82+
isZip?: boolean;
83+
build?: string;
84+
fields?: {
85+
testCycle?: {
86+
labels?: string[];
87+
status?: string;
88+
summary?: string;
89+
description?: string;
90+
customFields?: CustomField[];
91+
};
92+
testCase?: {
93+
labels?: string[];
94+
description?: string;
95+
customFields?: CustomField[];
96+
}
97+
}
98+
}
99+
100+
export interface CustomField {
101+
name: string;
102+
value: string;
103+
}
104+
105+
export interface ImportResultResponse {
106+
url: string;
107+
trackingId: string;
108+
}
109+
110+
export interface importResultProps {
111+
format: string;
112+
attachFile?: boolean;
113+
isZip?: boolean;
114+
build?: string;
115+
fields: {
116+
testCycle: {
117+
labels?: string[];
118+
status?: string;
119+
summary?: string;
120+
description?: string;
121+
customFields?: CustomField[];
122+
};
123+
testCase: {
124+
labels?: string[];
125+
description?: string;
126+
customFields?: CustomField[];
127+
}
128+
}
75129
}

test/qmetry.config.json

Lines changed: 37 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -2,5 +2,40 @@
22
"baseUrl": "",
33
"apiKey": "",
44
"authorization": "",
5-
"projectId": 0
6-
}
5+
"projectId": 0,
6+
"testCycleId": "",
7+
"summary":"",
8+
"description": "",
9+
10+
"automationApiKey": "",
11+
"automation": {
12+
"format": "cucumber",
13+
"attachFile": true,
14+
"isZip":false,
15+
"build":"",
16+
"fields":{
17+
"testCycle":{
18+
"labels": [""],
19+
"status":"Done",
20+
"summary":"",
21+
"description": "",
22+
"customFields": [
23+
{
24+
"name": "Environment",
25+
"value": "DEV"
26+
}
27+
]
28+
},
29+
"testCase":{
30+
"labels": [""],
31+
"description": "",
32+
"customFields": [
33+
{
34+
"name": "Environment",
35+
"value": "DEV"
36+
}
37+
]
38+
}
39+
}
40+
}
41+
}

test/src/test/hooks/hooks.ts

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -5,7 +5,7 @@ import { config } from "../../../playwright.config";
55
import { getEnv } from "../helper/env/env";
66
import { createLogger } from "winston";
77
import { options } from "../helper/utils/logger";
8-
import { updateQmetryStatus } from "../../../../src/qmetry-cucumber";
8+
import { updateQmetryStatus, sendTestResultToQmetry } from "../../../../src/qmetry-cucumber";
99

1010
export let context: BrowserContext;
1111
let browser: Browser;
@@ -71,4 +71,5 @@ After(async function ({ pickle, result }){
7171

7272
AfterAll(async function (){
7373
await browser.close();
74+
sendTestResultToQmetry(process.cwd() + '/test-result/reports/cucumber-report.json');
7475
});

0 commit comments

Comments
 (0)