@testmonitor/testmonitor-cli 0.0.1
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/LICENSE.md +1 -0
- package/README.md +95 -0
- package/actions/SubmitReport.js +83 -0
- package/commands/submit.js +64 -0
- package/index.js +20 -0
- package/package.json +43 -0
package/LICENSE.md
ADDED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
Copyright (c) 2025 TestMonitor | we are Cerios B.V. <info@testmonitor.com>
|
package/README.md
ADDED
|
@@ -0,0 +1,95 @@
|
|
|
1
|
+
# TestMonitor CLI
|
|
2
|
+
|
|
3
|
+
TestMonitor CLI (`testmonitor-cli`) is a command-line tool to submit JUnit XML test results to a JSON API.
|
|
4
|
+
|
|
5
|
+
## Installation
|
|
6
|
+
|
|
7
|
+
Simply install the package by using NPM or Yarn:
|
|
8
|
+
|
|
9
|
+
```sh
|
|
10
|
+
npm install -g testmonitor-cli
|
|
11
|
+
```
|
|
12
|
+
|
|
13
|
+
or
|
|
14
|
+
|
|
15
|
+
```sh
|
|
16
|
+
yarn global add testmonitor-cli
|
|
17
|
+
```
|
|
18
|
+
|
|
19
|
+
This installs the TestMonitor CLI tool globally on your system.
|
|
20
|
+
|
|
21
|
+
## Authentication
|
|
22
|
+
|
|
23
|
+
TestMonitor CLI requires authentication via an API token. Set the token as an environment variable:
|
|
24
|
+
|
|
25
|
+
```sh
|
|
26
|
+
export TESTMONITOR_TOKEN=<your_api_token>
|
|
27
|
+
```
|
|
28
|
+
|
|
29
|
+
On Windows (PowerShell):
|
|
30
|
+
|
|
31
|
+
```sh
|
|
32
|
+
$env:TESTMONITOR_TOKEN="<your_api_token>"
|
|
33
|
+
```
|
|
34
|
+
|
|
35
|
+
## Usage
|
|
36
|
+
|
|
37
|
+
Once you've setup your TestMonitor token, you can start submitting JUnit reports:
|
|
38
|
+
|
|
39
|
+
```sh
|
|
40
|
+
testmonitor-cli submit -d <TESTMONITOR_DOMAIN> -i <INTEGRATION_ID> -f <FILE_PATH>
|
|
41
|
+
```
|
|
42
|
+
|
|
43
|
+
For example:
|
|
44
|
+
|
|
45
|
+
```sh
|
|
46
|
+
testmonitor-cli submit -d domain.testmonitor.com -i 12345-abcdef-67890-ghijkl -f results.xml
|
|
47
|
+
```
|
|
48
|
+
|
|
49
|
+
## Commands
|
|
50
|
+
|
|
51
|
+
### `submit`
|
|
52
|
+
|
|
53
|
+
Submit a JUnit XML test report.
|
|
54
|
+
|
|
55
|
+
**Options:**
|
|
56
|
+
```sh
|
|
57
|
+
-d, --domain <domain> TestMonitor domain (required)
|
|
58
|
+
-i, --integration-id <id> Integration ID (required)
|
|
59
|
+
-f, --file <path> Path to JUnit XML file (required)
|
|
60
|
+
```
|
|
61
|
+
|
|
62
|
+
## Development
|
|
63
|
+
|
|
64
|
+
Clone the repository and install dependencies:
|
|
65
|
+
|
|
66
|
+
```sh
|
|
67
|
+
git clone https://github.com/testmonitor/testmonitor-cli.git
|
|
68
|
+
cd testmonitor-cli
|
|
69
|
+
npm install
|
|
70
|
+
```
|
|
71
|
+
|
|
72
|
+
Run locally:
|
|
73
|
+
```sh
|
|
74
|
+
node index.js submit -d api.testmonitor.com -i 12345-abcdef-67890-ghijkl -f test-results.xml
|
|
75
|
+
```
|
|
76
|
+
|
|
77
|
+
Run tests:
|
|
78
|
+
```sh
|
|
79
|
+
npm test
|
|
80
|
+
```
|
|
81
|
+
|
|
82
|
+
## Versioning
|
|
83
|
+
|
|
84
|
+
We use [SemVer](http://semver.org/) for versioning. For the versions available, see the [tags](https://github.com/testmonitor/testmonitor/tags)
|
|
85
|
+
and the [releases](https://github.com/testmonitor/testmonitor/releases) on this repository.
|
|
86
|
+
|
|
87
|
+
## Authors
|
|
88
|
+
|
|
89
|
+
* **Thijs Kok** - *Lead developer* - [ThijsKok](https://github.com/thijskok)
|
|
90
|
+
* **Stephan Grootveld** - *Developer* - [Stefanius](https://github.com/stefanius)
|
|
91
|
+
* **Frank Keulen** - *Developer* - [FrankIsGek](https://github.com/frankisgek)
|
|
92
|
+
|
|
93
|
+
## License
|
|
94
|
+
|
|
95
|
+
TestMonitor is a commercial product, provided as a SaaS application to the customers of TestManagement BV.
|
|
@@ -0,0 +1,83 @@
|
|
|
1
|
+
import fs from 'fs';
|
|
2
|
+
import axios from 'axios';
|
|
3
|
+
import FormData from 'form-data';
|
|
4
|
+
import chalk from 'chalk';
|
|
5
|
+
import { table, getBorderCharacters } from 'table';
|
|
6
|
+
|
|
7
|
+
export class SubmitReport {
|
|
8
|
+
constructor({ domain, apiKey, integrationId, file, name, type, milestoneId, milestoneName, preserveNames, skipRootSuite, testEnvironmentId }) {
|
|
9
|
+
this.domain = domain;
|
|
10
|
+
this.apiKey = apiKey;
|
|
11
|
+
this.integrationId = integrationId;
|
|
12
|
+
this.file = file;
|
|
13
|
+
this.name = name;
|
|
14
|
+
this.type = type;
|
|
15
|
+
this.milestoneId = milestoneId;
|
|
16
|
+
this.milestoneName = milestoneName;
|
|
17
|
+
this.preserveNames = preserveNames;
|
|
18
|
+
this.skipRootSuite = skipRootSuite;
|
|
19
|
+
this.testEnvironmentId = testEnvironmentId;
|
|
20
|
+
}
|
|
21
|
+
|
|
22
|
+
async run() {
|
|
23
|
+
const formData = new FormData();
|
|
24
|
+
|
|
25
|
+
// Required
|
|
26
|
+
formData.append('integration_id', this.integrationId);
|
|
27
|
+
formData.append('report', fs.createReadStream(this.file));
|
|
28
|
+
|
|
29
|
+
// Optional
|
|
30
|
+
const optional = {
|
|
31
|
+
name: this.name,
|
|
32
|
+
type: this.type,
|
|
33
|
+
milestone: this.milestoneName,
|
|
34
|
+
milestone_id: this.milestoneId,
|
|
35
|
+
preserve_names: this.preserveNames ? 1: null,
|
|
36
|
+
skip_root_suite: this.skipRootSuite ? 1 : null,
|
|
37
|
+
test_environment_id: this.testEnvironmentId,
|
|
38
|
+
};
|
|
39
|
+
|
|
40
|
+
for (const [key, value] of Object.entries(optional)) {
|
|
41
|
+
if (value !== undefined && value !== null) {
|
|
42
|
+
formData.append(key, value);
|
|
43
|
+
}
|
|
44
|
+
}
|
|
45
|
+
|
|
46
|
+
try {
|
|
47
|
+
const response = await axios.post(
|
|
48
|
+
`https://${this.domain}/api/v1/reporters/junit/submit`,
|
|
49
|
+
formData,
|
|
50
|
+
{
|
|
51
|
+
headers: {
|
|
52
|
+
...formData.getHeaders(),
|
|
53
|
+
Authorization: `Bearer ${this.apiKey}`,
|
|
54
|
+
},
|
|
55
|
+
}
|
|
56
|
+
);
|
|
57
|
+
|
|
58
|
+
const { data } = response.data;
|
|
59
|
+
|
|
60
|
+
const config = {
|
|
61
|
+
border: getBorderCharacters('ramac'),
|
|
62
|
+
singleLine: true,
|
|
63
|
+
};
|
|
64
|
+
|
|
65
|
+
const rows = [
|
|
66
|
+
[chalk.bold('File'), data.name],
|
|
67
|
+
[chalk.bold('Date'), data.created_at],
|
|
68
|
+
[chalk.bold('ID'), data.test_run.id],
|
|
69
|
+
[chalk.bold('Code'), data.test_run.code],
|
|
70
|
+
[chalk.bold('Name'), data.test_run.name],
|
|
71
|
+
[chalk.bold('URL'), data.test_run.links.show],
|
|
72
|
+
];
|
|
73
|
+
|
|
74
|
+
console.log(table(rows, config));
|
|
75
|
+
|
|
76
|
+
console.log('Report submitted ' + chalk.green('successfully') + '.');
|
|
77
|
+
} catch (error) {
|
|
78
|
+
const message = error.response?.data?.message || error.message;
|
|
79
|
+
console.error(chalk.red('Error') + ': ' + message);
|
|
80
|
+
process.exit(1);
|
|
81
|
+
}
|
|
82
|
+
}
|
|
83
|
+
}
|
|
@@ -0,0 +1,64 @@
|
|
|
1
|
+
import { Command } from 'commander';
|
|
2
|
+
import { SubmitReport } from '../actions/SubmitReport.js';
|
|
3
|
+
import fs from 'fs';
|
|
4
|
+
import chalk from 'chalk';
|
|
5
|
+
import 'dotenv/config';
|
|
6
|
+
|
|
7
|
+
const submitCommand = new Command('submit')
|
|
8
|
+
.description('Submit a JUnit XML file to your TestMonitor instance.')
|
|
9
|
+
.helpOption('-h, --help', 'Display help for command')
|
|
10
|
+
.requiredOption('-d, --domain <domain>', 'Your TestMonitor domain name (e.g., mydomain.testmonitor.com)')
|
|
11
|
+
.requiredOption('-i, --integration-id <id>', 'The JUnit integration ID')
|
|
12
|
+
.requiredOption('-f, --file <path>', 'Path to your JUnit XML file')
|
|
13
|
+
.option('-m, --milestone-id <id>', 'The milestone ID for the new test run (required if not configured in your JUnit configuration)')
|
|
14
|
+
.option('-o, --milestone-name <name>', 'Finds or creates a milestone matching the name for the new test run')
|
|
15
|
+
.option('-n, --name <name>', 'The name for the new test run (will be auto-generated if not provided)')
|
|
16
|
+
.option('-p, --preserve-names', 'Preserve test case names exactly as they appear in the XML file.')
|
|
17
|
+
.option('-s, --skip-root-suite', 'Skip the root test suite and start from its nested suites.')
|
|
18
|
+
.option('-e, --test-environment-id <id>', 'The test environment ID for the new test run')
|
|
19
|
+
.option('-t, --type <type>', 'The automation test type (cypress, playwright, phpunit, selenium)')
|
|
20
|
+
.option('-v, --verbose', 'Output additional debug information')
|
|
21
|
+
.action(async (options) => {
|
|
22
|
+
const {
|
|
23
|
+
domain,
|
|
24
|
+
integrationId,
|
|
25
|
+
file,
|
|
26
|
+
name,
|
|
27
|
+
milestoneId,
|
|
28
|
+
milestoneName,
|
|
29
|
+
preserveNames,
|
|
30
|
+
skipRootSuite,
|
|
31
|
+
testEnvironmentId,
|
|
32
|
+
type,
|
|
33
|
+
verbose
|
|
34
|
+
} = options;
|
|
35
|
+
|
|
36
|
+
const apiKey = process.env.TESTMONITOR_TOKEN;
|
|
37
|
+
|
|
38
|
+
if (!apiKey) {
|
|
39
|
+
console.error(chalk.red('Error') + ': TESTMONITOR_TOKEN environment variable is not set.');
|
|
40
|
+
process.exit(1);
|
|
41
|
+
}
|
|
42
|
+
|
|
43
|
+
if (!fs.existsSync(file)) {
|
|
44
|
+
console.error(chalk.red('Error') + `: File not found at path ${file}`);
|
|
45
|
+
process.exit(1);
|
|
46
|
+
}
|
|
47
|
+
|
|
48
|
+
const action = new SubmitReport({
|
|
49
|
+
domain,
|
|
50
|
+
apiKey,
|
|
51
|
+
integrationId,
|
|
52
|
+
file,
|
|
53
|
+
name,
|
|
54
|
+
type,
|
|
55
|
+
milestoneId,
|
|
56
|
+
milestoneName,
|
|
57
|
+
preserveNames,
|
|
58
|
+
skipRootSuite,
|
|
59
|
+
testEnvironmentId
|
|
60
|
+
});
|
|
61
|
+
await action.run();
|
|
62
|
+
});
|
|
63
|
+
|
|
64
|
+
export default submitCommand;
|
package/index.js
ADDED
|
@@ -0,0 +1,20 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
|
|
3
|
+
import { Command } from 'commander';
|
|
4
|
+
import submitCommand from './commands/submit.js';
|
|
5
|
+
import 'dotenv/config';
|
|
6
|
+
|
|
7
|
+
const program = new Command();
|
|
8
|
+
|
|
9
|
+
program
|
|
10
|
+
.name('testmonitor-cli')
|
|
11
|
+
.version('0.0.1')
|
|
12
|
+
.description('CLI tool for interacting with the TestMonitor API.');
|
|
13
|
+
|
|
14
|
+
program.addCommand(submitCommand);
|
|
15
|
+
|
|
16
|
+
program.on('option:verbose', function () {
|
|
17
|
+
process.env.VERBOSE = this.opts().verbose;
|
|
18
|
+
});
|
|
19
|
+
|
|
20
|
+
program.parse(process.argv);
|
package/package.json
ADDED
|
@@ -0,0 +1,43 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "@testmonitor/testmonitor-cli",
|
|
3
|
+
"version": "0.0.1",
|
|
4
|
+
"description": "TestMonitor CLI tool",
|
|
5
|
+
"keywords": [
|
|
6
|
+
"testmonitor",
|
|
7
|
+
"cli"
|
|
8
|
+
],
|
|
9
|
+
"homepage": "https://www.testmonitor.com/",
|
|
10
|
+
"bugs": {
|
|
11
|
+
"url": "https://github.com/testmonitor/testmonitor-cli/issues"
|
|
12
|
+
},
|
|
13
|
+
"repository": {
|
|
14
|
+
"type": "git",
|
|
15
|
+
"url": "git+https://github.com/testmonitor/testmonitor-cli.git"
|
|
16
|
+
},
|
|
17
|
+
"author": "TestMonitor | we are Cerios B.V.",
|
|
18
|
+
"main": "index.js",
|
|
19
|
+
"bin": {
|
|
20
|
+
"testmonitor-cli": "index.js"
|
|
21
|
+
},
|
|
22
|
+
"scripts": {
|
|
23
|
+
"start": "node index.js",
|
|
24
|
+
"lint": "eslint .",
|
|
25
|
+
"test": "mocha"
|
|
26
|
+
},
|
|
27
|
+
"dependencies": {
|
|
28
|
+
"axios": "^1.7.9",
|
|
29
|
+
"chalk": "^5.4.1",
|
|
30
|
+
"commander": "^13.1.0",
|
|
31
|
+
"dotenv": "^16.4.7",
|
|
32
|
+
"table": "^6.9.0"
|
|
33
|
+
},
|
|
34
|
+
"devDependencies": {
|
|
35
|
+
"chai": "^5.2.0",
|
|
36
|
+
"eslint": "^9.21.0",
|
|
37
|
+
"mocha": "^11.1.0",
|
|
38
|
+
"sinon": "^19.0.2"
|
|
39
|
+
},
|
|
40
|
+
"engines": {
|
|
41
|
+
"node": ">=16.0.0"
|
|
42
|
+
}
|
|
43
|
+
}
|