@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 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
+ }