@msalaam/xray-qe-toolkit 1.1.0 → 1.3.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/README.md +427 -16
- package/bin/cli.js +6 -4
- package/commands/importResults.js +44 -10
- package/lib/playwrightConverter.js +297 -0
- package/lib/postmanGenerator.js +1 -2
- package/lib/xrayClient.js +24 -1
- package/package.json +1 -1
- package/templates/tests.json +564 -33
package/README.md
CHANGED
|
@@ -11,6 +11,7 @@
|
|
|
11
11
|
- [Installation](#installation)
|
|
12
12
|
- [AI Setup (Optional)](#ai-setup-optional)
|
|
13
13
|
- [Quick Start](#quick-start)
|
|
14
|
+
- [Playwright Quick Start](#playwright-quick-start)
|
|
14
15
|
- [CLI Commands](#cli-commands)
|
|
15
16
|
- [init](#xray-qe-init)
|
|
16
17
|
- [gen-tests](#xray-qe-gen-tests)
|
|
@@ -31,6 +32,7 @@
|
|
|
31
32
|
- [Jira/Xray Project Setup](#jiraxray-project-setup)
|
|
32
33
|
- [QE Workflow](#qe-workflow)
|
|
33
34
|
- [Building Regression Packs](#building-regression-packs)
|
|
35
|
+
- [Working with Existing Xray Tests](#working-with-existing-xray-tests)
|
|
34
36
|
- [Idempotent Push](#idempotent-push)
|
|
35
37
|
- [Programmatic API](#programmatic-api)
|
|
36
38
|
- [Troubleshooting](#troubleshooting)
|
|
@@ -46,8 +48,9 @@
|
|
|
46
48
|
3. **Idempotent push** — updates existing tests, creates new ones, skips duplicates
|
|
47
49
|
4. **Postman collection generation** from test definitions
|
|
48
50
|
5. **CI pipeline template** for Azure DevOps (Newman + Xray import)
|
|
49
|
-
6. **
|
|
50
|
-
7. **
|
|
51
|
+
6. **Playwright integration** — import Playwright JSON results with automatic test mapping
|
|
52
|
+
7. **Modular architecture** — every function is importable for programmatic use
|
|
53
|
+
8. **AI-ready scaffolds** — optional AI assistance for test generation (manual workflow fully supported)
|
|
51
54
|
|
|
52
55
|
### QE Review Gate Philosophy
|
|
53
56
|
|
|
@@ -242,7 +245,7 @@ All commands support these global options:
|
|
|
242
245
|
|
|
243
246
|
---
|
|
244
247
|
|
|
245
|
-
### `
|
|
248
|
+
### `xqt init`
|
|
246
249
|
|
|
247
250
|
Scaffold a new project with starter templates.
|
|
248
251
|
|
|
@@ -261,7 +264,7 @@ Existing files are **never overwritten** — the command skips them with a warni
|
|
|
261
264
|
|
|
262
265
|
---
|
|
263
266
|
|
|
264
|
-
### `
|
|
267
|
+
### `xqt gen-tests`
|
|
265
268
|
|
|
266
269
|
Generate test cases from `knowledge/` folder documentation (AI-assisted or manual guidance).
|
|
267
270
|
|
|
@@ -300,7 +303,7 @@ Existing files are **never overwritten** — the command skips them with a warni
|
|
|
300
303
|
|
|
301
304
|
---
|
|
302
305
|
|
|
303
|
-
### `
|
|
306
|
+
### `xqt edit-json`
|
|
304
307
|
|
|
305
308
|
Launch the browser-based QE review gate editor.
|
|
306
309
|
|
|
@@ -325,7 +328,7 @@ npx xqt edit-json --port 3000
|
|
|
325
328
|
|
|
326
329
|
---
|
|
327
330
|
|
|
328
|
-
### `
|
|
331
|
+
### `xqt push-tests`
|
|
329
332
|
|
|
330
333
|
Push or update tests in Xray Cloud from `tests.json`.
|
|
331
334
|
|
|
@@ -354,7 +357,7 @@ npx xqt push-tests --skip-exec
|
|
|
354
357
|
|
|
355
358
|
---
|
|
356
359
|
|
|
357
|
-
### `
|
|
360
|
+
### `xqt gen-postman`
|
|
358
361
|
|
|
359
362
|
Generate a Postman Collection v2.1 JSON from `tests.json` (works with or without AI).
|
|
360
363
|
|
|
@@ -398,7 +401,7 @@ npx xqt gen-postman --knowledge ./docs
|
|
|
398
401
|
|
|
399
402
|
---
|
|
400
403
|
|
|
401
|
-
### `
|
|
404
|
+
### `xqt create-execution`
|
|
402
405
|
|
|
403
406
|
Create a standalone Test Execution issue in JIRA.
|
|
404
407
|
|
|
@@ -415,22 +418,92 @@ npx xqt create-execution --summary "Feature XYZ" --issue QE-123
|
|
|
415
418
|
|
|
416
419
|
---
|
|
417
420
|
|
|
418
|
-
### `
|
|
421
|
+
### `xqt import-results`
|
|
419
422
|
|
|
420
|
-
Import
|
|
423
|
+
Import test results into Xray Cloud. Supports JUnit XML and Playwright JSON formats. Designed for CI — no human interaction.
|
|
424
|
+
|
|
425
|
+
#### Format Comparison
|
|
426
|
+
|
|
427
|
+
| Feature | JUnit XML | Playwright JSON |
|
|
428
|
+
|---------|-----------|----------------|
|
|
429
|
+
| **Update existing tests** | ❌ No - always creates new tests | ✅ Yes - via annotations |
|
|
430
|
+
| **Test key mapping** | ❌ Not supported | ✅ `test.info().annotations` |
|
|
431
|
+
| **Attachments/Evidence** | ❌ Not supported | ✅ Supported |
|
|
432
|
+
| **Best for** | Newman, generic test runners | Playwright tests |
|
|
433
|
+
| **Recommendation** | ⚠️ Use only for tools without test keys | ✅ **Recommended for Playwright** |
|
|
434
|
+
|
|
435
|
+
#### JUnit XML (Newman, generic test runners)
|
|
436
|
+
|
|
437
|
+
⚠️ **Important:** JUnit XML **cannot update existing Xray tests** - it will always create new test cases. Only use this for Newman or test runners that don't support test keys.
|
|
421
438
|
|
|
422
439
|
```bash
|
|
423
440
|
npx xqt import-results --file results.xml --testExecKey QE-123
|
|
424
441
|
```
|
|
425
442
|
|
|
426
|
-
|
|
427
|
-
|
|
428
|
-
|
|
429
|
-
|
|
443
|
+
#### Playwright JSON (Recommended)
|
|
444
|
+
|
|
445
|
+
✅ **Updates existing tests** via annotations. Use this format to link results to your existing Xray test cases.
|
|
446
|
+
|
|
447
|
+
```bash
|
|
448
|
+
# Generate JSON report in Playwright
|
|
449
|
+
npx playwright test --reporter=json > playwright-results.json
|
|
450
|
+
|
|
451
|
+
# Import to Xray (updates existing tests via annotations)
|
|
452
|
+
npx xqt import-results --file playwright-results.json --testExecKey QE-123
|
|
453
|
+
|
|
454
|
+
# Create new Test Execution automatically
|
|
455
|
+
npx xqt import-results --file playwright-results.json --summary "Regression Suite"
|
|
456
|
+
```
|
|
457
|
+
|
|
458
|
+
**Required test code:**
|
|
459
|
+
```typescript
|
|
460
|
+
import { test, expect } from '@playwright/test';
|
|
461
|
+
|
|
462
|
+
test('Verify API endpoint', async ({ request }) => {
|
|
463
|
+
// THIS LINE links to existing Xray test
|
|
464
|
+
test.info().annotations.push({ type: 'xray', description: 'PROJ-123' });
|
|
465
|
+
|
|
466
|
+
// Your test code...
|
|
467
|
+
});
|
|
468
|
+
```
|
|
469
|
+
|
|
470
|
+
| Option | Description | Required |
|
|
471
|
+
|-----------------------------|---------------------------------------------------|----------|
|
|
472
|
+
| `--file <path>` | Path to results file (.xml or .json) | Yes |
|
|
473
|
+
| `--testExecKey <key>` | Test Execution to link results to | No* |
|
|
474
|
+
| `--summary <text>` | Summary for new Test Execution (if no testExecKey) | No |
|
|
475
|
+
| `--description <text>` | Description for new Test Execution | No |
|
|
476
|
+
|
|
477
|
+
\* If `--testExecKey` is omitted, a new Test Execution will be created automatically.
|
|
478
|
+
|
|
479
|
+
**Mapping Playwright Tests to Xray:**
|
|
480
|
+
|
|
481
|
+
To link Playwright test results to existing Xray test cases, **you must use annotations**:
|
|
482
|
+
|
|
483
|
+
```typescript
|
|
484
|
+
// ✅ CORRECT - Updates existing test PROJ-123
|
|
485
|
+
test('User login flow', async ({ page }) => {
|
|
486
|
+
test.info().annotations.push({ type: 'xray', description: 'PROJ-123' });
|
|
487
|
+
// ... test code
|
|
488
|
+
});
|
|
489
|
+
|
|
490
|
+
// ✅ Alternative - Include test key in title
|
|
491
|
+
test('[PROJ-456] User registration validates email', async ({ page }) => {
|
|
492
|
+
// ... test code
|
|
493
|
+
});
|
|
494
|
+
|
|
495
|
+
// ❌ WRONG - Creates new test every time
|
|
496
|
+
test('User login flow', async ({ page }) => {
|
|
497
|
+
// Missing annotation - will create duplicate test!
|
|
498
|
+
// ... test code
|
|
499
|
+
});
|
|
500
|
+
```
|
|
501
|
+
|
|
502
|
+
**Without annotations:** A new test will be created in Xray with the test title as the summary (not recommended for existing tests).
|
|
430
503
|
|
|
431
504
|
---
|
|
432
505
|
|
|
433
|
-
### `
|
|
506
|
+
### `xqt gen-pipeline`
|
|
434
507
|
|
|
435
508
|
Generate an Azure Pipelines YAML template.
|
|
436
509
|
|
|
@@ -453,7 +526,7 @@ The generated pipeline:
|
|
|
453
526
|
|
|
454
527
|
---
|
|
455
528
|
|
|
456
|
-
### `
|
|
529
|
+
### `xqt mcp-server`
|
|
457
530
|
|
|
458
531
|
Start a Model Context Protocol server for GitHub Copilot agent-mode integration.
|
|
459
532
|
|
|
@@ -682,6 +755,177 @@ Use this checklist to align a new team's board and Xray configuration with the t
|
|
|
682
755
|
└─────────────────────────────────────────────────────────────────────────┘
|
|
683
756
|
```
|
|
684
757
|
|
|
758
|
+
## Playwright Quick Start
|
|
759
|
+
|
|
760
|
+
### Complete Setup for Updating Existing Xray Tests
|
|
761
|
+
|
|
762
|
+
This is the **recommended workflow** for teams using Playwright with existing Xray test cases.
|
|
763
|
+
|
|
764
|
+
#### Step 1: Install Playwright (in your test repo)
|
|
765
|
+
|
|
766
|
+
```bash
|
|
767
|
+
npm install --save-dev @playwright/test
|
|
768
|
+
```
|
|
769
|
+
|
|
770
|
+
#### Step 2: Configure Playwright
|
|
771
|
+
|
|
772
|
+
Create `playwright.config.ts` in your test repo:
|
|
773
|
+
|
|
774
|
+
```typescript
|
|
775
|
+
import { defineConfig } from '@playwright/test';
|
|
776
|
+
|
|
777
|
+
export default defineConfig({
|
|
778
|
+
reporter: [
|
|
779
|
+
['html'], // For local viewing
|
|
780
|
+
['json', { outputFile: 'playwright-results.json' }], // For Xray import
|
|
781
|
+
],
|
|
782
|
+
|
|
783
|
+
use: {
|
|
784
|
+
baseURL: process.env.API_BASE_URL || 'https://your-api.com',
|
|
785
|
+
extraHTTPHeaders: {
|
|
786
|
+
'Authorization': `Bearer ${process.env.API_TOKEN}`,
|
|
787
|
+
'X-API-Key': process.env.API_KEY || '',
|
|
788
|
+
},
|
|
789
|
+
},
|
|
790
|
+
});
|
|
791
|
+
```
|
|
792
|
+
|
|
793
|
+
#### Step 3: Write Tests with Xray Annotations
|
|
794
|
+
|
|
795
|
+
⚠️ **Critical:** Every test MUST have an annotation to update existing Xray tests.
|
|
796
|
+
|
|
797
|
+
```typescript
|
|
798
|
+
import { test, expect } from '@playwright/test';
|
|
799
|
+
|
|
800
|
+
test.describe('Regression Tests', () => {
|
|
801
|
+
|
|
802
|
+
test('Verify API returns 200 for valid request', async ({ request }) => {
|
|
803
|
+
// THIS LINE links to your existing Xray test
|
|
804
|
+
test.info().annotations.push({ type: 'xray', description: 'APIEE-7131' });
|
|
805
|
+
|
|
806
|
+
const response = await request.post('/api/verify', {
|
|
807
|
+
data: { userId: '123', action: 'validate' }
|
|
808
|
+
});
|
|
809
|
+
|
|
810
|
+
// Attach response as evidence for Xray
|
|
811
|
+
test.info().attach('response-evidence', {
|
|
812
|
+
body: JSON.stringify({
|
|
813
|
+
status: response.status(),
|
|
814
|
+
headers: response.headers(),
|
|
815
|
+
body: await response.json()
|
|
816
|
+
}, null, 2),
|
|
817
|
+
contentType: 'application/json'
|
|
818
|
+
});
|
|
819
|
+
|
|
820
|
+
expect(response.status()).toBe(200);
|
|
821
|
+
});
|
|
822
|
+
|
|
823
|
+
test('Verify API returns 400 for invalid data', async ({ request }) => {
|
|
824
|
+
test.info().annotations.push({ type: 'xray', description: 'APIEE-7132' });
|
|
825
|
+
// ... test implementation
|
|
826
|
+
});
|
|
827
|
+
|
|
828
|
+
});
|
|
829
|
+
```
|
|
830
|
+
|
|
831
|
+
#### Step 4: Map All Your Tests
|
|
832
|
+
|
|
833
|
+
Based on your `xray-mapping.json`, add annotations to each test:
|
|
834
|
+
|
|
835
|
+
```typescript
|
|
836
|
+
// If your xray-mapping.json shows:
|
|
837
|
+
// "TC-001": { "key": "APIEE-7131", "id": "1879092" }
|
|
838
|
+
// "TC-002": { "key": "APIEE-7132", "id": "1879095" }
|
|
839
|
+
|
|
840
|
+
test('Test Case 1', async ({ request }) => {
|
|
841
|
+
test.info().annotations.push({ type: 'xray', description: 'APIEE-7131' });
|
|
842
|
+
// ...
|
|
843
|
+
});
|
|
844
|
+
|
|
845
|
+
test('Test Case 2', async ({ request }) => {
|
|
846
|
+
test.info().annotations.push({ type: 'xray', description: 'APIEE-7132' });
|
|
847
|
+
// ...
|
|
848
|
+
});
|
|
849
|
+
```
|
|
850
|
+
|
|
851
|
+
#### Step 5: Run Locally
|
|
852
|
+
|
|
853
|
+
```bash
|
|
854
|
+
# Run tests
|
|
855
|
+
npx playwright test
|
|
856
|
+
|
|
857
|
+
# View HTML report
|
|
858
|
+
npx playwright show-report
|
|
859
|
+
|
|
860
|
+
# Upload to Xray (updates existing tests)
|
|
861
|
+
npx xqt import-results --file playwright-results.json --testExecKey APIEE-6811
|
|
862
|
+
```
|
|
863
|
+
|
|
864
|
+
#### Step 6: Configure CI/CD
|
|
865
|
+
|
|
866
|
+
**Azure Pipelines:**
|
|
867
|
+
|
|
868
|
+
```yaml
|
|
869
|
+
steps:
|
|
870
|
+
- task: NodeTool@0
|
|
871
|
+
inputs:
|
|
872
|
+
versionSpec: '18.x'
|
|
873
|
+
|
|
874
|
+
- script: npm ci
|
|
875
|
+
displayName: 'Install dependencies'
|
|
876
|
+
|
|
877
|
+
- script: npx playwright test
|
|
878
|
+
displayName: 'Run Playwright tests'
|
|
879
|
+
continueOnError: true
|
|
880
|
+
|
|
881
|
+
- script: |
|
|
882
|
+
npx xqt import-results \
|
|
883
|
+
--file playwright-results.json \
|
|
884
|
+
--testExecKey APIEE-6811
|
|
885
|
+
displayName: 'Upload results to Xray'
|
|
886
|
+
env:
|
|
887
|
+
XRAY_ID: $(XRAY_ID)
|
|
888
|
+
XRAY_SECRET: $(XRAY_SECRET)
|
|
889
|
+
JIRA_PROJECT_KEY: $(JIRA_PROJECT_KEY)
|
|
890
|
+
JIRA_URL: $(JIRA_URL)
|
|
891
|
+
JIRA_API_TOKEN: $(JIRA_API_TOKEN)
|
|
892
|
+
JIRA_EMAIL: $(JIRA_EMAIL)
|
|
893
|
+
```
|
|
894
|
+
|
|
895
|
+
**GitHub Actions:**
|
|
896
|
+
|
|
897
|
+
```yaml
|
|
898
|
+
steps:
|
|
899
|
+
- uses: actions/setup-node@v3
|
|
900
|
+
with:
|
|
901
|
+
node-version: '18'
|
|
902
|
+
|
|
903
|
+
- run: npm ci
|
|
904
|
+
|
|
905
|
+
- run: npx playwright test
|
|
906
|
+
|
|
907
|
+
- run: |
|
|
908
|
+
npx xqt import-results \
|
|
909
|
+
--file playwright-results.json \
|
|
910
|
+
--testExecKey APIEE-6811
|
|
911
|
+
env:
|
|
912
|
+
XRAY_ID: ${{ secrets.XRAY_ID }}
|
|
913
|
+
XRAY_SECRET: ${{ secrets.XRAY_SECRET }}
|
|
914
|
+
JIRA_PROJECT_KEY: ${{ secrets.JIRA_PROJECT_KEY }}
|
|
915
|
+
JIRA_URL: ${{ secrets.JIRA_URL }}
|
|
916
|
+
JIRA_API_TOKEN: ${{ secrets.JIRA_API_TOKEN }}
|
|
917
|
+
JIRA_EMAIL: ${{ secrets.JIRA_EMAIL }}
|
|
918
|
+
```
|
|
919
|
+
|
|
920
|
+
### Benefits
|
|
921
|
+
|
|
922
|
+
✅ **Updates existing tests** - No duplicate test creation
|
|
923
|
+
✅ **Automatic mapping** - Via annotations in test code
|
|
924
|
+
✅ **Evidence attachments** - Screenshots, responses, traces
|
|
925
|
+
✅ **Detailed reporting** - Retries, worker info, error details
|
|
926
|
+
✅ **CI/CD ready** - Standard workflow for automation
|
|
927
|
+
✅ **Single source of truth** - Test code + Xray together
|
|
928
|
+
|
|
685
929
|
---
|
|
686
930
|
|
|
687
931
|
## Building Regression Packs
|
|
@@ -823,6 +1067,173 @@ newman run collection.postman.json # Full regression weekly
|
|
|
823
1067
|
|
|
824
1068
|
---
|
|
825
1069
|
|
|
1070
|
+
## Working with Existing Xray Tests
|
|
1071
|
+
|
|
1072
|
+
If your team already has test cases in Xray Cloud that were created manually or by another tool, you can set up this toolkit to manage and update those existing tests.
|
|
1073
|
+
|
|
1074
|
+
### Step 1: Query Existing Tests from Xray
|
|
1075
|
+
|
|
1076
|
+
Use the Xray GraphQL API to fetch your existing tests. Here's a script to generate the mapping file:
|
|
1077
|
+
|
|
1078
|
+
**fetch-existing-tests.js:**
|
|
1079
|
+
```javascript
|
|
1080
|
+
import { authenticate, loadConfig } from "@msalaam/xray-qe-toolkit";
|
|
1081
|
+
import fs from "fs";
|
|
1082
|
+
|
|
1083
|
+
const cfg = loadConfig();
|
|
1084
|
+
const token = await authenticate(cfg);
|
|
1085
|
+
|
|
1086
|
+
// GraphQL query to fetch all tests in your project
|
|
1087
|
+
const query = `
|
|
1088
|
+
query {
|
|
1089
|
+
getTests(jql: "project = ${cfg.jiraProjectKey} AND issuetype = Test", limit: 1000) {
|
|
1090
|
+
total
|
|
1091
|
+
results {
|
|
1092
|
+
issueId
|
|
1093
|
+
jira(fields: ["key", "summary", "description", "priority", "labels"])
|
|
1094
|
+
}
|
|
1095
|
+
}
|
|
1096
|
+
}
|
|
1097
|
+
`;
|
|
1098
|
+
|
|
1099
|
+
const response = await fetch(cfg.xrayGraphQLUrl || "https://us.xray.cloud.getxray.app/api/v2/graphql", {
|
|
1100
|
+
method: "POST",
|
|
1101
|
+
headers: {
|
|
1102
|
+
"Content-Type": "application/json",
|
|
1103
|
+
Authorization: `Bearer ${token}`,
|
|
1104
|
+
},
|
|
1105
|
+
body: JSON.stringify({ query }),
|
|
1106
|
+
});
|
|
1107
|
+
|
|
1108
|
+
const data = await response.json();
|
|
1109
|
+
const tests = data.data.getTests.results;
|
|
1110
|
+
|
|
1111
|
+
// Generate xray-mapping.json
|
|
1112
|
+
const mapping = {};
|
|
1113
|
+
tests.forEach((test) => {
|
|
1114
|
+
const testId = test.jira.key; // Use JIRA key as test_id initially
|
|
1115
|
+
mapping[testId] = {
|
|
1116
|
+
key: test.jira.key,
|
|
1117
|
+
id: test.issueId,
|
|
1118
|
+
};
|
|
1119
|
+
});
|
|
1120
|
+
|
|
1121
|
+
fs.writeFileSync("xray-mapping.json", JSON.stringify(mapping, null, 2));
|
|
1122
|
+
console.log(`✓ Created xray-mapping.json with ${tests.length} tests`);
|
|
1123
|
+
|
|
1124
|
+
// Generate tests.json scaffold
|
|
1125
|
+
const testsJson = {
|
|
1126
|
+
testExecution: {
|
|
1127
|
+
summary: "Existing Tests - Managed by Toolkit",
|
|
1128
|
+
description: "Imported from existing Xray tests",
|
|
1129
|
+
},
|
|
1130
|
+
tests: tests.map((test) => ({
|
|
1131
|
+
test_id: test.jira.key,
|
|
1132
|
+
skip: false,
|
|
1133
|
+
tags: [],
|
|
1134
|
+
xray: {
|
|
1135
|
+
summary: test.jira.summary,
|
|
1136
|
+
description: test.jira.description || "",
|
|
1137
|
+
priority: test.jira.priority?.name || "Medium",
|
|
1138
|
+
labels: test.jira.labels || [],
|
|
1139
|
+
steps: [
|
|
1140
|
+
// You'll need to fetch test steps separately via another API call
|
|
1141
|
+
{
|
|
1142
|
+
action: "PLACEHOLDER - Edit this in npx xqt edit-json",
|
|
1143
|
+
data: "",
|
|
1144
|
+
expected_result: "PLACEHOLDER",
|
|
1145
|
+
},
|
|
1146
|
+
],
|
|
1147
|
+
},
|
|
1148
|
+
})),
|
|
1149
|
+
};
|
|
1150
|
+
|
|
1151
|
+
fs.writeFileSync("tests.json", JSON.stringify(testsJson, null, 2));
|
|
1152
|
+
console.log(`✓ Created tests.json with ${tests.length} test scaffolds`);
|
|
1153
|
+
console.log("\nNext steps:");
|
|
1154
|
+
console.log("1. Run 'npx xqt edit-json' to review and complete test steps");
|
|
1155
|
+
console.log("2. Run 'npx xqt push-tests' to update tests in Xray");
|
|
1156
|
+
```
|
|
1157
|
+
|
|
1158
|
+
### Step 2: Run the Script
|
|
1159
|
+
|
|
1160
|
+
```bash
|
|
1161
|
+
# Save the script above as fetch-existing-tests.js
|
|
1162
|
+
node fetch-existing-tests.js
|
|
1163
|
+
```
|
|
1164
|
+
|
|
1165
|
+
This generates:
|
|
1166
|
+
- `xray-mapping.json` — maps your existing JIRA test keys to their IDs
|
|
1167
|
+
- `tests.json` — scaffold with summaries, descriptions, priorities, labels
|
|
1168
|
+
|
|
1169
|
+
### Step 3: Complete Test Steps
|
|
1170
|
+
|
|
1171
|
+
The script can't fetch test steps automatically (requires additional API calls). Complete them in the editor:
|
|
1172
|
+
|
|
1173
|
+
```bash
|
|
1174
|
+
npx xqt edit-json
|
|
1175
|
+
# Edit each test to add proper steps
|
|
1176
|
+
# Save when done
|
|
1177
|
+
```
|
|
1178
|
+
|
|
1179
|
+
### Step 4: Update Existing Tests
|
|
1180
|
+
|
|
1181
|
+
Now you can update your existing Xray tests:
|
|
1182
|
+
|
|
1183
|
+
```bash
|
|
1184
|
+
npx xqt push-tests
|
|
1185
|
+
```
|
|
1186
|
+
|
|
1187
|
+
Because the tests are in `xray-mapping.json`, they'll be **updated** (not duplicated).
|
|
1188
|
+
|
|
1189
|
+
### Alternative: Manual Mapping Creation
|
|
1190
|
+
|
|
1191
|
+
If you have a small number of tests, create the mapping manually:
|
|
1192
|
+
|
|
1193
|
+
**xray-mapping.json:**
|
|
1194
|
+
```json
|
|
1195
|
+
{
|
|
1196
|
+
"APIEE-6933": { "key": "APIEE-6933", "id": "1865623" },
|
|
1197
|
+
"APIEE-6934": { "key": "APIEE-6934", "id": "1865627" },
|
|
1198
|
+
"APIEE-6935": { "key": "APIEE-6935", "id": "1865628" }
|
|
1199
|
+
}
|
|
1200
|
+
```
|
|
1201
|
+
|
|
1202
|
+
**tests.json:**
|
|
1203
|
+
```json
|
|
1204
|
+
{
|
|
1205
|
+
"tests": [
|
|
1206
|
+
{
|
|
1207
|
+
"test_id": "APIEE-6933",
|
|
1208
|
+
"xray": {
|
|
1209
|
+
"summary": "Test User Login",
|
|
1210
|
+
"steps": [
|
|
1211
|
+
{ "action": "...", "expected_result": "..." }
|
|
1212
|
+
]
|
|
1213
|
+
}
|
|
1214
|
+
}
|
|
1215
|
+
]
|
|
1216
|
+
}
|
|
1217
|
+
```
|
|
1218
|
+
|
|
1219
|
+
Then run `npx xqt push-tests` to update.
|
|
1220
|
+
|
|
1221
|
+
### Future Enhancement: Pull Command
|
|
1222
|
+
|
|
1223
|
+
A `pull-tests` command to automatically fetch and sync existing tests is planned:
|
|
1224
|
+
|
|
1225
|
+
```bash
|
|
1226
|
+
# Future feature (not yet implemented)
|
|
1227
|
+
npx xqt pull-tests --project APIEE
|
|
1228
|
+
npx xqt pull-tests --jql "project = APIEE AND labels = regression"
|
|
1229
|
+
```
|
|
1230
|
+
|
|
1231
|
+
This would automatically generate both `tests.json` and `xray-mapping.json` from Xray.
|
|
1232
|
+
|
|
1233
|
+
**Want this feature?** [Open an issue on GitHub](https://github.com/Muhammad-Salaam_omit/xray-qe-toolkit/issues) or contribute via PR.
|
|
1234
|
+
|
|
1235
|
+
---
|
|
1236
|
+
|
|
826
1237
|
## Idempotent Push
|
|
827
1238
|
|
|
828
1239
|
`push-tests` checks `xray-mapping.json` before each operation:
|
package/bin/cli.js
CHANGED
|
@@ -13,7 +13,7 @@
|
|
|
13
13
|
* push-tests Push / update tests in Xray Cloud
|
|
14
14
|
* gen-postman Generate Postman collection from tests.json (with optional AI)
|
|
15
15
|
* create-execution Create a new Test Execution in JIRA
|
|
16
|
-
* import-results Import
|
|
16
|
+
* import-results Import test results (JUnit XML or Playwright JSON) into Xray
|
|
17
17
|
* gen-pipeline Generate an Azure Pipelines YAML template
|
|
18
18
|
* mcp-server Start Model Context Protocol server for agent integration
|
|
19
19
|
*/
|
|
@@ -103,9 +103,11 @@ program
|
|
|
103
103
|
|
|
104
104
|
program
|
|
105
105
|
.command("import-results")
|
|
106
|
-
.description("Import
|
|
107
|
-
.requiredOption("--file <path>", "Path to the results
|
|
108
|
-
.
|
|
106
|
+
.description("Import test results into Xray Cloud (JUnit XML or Playwright JSON)")
|
|
107
|
+
.requiredOption("--file <path>", "Path to the results file (.xml for JUnit, .json for Playwright)")
|
|
108
|
+
.option("--testExecKey <key>", "Test Execution key to associate results with (creates new if omitted)")
|
|
109
|
+
.option("--summary <text>", "Test Execution summary (for new executions)")
|
|
110
|
+
.option("--description <text>", "Test Execution description (for new executions)")
|
|
109
111
|
.action(async (opts, cmd) => {
|
|
110
112
|
const mod = await import("../commands/importResults.js");
|
|
111
113
|
await mod.default({ ...opts, ...cmd.optsWithGlobals() });
|
|
@@ -1,8 +1,11 @@
|
|
|
1
1
|
/**
|
|
2
|
-
* Command:
|
|
2
|
+
* Command: xqt import-results --file <path> [--testExecKey <key>]
|
|
3
3
|
*
|
|
4
|
-
* Imports
|
|
5
|
-
*
|
|
4
|
+
* Imports test results into Xray Cloud and associates them with a Test Execution.
|
|
5
|
+
*
|
|
6
|
+
* Supported formats:
|
|
7
|
+
* - JUnit XML (.xml) - Standard JUnit or XUnit format
|
|
8
|
+
* - Playwright JSON (.json) - Playwright JSON reporter output
|
|
6
9
|
*
|
|
7
10
|
* Designed to run in CI — no human interaction required.
|
|
8
11
|
*/
|
|
@@ -11,7 +14,8 @@ import fs from "node:fs";
|
|
|
11
14
|
import path from "node:path";
|
|
12
15
|
import logger, { setVerbose } from "../lib/logger.js";
|
|
13
16
|
import { loadConfig, validateConfig } from "../lib/config.js";
|
|
14
|
-
import { authenticate, importResults as
|
|
17
|
+
import { authenticate, importResults as importResultsXml, importResultsXrayJson } from "../lib/xrayClient.js";
|
|
18
|
+
import { convertPlaywrightToXray } from "../lib/playwrightConverter.js";
|
|
15
19
|
|
|
16
20
|
export default async function importResults(opts = {}) {
|
|
17
21
|
if (opts.verbose) setVerbose(true);
|
|
@@ -27,23 +31,53 @@ export default async function importResults(opts = {}) {
|
|
|
27
31
|
process.exit(1);
|
|
28
32
|
}
|
|
29
33
|
|
|
30
|
-
|
|
31
|
-
|
|
34
|
+
const fileName = path.basename(filePath);
|
|
35
|
+
const fileExt = path.extname(filePath).toLowerCase();
|
|
36
|
+
|
|
37
|
+
logger.info(`File: ${fileName}`);
|
|
38
|
+
if (opts.testExecKey) {
|
|
39
|
+
logger.info(`Test Execution: ${opts.testExecKey}`);
|
|
40
|
+
}
|
|
32
41
|
logger.blank();
|
|
33
42
|
|
|
34
43
|
// Authenticate
|
|
35
44
|
const xrayToken = await authenticate(cfg);
|
|
36
45
|
|
|
37
|
-
//
|
|
38
|
-
|
|
39
|
-
|
|
46
|
+
// Detect format and import
|
|
47
|
+
let result;
|
|
48
|
+
|
|
49
|
+
if (fileExt === '.json') {
|
|
50
|
+
// Playwright JSON format
|
|
51
|
+
logger.send(`Importing Playwright JSON results...`);
|
|
40
52
|
|
|
41
|
-
|
|
53
|
+
const playwrightJson = JSON.parse(fs.readFileSync(filePath, 'utf-8'));
|
|
54
|
+
|
|
55
|
+
// Convert to Xray format
|
|
56
|
+
const xrayJson = convertPlaywrightToXray(playwrightJson, {
|
|
57
|
+
testExecutionKey: opts.testExecKey,
|
|
58
|
+
projectKey: cfg.jiraProjectKey,
|
|
59
|
+
summary: opts.summary || `Playwright Test Execution - ${new Date().toLocaleString()}`,
|
|
60
|
+
description: opts.description,
|
|
61
|
+
});
|
|
62
|
+
|
|
63
|
+
logger.step(`Converted ${xrayJson.tests.length} test results to Xray format`);
|
|
64
|
+
|
|
65
|
+
// Import to Xray
|
|
66
|
+
result = await importResultsXrayJson(cfg, xrayToken, xrayJson);
|
|
67
|
+
} else {
|
|
68
|
+
// JUnit XML format (default)
|
|
69
|
+
logger.send(`Importing JUnit XML results...`);
|
|
70
|
+
|
|
71
|
+
const xmlBuffer = fs.readFileSync(filePath);
|
|
72
|
+
result = await importResultsXml(cfg, xrayToken, xmlBuffer, opts.testExecKey);
|
|
73
|
+
}
|
|
42
74
|
|
|
43
75
|
logger.success("Results imported successfully");
|
|
44
76
|
|
|
45
77
|
if (result?.key) {
|
|
46
78
|
logger.link(`View: ${cfg.jiraUrl}/browse/${result.key}`);
|
|
79
|
+
} else if (result?.testExecIssue?.key) {
|
|
80
|
+
logger.link(`View: ${cfg.jiraUrl}/browse/${result.testExecIssue.key}`);
|
|
47
81
|
}
|
|
48
82
|
|
|
49
83
|
logger.blank();
|