@testrevolution/bugbug-cli 8.14.6 → 8.16.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/package.json
CHANGED
package/src/__mocks__/api.js
CHANGED
|
@@ -41,6 +41,12 @@ module.exports = {
|
|
|
41
41
|
webappUrl: 'http://localhost:3000/organizations/ed67dc98-16be-48d5-97fe-2f579ca6a62a/projects/cli-cc3abe1c-4540-4451-8bdc-41ac893e5720/runs-history/tests/cabe0d21-7693-4953-8851-581554a70368/',
|
|
42
42
|
},
|
|
43
43
|
},
|
|
44
|
+
stopTestRunRunSuccess: {
|
|
45
|
+
data: {
|
|
46
|
+
id: '95a37d6a-a7a5-42ae-8fe3-336a120b807b',
|
|
47
|
+
status: 'stopped',
|
|
48
|
+
},
|
|
49
|
+
},
|
|
44
50
|
getResultTestRunSuccess: {
|
|
45
51
|
data: {
|
|
46
52
|
details: [{
|
|
@@ -21,13 +21,12 @@ beforeAll(() => {
|
|
|
21
21
|
afterAll(() => {
|
|
22
22
|
config.__RewireAPI__.__ResetDependency__('readConfig');
|
|
23
23
|
});
|
|
24
|
+
jest.mock('axios');
|
|
24
25
|
|
|
25
26
|
afterEach(() => {
|
|
26
27
|
jest.restoreAllMocks();
|
|
27
28
|
});
|
|
28
29
|
|
|
29
|
-
jest.mock('axios');
|
|
30
|
-
|
|
31
30
|
describe('commands module', () => {
|
|
32
31
|
describe('help', () => {
|
|
33
32
|
it('should console log main help menu', async () => {
|
|
@@ -0,0 +1,95 @@
|
|
|
1
|
+
const axios = require('axios');
|
|
2
|
+
|
|
3
|
+
const {
|
|
4
|
+
remote: remoteCommand,
|
|
5
|
+
} = require('../commands');
|
|
6
|
+
const settings = require('../settings');
|
|
7
|
+
const config = require('../utils/config');
|
|
8
|
+
// eslint-disable-next-line jest/no-mocks-import
|
|
9
|
+
const apiMocks = require('../__mocks__/api');
|
|
10
|
+
|
|
11
|
+
const configValue = { item: 'value', token: '1337' };
|
|
12
|
+
|
|
13
|
+
beforeAll(() => {
|
|
14
|
+
// rewire discussion
|
|
15
|
+
// https://github.com/facebook/jest/issues/936#issuecomment-545080082
|
|
16
|
+
config.__RewireAPI__.__Rewire__('readConfig', jest.fn().mockReturnValue(configValue));
|
|
17
|
+
});
|
|
18
|
+
|
|
19
|
+
afterAll(() => {
|
|
20
|
+
config.__RewireAPI__.__ResetDependency__('readConfig');
|
|
21
|
+
});
|
|
22
|
+
jest.mock('axios');
|
|
23
|
+
|
|
24
|
+
afterEach(() => {
|
|
25
|
+
jest.restoreAllMocks();
|
|
26
|
+
});
|
|
27
|
+
|
|
28
|
+
describe('commands stop module', () => {
|
|
29
|
+
beforeAll(() => {
|
|
30
|
+
settings.API_POLLING_INTERVAL = 1;
|
|
31
|
+
settings.API_POLLING_MAX_RETRY_TIMES = 5;
|
|
32
|
+
settings.API_URL = 'https://bugbug.io/test-api/';
|
|
33
|
+
});
|
|
34
|
+
|
|
35
|
+
it('should return error when testRunId is missing', async () => {
|
|
36
|
+
const consoleLogSpy = jest.spyOn(console, 'error').mockImplementation();
|
|
37
|
+
const args = {
|
|
38
|
+
_: ['remote', 'stop', 'test'],
|
|
39
|
+
noprogress: true,
|
|
40
|
+
};
|
|
41
|
+
await remoteCommand(args);
|
|
42
|
+
|
|
43
|
+
expect(consoleLogSpy).toHaveBeenNthCalledWith(1, 'Missing testRun id.');
|
|
44
|
+
});
|
|
45
|
+
|
|
46
|
+
it('stop test command should call API', async () => {
|
|
47
|
+
const consoleLogSpy = jest.spyOn(console, 'error').mockImplementation();
|
|
48
|
+
axios.mockResolvedValueOnce(apiMocks.stopTestRunRunSuccess);
|
|
49
|
+
const id = '95a37d6a-a7a5-42ae-8fe3-336a120b807b';
|
|
50
|
+
const args = {
|
|
51
|
+
_: ['remote', 'stop', 'test', id],
|
|
52
|
+
noprogress: true,
|
|
53
|
+
};
|
|
54
|
+
await remoteCommand(args);
|
|
55
|
+
|
|
56
|
+
expect(consoleLogSpy).toHaveBeenNthCalledWith(1, `Status: ${apiMocks.stopTestRunRunSuccess.data.status}`);
|
|
57
|
+
expect(axios).toHaveBeenCalledWith({
|
|
58
|
+
method: 'POST',
|
|
59
|
+
url: `https://bugbug.io/test-api/v1/testruns/${id}/stop/`,
|
|
60
|
+
data: { triggeredBy: 'cli' },
|
|
61
|
+
params: {},
|
|
62
|
+
headers: { Authorization: `Token ${configValue.token}`, 'User-Agent': settings.USER_AGENT },
|
|
63
|
+
});
|
|
64
|
+
});
|
|
65
|
+
|
|
66
|
+
it('stop test action should call stopTestRun function', async () => {
|
|
67
|
+
const stopMock = jest.fn();
|
|
68
|
+
remoteCommand.__RewireAPI__.__Rewire__('stopTestRun', stopMock);
|
|
69
|
+
|
|
70
|
+
const id = '95a37d6a-a7a5-42ae-8fe3-336a120b807b';
|
|
71
|
+
const args = {
|
|
72
|
+
_: ['remote', 'stop', 'test', id],
|
|
73
|
+
noprogress: true,
|
|
74
|
+
};
|
|
75
|
+
await remoteCommand(args);
|
|
76
|
+
expect(stopMock).toHaveBeenCalledWith(id, {
|
|
77
|
+
noprogress: true, nowait: false, outputPath: 'test-report.xml', reporter: 'inline', triggeredBy: 'cli', withDetails: false,
|
|
78
|
+
});
|
|
79
|
+
});
|
|
80
|
+
|
|
81
|
+
it('stop suite action should call stopSuiteRun function', async () => {
|
|
82
|
+
const stopMock = jest.fn();
|
|
83
|
+
remoteCommand.__RewireAPI__.__Rewire__('stopSuiteRun', stopMock);
|
|
84
|
+
|
|
85
|
+
const id = '95a37d6a-a7a5-42ae-8fe3-336a120b807b';
|
|
86
|
+
const args = {
|
|
87
|
+
_: ['remote', 'stop', 'suite', id],
|
|
88
|
+
noprogress: true,
|
|
89
|
+
};
|
|
90
|
+
await remoteCommand(args);
|
|
91
|
+
expect(stopMock).toHaveBeenCalledWith(id, {
|
|
92
|
+
noprogress: true, nowait: false, outputPath: 'test-report.xml', reporter: 'inline', triggeredBy: 'cli', withDetails: false,
|
|
93
|
+
});
|
|
94
|
+
});
|
|
95
|
+
});
|
package/src/commands/help.js
CHANGED
|
@@ -23,6 +23,7 @@ const help = {
|
|
|
23
23
|
* run [test|suite] <string:testId|suiteId> [--no-wait] [--no-progress] [--debug] [--with-details] [--profile] [--variable] [--result-timeout <int>]
|
|
24
24
|
* status [test|suite] <string:testRunId|suiteRunId> [--no-progress] [--debug]
|
|
25
25
|
* result [test|suite] <string:testRunId|suiteRunId> [--no-progress] [--debug] [--with-details] [--result-timeout <int>]
|
|
26
|
+
* stop [test|suite] <string:testRunId|suiteRunId> [--no-progress] [--debug] [--result-timeout <int>]
|
|
26
27
|
|
|
27
28
|
optional flags:
|
|
28
29
|
* --debug - show more data (like raw API response)
|
package/src/commands/remote.js
CHANGED
|
@@ -128,6 +128,33 @@ const run = async (type, data, extraParams) => {
|
|
|
128
128
|
return getExitCode(false);
|
|
129
129
|
};
|
|
130
130
|
|
|
131
|
+
const stop = async (type, { id }, extraParams) => {
|
|
132
|
+
const { noprogress } = extraParams;
|
|
133
|
+
const route = settings.API_ROUTING[`${type}Stop`];
|
|
134
|
+
const spinner = getSpinner(noprogress);
|
|
135
|
+
|
|
136
|
+
if (!id) {
|
|
137
|
+
spinner.fail(`Missing ${type}Run id.`);
|
|
138
|
+
return getExitCode(false);
|
|
139
|
+
}
|
|
140
|
+
|
|
141
|
+
const path = format(route.path, id);
|
|
142
|
+
|
|
143
|
+
try {
|
|
144
|
+
const response = await apiCall(path, route.method, {}, {}, extraParams.triggeredBy);
|
|
145
|
+
printStatus(spinner, response.data.status);
|
|
146
|
+
|
|
147
|
+
return getExitCode(true);
|
|
148
|
+
} catch (error) {
|
|
149
|
+
if (error.response?.status === 404) {
|
|
150
|
+
spinner.fail(`No ${type}Run with id ${id} found.`);
|
|
151
|
+
} else {
|
|
152
|
+
await printErrorResponse(spinner, error);
|
|
153
|
+
}
|
|
154
|
+
}
|
|
155
|
+
return getExitCode(false);
|
|
156
|
+
};
|
|
157
|
+
|
|
131
158
|
const runTest = async (testId, profileName, variables, extraParams) => run(settings.TYPE_TEST, {
|
|
132
159
|
test_id: testId, profile_name: profileName, variables,
|
|
133
160
|
}, extraParams);
|
|
@@ -136,6 +163,14 @@ const runSuite = async (suiteId, profileName, variables, extraParams) => run(set
|
|
|
136
163
|
suite_id: suiteId, profile_name: profileName, variables,
|
|
137
164
|
}, extraParams);
|
|
138
165
|
|
|
166
|
+
const stopTestRun = async (testRunId, extraParams) => stop(settings.TYPE_TEST, {
|
|
167
|
+
id: testRunId,
|
|
168
|
+
}, extraParams);
|
|
169
|
+
|
|
170
|
+
const stopSuiteRun = async (suiteRunId, extraParams) => stop(settings.TYPE_SUITE, {
|
|
171
|
+
id: suiteRunId,
|
|
172
|
+
}, extraParams);
|
|
173
|
+
|
|
139
174
|
const checkTokenConfig = async () => {
|
|
140
175
|
try {
|
|
141
176
|
if (await getConfigValue('token') === undefined) {
|
|
@@ -223,6 +258,13 @@ module.exports = async (args) => {
|
|
|
223
258
|
case settings.ACTION_STATUS:
|
|
224
259
|
exitCode = await checkStatus(objectType, id, extraParams);
|
|
225
260
|
break;
|
|
261
|
+
case settings.ACTION_STOP:
|
|
262
|
+
if (objectType === settings.TYPE_TEST) {
|
|
263
|
+
exitCode = await stopTestRun(id, extraParams);
|
|
264
|
+
} else if (objectType === settings.TYPE_SUITE) {
|
|
265
|
+
exitCode = await stopSuiteRun(id, extraParams);
|
|
266
|
+
}
|
|
267
|
+
break;
|
|
226
268
|
case settings.ACTION_RESULT:
|
|
227
269
|
exitCode = await getResult(objectType, id, extraParams);
|
|
228
270
|
break;
|
package/src/settings.js
CHANGED
|
@@ -25,6 +25,7 @@ const ACTION_HELP = 'help';
|
|
|
25
25
|
const ACTION_SET_TOKEN = 'set-token';
|
|
26
26
|
const ACTION_LIST = 'list';
|
|
27
27
|
const ACTION_RUN = 'run';
|
|
28
|
+
const ACTION_STOP = 'stop';
|
|
28
29
|
const ACTION_STATUS = 'status';
|
|
29
30
|
const ACTION_RESULT = 'result';
|
|
30
31
|
|
|
@@ -35,10 +36,12 @@ const API_ROUTING = {
|
|
|
35
36
|
suiteResult: { method: 'GET', path: `${API_VERSION}/suiteruns/%s/` },
|
|
36
37
|
suiteRun: { method: 'POST', path: `${API_VERSION}/suiteruns/` },
|
|
37
38
|
suiteStatus: { method: 'GET', path: `${API_VERSION}/suiteruns/%s/status/` },
|
|
39
|
+
suiteStop: { method: 'POST', path: `${API_VERSION}/suiteruns/%s/stop/` },
|
|
38
40
|
testList: { method: 'GET', path: `${API_VERSION}/tests/` },
|
|
39
41
|
testResult: { method: 'GET', path: `${API_VERSION}/testruns/%s/` },
|
|
40
42
|
testRun: { method: 'POST', path: `${API_VERSION}/testruns/` },
|
|
41
43
|
testStatus: { method: 'GET', path: `${API_VERSION}/testruns/%s/status/` },
|
|
44
|
+
testStop: { method: 'POST', path: `${API_VERSION}/testruns/%s/stop/` },
|
|
42
45
|
};
|
|
43
46
|
|
|
44
47
|
const API_POLLING_MODIFIED_INTERVAL = 120000; // 120 seconds
|
|
@@ -81,6 +84,7 @@ module.exports = {
|
|
|
81
84
|
ACTION_RUN,
|
|
82
85
|
ACTION_SET_TOKEN,
|
|
83
86
|
ACTION_STATUS,
|
|
87
|
+
ACTION_STOP,
|
|
84
88
|
API_CALL_RETRIES,
|
|
85
89
|
API_CALL_RETRY_DELAY,
|
|
86
90
|
API_ERROR_QUOTA_EXCEEDED,
|