@wdio/browserstack-service 9.0.0-alpha.78 → 9.0.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/README.md +1 -1
- package/build/Percy/Percy-Handler.d.ts +1 -1
- package/build/Percy/Percy-Handler.d.ts.map +1 -1
- package/build/Percy/PercyHelper.d.ts +1 -1
- package/build/Percy/PercyHelper.d.ts.map +1 -1
- package/build/accessibility-handler.d.ts +2 -2
- package/build/accessibility-handler.d.ts.map +1 -1
- package/build/ai-handler.d.ts +23 -0
- package/build/ai-handler.d.ts.map +1 -0
- package/build/constants.d.ts +10 -1
- package/build/constants.d.ts.map +1 -1
- package/build/crash-reporter.d.ts +2 -2
- package/build/crash-reporter.d.ts.map +1 -1
- package/build/fileStream.d.ts +0 -2
- package/build/fileStream.d.ts.map +1 -1
- package/build/index.js +5822 -12
- package/build/insights-handler.d.ts +5 -1
- package/build/insights-handler.d.ts.map +1 -1
- package/build/instrumentation/funnelInstrumentation.d.ts +2 -0
- package/build/instrumentation/funnelInstrumentation.d.ts.map +1 -1
- package/build/launcher.d.ts +6 -6
- package/build/launcher.d.ts.map +1 -1
- package/build/performance-tester.d.ts +0 -1
- package/build/performance-tester.d.ts.map +1 -1
- package/build/reporter.d.ts.map +1 -1
- package/build/service.d.ts +4 -4
- package/build/service.d.ts.map +1 -1
- package/build/testOps/listener.d.ts +1 -0
- package/build/testOps/listener.d.ts.map +1 -1
- package/build/types.d.ts +9 -3
- package/build/types.d.ts.map +1 -1
- package/build/util.d.ts +43 -30
- package/build/util.d.ts.map +1 -1
- package/package.json +13 -10
- package/build/Percy/Percy-Handler.js +0 -156
- package/build/Percy/Percy.js +0 -123
- package/build/Percy/PercyBinary.js +0 -142
- package/build/Percy/PercyCaptureMap.js +0 -35
- package/build/Percy/PercyHelper.js +0 -67
- package/build/Percy/PercyLogger.js +0 -67
- package/build/Percy/PercySDK.js +0 -39
- package/build/accessibility-handler.js +0 -287
- package/build/bstackLogger.js +0 -70
- package/build/cleanup.js +0 -89
- package/build/config.js +0 -39
- package/build/constants.js +0 -73
- package/build/crash-reporter.js +0 -138
- package/build/cucumber-types.js +0 -1
- package/build/data-store.js +0 -41
- package/build/exitHandler.js +0 -29
- package/build/fetchWrapper.js +0 -14
- package/build/fileStream.js +0 -12
- package/build/insights-handler.js +0 -719
- package/build/instrumentation/funnelInstrumentation.js +0 -120
- package/build/launcher.js +0 -741
- package/build/log4jsAppender.js +0 -19
- package/build/logPatcher.js +0 -38
- package/build/logReportingAPI.js +0 -56
- package/build/performance-tester.js +0 -94
- package/build/reporter.js +0 -251
- package/build/request-handler.js +0 -74
- package/build/scripts/accessibility-scripts.js +0 -61
- package/build/service.js +0 -428
- package/build/testOps/featureStats.js +0 -116
- package/build/testOps/featureUsage.js +0 -47
- package/build/testOps/listener.js +0 -222
- package/build/testOps/requestUtils.js +0 -39
- package/build/testOps/testOpsConfig.js +0 -19
- package/build/testOps/usageStats.js +0 -114
- package/build/types.js +0 -1
- package/build/util.js +0 -1132
- /package/{LICENSE-MIT → LICENSE} +0 -0
package/build/log4jsAppender.js
DELETED
|
@@ -1,19 +0,0 @@
|
|
|
1
|
-
import logReportingAPI from './logReportingAPI.js';
|
|
2
|
-
const BSTestOpsLogger = new logReportingAPI({});
|
|
3
|
-
//Disabling eslint here as there params can be used later
|
|
4
|
-
// eslint-disable-next-line @typescript-eslint/no-unused-vars
|
|
5
|
-
function BSTestOpsLog4JSAppender(layout, timezoneOffset) {
|
|
6
|
-
return (loggingEvent) => {
|
|
7
|
-
BSTestOpsLogger.log({
|
|
8
|
-
level: loggingEvent.level ? loggingEvent.level.levelStr : null,
|
|
9
|
-
message: loggingEvent.data ? loggingEvent.data.join(' ') : null
|
|
10
|
-
});
|
|
11
|
-
};
|
|
12
|
-
}
|
|
13
|
-
export const configure = (config, layouts) => {
|
|
14
|
-
let layout = layouts.colouredLayout;
|
|
15
|
-
if (config.layout) {
|
|
16
|
-
layout = layouts.layout(config.layout.type, config.layout);
|
|
17
|
-
}
|
|
18
|
-
return BSTestOpsLog4JSAppender(layout, config.timezoneOffset);
|
|
19
|
-
};
|
package/build/logPatcher.js
DELETED
|
@@ -1,38 +0,0 @@
|
|
|
1
|
-
import Transport from 'winston-transport';
|
|
2
|
-
const LOG_LEVELS = {
|
|
3
|
-
INFO: 'INFO', ERROR: 'ERROR', DEBUG: 'DEBUG', TRACE: 'TRACE', WARN: 'WARN',
|
|
4
|
-
};
|
|
5
|
-
class logPatcher extends Transport {
|
|
6
|
-
constructor(opts) {
|
|
7
|
-
super(opts);
|
|
8
|
-
}
|
|
9
|
-
logToTestOps = (level = LOG_LEVELS.INFO, message = ['']) => {
|
|
10
|
-
process.emit(`bs:addLog:${process.pid}`, {
|
|
11
|
-
timestamp: new Date().toISOString(),
|
|
12
|
-
level: level.toUpperCase(),
|
|
13
|
-
message: `"${message.join(', ')}"`,
|
|
14
|
-
kind: 'TEST_LOG',
|
|
15
|
-
http_response: {}
|
|
16
|
-
});
|
|
17
|
-
};
|
|
18
|
-
/* Patching this would show user an extended trace on their cli */
|
|
19
|
-
trace = (...message) => {
|
|
20
|
-
this.logToTestOps(LOG_LEVELS.TRACE, message);
|
|
21
|
-
};
|
|
22
|
-
debug = (...message) => {
|
|
23
|
-
this.logToTestOps(LOG_LEVELS.DEBUG, message);
|
|
24
|
-
};
|
|
25
|
-
info = (...message) => {
|
|
26
|
-
this.logToTestOps(LOG_LEVELS.INFO, message);
|
|
27
|
-
};
|
|
28
|
-
warn = (...message) => {
|
|
29
|
-
this.logToTestOps(LOG_LEVELS.WARN, message);
|
|
30
|
-
};
|
|
31
|
-
error = (...message) => {
|
|
32
|
-
this.logToTestOps(LOG_LEVELS.ERROR, message);
|
|
33
|
-
};
|
|
34
|
-
log = (...message) => {
|
|
35
|
-
this.logToTestOps(LOG_LEVELS.INFO, message);
|
|
36
|
-
};
|
|
37
|
-
}
|
|
38
|
-
export default logPatcher;
|
package/build/logReportingAPI.js
DELETED
|
@@ -1,56 +0,0 @@
|
|
|
1
|
-
import Transport from 'winston-transport';
|
|
2
|
-
import { consoleHolder } from './constants.js';
|
|
3
|
-
const LOG_LEVELS = {
|
|
4
|
-
INFO: 'INFO',
|
|
5
|
-
ERROR: 'ERROR',
|
|
6
|
-
DEBUG: 'DEBUG',
|
|
7
|
-
TRACE: 'TRACE',
|
|
8
|
-
WARN: 'WARN',
|
|
9
|
-
};
|
|
10
|
-
class logReportingAPI extends Transport {
|
|
11
|
-
log(info, callback = undefined) {
|
|
12
|
-
setImmediate(() => {
|
|
13
|
-
this.emit('logged', info);
|
|
14
|
-
});
|
|
15
|
-
if (typeof (info) === 'object') {
|
|
16
|
-
/* From log appender */
|
|
17
|
-
this.logToTestOps(info.level || LOG_LEVELS.INFO, info.message, false);
|
|
18
|
-
}
|
|
19
|
-
else {
|
|
20
|
-
/* From default console */
|
|
21
|
-
this.logToTestOps(LOG_LEVELS.INFO, info);
|
|
22
|
-
}
|
|
23
|
-
if (callback && typeof callback === 'function') {
|
|
24
|
-
callback();
|
|
25
|
-
}
|
|
26
|
-
}
|
|
27
|
-
logToTestOps = (level = LOG_LEVELS.INFO, message = '', consoleLog = true) => {
|
|
28
|
-
if (consoleLog) {
|
|
29
|
-
consoleHolder[level.toLowerCase()](message);
|
|
30
|
-
}
|
|
31
|
-
process.emit(`bs:addLog:${process.pid}`, {
|
|
32
|
-
timestamp: new Date().toISOString(),
|
|
33
|
-
level: level.toUpperCase(),
|
|
34
|
-
message: message,
|
|
35
|
-
kind: 'TEST_LOG',
|
|
36
|
-
http_response: {}
|
|
37
|
-
});
|
|
38
|
-
};
|
|
39
|
-
/* Patching this would show user an extended trace on their cli */
|
|
40
|
-
trace = (message) => {
|
|
41
|
-
this.logToTestOps(LOG_LEVELS.TRACE, message);
|
|
42
|
-
};
|
|
43
|
-
debug = (message) => {
|
|
44
|
-
this.logToTestOps(LOG_LEVELS.DEBUG, message);
|
|
45
|
-
};
|
|
46
|
-
info = (message) => {
|
|
47
|
-
this.logToTestOps(LOG_LEVELS.INFO, message);
|
|
48
|
-
};
|
|
49
|
-
warn = (message) => {
|
|
50
|
-
this.logToTestOps(LOG_LEVELS.WARN, message);
|
|
51
|
-
};
|
|
52
|
-
error = (message) => {
|
|
53
|
-
this.logToTestOps(LOG_LEVELS.ERROR, message);
|
|
54
|
-
};
|
|
55
|
-
}
|
|
56
|
-
export default logReportingAPI;
|
|
@@ -1,94 +0,0 @@
|
|
|
1
|
-
import { createObjectCsvWriter } from 'csv-writer';
|
|
2
|
-
import fs from 'node:fs';
|
|
3
|
-
import { performance, PerformanceObserver } from 'node:perf_hooks';
|
|
4
|
-
import { sleep } from './util.js';
|
|
5
|
-
import { BStackLogger } from './bstackLogger.js';
|
|
6
|
-
export default class PerformanceTester {
|
|
7
|
-
static _observer;
|
|
8
|
-
static _csvWriter;
|
|
9
|
-
static _events = [];
|
|
10
|
-
static started = false;
|
|
11
|
-
static startMonitoring(csvName = 'performance-report.csv') {
|
|
12
|
-
this._observer = new PerformanceObserver(list => {
|
|
13
|
-
list.getEntries().forEach(entry => {
|
|
14
|
-
this._events.push(entry);
|
|
15
|
-
});
|
|
16
|
-
});
|
|
17
|
-
this._observer.observe({ buffered: true, entryTypes: ['function'] });
|
|
18
|
-
this.started = true;
|
|
19
|
-
this._csvWriter = createObjectCsvWriter({
|
|
20
|
-
path: csvName,
|
|
21
|
-
header: [
|
|
22
|
-
{ id: 'name', title: 'Function Name' },
|
|
23
|
-
{ id: 'time', title: 'Execution Time (ms)' }
|
|
24
|
-
]
|
|
25
|
-
});
|
|
26
|
-
}
|
|
27
|
-
static getPerformance() {
|
|
28
|
-
return performance;
|
|
29
|
-
}
|
|
30
|
-
static calculateTimes(methods) {
|
|
31
|
-
const times = {};
|
|
32
|
-
this._events.map((entry) => {
|
|
33
|
-
if (!times[entry.name]) {
|
|
34
|
-
times[entry.name] = 0;
|
|
35
|
-
}
|
|
36
|
-
times[entry.name] += entry.duration;
|
|
37
|
-
});
|
|
38
|
-
const timeTaken = methods.reduce((a, c) => {
|
|
39
|
-
return times[c] + (a || 0);
|
|
40
|
-
}, 0);
|
|
41
|
-
BStackLogger.info(`Time for ${methods} is ${timeTaken}`);
|
|
42
|
-
return timeTaken;
|
|
43
|
-
}
|
|
44
|
-
static async stopAndGenerate(filename = 'performance-own.html') {
|
|
45
|
-
if (!this.started) {
|
|
46
|
-
return;
|
|
47
|
-
}
|
|
48
|
-
await sleep(2000); // Wait to 2s just to finish any running callbacks for timerify
|
|
49
|
-
this._observer.disconnect();
|
|
50
|
-
this.started = false;
|
|
51
|
-
this.generateCSV(this._events);
|
|
52
|
-
const content = this.generateReport(this._events);
|
|
53
|
-
const path = process.cwd() + '/' + filename;
|
|
54
|
-
fs.writeFile(path, content, err => {
|
|
55
|
-
if (err) {
|
|
56
|
-
BStackLogger.error(`Error in writing html ${err}`);
|
|
57
|
-
return;
|
|
58
|
-
}
|
|
59
|
-
BStackLogger.info(`Performance report is at ${path}`);
|
|
60
|
-
});
|
|
61
|
-
}
|
|
62
|
-
static generateReport(entries) {
|
|
63
|
-
let html = '<!DOCTYPE html><html><head><title>Performance Report</title></head><body>';
|
|
64
|
-
html += '<h1>Performance Report</h1>';
|
|
65
|
-
html += '<table><thead><tr><th>Function Name</th><th>Duration (ms)</th></tr></thead><tbody>';
|
|
66
|
-
entries.forEach((entry) => {
|
|
67
|
-
html += `<tr><td>${entry.name}</td><td>${entry.duration}</td></tr>`;
|
|
68
|
-
});
|
|
69
|
-
html += '</tbody></table></body></html>';
|
|
70
|
-
return html;
|
|
71
|
-
}
|
|
72
|
-
static generateCSV(entries) {
|
|
73
|
-
const times = {};
|
|
74
|
-
entries.map((entry) => {
|
|
75
|
-
if (!times[entry.name]) {
|
|
76
|
-
times[entry.name] = 0;
|
|
77
|
-
}
|
|
78
|
-
times[entry.name] += entry.duration;
|
|
79
|
-
return {
|
|
80
|
-
name: entry.name,
|
|
81
|
-
time: entry.duration
|
|
82
|
-
};
|
|
83
|
-
});
|
|
84
|
-
const dat = Object.entries(times).map(([key, value]) => {
|
|
85
|
-
return {
|
|
86
|
-
name: key,
|
|
87
|
-
time: value
|
|
88
|
-
};
|
|
89
|
-
});
|
|
90
|
-
this._csvWriter.writeRecords(dat)
|
|
91
|
-
.then(() => BStackLogger.info('Performance CSV report generated successfully'))
|
|
92
|
-
.catch((error) => console.error(error));
|
|
93
|
-
}
|
|
94
|
-
}
|
package/build/reporter.js
DELETED
|
@@ -1,251 +0,0 @@
|
|
|
1
|
-
import path from 'node:path';
|
|
2
|
-
import WDIOReporter from '@wdio/reporter';
|
|
3
|
-
import * as url from 'node:url';
|
|
4
|
-
import { v4 as uuidv4 } from 'uuid';
|
|
5
|
-
import { getCloudProvider, o11yClassErrorHandler, getGitMetaData, removeAnsiColors, getHookType, getPlatformVersion } from './util.js';
|
|
6
|
-
import { BStackLogger } from './bstackLogger.js';
|
|
7
|
-
import Listener from './testOps/listener.js';
|
|
8
|
-
class _TestReporter extends WDIOReporter {
|
|
9
|
-
_capabilities = {};
|
|
10
|
-
_config;
|
|
11
|
-
_observability = true;
|
|
12
|
-
_sessionId;
|
|
13
|
-
_suiteName;
|
|
14
|
-
_suites = [];
|
|
15
|
-
static _tests = {};
|
|
16
|
-
_gitConfigPath;
|
|
17
|
-
_gitConfigured = false;
|
|
18
|
-
_currentHook = {};
|
|
19
|
-
_currentTest = {};
|
|
20
|
-
_userCaps = {};
|
|
21
|
-
listener = Listener.getInstance();
|
|
22
|
-
async onRunnerStart(runnerStats) {
|
|
23
|
-
this._capabilities = runnerStats.capabilities;
|
|
24
|
-
this._userCaps = this.getUserCaps(runnerStats);
|
|
25
|
-
this._config = runnerStats.config;
|
|
26
|
-
this._sessionId = runnerStats.sessionId;
|
|
27
|
-
if (typeof this._config.testObservability !== 'undefined') {
|
|
28
|
-
this._observability = this._config.testObservability;
|
|
29
|
-
}
|
|
30
|
-
await this.configureGit();
|
|
31
|
-
this.registerListeners();
|
|
32
|
-
}
|
|
33
|
-
getUserCaps(runnerStats) {
|
|
34
|
-
return runnerStats.instanceOptions[runnerStats.sessionId]?.capabilities;
|
|
35
|
-
}
|
|
36
|
-
registerListeners() {
|
|
37
|
-
if (this._config?.framework !== 'jasmine') {
|
|
38
|
-
return;
|
|
39
|
-
}
|
|
40
|
-
process.removeAllListeners(`bs:addLog:${process.pid}`);
|
|
41
|
-
process.on(`bs:addLog:${process.pid}`, this.appendTestItemLog.bind(this));
|
|
42
|
-
}
|
|
43
|
-
async appendTestItemLog(stdLog) {
|
|
44
|
-
if (this._currentHook.uuid && !this._currentHook.finished) {
|
|
45
|
-
stdLog.hook_run_uuid = this._currentHook.uuid;
|
|
46
|
-
}
|
|
47
|
-
else if (this._currentTest.uuid) {
|
|
48
|
-
stdLog.test_run_uuid = this._currentTest.uuid;
|
|
49
|
-
}
|
|
50
|
-
if (stdLog.hook_run_uuid || stdLog.test_run_uuid) {
|
|
51
|
-
this.listener.logCreated([stdLog]);
|
|
52
|
-
}
|
|
53
|
-
}
|
|
54
|
-
setCurrentHook(hookDetails) {
|
|
55
|
-
if (hookDetails.finished) {
|
|
56
|
-
if (this._currentHook.uuid === hookDetails.uuid) {
|
|
57
|
-
this._currentHook.finished = true;
|
|
58
|
-
}
|
|
59
|
-
return;
|
|
60
|
-
}
|
|
61
|
-
this._currentHook = {
|
|
62
|
-
uuid: hookDetails.uuid,
|
|
63
|
-
finished: false
|
|
64
|
-
};
|
|
65
|
-
}
|
|
66
|
-
async configureGit() {
|
|
67
|
-
if (this._gitConfigured) {
|
|
68
|
-
return;
|
|
69
|
-
}
|
|
70
|
-
const gitMeta = await getGitMetaData();
|
|
71
|
-
if (gitMeta) {
|
|
72
|
-
this._gitConfigPath = gitMeta.root;
|
|
73
|
-
}
|
|
74
|
-
this._gitConfigured = true;
|
|
75
|
-
}
|
|
76
|
-
static getTests() {
|
|
77
|
-
return _TestReporter._tests;
|
|
78
|
-
}
|
|
79
|
-
onSuiteStart(suiteStats) {
|
|
80
|
-
let filename = suiteStats.file;
|
|
81
|
-
if (this._config?.framework === 'jasmine') {
|
|
82
|
-
try {
|
|
83
|
-
if (suiteStats.file.startsWith('file://')) {
|
|
84
|
-
filename = url.fileURLToPath(suiteStats.file);
|
|
85
|
-
}
|
|
86
|
-
if (filename === 'unknown spec file') {
|
|
87
|
-
// Sometimes in cases where a file has two suites. Then the file name be unknown for second suite, so getting the filename from first suite
|
|
88
|
-
filename = this._suiteName || suiteStats.file;
|
|
89
|
-
}
|
|
90
|
-
}
|
|
91
|
-
catch (e) {
|
|
92
|
-
BStackLogger.debug('Error in decoding file name of suite');
|
|
93
|
-
}
|
|
94
|
-
}
|
|
95
|
-
this._suiteName = filename;
|
|
96
|
-
this._suites.push(suiteStats);
|
|
97
|
-
}
|
|
98
|
-
onSuiteEnd() {
|
|
99
|
-
this._suites.pop();
|
|
100
|
-
}
|
|
101
|
-
needToSendData(testType, event) {
|
|
102
|
-
if (!this._observability) {
|
|
103
|
-
return false;
|
|
104
|
-
}
|
|
105
|
-
switch (this._config?.framework) {
|
|
106
|
-
case 'mocha':
|
|
107
|
-
return event === 'skip';
|
|
108
|
-
case 'cucumber':
|
|
109
|
-
return false;
|
|
110
|
-
case 'jasmine':
|
|
111
|
-
return event !== 'skip';
|
|
112
|
-
default:
|
|
113
|
-
return false;
|
|
114
|
-
}
|
|
115
|
-
}
|
|
116
|
-
async onTestEnd(testStats) {
|
|
117
|
-
if (!this.needToSendData('test', 'end')) {
|
|
118
|
-
return;
|
|
119
|
-
}
|
|
120
|
-
if (testStats.fullTitle === '<unknown test>') {
|
|
121
|
-
return;
|
|
122
|
-
}
|
|
123
|
-
testStats.end ||= new Date();
|
|
124
|
-
this.listener.testFinished(await this.getRunData(testStats, 'TestRunFinished'));
|
|
125
|
-
}
|
|
126
|
-
async onTestStart(testStats) {
|
|
127
|
-
if (!this.needToSendData('test', 'start')) {
|
|
128
|
-
return;
|
|
129
|
-
}
|
|
130
|
-
if (testStats.fullTitle === '<unknown test>') {
|
|
131
|
-
return;
|
|
132
|
-
}
|
|
133
|
-
const uuid = uuidv4();
|
|
134
|
-
this._currentTest.uuid = uuid;
|
|
135
|
-
_TestReporter._tests[testStats.fullTitle] = {
|
|
136
|
-
uuid: uuid,
|
|
137
|
-
};
|
|
138
|
-
this.listener.testStarted(await this.getRunData(testStats, 'TestRunStarted'));
|
|
139
|
-
}
|
|
140
|
-
async onHookStart(hookStats) {
|
|
141
|
-
if (!this.needToSendData('hook', 'start')) {
|
|
142
|
-
return;
|
|
143
|
-
}
|
|
144
|
-
const identifier = this.getHookIdentifier(hookStats);
|
|
145
|
-
const hookId = uuidv4();
|
|
146
|
-
this.setCurrentHook({ uuid: hookId });
|
|
147
|
-
_TestReporter._tests[identifier] = {
|
|
148
|
-
uuid: hookId,
|
|
149
|
-
startedAt: (new Date()).toISOString()
|
|
150
|
-
};
|
|
151
|
-
this.listener.hookStarted(await this.getRunData(hookStats, 'HookRunStarted'));
|
|
152
|
-
}
|
|
153
|
-
async onHookEnd(hookStats) {
|
|
154
|
-
if (!this.needToSendData('hook', 'end')) {
|
|
155
|
-
return;
|
|
156
|
-
}
|
|
157
|
-
const identifier = this.getHookIdentifier(hookStats);
|
|
158
|
-
if (_TestReporter._tests[identifier]) {
|
|
159
|
-
_TestReporter._tests[identifier].finishedAt = (new Date()).toISOString();
|
|
160
|
-
}
|
|
161
|
-
else {
|
|
162
|
-
_TestReporter._tests[identifier] = {
|
|
163
|
-
finishedAt: (new Date()).toISOString()
|
|
164
|
-
};
|
|
165
|
-
}
|
|
166
|
-
this.setCurrentHook({ uuid: _TestReporter._tests[identifier].uuid, finished: true });
|
|
167
|
-
if (!hookStats.state && !hookStats.error) {
|
|
168
|
-
hookStats.state = 'passed';
|
|
169
|
-
}
|
|
170
|
-
this.listener.hookFinished(await this.getRunData(hookStats, 'HookRunFinished'));
|
|
171
|
-
}
|
|
172
|
-
getHookIdentifier(hookStats) {
|
|
173
|
-
return `${hookStats.title} for ${this._suites.at(-1)?.title}`;
|
|
174
|
-
}
|
|
175
|
-
async onTestSkip(testStats) {
|
|
176
|
-
// cucumber steps call this method. We don't want step skipped state so skip for cucumber
|
|
177
|
-
if (!this.needToSendData('test', 'skip')) {
|
|
178
|
-
return;
|
|
179
|
-
}
|
|
180
|
-
testStats.start ||= new Date();
|
|
181
|
-
testStats.end ||= new Date();
|
|
182
|
-
this.listener.testFinished(await this.getRunData(testStats, 'TestRunSkipped'));
|
|
183
|
-
}
|
|
184
|
-
async getRunData(testStats, eventType) {
|
|
185
|
-
const framework = this._config?.framework;
|
|
186
|
-
const scopes = this._suites.map(s => s.title);
|
|
187
|
-
const identifier = testStats.type === 'test' ? testStats.fullTitle : this.getHookIdentifier(testStats);
|
|
188
|
-
const testMetaData = _TestReporter._tests[identifier];
|
|
189
|
-
const scope = testStats.type === 'test' ? testStats.fullTitle : `${this._suites[0].title} - ${testStats.title}`;
|
|
190
|
-
await this.configureGit();
|
|
191
|
-
const testData = {
|
|
192
|
-
uuid: testMetaData ? testMetaData.uuid : uuidv4(),
|
|
193
|
-
type: testStats.type,
|
|
194
|
-
name: testStats.title,
|
|
195
|
-
body: {
|
|
196
|
-
lang: 'webdriverio',
|
|
197
|
-
code: null
|
|
198
|
-
},
|
|
199
|
-
scope: scope,
|
|
200
|
-
scopes: scopes,
|
|
201
|
-
identifier: identifier,
|
|
202
|
-
file_name: this._suiteName ? path.relative(process.cwd(), this._suiteName) : undefined,
|
|
203
|
-
location: this._suiteName ? path.relative(process.cwd(), this._suiteName) : undefined,
|
|
204
|
-
vc_filepath: (this._gitConfigPath && this._suiteName) ? path.relative(this._gitConfigPath, this._suiteName) : undefined,
|
|
205
|
-
started_at: testStats.start && testStats.start.toISOString(),
|
|
206
|
-
finished_at: testStats.end && testStats.end.toISOString(),
|
|
207
|
-
framework: framework,
|
|
208
|
-
duration_in_ms: testStats._duration,
|
|
209
|
-
result: testStats.state,
|
|
210
|
-
};
|
|
211
|
-
if (testStats.type === 'test') {
|
|
212
|
-
testData.retries = { limit: testStats.retries || 0, attempts: testStats.retries || 0 };
|
|
213
|
-
}
|
|
214
|
-
if (eventType.startsWith('TestRun') || eventType === 'HookRunStarted') {
|
|
215
|
-
/* istanbul ignore next */
|
|
216
|
-
const cloudProvider = getCloudProvider({ options: { hostname: this._config?.hostname } });
|
|
217
|
-
testData.integrations = {};
|
|
218
|
-
/* istanbul ignore next */
|
|
219
|
-
testData.integrations[cloudProvider] = {
|
|
220
|
-
capabilities: this._capabilities,
|
|
221
|
-
session_id: this._sessionId,
|
|
222
|
-
browser: this._capabilities?.browserName,
|
|
223
|
-
browser_version: this._capabilities?.browserVersion,
|
|
224
|
-
platform: this._capabilities?.platformName,
|
|
225
|
-
platform_version: getPlatformVersion(this._userCaps)
|
|
226
|
-
};
|
|
227
|
-
}
|
|
228
|
-
if (eventType === 'TestRunFinished' || eventType === 'HookRunFinished') {
|
|
229
|
-
const { error } = testStats;
|
|
230
|
-
const failed = testStats.state === 'failed';
|
|
231
|
-
if (failed) {
|
|
232
|
-
testData.result = (error && error.message && error.message.includes('sync skip; aborting execution')) ? 'ignore' : 'failed';
|
|
233
|
-
if (error && testData.result !== 'skipped') {
|
|
234
|
-
testData.failure = [{ backtrace: [removeAnsiColors(error.message)] }]; // add all errors here
|
|
235
|
-
testData.failure_reason = removeAnsiColors(error.message);
|
|
236
|
-
testData.failure_type = error.message === null ? null : error.message.toString().match(/AssertionError/) ? 'AssertionError' : 'UnhandledError'; //verify if this is working
|
|
237
|
-
}
|
|
238
|
-
}
|
|
239
|
-
}
|
|
240
|
-
if (eventType === 'TestRunSkipped') {
|
|
241
|
-
eventType = 'TestRunFinished';
|
|
242
|
-
}
|
|
243
|
-
if (eventType.match(/HookRun/)) {
|
|
244
|
-
testData.hook_type = testData.name?.toLowerCase() ? getHookType(testData.name.toLowerCase()) : 'undefined';
|
|
245
|
-
}
|
|
246
|
-
return testData;
|
|
247
|
-
}
|
|
248
|
-
}
|
|
249
|
-
// https://github.com/microsoft/TypeScript/issues/6543
|
|
250
|
-
const TestReporter = o11yClassErrorHandler(_TestReporter);
|
|
251
|
-
export default TestReporter;
|
package/build/request-handler.js
DELETED
|
@@ -1,74 +0,0 @@
|
|
|
1
|
-
import { DATA_BATCH_SIZE, DATA_BATCH_INTERVAL, TESTOPS_BUILD_COMPLETED_ENV } from './constants.js';
|
|
2
|
-
import { BStackLogger } from './bstackLogger.js';
|
|
3
|
-
export default class RequestQueueHandler {
|
|
4
|
-
queue = [];
|
|
5
|
-
callback;
|
|
6
|
-
pollEventBatchInterval;
|
|
7
|
-
static tearDownInvoked = false;
|
|
8
|
-
static instance;
|
|
9
|
-
// making it private to use singleton pattern
|
|
10
|
-
constructor(callback) {
|
|
11
|
-
this.callback = callback;
|
|
12
|
-
this.startEventBatchPolling();
|
|
13
|
-
}
|
|
14
|
-
static getInstance(callback) {
|
|
15
|
-
if (!RequestQueueHandler.instance && callback) {
|
|
16
|
-
RequestQueueHandler.instance = new RequestQueueHandler(callback);
|
|
17
|
-
}
|
|
18
|
-
return RequestQueueHandler.instance;
|
|
19
|
-
}
|
|
20
|
-
add(event) {
|
|
21
|
-
if (!process.env[TESTOPS_BUILD_COMPLETED_ENV]) {
|
|
22
|
-
throw new Error('Observability build start not completed yet.');
|
|
23
|
-
}
|
|
24
|
-
this.queue.push(event);
|
|
25
|
-
BStackLogger.debug(`Added data to request queue. Queue length = ${this.queue.length}`);
|
|
26
|
-
const shouldProceed = this.shouldProceed();
|
|
27
|
-
if (shouldProceed) {
|
|
28
|
-
this.sendBatch().catch((e) => {
|
|
29
|
-
BStackLogger.debug('Exception in sending batch: ' + e);
|
|
30
|
-
});
|
|
31
|
-
}
|
|
32
|
-
}
|
|
33
|
-
async shutdown() {
|
|
34
|
-
BStackLogger.debug('shutdown started');
|
|
35
|
-
this.removeEventBatchPolling('Shutting down');
|
|
36
|
-
while (this.queue.length > 0) {
|
|
37
|
-
const data = this.queue.splice(0, DATA_BATCH_SIZE);
|
|
38
|
-
await this.callCallback(data, 'SHUTDOWN_QUEUE');
|
|
39
|
-
}
|
|
40
|
-
BStackLogger.debug('shutdown ended');
|
|
41
|
-
}
|
|
42
|
-
startEventBatchPolling() {
|
|
43
|
-
this.pollEventBatchInterval = setInterval(this.sendBatch.bind(this), DATA_BATCH_INTERVAL);
|
|
44
|
-
}
|
|
45
|
-
async sendBatch() {
|
|
46
|
-
const data = this.queue.splice(0, DATA_BATCH_SIZE);
|
|
47
|
-
if (data.length === 0) {
|
|
48
|
-
return;
|
|
49
|
-
}
|
|
50
|
-
BStackLogger.debug(`Sending data from request queue. Data length = ${data.length}, Queue length after removal = ${this.queue.length}`);
|
|
51
|
-
await this.callCallback(data, 'INTERVAL_QUEUE');
|
|
52
|
-
}
|
|
53
|
-
callCallback = async (data, kind) => {
|
|
54
|
-
BStackLogger.debug('calling callback with kind ' + kind);
|
|
55
|
-
this.callback && await this.callback(data);
|
|
56
|
-
};
|
|
57
|
-
resetEventBatchPolling() {
|
|
58
|
-
this.removeEventBatchPolling('Resetting');
|
|
59
|
-
this.startEventBatchPolling();
|
|
60
|
-
}
|
|
61
|
-
removeEventBatchPolling(tag) {
|
|
62
|
-
if (this.pollEventBatchInterval) {
|
|
63
|
-
BStackLogger.debug(`${tag} request queue`);
|
|
64
|
-
clearInterval(this.pollEventBatchInterval);
|
|
65
|
-
}
|
|
66
|
-
}
|
|
67
|
-
shouldProceed() {
|
|
68
|
-
if (RequestQueueHandler.tearDownInvoked) {
|
|
69
|
-
BStackLogger.debug('Force request-queue shutdown, as test run event is received after teardown');
|
|
70
|
-
return true;
|
|
71
|
-
}
|
|
72
|
-
return this.queue.length >= DATA_BATCH_SIZE;
|
|
73
|
-
}
|
|
74
|
-
}
|
|
@@ -1,61 +0,0 @@
|
|
|
1
|
-
import path from 'node:path';
|
|
2
|
-
import fs from 'node:fs';
|
|
3
|
-
import os from 'node:os';
|
|
4
|
-
class AccessibilityScripts {
|
|
5
|
-
static instance = null;
|
|
6
|
-
performScan = null;
|
|
7
|
-
getResults = null;
|
|
8
|
-
getResultsSummary = null;
|
|
9
|
-
saveTestResults = null;
|
|
10
|
-
commandsToWrap = null;
|
|
11
|
-
browserstackFolderPath = path.join(os.homedir(), '.browserstack');
|
|
12
|
-
commandsPath = path.join(this.browserstackFolderPath, 'commands.json');
|
|
13
|
-
// don't allow to create instances from it other than through `checkAndGetInstance`
|
|
14
|
-
constructor() { }
|
|
15
|
-
static checkAndGetInstance() {
|
|
16
|
-
if (!AccessibilityScripts.instance) {
|
|
17
|
-
AccessibilityScripts.instance = new AccessibilityScripts();
|
|
18
|
-
AccessibilityScripts.instance.readFromExistingFile();
|
|
19
|
-
}
|
|
20
|
-
return AccessibilityScripts.instance;
|
|
21
|
-
}
|
|
22
|
-
readFromExistingFile() {
|
|
23
|
-
try {
|
|
24
|
-
if (fs.existsSync(this.commandsPath)) {
|
|
25
|
-
const data = fs.readFileSync(this.commandsPath, 'utf8');
|
|
26
|
-
if (data) {
|
|
27
|
-
this.update(JSON.parse(data));
|
|
28
|
-
}
|
|
29
|
-
}
|
|
30
|
-
}
|
|
31
|
-
catch (error) {
|
|
32
|
-
/* Do nothing */
|
|
33
|
-
}
|
|
34
|
-
}
|
|
35
|
-
update(data) {
|
|
36
|
-
if (data.scripts) {
|
|
37
|
-
this.performScan = data.scripts.scan;
|
|
38
|
-
this.getResults = data.scripts.getResults;
|
|
39
|
-
this.getResultsSummary = data.scripts.getResultsSummary;
|
|
40
|
-
this.saveTestResults = data.scripts.saveResults;
|
|
41
|
-
}
|
|
42
|
-
if (data.commands && data.commands.length) {
|
|
43
|
-
this.commandsToWrap = data.commands;
|
|
44
|
-
}
|
|
45
|
-
}
|
|
46
|
-
store() {
|
|
47
|
-
if (!fs.existsSync(this.browserstackFolderPath)) {
|
|
48
|
-
fs.mkdirSync(this.browserstackFolderPath);
|
|
49
|
-
}
|
|
50
|
-
fs.writeFileSync(this.commandsPath, JSON.stringify({
|
|
51
|
-
commands: this.commandsToWrap,
|
|
52
|
-
scripts: {
|
|
53
|
-
scan: this.performScan,
|
|
54
|
-
getResults: this.getResults,
|
|
55
|
-
getResultsSummary: this.getResultsSummary,
|
|
56
|
-
saveResults: this.saveTestResults,
|
|
57
|
-
}
|
|
58
|
-
}));
|
|
59
|
-
}
|
|
60
|
-
}
|
|
61
|
-
export default AccessibilityScripts.checkAndGetInstance();
|