@testrigor/testrigor-cli 0.0.42-beta

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 ADDED
@@ -0,0 +1,33 @@
1
+ ## TestRigor Command Line
2
+
3
+ This is a command line tool for TestRigor. It allows you to run TestRigor tests from the command line.
4
+
5
+ ### Installation
6
+
7
+ 1. Install [Node.js](https://nodejs.org/en/download/) (version 18 or higher)
8
+ 2. Install TestRigor CLI: `npm install -g testrigor-cli`
9
+
10
+ ### Examples
11
+
12
+ 1. Basic `testrigor test-suite run <test-suite-id> --token <token>`
13
+ 2. With new URL `testrigor test-suite run <test-suite-id> --token <token> --url <url>`
14
+ 3. With file upload `testrigor test-suite run <test-suite-id> --token <token> --file-path <path-to-file>`
15
+ 4. With branch `testrigor test-suite run <test-suite-id> --token <token> --branch <branch> --commit <commit>`
16
+ 5. With variables `testrigor test-suite run <test-suite-id> --token <token> --variables-path file.json`
17
+ 6. Localhost mode `testrigor test-suite run <test-suite-id> --token <token> --localhost`
18
+ 7. With test cases `testrigor test-suite run <test-suite-id> --token <token> --test-cases-path test_cases/**/*.{yaml,txt}`
19
+ 8. With rules `testrigor test-suite run <test-suite-id> --token <token> --rules-path rules/**/*.yaml`
20
+ 9. With settings `testrigor test-suite run <test-suite-id> --token <token> --settings-path settings.yaml` (Can be YAML or JSON)
21
+ 10. Run a single test case `testrigor test-suite run <test-suite-id> --token <token> --test-case-uuid <test-case-uuid>`
22
+ 11. Run with auto create AI rules enabled `testrigor test-suite run <test-suite-id> --token <token> --test-cases-path test_cases/**/*.{yaml,txt} --auto-create-ai-rules`
23
+ 12. Run with explicit mutations enabled `testrigor test-suite run <test-suite-id> --token <token> --test-cases-path test_cases/**/*.{yaml,txt} --explicit-mutations`
24
+ 13. With all options `testrigor test-suite run <test-suite-id> --token <token> --url <url> --branch <branch> --commit <commit> --variables-path file.json --localhost --test-cases-path test_cases/**/*.{yaml,txt} --rules-path rules/**/*.{yaml,txt} --auto-create-ai-rules --explicit-mutations`
25
+ 14. Save JUnit report to `./junit-report.xml` (works only in sync mode): `testrigor test-suite run <test-suite-id> --token <token> --junit-report-save-path ./report.xml`
26
+ 15. With comma-separated labels `testrigor test-suite run <test-suite-id> --token <token> --labels <labels>`
27
+ 16. Excluding comma-separated labels `testrigor test-suite run <test-suite-id> --token <token> --excluded-labels <excluded-labels>`
28
+ 17. With different WEB and API URLs `testrigor test-suite run <test-suite-id> --token <token> --base-url-web=<base-web-url> --base-url-api=<base_api_url>`
29
+ 18. Set the default test suite ID: `testrigor test-suite config --default <test-suite-id>`
30
+ 19. Remove the default test suite ID: `testrigor test-suite config --delete`
31
+ 20. Show current configuration: `testrigor test-suite config --show`
32
+ 21. Authenticate with TestRigor and store credentials (interactive prompt): `testrigor authenticate`
33
+ 22. Run with override chrome extensions at runtime (one or more chrome extensions): `test-suite run <test-suite-id> --token <token> --chrome-extension "name=<extension-name> file=<extension-file>" --chrome-extension "name=<extension-name> file=<extension-file>"`
package/bin/dev ADDED
@@ -0,0 +1,18 @@
1
+ #!/usr/bin/env node
2
+
3
+ const oclif = require('@oclif/core')
4
+
5
+ const path = require('path')
6
+ const project = path.join(__dirname, '..', 'tsconfig.json')
7
+
8
+ // In dev mode -> use ts-node and dev plugins
9
+ process.env.NODE_ENV = 'development'
10
+
11
+ require('ts-node').register({project})
12
+
13
+ // In dev mode, always show stack traces
14
+ oclif.settings.debug = true;
15
+
16
+
17
+ // Start the CLI
18
+ oclif.run().then(oclif.flush).catch(oclif.Errors.handle)
package/bin/dev.cmd ADDED
@@ -0,0 +1,3 @@
1
+ @echo off
2
+
3
+ node "%~dp0\dev" %*
package/bin/run ADDED
@@ -0,0 +1,5 @@
1
+ #!/usr/bin/env node
2
+
3
+ const oclif = require('@oclif/core')
4
+
5
+ oclif.run().then(require('@oclif/core/flush')).catch(require('@oclif/core/handle'))
package/bin/run.cmd ADDED
@@ -0,0 +1,3 @@
1
+ @echo off
2
+
3
+ node "%~dp0\run" %*
@@ -0,0 +1,27 @@
1
+ import { Command, Interfaces } from "@oclif/core";
2
+ import Tunnel from "./util/tunnel";
3
+ export type CommandFlags<T extends typeof Command> = Interfaces.InferredFlags<(typeof CommandBase)["baseFlags"] & T["flags"]>;
4
+ export type Args<T extends typeof Command> = Interfaces.InferredArgs<T["args"]>;
5
+ export declare abstract class CommandBase<T extends typeof Command> extends Command {
6
+ static baseFlags: {
7
+ "auth-token": Interfaces.OptionFlag<string | undefined, import("@oclif/core/lib/interfaces/parser").CustomOptions>;
8
+ token: Interfaces.OptionFlag<string | undefined, import("@oclif/core/lib/interfaces/parser").CustomOptions>;
9
+ "min-port": Interfaces.OptionFlag<number, import("@oclif/core/lib/interfaces/parser").CustomOptions>;
10
+ "max-port": Interfaces.OptionFlag<number, import("@oclif/core/lib/interfaces/parser").CustomOptions>;
11
+ verbose: Interfaces.BooleanFlag<boolean>;
12
+ };
13
+ protected flags: CommandFlags<T>;
14
+ protected args: Args<T>;
15
+ protected tunnel: Tunnel;
16
+ init(): Promise<void>;
17
+ protected catch(err: Error & {
18
+ exitCode?: number;
19
+ }): Promise<any>;
20
+ protected finally(_: Error | undefined): Promise<any>;
21
+ protected setTunnel(tunnel: Tunnel): void;
22
+ protected getTunnel(): Tunnel;
23
+ private readTokenFromConfig;
24
+ protected readDefaultTestSuiteId(): Promise<string | null>;
25
+ protected resolveTestSuiteId(testSuiteId?: string | null): Promise<string>;
26
+ protected resolveToken(): Promise<string>;
27
+ }
@@ -0,0 +1,110 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.CommandBase = void 0;
4
+ const core_1 = require("@oclif/core");
5
+ const config_1 = require("./util/config");
6
+ class CommandBase extends core_1.Command {
7
+ async init() {
8
+ await super.init();
9
+ const { args, flags } = await this.parse({
10
+ flags: this.ctor.flags,
11
+ baseFlags: super.ctor.baseFlags,
12
+ args: this.ctor.args,
13
+ strict: this.ctor.strict,
14
+ });
15
+ this.flags = flags;
16
+ this.args = args;
17
+ }
18
+ async catch(err) {
19
+ if (this.tunnel) {
20
+ await this.tunnel.stop();
21
+ }
22
+ return super.catch(err);
23
+ }
24
+ async finally(_) {
25
+ if (this.tunnel) {
26
+ await this.tunnel.stop();
27
+ }
28
+ return super.finally(_);
29
+ }
30
+ setTunnel(tunnel) {
31
+ this.tunnel = tunnel;
32
+ }
33
+ getTunnel() {
34
+ return this.tunnel;
35
+ }
36
+ async readTokenFromConfig() {
37
+ return (await (0, config_1.readConfigProperty)("authToken")) || null;
38
+ }
39
+ async readDefaultTestSuiteId() {
40
+ return (await (0, config_1.readConfigProperty)("defaultTestSuiteId")) || null;
41
+ }
42
+ async resolveTestSuiteId(testSuiteId) {
43
+ if (testSuiteId) {
44
+ return testSuiteId;
45
+ }
46
+ const defaultTestSuiteId = await this.readDefaultTestSuiteId();
47
+ if (defaultTestSuiteId) {
48
+ return defaultTestSuiteId;
49
+ }
50
+ this.error("No test suite ID provided and none found in configuration.\n" +
51
+ "Please:\n" +
52
+ " 1. Provide a test suite ID as an argument, or\n" +
53
+ " 2. Run 'testrigor test-suite config --default YOUR_SUITE_ID' to set a default", { exit: 1 });
54
+ }
55
+ async resolveToken() {
56
+ // Priority 1: TESTRIGOR_API_KEY environment variable (highest priority)
57
+ if (process.env.TESTRIGOR_API_KEY) {
58
+ return process.env.TESTRIGOR_API_KEY;
59
+ }
60
+ // Priority 2: --authToken flag
61
+ if (this.flags["auth-token"]) {
62
+ return this.flags["auth-token"];
63
+ }
64
+ // Priority 3: --token flag
65
+ if (this.flags.token) {
66
+ return this.flags.token;
67
+ }
68
+ // Priority 4: Config yml file
69
+ const configToken = await this.readTokenFromConfig();
70
+ if (configToken) {
71
+ return configToken;
72
+ }
73
+ this.error("No authentication token found. Please:\n" +
74
+ " 1. Set TESTRIGOR_API_KEY environment variable, or\n" +
75
+ " 2. Use --auth-token TOKEN, or\n" +
76
+ " 3. Use --token TOKEN, or\n" +
77
+ " 4. Run 'testrigor authenticate' to store your token", { exit: -1 });
78
+ }
79
+ }
80
+ exports.CommandBase = CommandBase;
81
+ CommandBase.baseFlags = {
82
+ "auth-token": core_1.Flags.string({
83
+ description: "Personal authentication token",
84
+ required: false,
85
+ helpGroup: "GLOBAL",
86
+ }),
87
+ token: core_1.Flags.string({
88
+ char: "t",
89
+ description: "Suite authentication token",
90
+ required: false,
91
+ helpGroup: "GLOBAL",
92
+ }),
93
+ "min-port": core_1.Flags.integer({
94
+ description: "Min port for tunnel",
95
+ default: 40000,
96
+ min: 40000,
97
+ max: 50000,
98
+ }),
99
+ "max-port": core_1.Flags.integer({
100
+ description: "Max port for tunnel",
101
+ default: 50000,
102
+ min: 40000,
103
+ max: 50000,
104
+ }),
105
+ verbose: core_1.Flags.boolean({
106
+ description: "Verbose output",
107
+ default: false,
108
+ helpGroup: "GLOBAL",
109
+ }),
110
+ };
@@ -0,0 +1,6 @@
1
+ import { Command } from "@oclif/core";
2
+ export default class Authenticate extends Command {
3
+ static description: string;
4
+ static examples: string[];
5
+ run(): Promise<void>;
6
+ }
@@ -0,0 +1,59 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ const core_1 = require("@oclif/core");
4
+ const core_2 = require("@oclif/core");
5
+ const config_1 = require("../util/config");
6
+ class Authenticate extends core_2.Command {
7
+ async run() {
8
+ try {
9
+ // Load existing config (readConfig handles parse errors gracefully)
10
+ const config = await (0, config_1.readConfig)();
11
+ // Handle authentication token
12
+ let tokenPromptText;
13
+ if (config.authToken) {
14
+ tokenPromptText =
15
+ "Enter your testRigor API token (press enter to remove)";
16
+ }
17
+ else {
18
+ tokenPromptText =
19
+ "Enter your testRigor API token (press enter to skip)";
20
+ }
21
+ const token = await core_1.ux.prompt(tokenPromptText, {
22
+ type: "hide",
23
+ required: false,
24
+ });
25
+ if (!token || token.trim() === "") {
26
+ if (config.authToken) {
27
+ delete config.authToken;
28
+ await (0, config_1.writeConfig)(config);
29
+ core_1.ux.info("Authentication token removed");
30
+ }
31
+ else {
32
+ core_1.ux.info("Authentication token setup skipped");
33
+ }
34
+ }
35
+ else {
36
+ config.authToken = token.trim();
37
+ await (0, config_1.writeConfig)(config);
38
+ core_1.ux.info("Authentication token successfully saved");
39
+ if (config.defaultTestSuiteId) {
40
+ core_1.ux.info("You can now use 'testrigor run' to run your default test suite");
41
+ }
42
+ else {
43
+ core_1.ux.info("Use 'testrigor test-suite config --default TEST_SUITE_ID' to set your default test suite ID, then use 'testrigor run'");
44
+ }
45
+ }
46
+ }
47
+ catch (error) {
48
+ core_1.ux.error(`Failed to save configuration: ${error instanceof Error ? error.message : String(error)}`);
49
+ }
50
+ }
51
+ }
52
+ exports.default = Authenticate;
53
+ Authenticate.description = "Set your testRigor authentication token";
54
+ Authenticate.examples = [
55
+ "testrigor authenticate",
56
+ "Prompts for your API authentication token",
57
+ "Use 'testrigor test-suite config' to set default test suite ID separately",
58
+ "Config will be stored in ~/.testrigor/testrigor.yml",
59
+ ];
@@ -0,0 +1,14 @@
1
+ import { Command } from "@oclif/core";
2
+ export default class Config extends Command {
3
+ static description: string;
4
+ static examples: string[];
5
+ static flags: {
6
+ default: import("@oclif/core/lib/interfaces").OptionFlag<string | undefined, import("@oclif/core/lib/interfaces/parser").CustomOptions>;
7
+ delete: import("@oclif/core/lib/interfaces").BooleanFlag<boolean>;
8
+ show: import("@oclif/core/lib/interfaces").BooleanFlag<boolean>;
9
+ };
10
+ run(): Promise<void>;
11
+ private setDefaultTestSuite;
12
+ private deleteDefaultTestSuite;
13
+ private showConfiguration;
14
+ }
@@ -0,0 +1,97 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ const core_1 = require("@oclif/core");
4
+ const config_1 = require("../../util/config");
5
+ const allExclusiveFlags = ["default", "delete", "show"];
6
+ function getExclusiveFlags(currentFlag) {
7
+ return allExclusiveFlags.filter((flag) => flag !== currentFlag);
8
+ }
9
+ class Config extends core_1.Command {
10
+ async run() {
11
+ const { flags } = await this.parse(Config);
12
+ try {
13
+ if (flags.default) {
14
+ await this.setDefaultTestSuite(flags.default);
15
+ return;
16
+ }
17
+ if (flags.delete) {
18
+ await this.deleteDefaultTestSuite();
19
+ return;
20
+ }
21
+ if (flags.show) {
22
+ await this.showConfiguration();
23
+ return;
24
+ }
25
+ this.error("No action specified.\nFor usage details, run with --help.");
26
+ }
27
+ catch (error) {
28
+ this.error(`Failed to configure test suite: ${error instanceof Error ? error.message : String(error)}`);
29
+ }
30
+ }
31
+ async setDefaultTestSuite(testSuiteId) {
32
+ const config = await (0, config_1.readConfig)();
33
+ config.defaultTestSuiteId = testSuiteId.trim();
34
+ await (0, config_1.writeConfig)(config);
35
+ core_1.ux.info(`Default test suite ID set to: ${config.defaultTestSuiteId}`);
36
+ if (config.authToken) {
37
+ core_1.ux.info("You can now use 'testrigor run' to run your default test suite");
38
+ }
39
+ else {
40
+ core_1.ux.info("Use 'testrigor authenticate' to set your authentication token");
41
+ }
42
+ }
43
+ async deleteDefaultTestSuite() {
44
+ const config = await (0, config_1.readConfig)();
45
+ if (!config.defaultTestSuiteId) {
46
+ core_1.ux.info("No default test suite ID is currently set");
47
+ return;
48
+ }
49
+ delete config.defaultTestSuiteId;
50
+ await (0, config_1.writeConfig)(config);
51
+ core_1.ux.info("Default test suite ID removed");
52
+ if (config.authToken) {
53
+ core_1.ux.info("Authentication token preserved");
54
+ }
55
+ }
56
+ async showConfiguration() {
57
+ const config = await (0, config_1.readConfig)();
58
+ if (Object.keys(config).length === 0) {
59
+ core_1.ux.info("No configuration found");
60
+ return;
61
+ }
62
+ core_1.ux.info("Current testRigor configuration:");
63
+ if (config.defaultTestSuiteId) {
64
+ core_1.ux.info(` Default test suite ID: ${config.defaultTestSuiteId}`);
65
+ }
66
+ else {
67
+ core_1.ux.info(" Default test suite ID: not set");
68
+ }
69
+ if (config.authToken) {
70
+ core_1.ux.info(" Authentication token: configured");
71
+ }
72
+ else {
73
+ core_1.ux.info(" Authentication token: not set");
74
+ }
75
+ }
76
+ }
77
+ exports.default = Config;
78
+ Config.description = "Configure test suite settings and default test suite ID";
79
+ Config.examples = [
80
+ "testrigor test-suite config --default TEST-SUITE-ID",
81
+ "testrigor test-suite config --show",
82
+ "testrigor test-suite config --delete",
83
+ ];
84
+ Config.flags = {
85
+ default: core_1.Flags.string({
86
+ description: "Set the default test suite ID",
87
+ exclusive: getExclusiveFlags("default"),
88
+ }),
89
+ delete: core_1.Flags.boolean({
90
+ description: "Remove the default test suite ID",
91
+ exclusive: getExclusiveFlags("delete"),
92
+ }),
93
+ show: core_1.Flags.boolean({
94
+ description: "Show current configuration",
95
+ exclusive: getExclusiveFlags("show"),
96
+ }),
97
+ };
@@ -0,0 +1,46 @@
1
+ import { CommandBase } from "../../command-base";
2
+ export default class Run extends CommandBase<typeof Run> {
3
+ static description: string;
4
+ static examples: never[];
5
+ private TESTRIGOR_URL;
6
+ private TESTRIGOR_API_URL;
7
+ private TESTRIGOR_API2_URL;
8
+ static flags: {
9
+ async: import("@oclif/core/lib/interfaces").BooleanFlag<boolean>;
10
+ branch: import("@oclif/core/lib/interfaces").OptionFlag<string | undefined, import("@oclif/core/lib/interfaces/parser").CustomOptions>;
11
+ commit: import("@oclif/core/lib/interfaces").OptionFlag<string | undefined, import("@oclif/core/lib/interfaces/parser").CustomOptions>;
12
+ localhost: import("@oclif/core/lib/interfaces").BooleanFlag<boolean>;
13
+ url: import("@oclif/core/lib/interfaces").OptionFlag<string | undefined, import("@oclif/core/lib/interfaces/parser").CustomOptions>;
14
+ "file-path": import("@oclif/core/lib/interfaces").OptionFlag<string | undefined, import("@oclif/core/lib/interfaces/parser").CustomOptions>;
15
+ "junit-report-save-path": import("@oclif/core/lib/interfaces").OptionFlag<string | undefined, import("@oclif/core/lib/interfaces/parser").CustomOptions>;
16
+ "variables-path": import("@oclif/core/lib/interfaces").OptionFlag<string | undefined, import("@oclif/core/lib/interfaces/parser").CustomOptions>;
17
+ "test-cases-path": import("@oclif/core/lib/interfaces").OptionFlag<string | undefined, import("@oclif/core/lib/interfaces/parser").CustomOptions>;
18
+ "rules-path": import("@oclif/core/lib/interfaces").OptionFlag<string | undefined, import("@oclif/core/lib/interfaces/parser").CustomOptions>;
19
+ "settings-path": import("@oclif/core/lib/interfaces").OptionFlag<string | undefined, import("@oclif/core/lib/interfaces/parser").CustomOptions>;
20
+ "test-case-uuid": import("@oclif/core/lib/interfaces").OptionFlag<string | undefined, import("@oclif/core/lib/interfaces/parser").CustomOptions>;
21
+ "auto-create-ai-rules": import("@oclif/core/lib/interfaces").BooleanFlag<boolean>;
22
+ "explicit-mutations": import("@oclif/core/lib/interfaces").BooleanFlag<boolean>;
23
+ labels: import("@oclif/core/lib/interfaces").OptionFlag<string[] | undefined, import("@oclif/core/lib/interfaces/parser").CustomOptions>;
24
+ "excluded-labels": import("@oclif/core/lib/interfaces").OptionFlag<string[] | undefined, import("@oclif/core/lib/interfaces/parser").CustomOptions>;
25
+ "base-url-web": import("@oclif/core/lib/interfaces").OptionFlag<string | undefined, import("@oclif/core/lib/interfaces/parser").CustomOptions>;
26
+ "base-url-api": import("@oclif/core/lib/interfaces").OptionFlag<string | undefined, import("@oclif/core/lib/interfaces/parser").CustomOptions>;
27
+ "chrome-extension": import("@oclif/core/lib/interfaces").OptionFlag<{
28
+ name: string;
29
+ file: string;
30
+ } | undefined, import("@oclif/core/lib/interfaces/parser").CustomOptions>;
31
+ };
32
+ static args: {
33
+ testSuiteId: import("@oclif/core/lib/interfaces/parser").Arg<string | undefined, Record<string, unknown>>;
34
+ };
35
+ private initializeUrls;
36
+ run(): Promise<void>;
37
+ private fetchStatus;
38
+ private getStatusApiEndpoint;
39
+ private callRetest;
40
+ private uploadFile;
41
+ private waitForTestSuiteToBeCreated;
42
+ private waitForTestSuiteToFinish;
43
+ private fetchTestSuiteStatus;
44
+ private retryForValidStatus;
45
+ private startAndWaitForJunitReportToFinish;
46
+ }