@wdio/browserstack-service 8.32.4 → 8.33.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/build/bstackLogger.d.ts +2 -1
- package/build/bstackLogger.d.ts.map +1 -1
- package/build/bstackLogger.js +6 -3
- package/build/cleanup.d.ts +5 -1
- package/build/cleanup.d.ts.map +1 -1
- package/build/cleanup.js +72 -7
- package/build/config.d.ts +23 -0
- package/build/config.d.ts.map +1 -0
- package/build/config.js +39 -0
- package/build/constants.d.ts +14 -0
- package/build/constants.d.ts.map +1 -1
- package/build/constants.js +22 -0
- package/build/crash-reporter.js +2 -2
- package/build/data-store.d.ts +4 -0
- package/build/data-store.d.ts.map +1 -0
- package/build/data-store.js +41 -0
- package/build/exitHandler.d.ts +4 -0
- package/build/exitHandler.d.ts.map +1 -0
- package/build/exitHandler.js +32 -0
- package/build/insights-handler.d.ts +5 -8
- package/build/insights-handler.d.ts.map +1 -1
- package/build/insights-handler.js +40 -93
- package/build/instrumentation/funnelInstrumentation.d.ts +6 -0
- package/build/instrumentation/funnelInstrumentation.d.ts.map +1 -0
- package/build/instrumentation/funnelInstrumentation.js +119 -0
- package/build/launcher.d.ts +1 -1
- package/build/launcher.d.ts.map +1 -1
- package/build/launcher.js +22 -13
- package/build/reporter.d.ts +3 -3
- package/build/reporter.d.ts.map +1 -1
- package/build/reporter.js +11 -27
- package/build/request-handler.d.ts +5 -13
- package/build/request-handler.d.ts.map +1 -1
- package/build/request-handler.js +30 -48
- package/build/service.d.ts +1 -0
- package/build/service.d.ts.map +1 -1
- package/build/service.js +13 -5
- package/build/testOps/featureStats.d.ts +45 -0
- package/build/testOps/featureStats.d.ts.map +1 -0
- package/build/testOps/featureStats.js +116 -0
- package/build/testOps/featureUsage.d.ts +22 -0
- package/build/testOps/featureUsage.d.ts.map +1 -0
- package/build/testOps/featureUsage.js +47 -0
- package/build/testOps/listener.d.ts +33 -0
- package/build/testOps/listener.d.ts.map +1 -0
- package/build/testOps/listener.js +222 -0
- package/build/testOps/requestUtils.d.ts +4 -0
- package/build/testOps/requestUtils.d.ts.map +1 -0
- package/build/testOps/requestUtils.js +39 -0
- package/build/testOps/testOpsConfig.d.ts +11 -0
- package/build/testOps/testOpsConfig.d.ts.map +1 -0
- package/build/testOps/testOpsConfig.js +19 -0
- package/build/testOps/usageStats.d.ts +404 -0
- package/build/testOps/usageStats.d.ts.map +1 -0
- package/build/testOps/usageStats.js +114 -0
- package/build/types.d.ts +33 -7
- package/build/types.d.ts.map +1 -1
- package/build/util.d.ts +3 -7
- package/build/util.d.ts.map +1 -1
- package/build/util.js +57 -77
- package/package.json +4 -4
|
@@ -0,0 +1,222 @@
|
|
|
1
|
+
import UsageStats from './usageStats.js';
|
|
2
|
+
import RequestQueueHandler from '../request-handler.js';
|
|
3
|
+
import { batchAndPostEvents, sleep } from '../util.js';
|
|
4
|
+
import { DATA_BATCH_ENDPOINT, DEFAULT_WAIT_INTERVAL_FOR_PENDING_UPLOADS, DEFAULT_WAIT_TIMEOUT_FOR_PENDING_UPLOADS, LOG_KIND_USAGE_MAP } from '../constants.js';
|
|
5
|
+
import { sendScreenshots } from './requestUtils.js';
|
|
6
|
+
import { BStackLogger } from '../bstackLogger.js';
|
|
7
|
+
class Listener {
|
|
8
|
+
static instance;
|
|
9
|
+
usageStats = UsageStats.getInstance();
|
|
10
|
+
testStartedStats = this.usageStats.testStartedStats;
|
|
11
|
+
testFinishedStats = this.usageStats.testFinishedStats;
|
|
12
|
+
hookStartedStats = this.usageStats.hookStartedStats;
|
|
13
|
+
hookFinishedStats = this.usageStats.hookFinishedStats;
|
|
14
|
+
cbtSessionStats = this.usageStats.cbtSessionStats;
|
|
15
|
+
logEvents = this.usageStats.logStats;
|
|
16
|
+
requestBatcher;
|
|
17
|
+
pendingUploads = 0;
|
|
18
|
+
// Making the constructor private to use singleton pattern
|
|
19
|
+
constructor() {
|
|
20
|
+
}
|
|
21
|
+
static getInstance() {
|
|
22
|
+
if (!Listener.instance) {
|
|
23
|
+
Listener.instance = new Listener();
|
|
24
|
+
}
|
|
25
|
+
return Listener.instance;
|
|
26
|
+
}
|
|
27
|
+
async onWorkerEnd() {
|
|
28
|
+
try {
|
|
29
|
+
await this.uploadPending();
|
|
30
|
+
await this.teardown();
|
|
31
|
+
}
|
|
32
|
+
catch (e) {
|
|
33
|
+
BStackLogger.debug('Exception in onWorkerEnd: ' + e);
|
|
34
|
+
}
|
|
35
|
+
}
|
|
36
|
+
async uploadPending(waitTimeout = DEFAULT_WAIT_TIMEOUT_FOR_PENDING_UPLOADS, waitInterval = DEFAULT_WAIT_INTERVAL_FOR_PENDING_UPLOADS) {
|
|
37
|
+
if ((this.pendingUploads <= 0) || waitTimeout <= 0) {
|
|
38
|
+
return;
|
|
39
|
+
}
|
|
40
|
+
await sleep(waitInterval);
|
|
41
|
+
return this.uploadPending(waitTimeout - waitInterval);
|
|
42
|
+
}
|
|
43
|
+
async teardown() {
|
|
44
|
+
BStackLogger.debug('teardown started');
|
|
45
|
+
RequestQueueHandler.tearDownInvoked = true;
|
|
46
|
+
await this.requestBatcher?.shutdown();
|
|
47
|
+
BStackLogger.debug('teardown ended');
|
|
48
|
+
}
|
|
49
|
+
hookStarted(hookData) {
|
|
50
|
+
try {
|
|
51
|
+
this.hookStartedStats.triggered();
|
|
52
|
+
this.sendBatchEvents(this.getEventForHook('HookRunStarted', hookData));
|
|
53
|
+
}
|
|
54
|
+
catch (e) {
|
|
55
|
+
this.hookStartedStats.failed();
|
|
56
|
+
throw e;
|
|
57
|
+
}
|
|
58
|
+
}
|
|
59
|
+
hookFinished(hookData) {
|
|
60
|
+
try {
|
|
61
|
+
this.hookFinishedStats.triggered(hookData.result);
|
|
62
|
+
this.sendBatchEvents(this.getEventForHook('HookRunFinished', hookData));
|
|
63
|
+
}
|
|
64
|
+
catch (e) {
|
|
65
|
+
this.hookFinishedStats.failed(hookData.result);
|
|
66
|
+
throw e;
|
|
67
|
+
}
|
|
68
|
+
}
|
|
69
|
+
testStarted(testData) {
|
|
70
|
+
try {
|
|
71
|
+
this.testStartedStats.triggered();
|
|
72
|
+
this.sendBatchEvents(this.getEventForHook('TestRunStarted', testData));
|
|
73
|
+
}
|
|
74
|
+
catch (e) {
|
|
75
|
+
this.testStartedStats.failed();
|
|
76
|
+
throw e;
|
|
77
|
+
}
|
|
78
|
+
}
|
|
79
|
+
testFinished(testData) {
|
|
80
|
+
try {
|
|
81
|
+
this.testFinishedStats.triggered(testData.result);
|
|
82
|
+
this.sendBatchEvents(this.getEventForHook('TestRunFinished', testData));
|
|
83
|
+
}
|
|
84
|
+
catch (e) {
|
|
85
|
+
this.testFinishedStats.failed(testData.result);
|
|
86
|
+
throw e;
|
|
87
|
+
}
|
|
88
|
+
}
|
|
89
|
+
logCreated(logs) {
|
|
90
|
+
try {
|
|
91
|
+
this.markLogs('triggered', logs);
|
|
92
|
+
this.sendBatchEvents({
|
|
93
|
+
event_type: 'LogCreated', logs: logs
|
|
94
|
+
});
|
|
95
|
+
}
|
|
96
|
+
catch (e) {
|
|
97
|
+
this.markLogs('failed', logs);
|
|
98
|
+
throw e;
|
|
99
|
+
}
|
|
100
|
+
}
|
|
101
|
+
async onScreenshot(jsonArray) {
|
|
102
|
+
try {
|
|
103
|
+
this.markLogs('triggered', jsonArray);
|
|
104
|
+
this.pendingUploads += 1;
|
|
105
|
+
await sendScreenshots([{
|
|
106
|
+
event_type: 'LogCreated', logs: jsonArray
|
|
107
|
+
}]);
|
|
108
|
+
this.markLogs('success', jsonArray);
|
|
109
|
+
}
|
|
110
|
+
catch (e) {
|
|
111
|
+
this.markLogs('failed', jsonArray);
|
|
112
|
+
throw e;
|
|
113
|
+
}
|
|
114
|
+
finally {
|
|
115
|
+
this.pendingUploads -= 1;
|
|
116
|
+
}
|
|
117
|
+
}
|
|
118
|
+
cbtSessionCreated(data) {
|
|
119
|
+
try {
|
|
120
|
+
this.cbtSessionStats.triggered();
|
|
121
|
+
this.sendBatchEvents({ event_type: 'CBTSessionCreated', test_run: data });
|
|
122
|
+
}
|
|
123
|
+
catch (e) {
|
|
124
|
+
this.cbtSessionStats.failed();
|
|
125
|
+
throw e;
|
|
126
|
+
}
|
|
127
|
+
}
|
|
128
|
+
markLogs(status, data) {
|
|
129
|
+
if (!data) {
|
|
130
|
+
BStackLogger.debug('No log data');
|
|
131
|
+
return;
|
|
132
|
+
}
|
|
133
|
+
try {
|
|
134
|
+
for (const _log of data) {
|
|
135
|
+
const kind = _log.kind;
|
|
136
|
+
this.logEvents.mark(status, LOG_KIND_USAGE_MAP[kind] || kind);
|
|
137
|
+
}
|
|
138
|
+
}
|
|
139
|
+
catch (e) {
|
|
140
|
+
BStackLogger.debug('Exception in marking logs status ' + e);
|
|
141
|
+
throw e;
|
|
142
|
+
}
|
|
143
|
+
}
|
|
144
|
+
getResult(jsonObject, kind) {
|
|
145
|
+
const runStr = kind === 'test' ? 'test_run' : 'hook_run';
|
|
146
|
+
const runData = jsonObject[runStr];
|
|
147
|
+
return runData?.result;
|
|
148
|
+
}
|
|
149
|
+
sendBatchEvents(jsonObject) {
|
|
150
|
+
if (!this.requestBatcher) {
|
|
151
|
+
this.requestBatcher = RequestQueueHandler.getInstance(async (data) => {
|
|
152
|
+
BStackLogger.debug('callback: called with events ' + data.length);
|
|
153
|
+
try {
|
|
154
|
+
this.pendingUploads += 1;
|
|
155
|
+
await batchAndPostEvents(DATA_BATCH_ENDPOINT, 'BATCH_DATA', data);
|
|
156
|
+
BStackLogger.debug('callback: marking events success ' + data.length);
|
|
157
|
+
this.eventsSuccess(data);
|
|
158
|
+
}
|
|
159
|
+
catch (e) {
|
|
160
|
+
BStackLogger.debug('callback: marking events failed ' + data.length);
|
|
161
|
+
this.eventsFailed(data);
|
|
162
|
+
}
|
|
163
|
+
finally {
|
|
164
|
+
this.pendingUploads -= 1;
|
|
165
|
+
}
|
|
166
|
+
});
|
|
167
|
+
}
|
|
168
|
+
this.requestBatcher.add(jsonObject);
|
|
169
|
+
}
|
|
170
|
+
eventsFailed(events) {
|
|
171
|
+
for (const event of events) {
|
|
172
|
+
const eventType = event.event_type;
|
|
173
|
+
if (eventType === 'TestRunStarted') {
|
|
174
|
+
this.testStartedStats.failed();
|
|
175
|
+
}
|
|
176
|
+
else if (eventType === 'TestRunFinished') {
|
|
177
|
+
this.testFinishedStats.failed(this.getResult(event, 'test'));
|
|
178
|
+
}
|
|
179
|
+
else if (eventType === 'HookRunStarted') {
|
|
180
|
+
this.hookStartedStats.failed();
|
|
181
|
+
}
|
|
182
|
+
else if (eventType === 'HookRunFinished') {
|
|
183
|
+
this.hookFinishedStats.failed(this.getResult(event, 'hook'));
|
|
184
|
+
}
|
|
185
|
+
else if (eventType === 'CBTSessionCreated') {
|
|
186
|
+
this.cbtSessionStats.failed();
|
|
187
|
+
}
|
|
188
|
+
else if (eventType === 'LogCreated') {
|
|
189
|
+
this.markLogs('failed', event.logs);
|
|
190
|
+
}
|
|
191
|
+
}
|
|
192
|
+
}
|
|
193
|
+
eventsSuccess(events) {
|
|
194
|
+
for (const event of events) {
|
|
195
|
+
const eventType = event.event_type;
|
|
196
|
+
if (eventType === 'TestRunStarted') {
|
|
197
|
+
this.testStartedStats.success();
|
|
198
|
+
}
|
|
199
|
+
else if (eventType === 'TestRunFinished') {
|
|
200
|
+
this.testFinishedStats.success(this.getResult(event, 'test'));
|
|
201
|
+
}
|
|
202
|
+
else if (eventType === 'HookRunStarted') {
|
|
203
|
+
this.hookStartedStats.success();
|
|
204
|
+
}
|
|
205
|
+
else if (eventType === 'HookRunFinished') {
|
|
206
|
+
this.hookFinishedStats.success(this.getResult(event, 'hook'));
|
|
207
|
+
}
|
|
208
|
+
else if (eventType === 'CBTSessionCreated') {
|
|
209
|
+
this.cbtSessionStats.success();
|
|
210
|
+
}
|
|
211
|
+
else if (eventType === 'LogCreated') {
|
|
212
|
+
this.markLogs('success', event.logs);
|
|
213
|
+
}
|
|
214
|
+
}
|
|
215
|
+
}
|
|
216
|
+
getEventForHook(eventType, data) {
|
|
217
|
+
return {
|
|
218
|
+
event_type: eventType, [data.type === 'hook' ? 'hook_run' : 'test_run']: data
|
|
219
|
+
};
|
|
220
|
+
}
|
|
221
|
+
}
|
|
222
|
+
export default Listener;
|
|
@@ -0,0 +1,4 @@
|
|
|
1
|
+
import type { UploadType } from '../types.js';
|
|
2
|
+
export declare function uploadEventData(eventData: UploadType | Array<UploadType>, eventUrl?: string): Promise<void>;
|
|
3
|
+
export declare function sendScreenshots(eventData: Array<UploadType>): Promise<void>;
|
|
4
|
+
//# sourceMappingURL=requestUtils.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"requestUtils.d.ts","sourceRoot":"","sources":["../../src/testOps/requestUtils.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,UAAU,EAAE,MAAM,aAAa,CAAA;AAW7C,wBAAsB,eAAe,CAAE,SAAS,EAAE,UAAU,GAAG,KAAK,CAAC,UAAU,CAAC,EAAE,QAAQ,GAAE,MAA4B,iBAkCvH;AAED,wBAAgB,eAAe,CAAC,SAAS,EAAE,KAAK,CAAC,UAAU,CAAC,iBAE3D"}
|
|
@@ -0,0 +1,39 @@
|
|
|
1
|
+
import { DATA_ENDPOINT, DATA_EVENT_ENDPOINT, DATA_SCREENSHOT_ENDPOINT, TESTOPS_BUILD_COMPLETED_ENV, TESTOPS_JWT_ENV } from '../constants.js';
|
|
2
|
+
import { BStackLogger } from '../bstackLogger.js';
|
|
3
|
+
import { DEFAULT_REQUEST_CONFIG, getLogTag } from '../util.js';
|
|
4
|
+
import got from 'got';
|
|
5
|
+
export async function uploadEventData(eventData, eventUrl = DATA_EVENT_ENDPOINT) {
|
|
6
|
+
let logTag = 'BATCH_UPLOAD';
|
|
7
|
+
if (!Array.isArray(eventData)) {
|
|
8
|
+
logTag = getLogTag(eventData.event_type);
|
|
9
|
+
}
|
|
10
|
+
if (eventUrl === DATA_SCREENSHOT_ENDPOINT) {
|
|
11
|
+
logTag = 'screenshot_upload';
|
|
12
|
+
}
|
|
13
|
+
if (!process.env[TESTOPS_BUILD_COMPLETED_ENV]) {
|
|
14
|
+
throw new Error('Build start not completed yet');
|
|
15
|
+
}
|
|
16
|
+
if (!process.env[TESTOPS_JWT_ENV]) {
|
|
17
|
+
BStackLogger.debug(`[${logTag}] Missing Authentication Token/ Build ID`);
|
|
18
|
+
throw new Error('Token/buildID is undefined, build creation might have failed');
|
|
19
|
+
}
|
|
20
|
+
try {
|
|
21
|
+
const url = `${DATA_ENDPOINT}/${eventUrl}`;
|
|
22
|
+
const data = await got.post(url, {
|
|
23
|
+
agent: DEFAULT_REQUEST_CONFIG.agent,
|
|
24
|
+
headers: {
|
|
25
|
+
...DEFAULT_REQUEST_CONFIG.headers,
|
|
26
|
+
'Authorization': `Bearer ${process.env[TESTOPS_JWT_ENV]}`
|
|
27
|
+
},
|
|
28
|
+
json: eventData
|
|
29
|
+
}).json();
|
|
30
|
+
BStackLogger.debug(`[${logTag}] Success response: ${JSON.stringify(data)}`);
|
|
31
|
+
}
|
|
32
|
+
catch (error) {
|
|
33
|
+
BStackLogger.debug(`[${logTag}] Failed. Error: ${error}`);
|
|
34
|
+
throw new Error('Request failed with exception: ' + error);
|
|
35
|
+
}
|
|
36
|
+
}
|
|
37
|
+
export function sendScreenshots(eventData) {
|
|
38
|
+
return uploadEventData(eventData, DATA_SCREENSHOT_ENDPOINT);
|
|
39
|
+
}
|
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
declare class TestOpsConfig {
|
|
2
|
+
enabled: boolean;
|
|
3
|
+
manuallySet: boolean;
|
|
4
|
+
private static _instance;
|
|
5
|
+
buildStopped: boolean;
|
|
6
|
+
buildHashedId?: string;
|
|
7
|
+
static getInstance(...args: any[]): TestOpsConfig;
|
|
8
|
+
constructor(enabled?: boolean, manuallySet?: boolean);
|
|
9
|
+
}
|
|
10
|
+
export default TestOpsConfig;
|
|
11
|
+
//# sourceMappingURL=testOpsConfig.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"testOpsConfig.d.ts","sourceRoot":"","sources":["../../src/testOps/testOpsConfig.ts"],"names":[],"mappings":"AAAA,cAAM,aAAa;IAaJ,OAAO,EAAE,OAAO;IAChB,WAAW,EAAE,OAAO;IAb/B,OAAO,CAAC,MAAM,CAAC,SAAS,CAAe;IAChC,YAAY,EAAE,OAAO,CAAQ;IAC7B,aAAa,CAAC,EAAE,MAAM,CAAA;IAE7B,MAAM,CAAC,WAAW,CAAC,GAAG,IAAI,EAAE,GAAG,EAAE;gBAQtB,OAAO,GAAE,OAAc,EACvB,WAAW,GAAE,OAAe;CAI1C;AAED,eAAe,aAAa,CAAA"}
|
|
@@ -0,0 +1,19 @@
|
|
|
1
|
+
class TestOpsConfig {
|
|
2
|
+
enabled;
|
|
3
|
+
manuallySet;
|
|
4
|
+
static _instance;
|
|
5
|
+
buildStopped = false;
|
|
6
|
+
buildHashedId;
|
|
7
|
+
static getInstance(...args) {
|
|
8
|
+
if (!this._instance) {
|
|
9
|
+
this._instance = new TestOpsConfig(...args);
|
|
10
|
+
}
|
|
11
|
+
return this._instance;
|
|
12
|
+
}
|
|
13
|
+
constructor(enabled = true, manuallySet = false) {
|
|
14
|
+
this.enabled = enabled;
|
|
15
|
+
this.manuallySet = manuallySet;
|
|
16
|
+
TestOpsConfig._instance = this;
|
|
17
|
+
}
|
|
18
|
+
}
|
|
19
|
+
export default TestOpsConfig;
|