suitest-js-api 4.2.0 → 4.2.2
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/lib/api/request.js +2 -2
- package/lib/api/webSockets.js +6 -2
- package/lib/commands/startREPL.js +1 -1
- package/lib/composers/thenComposer.js +1 -1
- package/lib/testLauncher/SuitestLauncher.js +1 -1
- package/lib/texts.js +2 -0
- package/lib/utils/chainPromise.js +1 -1
- package/lib/utils/logger.js +2 -2
- package/lib/utils/makeChain.js +1 -1
- package/lib/utils/progressHandler.js +2 -2
- package/lib/utils/sentry/Sentry.js +120 -0
- package/lib/utils/sentry/isSuitestUncaughtError.js +6 -6
- package/lib/utils/sessionStarter.js +1 -1
- package/package.json +3 -3
- package/suitest.js +3 -3
- package/lib/utils/sentry/Raven.js +0 -95
- package/lib/utils/testHelpers/mockRaven.js +0 -4
package/lib/api/request.js
CHANGED
|
@@ -8,7 +8,7 @@ const {apiUrl} = require('../../config');
|
|
|
8
8
|
const SuitestError = require('../utils/SuitestError');
|
|
9
9
|
const makeUrlFromArray = require('../utils/makeUrlFromArray');
|
|
10
10
|
const {suitestServerError} = require('../texts');
|
|
11
|
-
const {captureException} = require('../utils/sentry/
|
|
11
|
+
const {captureException} = require('../utils/sentry/Sentry');
|
|
12
12
|
|
|
13
13
|
/**
|
|
14
14
|
* Make http request
|
|
@@ -38,7 +38,7 @@ async function request(url, requestObject, onFail) {
|
|
|
38
38
|
} catch (e) {
|
|
39
39
|
// Caught low-level network error, i.e. not HTTP error
|
|
40
40
|
// Report it to Sentry
|
|
41
|
-
await captureException(e, {extra:{networkingError: true}});
|
|
41
|
+
await captureException(e, {extra: {networkingError: true}});
|
|
42
42
|
|
|
43
43
|
throw e;
|
|
44
44
|
}
|
package/lib/api/webSockets.js
CHANGED
|
@@ -6,7 +6,7 @@
|
|
|
6
6
|
const WS = require('ws');
|
|
7
7
|
const {v1: uuid} = require('uuid');
|
|
8
8
|
const {path} = require('ramda');
|
|
9
|
-
const
|
|
9
|
+
const {captureException} = require('../utils/sentry/Sentry');
|
|
10
10
|
const {fetch, setUserAgent} = require('../utils/fetch');
|
|
11
11
|
|
|
12
12
|
const SuitestError = require('../utils/SuitestError');
|
|
@@ -89,6 +89,10 @@ const webSocketsFactory = (self) => {
|
|
|
89
89
|
throw new SuitestError(texts.testingMinutesExceededMessage());
|
|
90
90
|
}
|
|
91
91
|
|
|
92
|
+
if (content.type === 'releasingDevice') {
|
|
93
|
+
throw new SuitestError(texts.releasingDeviceMessage());
|
|
94
|
+
}
|
|
95
|
+
|
|
92
96
|
if (content.type === 'executorStopped') {
|
|
93
97
|
// Notify user about executor being stopped
|
|
94
98
|
throw new SuitestError(texts.executorStopped());
|
|
@@ -276,7 +280,7 @@ const webSocketsFactory = (self) => {
|
|
|
276
280
|
try {
|
|
277
281
|
logger.log(translateNotStartedReason(res.reason));
|
|
278
282
|
} catch (error) {
|
|
279
|
-
|
|
283
|
+
captureException(error);
|
|
280
284
|
}
|
|
281
285
|
}
|
|
282
286
|
if (res.type === 'progress') {
|
|
@@ -10,7 +10,7 @@ const texts = require('../texts');
|
|
|
10
10
|
const {stackTraceParser} = require('../utils/stackTraceParser');
|
|
11
11
|
const suitest = require('../../index');
|
|
12
12
|
const {logger} = suitest;
|
|
13
|
-
const {captureMessage} = require('../utils/sentry/
|
|
13
|
+
const {captureMessage} = require('../utils/sentry/Sentry');
|
|
14
14
|
|
|
15
15
|
let isReplActive = false;
|
|
16
16
|
let replModeWasActivated = false;
|
|
@@ -5,7 +5,7 @@ const chainPromise = require('../utils/chainPromise');
|
|
|
5
5
|
const {fetchTestDefinitions} = require('../utils/chainUtils');
|
|
6
6
|
const {processServerResponse} = require('../utils/socketChainHelper');
|
|
7
7
|
const {translateLine} = require('../utils/chainUtils');
|
|
8
|
-
const {captureException} = require('../utils/sentry/
|
|
8
|
+
const {captureException} = require('../utils/sentry/Sentry');
|
|
9
9
|
const {connectionNotEstablished} = require('../texts');
|
|
10
10
|
|
|
11
11
|
// A map to find promise by chain data object
|
|
@@ -13,7 +13,7 @@ const {TEST_COMMAND, TOKEN} = require('../constants/modes');
|
|
|
13
13
|
const sessionConstants = require('../constants/session');
|
|
14
14
|
const {getDevicesDetails} = require('../utils/getDeviceInfo');
|
|
15
15
|
const {closeSessionUnchained} = require('../commands/closeSession');
|
|
16
|
-
const {captureException} = require('../utils/sentry/
|
|
16
|
+
const {captureException} = require('../utils/sentry/Sentry');
|
|
17
17
|
const t = require('../texts');
|
|
18
18
|
const {version} = require('../../package.json');
|
|
19
19
|
const ipcServer = require('./ipc/server');
|
package/lib/texts.js
CHANGED
|
@@ -164,6 +164,8 @@ ${leaves}`,
|
|
|
164
164
|
|
|
165
165
|
testingMinutesExceededMessage: () => 'You reached the limit of testing minutes specified by your subscription plan. If you need more minutes, contact us at sales@suite.st or upgrade your subscription.',
|
|
166
166
|
|
|
167
|
+
releasingDeviceMessage: () => 'The device has been disconnected.',
|
|
168
|
+
|
|
167
169
|
// ipc
|
|
168
170
|
ipcFailedToCreateServer: template`Failed to create IPC server. Port ${0} is busy.`,
|
|
169
171
|
|
package/lib/utils/logger.js
CHANGED
|
@@ -6,7 +6,7 @@ const timestamp = require('./timestamp');
|
|
|
6
6
|
const {truncate} = require('./stringUtils');
|
|
7
7
|
const {Transform} = require('stream');
|
|
8
8
|
const semver = require('semver');
|
|
9
|
-
const
|
|
9
|
+
const {captureException} = require('./sentry/Sentry');
|
|
10
10
|
|
|
11
11
|
/**
|
|
12
12
|
* Define custom colors
|
|
@@ -257,7 +257,7 @@ const createLogger = (config, pairedDeviceContext) => {
|
|
|
257
257
|
} else if (appLogger[lowercasedMethod]) {
|
|
258
258
|
appLogger[lowercasedMethod](...args);
|
|
259
259
|
} else {
|
|
260
|
-
|
|
260
|
+
captureException(new Error(`Received log method "${method}" does not exists`));
|
|
261
261
|
appLogger.log(...args);
|
|
262
262
|
}
|
|
263
263
|
};
|
package/lib/utils/makeChain.js
CHANGED
|
@@ -6,7 +6,7 @@
|
|
|
6
6
|
*/
|
|
7
7
|
|
|
8
8
|
const translate = require('../utils/translateResults');
|
|
9
|
-
const
|
|
9
|
+
const sentry = require('./sentry/Sentry');
|
|
10
10
|
|
|
11
11
|
/**
|
|
12
12
|
* Print progress description to stdout
|
|
@@ -21,7 +21,7 @@ function handleProgress(logger, res) {
|
|
|
21
21
|
logger.log(` - ${msg}`);
|
|
22
22
|
}
|
|
23
23
|
} catch (error) {
|
|
24
|
-
|
|
24
|
+
sentry.captureException(error);
|
|
25
25
|
}
|
|
26
26
|
}
|
|
27
27
|
|
|
@@ -0,0 +1,120 @@
|
|
|
1
|
+
/* istanbul ignore file */
|
|
2
|
+
|
|
3
|
+
/**
|
|
4
|
+
* Configure sentry reporting
|
|
5
|
+
*/
|
|
6
|
+
|
|
7
|
+
const Sentry = require('@sentry/node');
|
|
8
|
+
const isSuitestUncaughtError = require('./isSuitestUncaughtError');
|
|
9
|
+
const {version} = require('../../../package.json');
|
|
10
|
+
|
|
11
|
+
let isSetup = false;
|
|
12
|
+
|
|
13
|
+
const setUpSentry = (config, authContext) => {
|
|
14
|
+
if (!isSetup && !config.disallowCrashReports) {
|
|
15
|
+
Sentry.init({
|
|
16
|
+
dsn: config.sentryDsn,
|
|
17
|
+
release: version,
|
|
18
|
+
integrations(defaultIntegrations) {
|
|
19
|
+
// Keep behavior compatible with old Raven setup:
|
|
20
|
+
// - autoBreadcrumbs.console = false
|
|
21
|
+
// - autoBreadcrumbs.http = false
|
|
22
|
+
// - captureUnhandledRejections = false
|
|
23
|
+
return defaultIntegrations.filter(integration => {
|
|
24
|
+
return !['Console', 'Http', 'OnUnhandledRejection'].includes(integration.name);
|
|
25
|
+
});
|
|
26
|
+
},
|
|
27
|
+
beforeSend(data) {
|
|
28
|
+
// Populate error report with type of user session
|
|
29
|
+
data.user = {authType: authContext.context.toString()};
|
|
30
|
+
|
|
31
|
+
// send report if enabled in config and only uncaught suitest api errors
|
|
32
|
+
// and if message was sent
|
|
33
|
+
if (
|
|
34
|
+
!config.disallowCrashReports
|
|
35
|
+
&& (
|
|
36
|
+
(data.extra && data.extra.networkingError)
|
|
37
|
+
|| !data.exception
|
|
38
|
+
|| (
|
|
39
|
+
data.exception
|
|
40
|
+
&& data.exception.values
|
|
41
|
+
&& data.exception.values[0]
|
|
42
|
+
&& isSuitestUncaughtError(data.exception.values[0])
|
|
43
|
+
)
|
|
44
|
+
)
|
|
45
|
+
) {
|
|
46
|
+
return data;
|
|
47
|
+
}
|
|
48
|
+
|
|
49
|
+
return null;
|
|
50
|
+
},
|
|
51
|
+
});
|
|
52
|
+
isSetup = true;
|
|
53
|
+
}
|
|
54
|
+
};
|
|
55
|
+
|
|
56
|
+
/**
|
|
57
|
+
* Best-effort delivery for telemetry events.
|
|
58
|
+
* We intentionally do not fail the main execution flow if Sentry is unavailable.
|
|
59
|
+
*/
|
|
60
|
+
function flush() {
|
|
61
|
+
return Sentry.flush(2000)
|
|
62
|
+
.catch(() => undefined);
|
|
63
|
+
}
|
|
64
|
+
|
|
65
|
+
/**
|
|
66
|
+
* Explicitly capture provided exception
|
|
67
|
+
* @param {Error} error
|
|
68
|
+
* @param {Object} [extra]
|
|
69
|
+
* @returns {Promise<unknown>}
|
|
70
|
+
*/
|
|
71
|
+
function captureException(error, extra) {
|
|
72
|
+
Sentry.captureException(error, extra);
|
|
73
|
+
|
|
74
|
+
// Keep async contract
|
|
75
|
+
return flush();
|
|
76
|
+
}
|
|
77
|
+
|
|
78
|
+
/**
|
|
79
|
+
* @description Send log message to sentry
|
|
80
|
+
* @param {string} message
|
|
81
|
+
* @param {object} kwargs
|
|
82
|
+
* @returns {Promise<unknown>}
|
|
83
|
+
*/
|
|
84
|
+
function captureMessage(message, kwargs) {
|
|
85
|
+
Sentry.captureMessage(message, kwargs);
|
|
86
|
+
|
|
87
|
+
// Keep async contract
|
|
88
|
+
return flush();
|
|
89
|
+
}
|
|
90
|
+
|
|
91
|
+
/**
|
|
92
|
+
* Sentry's implementation of wrap does not trow an exception
|
|
93
|
+
* after it's reported. We need an error to be thrown to user.
|
|
94
|
+
* @param {Function} callback
|
|
95
|
+
* @returns {Function}
|
|
96
|
+
*/
|
|
97
|
+
const wrapThrow = callback => (...args) => {
|
|
98
|
+
try {
|
|
99
|
+
return callback.apply(undefined, args);
|
|
100
|
+
} catch (e) {
|
|
101
|
+
/*
|
|
102
|
+
* Capturing Sentry exception is asynchronous.
|
|
103
|
+
* While this function has to be synchronous.
|
|
104
|
+
* If client's application does not catch this exception and node
|
|
105
|
+
* crashes - we'll not get the report.
|
|
106
|
+
* If client's application does catch an error an process it somehow
|
|
107
|
+
* (e.g. mocha), we'll receive an exception in Sentry
|
|
108
|
+
*/
|
|
109
|
+
Sentry.captureException(e);
|
|
110
|
+
|
|
111
|
+
throw e;
|
|
112
|
+
}
|
|
113
|
+
};
|
|
114
|
+
|
|
115
|
+
module.exports = {
|
|
116
|
+
captureException,
|
|
117
|
+
captureMessage,
|
|
118
|
+
wrapThrow,
|
|
119
|
+
setUpSentry,
|
|
120
|
+
};
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
/**
|
|
2
|
-
* Investigate
|
|
2
|
+
* Investigate sentry error data.
|
|
3
3
|
* Error should not be reported if its not from suitest api code and not of defined SuitestError type
|
|
4
4
|
*/
|
|
5
5
|
|
|
@@ -8,13 +8,13 @@ const SuitestError = require('../SuitestError');
|
|
|
8
8
|
const isSuitestMethod = require('../isSuitestMethod');
|
|
9
9
|
|
|
10
10
|
/**
|
|
11
|
-
* @param {*}
|
|
11
|
+
* @param {*} sentryError
|
|
12
12
|
* @returns boolean
|
|
13
13
|
*/
|
|
14
|
-
function isSuitestUncaughtError(
|
|
15
|
-
return
|
|
16
|
-
&&
|
|
17
|
-
&&
|
|
14
|
+
function isSuitestUncaughtError(sentryError) {
|
|
15
|
+
return sentryError.type !== SuitestError.type // error is not SuitestError
|
|
16
|
+
&& sentryError.type !== ASSERTION_ERROR_TYPE // error is not node native AssertionError
|
|
17
|
+
&& sentryError.stacktrace.frames.some(fr => isSuitestMethod(fr.filename)); // but error occurred within suitest api code
|
|
18
18
|
}
|
|
19
19
|
|
|
20
20
|
module.exports = isSuitestUncaughtError;
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
const {TOKEN} = require('../constants/modes');
|
|
2
2
|
const chainPromise = require('./chainPromise');
|
|
3
3
|
const {validate, validators} = require('../validation');
|
|
4
|
-
const {captureException} = require('./sentry/
|
|
4
|
+
const {captureException} = require('./sentry/Sentry');
|
|
5
5
|
const envVars = require('../constants/environment');
|
|
6
6
|
const messageId = require('../constants/ipcMessageId');
|
|
7
7
|
const ipcClient = require('../testLauncher/ipc/client');
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "suitest-js-api",
|
|
3
|
-
"version": "4.2.
|
|
3
|
+
"version": "4.2.2",
|
|
4
4
|
"main": "index.js",
|
|
5
5
|
"repository": "github:SuitestAutomation/suitest-js-api",
|
|
6
6
|
"author": "Suitest <hello@suite.st>",
|
|
@@ -98,10 +98,11 @@
|
|
|
98
98
|
"typescript": "5.8.3"
|
|
99
99
|
},
|
|
100
100
|
"dependencies": {
|
|
101
|
+
"@sentry/node": "^7.120.3",
|
|
101
102
|
"@suitest/smst-to-text": "^4.28.5",
|
|
102
103
|
"@suitest/translate": "^4.31.0",
|
|
103
104
|
"@types/node": "^14.0.10",
|
|
104
|
-
"ajv": "^6.
|
|
105
|
+
"ajv": "^6.14.0",
|
|
105
106
|
"ansi-regex": "^5.0.0",
|
|
106
107
|
"chokidar": "^3.4.0",
|
|
107
108
|
"colors": "^1.4.0",
|
|
@@ -116,7 +117,6 @@
|
|
|
116
117
|
"package-json": "^7.0.0",
|
|
117
118
|
"prettyjson": "^1.2.1",
|
|
118
119
|
"ramda": "^0.27.0",
|
|
119
|
-
"raven": "^2.6.2",
|
|
120
120
|
"semver": "^7.3.2",
|
|
121
121
|
"stack-trace": "^0.0.10",
|
|
122
122
|
"uuid": "8.1.0",
|
package/suitest.js
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
require('./lib/utils/sentry/
|
|
1
|
+
require('./lib/utils/sentry/Sentry');
|
|
2
2
|
const {clone} = require('ramda');
|
|
3
3
|
|
|
4
4
|
// Commands
|
|
@@ -77,7 +77,7 @@ const ipcServer = require('./lib/testLauncher/ipc/server');
|
|
|
77
77
|
const Context = require('./lib/utils/Context');
|
|
78
78
|
const AuthContext = require('./lib/utils/AuthContext');
|
|
79
79
|
const {configFactory} = require('./config');
|
|
80
|
-
const {
|
|
80
|
+
const {setUpSentry} = require('./lib/utils/sentry/Sentry');
|
|
81
81
|
const {warnLauncherAndLibHasDiffVersions} = require('./lib/utils/packageMetadataHelper');
|
|
82
82
|
const {createLogger} = require('./lib/utils/logger');
|
|
83
83
|
|
|
@@ -106,7 +106,7 @@ class SUITEST_API extends EventEmitter {
|
|
|
106
106
|
this.logger = createLogger(this.configuration.config, this.pairedDeviceContext);
|
|
107
107
|
this.unusedExpressionWatchers = unusedExpressionWatchersFactory(this);
|
|
108
108
|
this.webSockets = webSocketsFactory(this);
|
|
109
|
-
|
|
109
|
+
setUpSentry(this.configuration.config, this.authContext);
|
|
110
110
|
|
|
111
111
|
this.openSession = (...args) => openSession(this, ...args);
|
|
112
112
|
this.pairDevice = (...args) => pairDevice(this, ...args);
|
|
@@ -1,95 +0,0 @@
|
|
|
1
|
-
/* istanbul ignore file */
|
|
2
|
-
|
|
3
|
-
/**
|
|
4
|
-
* Configure raven sentry reporting
|
|
5
|
-
*/
|
|
6
|
-
|
|
7
|
-
const Raven = require('raven');
|
|
8
|
-
const isSuitestUncaughtError = require('./isSuitestUncaughtError');
|
|
9
|
-
const {version} = require('../../../package.json');
|
|
10
|
-
|
|
11
|
-
let isSetup = false;
|
|
12
|
-
|
|
13
|
-
const setUpRaven = (config, authContext) => {
|
|
14
|
-
if (!isSetup && !config.disallowCrashReports) {
|
|
15
|
-
Raven
|
|
16
|
-
.config(config.sentryDsn, {
|
|
17
|
-
release: version,
|
|
18
|
-
dataCallback: data => {
|
|
19
|
-
// Populate error report with type of user session
|
|
20
|
-
data.user = {authType: authContext.context.toString()};
|
|
21
|
-
|
|
22
|
-
return data;
|
|
23
|
-
},
|
|
24
|
-
autoBreadcrumbs: {
|
|
25
|
-
'console': false, // console logging
|
|
26
|
-
'http': false, // rest requests (during unit testing, nock disables some requests)
|
|
27
|
-
},
|
|
28
|
-
captureUnhandledRejections: false,
|
|
29
|
-
shouldSendCallback(data) {
|
|
30
|
-
// send report if enabled in config and only uncaught suitest api errors
|
|
31
|
-
// and if message was sent
|
|
32
|
-
|
|
33
|
-
return !config.disallowCrashReports && (
|
|
34
|
-
data.extra.networkingError
|
|
35
|
-
|| !data.exception
|
|
36
|
-
|| isSuitestUncaughtError(data.exception[0])
|
|
37
|
-
);
|
|
38
|
-
},
|
|
39
|
-
})
|
|
40
|
-
.install(err => {
|
|
41
|
-
isSetup = !!err;
|
|
42
|
-
});
|
|
43
|
-
}
|
|
44
|
-
};
|
|
45
|
-
|
|
46
|
-
/**
|
|
47
|
-
* Explicitly capture provided exception
|
|
48
|
-
* @param {Error} error
|
|
49
|
-
* @param {Object} [extra]
|
|
50
|
-
* @returns {Promise<*>}
|
|
51
|
-
*/
|
|
52
|
-
function captureException(error, extra) {
|
|
53
|
-
return new Promise(res => Raven.captureException(error, extra, res));
|
|
54
|
-
}
|
|
55
|
-
|
|
56
|
-
/**
|
|
57
|
-
* @description Send log message to sentry
|
|
58
|
-
* @param {string} message
|
|
59
|
-
* @param {object} kwargs
|
|
60
|
-
* @returns {Promise<unknown>}
|
|
61
|
-
*/
|
|
62
|
-
function captureMessage(message, kwargs) {
|
|
63
|
-
return new Promise(res => Raven.captureMessage(message, kwargs, res));
|
|
64
|
-
}
|
|
65
|
-
|
|
66
|
-
/**
|
|
67
|
-
* Sentry's implementation of wrap does not trow an exception
|
|
68
|
-
* after it's reported. We need an error to be thrown to user.
|
|
69
|
-
* @param {Function} callback
|
|
70
|
-
* @returns {Function}
|
|
71
|
-
*/
|
|
72
|
-
const wrapThrow = callback => (...args) => {
|
|
73
|
-
try {
|
|
74
|
-
return callback.apply(undefined, args);
|
|
75
|
-
} catch (e) {
|
|
76
|
-
/*
|
|
77
|
-
* Capturing Raven exception is asynchronous.
|
|
78
|
-
* While this function has to be synchronous.
|
|
79
|
-
* If client's application does not catch this exception and node
|
|
80
|
-
* crashes - we'll not get the report.
|
|
81
|
-
* If client's application does catch an error an process it somehow
|
|
82
|
-
* (e.g. mocha), we'll receive an exception in Sentry
|
|
83
|
-
*/
|
|
84
|
-
Raven.captureException(e);
|
|
85
|
-
|
|
86
|
-
throw e;
|
|
87
|
-
}
|
|
88
|
-
};
|
|
89
|
-
|
|
90
|
-
module.exports = {
|
|
91
|
-
captureException,
|
|
92
|
-
captureMessage,
|
|
93
|
-
wrapThrow,
|
|
94
|
-
setUpRaven,
|
|
95
|
-
};
|