@wdio/runner 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/build/browser.d.ts +3 -4
- package/build/browser.d.ts.map +1 -1
- package/build/index.d.ts +0 -5
- package/build/index.d.ts.map +1 -1
- package/build/index.js +874 -432
- package/build/reporter.d.ts +2 -2
- package/build/reporter.d.ts.map +1 -1
- package/build/types.d.ts +2 -10
- package/build/types.d.ts.map +1 -1
- package/build/utils.d.ts +4 -4
- package/build/utils.d.ts.map +1 -1
- package/package.json +15 -13
- package/build/browser.js +0 -385
- package/build/reporter.js +0 -192
- package/build/types.js +0 -1
- package/build/utils.js +0 -152
- /package/{LICENSE-MIT → LICENSE} +0 -0
package/build/reporter.js
DELETED
|
@@ -1,192 +0,0 @@
|
|
|
1
|
-
import path from 'node:path';
|
|
2
|
-
import logger from '@wdio/logger';
|
|
3
|
-
import { initializePlugin } from '@wdio/utils';
|
|
4
|
-
const log = logger('@wdio/runner');
|
|
5
|
-
const mochaAllHooks = ['"before all" hook', '"after all" hook'];
|
|
6
|
-
/**
|
|
7
|
-
* BaseReporter
|
|
8
|
-
* responsible for initialising reporters for every testrun and propagating events
|
|
9
|
-
* to all these reporters
|
|
10
|
-
*/
|
|
11
|
-
export default class BaseReporter {
|
|
12
|
-
_config;
|
|
13
|
-
_cid;
|
|
14
|
-
caps;
|
|
15
|
-
_reporters = [];
|
|
16
|
-
listeners = [];
|
|
17
|
-
constructor(_config, _cid, caps) {
|
|
18
|
-
this._config = _config;
|
|
19
|
-
this._cid = _cid;
|
|
20
|
-
this.caps = caps;
|
|
21
|
-
}
|
|
22
|
-
async initReporters() {
|
|
23
|
-
this._reporters = await Promise.all(this._config.reporters.map(this._loadReporter.bind(this)));
|
|
24
|
-
}
|
|
25
|
-
/**
|
|
26
|
-
* emit events to all registered reporter and wdio launcer
|
|
27
|
-
*
|
|
28
|
-
* @param {string} e event name
|
|
29
|
-
* @param {object} payload event payload
|
|
30
|
-
*/
|
|
31
|
-
emit(e, payload) {
|
|
32
|
-
payload.cid = this._cid;
|
|
33
|
-
/**
|
|
34
|
-
* Send failure message (only once) in case of test or hook failure
|
|
35
|
-
*/
|
|
36
|
-
const isTestError = e === 'test:fail';
|
|
37
|
-
const isHookError = (e === 'hook:end' &&
|
|
38
|
-
payload.error &&
|
|
39
|
-
mochaAllHooks.some(hook => payload.title.startsWith(hook)));
|
|
40
|
-
if (isTestError || isHookError) {
|
|
41
|
-
this.#emitData({
|
|
42
|
-
origin: 'reporter',
|
|
43
|
-
name: 'printFailureMessage',
|
|
44
|
-
content: payload
|
|
45
|
-
});
|
|
46
|
-
}
|
|
47
|
-
this._reporters.forEach((reporter) => reporter.emit(e, payload));
|
|
48
|
-
}
|
|
49
|
-
onMessage(listener) {
|
|
50
|
-
this.listeners.push(listener);
|
|
51
|
-
}
|
|
52
|
-
getLogFile(name) {
|
|
53
|
-
// clone the config to avoid changing original properties
|
|
54
|
-
const options = Object.assign({}, this._config);
|
|
55
|
-
let filename = `wdio-${this._cid}-${name}-reporter.log`;
|
|
56
|
-
const reporterOptions = this._config.reporters.find((reporter) => (Array.isArray(reporter) &&
|
|
57
|
-
(reporter[0] === name ||
|
|
58
|
-
typeof reporter[0] === 'function' && reporter[0].name === name)));
|
|
59
|
-
if (reporterOptions && Array.isArray(reporterOptions)) {
|
|
60
|
-
const fileformat = reporterOptions[1].outputFileFormat;
|
|
61
|
-
options.cid = this._cid;
|
|
62
|
-
options.capabilities = this.caps;
|
|
63
|
-
Object.assign(options, reporterOptions[1]);
|
|
64
|
-
if (fileformat) {
|
|
65
|
-
if (typeof fileformat !== 'function') {
|
|
66
|
-
throw new Error('outputFileFormat must be a function');
|
|
67
|
-
}
|
|
68
|
-
filename = fileformat(options);
|
|
69
|
-
}
|
|
70
|
-
}
|
|
71
|
-
if (!options.outputDir) {
|
|
72
|
-
return;
|
|
73
|
-
}
|
|
74
|
-
return path.join(options.outputDir, filename);
|
|
75
|
-
}
|
|
76
|
-
/**
|
|
77
|
-
* return write stream object based on reporter name
|
|
78
|
-
*/
|
|
79
|
-
getWriteStreamObject(reporter) {
|
|
80
|
-
return {
|
|
81
|
-
write: /* istanbul ignore next */ (content) => this.#emitData({
|
|
82
|
-
origin: 'reporter',
|
|
83
|
-
name: reporter,
|
|
84
|
-
content
|
|
85
|
-
})
|
|
86
|
-
};
|
|
87
|
-
}
|
|
88
|
-
/**
|
|
89
|
-
* emit data either through process or listener
|
|
90
|
-
*/
|
|
91
|
-
#emitData(payload) {
|
|
92
|
-
if (typeof process.send === 'function') {
|
|
93
|
-
return process.send(payload);
|
|
94
|
-
}
|
|
95
|
-
this.listeners.forEach((fn) => fn(payload));
|
|
96
|
-
return true;
|
|
97
|
-
}
|
|
98
|
-
/**
|
|
99
|
-
* wait for reporter to finish synchronization, e.g. when sending data asynchronous
|
|
100
|
-
* to a server (e.g. sumo reporter)
|
|
101
|
-
*/
|
|
102
|
-
waitForSync() {
|
|
103
|
-
const startTime = Date.now();
|
|
104
|
-
return new Promise((resolve, reject) => {
|
|
105
|
-
const interval = setInterval(() => {
|
|
106
|
-
const unsyncedReporter = this._reporters
|
|
107
|
-
.filter((reporter) => !reporter.isSynchronised)
|
|
108
|
-
.map((reporter) => reporter.constructor.name);
|
|
109
|
-
if ((Date.now() - startTime) > this._config.reporterSyncTimeout && unsyncedReporter.length) {
|
|
110
|
-
clearInterval(interval);
|
|
111
|
-
return reject(new Error(`Some reporters are still unsynced: ${unsyncedReporter.join(', ')}`));
|
|
112
|
-
}
|
|
113
|
-
/**
|
|
114
|
-
* no reporter are in need to sync anymore, continue
|
|
115
|
-
*/
|
|
116
|
-
if (!unsyncedReporter.length) {
|
|
117
|
-
clearInterval(interval);
|
|
118
|
-
return resolve(true);
|
|
119
|
-
}
|
|
120
|
-
log.info(`Wait for ${unsyncedReporter.length} reporter to synchronise`);
|
|
121
|
-
// wait otherwise
|
|
122
|
-
}, this._config.reporterSyncInterval);
|
|
123
|
-
});
|
|
124
|
-
}
|
|
125
|
-
/**
|
|
126
|
-
* initialize reporters
|
|
127
|
-
*/
|
|
128
|
-
async _loadReporter(reporter) {
|
|
129
|
-
let ReporterClass;
|
|
130
|
-
let options = {};
|
|
131
|
-
/**
|
|
132
|
-
* check if reporter has custom options
|
|
133
|
-
*/
|
|
134
|
-
if (Array.isArray(reporter)) {
|
|
135
|
-
options = Object.assign({}, options, reporter[1]);
|
|
136
|
-
reporter = reporter[0];
|
|
137
|
-
}
|
|
138
|
-
/**
|
|
139
|
-
* check if reporter was passed in from a file, e.g.
|
|
140
|
-
*
|
|
141
|
-
* ```js
|
|
142
|
-
* import MyCustomReporter from '/some/path/MyCustomReporter.js'
|
|
143
|
-
* export const config = {
|
|
144
|
-
* //...
|
|
145
|
-
* reporters: [
|
|
146
|
-
* MyCustomReporter, // or
|
|
147
|
-
* [MyCustomReporter, { custom: 'option' }]
|
|
148
|
-
* ]
|
|
149
|
-
* //...
|
|
150
|
-
* }
|
|
151
|
-
* ```
|
|
152
|
-
*/
|
|
153
|
-
if (typeof reporter === 'function') {
|
|
154
|
-
ReporterClass = reporter;
|
|
155
|
-
options.logFile = options.setLogFile
|
|
156
|
-
? options.setLogFile(this._cid, ReporterClass.name)
|
|
157
|
-
: typeof options.logFile === 'string'
|
|
158
|
-
? options.logFile
|
|
159
|
-
: this.getLogFile(ReporterClass.name);
|
|
160
|
-
options.writeStream = this.getWriteStreamObject(ReporterClass.name);
|
|
161
|
-
return new ReporterClass(options);
|
|
162
|
-
}
|
|
163
|
-
/**
|
|
164
|
-
* check if reporter is a node package, e.g. wdio-dot reporter
|
|
165
|
-
*
|
|
166
|
-
* ```js
|
|
167
|
-
* export const config = {
|
|
168
|
-
* //...
|
|
169
|
-
* reporters: [
|
|
170
|
-
* 'dot', // or
|
|
171
|
-
* ['dot', { custom: 'option' }]
|
|
172
|
-
* ]
|
|
173
|
-
* //...
|
|
174
|
-
* }
|
|
175
|
-
* ```
|
|
176
|
-
*/
|
|
177
|
-
if (typeof reporter === 'string') {
|
|
178
|
-
ReporterClass = (await initializePlugin(reporter, 'reporter')).default;
|
|
179
|
-
options.logFile = options.setLogFile
|
|
180
|
-
? options.setLogFile(this._cid, reporter)
|
|
181
|
-
: typeof options.logFile === 'string'
|
|
182
|
-
? options.logFile
|
|
183
|
-
: this.getLogFile(reporter);
|
|
184
|
-
options.writeStream = this.getWriteStreamObject(reporter);
|
|
185
|
-
return new ReporterClass(options);
|
|
186
|
-
}
|
|
187
|
-
/**
|
|
188
|
-
* throw error if reporter property was invalid
|
|
189
|
-
*/
|
|
190
|
-
throw new Error('Invalid reporters config');
|
|
191
|
-
}
|
|
192
|
-
}
|
package/build/types.js
DELETED
|
@@ -1 +0,0 @@
|
|
|
1
|
-
export {};
|
package/build/utils.js
DELETED
|
@@ -1,152 +0,0 @@
|
|
|
1
|
-
import path from 'node:path';
|
|
2
|
-
import { deepmerge } from 'deepmerge-ts';
|
|
3
|
-
import logger from '@wdio/logger';
|
|
4
|
-
import { remote, multiremote, attach } from 'webdriverio';
|
|
5
|
-
import { DEFAULTS } from 'webdriver';
|
|
6
|
-
import { DEFAULT_CONFIGS } from '@wdio/config';
|
|
7
|
-
const log = logger('@wdio/runner');
|
|
8
|
-
/**
|
|
9
|
-
* sanitizes wdio config from capability properties
|
|
10
|
-
* @param {Object} caps desired session capabilities
|
|
11
|
-
* @return {Object} sanitized caps
|
|
12
|
-
*/
|
|
13
|
-
export function sanitizeCaps(caps, filterOut) {
|
|
14
|
-
const defaultConfigsKeys = [
|
|
15
|
-
// WDIO config keys
|
|
16
|
-
...Object.keys(DEFAULT_CONFIGS()),
|
|
17
|
-
// WebDriver config keys
|
|
18
|
-
...Object.keys(DEFAULTS)
|
|
19
|
-
];
|
|
20
|
-
return Object.keys(caps).filter((key) => (
|
|
21
|
-
/**
|
|
22
|
-
* filter out all wdio config keys
|
|
23
|
-
*/
|
|
24
|
-
!defaultConfigsKeys.includes(key) === !filterOut)).reduce((obj, key) => {
|
|
25
|
-
obj[key] = caps[key];
|
|
26
|
-
return obj;
|
|
27
|
-
}, {});
|
|
28
|
-
}
|
|
29
|
-
/**
|
|
30
|
-
* initialize browser instance depending whether remote or multiremote is requested
|
|
31
|
-
* @param {Object} config configuration of sessions
|
|
32
|
-
* @param {Object} capabilities desired session capabilities
|
|
33
|
-
* @param {boolean} isMultiremote isMultiremote
|
|
34
|
-
* @return {Promise} resolves with browser object
|
|
35
|
-
*/
|
|
36
|
-
export async function initializeInstance(config, capabilities, isMultiremote) {
|
|
37
|
-
/**
|
|
38
|
-
* Store all log events in a file
|
|
39
|
-
*/
|
|
40
|
-
if (config.outputDir && !process.env.WDIO_LOG_PATH) {
|
|
41
|
-
process.env.WDIO_LOG_PATH = path.join(config.outputDir, 'wdio.log');
|
|
42
|
-
}
|
|
43
|
-
/**
|
|
44
|
-
* check if config has sessionId and attach it to a running session if so
|
|
45
|
-
*/
|
|
46
|
-
if (config.sessionId) {
|
|
47
|
-
log.debug(`attach to session with id ${config.sessionId}`);
|
|
48
|
-
config.capabilities = sanitizeCaps(capabilities);
|
|
49
|
-
/**
|
|
50
|
-
* propagate connection details defined by services or user in capabilities
|
|
51
|
-
*/
|
|
52
|
-
const caps = capabilities;
|
|
53
|
-
const connectionProps = {
|
|
54
|
-
protocol: caps.protocol || config.protocol,
|
|
55
|
-
hostname: caps.hostname || config.hostname,
|
|
56
|
-
port: caps.port || config.port,
|
|
57
|
-
path: caps.path || config.path
|
|
58
|
-
};
|
|
59
|
-
const params = { ...config, ...connectionProps, capabilities };
|
|
60
|
-
return attach({ ...params, options: params });
|
|
61
|
-
}
|
|
62
|
-
if (!isMultiremote) {
|
|
63
|
-
log.debug('init remote session');
|
|
64
|
-
const sessionConfig = {
|
|
65
|
-
...config,
|
|
66
|
-
/**
|
|
67
|
-
* allow to overwrite connection details by user through capabilities
|
|
68
|
-
*/
|
|
69
|
-
...sanitizeCaps(capabilities, true),
|
|
70
|
-
capabilities: sanitizeCaps(capabilities)
|
|
71
|
-
};
|
|
72
|
-
return remote(sessionConfig);
|
|
73
|
-
}
|
|
74
|
-
const options = {};
|
|
75
|
-
log.debug('init multiremote session');
|
|
76
|
-
// @ts-expect-error ToDo(Christian): can be removed?
|
|
77
|
-
delete config.capabilities;
|
|
78
|
-
for (const browserName of Object.keys(capabilities)) {
|
|
79
|
-
options[browserName] = deepmerge(config, capabilities[browserName]);
|
|
80
|
-
}
|
|
81
|
-
const browser = await multiremote(options, config);
|
|
82
|
-
/**
|
|
83
|
-
* only attach to global environment if `injectGlobals` is set to true
|
|
84
|
-
*/
|
|
85
|
-
const browserNames = config.injectGlobals ? Object.keys(capabilities) : [];
|
|
86
|
-
for (const browserName of browserNames) {
|
|
87
|
-
// @ts-ignore allow random global browser names
|
|
88
|
-
global[browserName] = browser[browserName];
|
|
89
|
-
}
|
|
90
|
-
return browser;
|
|
91
|
-
}
|
|
92
|
-
/**
|
|
93
|
-
* Filter logTypes based on filter
|
|
94
|
-
* @param {string[]} excludeDriverLogs logTypes filter
|
|
95
|
-
* @param {string[]} driverLogTypes available driver log types
|
|
96
|
-
* @return {string[]} logTypes
|
|
97
|
-
*/
|
|
98
|
-
export function filterLogTypes(excludeDriverLogs, driverLogTypes) {
|
|
99
|
-
let logTypes = [...driverLogTypes];
|
|
100
|
-
if (Array.isArray(excludeDriverLogs)) {
|
|
101
|
-
log.debug('filtering logTypes', logTypes);
|
|
102
|
-
logTypes = excludeDriverLogs.length === 1 && excludeDriverLogs[0] === '*'
|
|
103
|
-
? []
|
|
104
|
-
: logTypes.filter(x => !excludeDriverLogs.includes(x)); // exclude specific logTypes
|
|
105
|
-
log.debug('filtered logTypes', logTypes);
|
|
106
|
-
}
|
|
107
|
-
return logTypes;
|
|
108
|
-
}
|
|
109
|
-
/**
|
|
110
|
-
* Gets { sessionId, isW3C, protocol, hostname, port, path, queryParams } of every Multiremote instance
|
|
111
|
-
* @param {object} browser browser
|
|
112
|
-
* @param {boolean} isMultiremote isMultiremote
|
|
113
|
-
* @return {object}
|
|
114
|
-
*/
|
|
115
|
-
export function getInstancesData(browser, isMultiremote) {
|
|
116
|
-
if (!isMultiremote) {
|
|
117
|
-
return;
|
|
118
|
-
}
|
|
119
|
-
const multiRemoteBrowser = browser;
|
|
120
|
-
const instances = {};
|
|
121
|
-
multiRemoteBrowser.instances.forEach((browserName) => {
|
|
122
|
-
const { protocol, hostname, port, path, queryParams } = multiRemoteBrowser.getInstance(browserName).options;
|
|
123
|
-
const { isW3C, sessionId } = multiRemoteBrowser.getInstance(browserName);
|
|
124
|
-
instances[browserName] = { sessionId, isW3C, protocol, hostname, port, path, queryParams };
|
|
125
|
-
});
|
|
126
|
-
return instances;
|
|
127
|
-
}
|
|
128
|
-
const SUPPORTED_ASYMMETRIC_MATCHER = {
|
|
129
|
-
Any: 'any',
|
|
130
|
-
Anything: 'anything',
|
|
131
|
-
ArrayContaining: 'arrayContaining',
|
|
132
|
-
ObjectContaining: 'objectContaining',
|
|
133
|
-
StringContaining: 'stringContaining',
|
|
134
|
-
StringMatching: 'stringMatching',
|
|
135
|
-
CloseTo: 'closeTo'
|
|
136
|
-
};
|
|
137
|
-
/**
|
|
138
|
-
* utility function to transform assertion parameters into asymmetric matchers if necessary
|
|
139
|
-
* @param arg raw value or a stringified asymmetric matcher
|
|
140
|
-
* @returns raw value or an actual asymmetric matcher
|
|
141
|
-
*/
|
|
142
|
-
export function transformExpectArgs(arg) {
|
|
143
|
-
if (typeof arg === 'object' && '$$typeof' in arg && Object.keys(SUPPORTED_ASYMMETRIC_MATCHER).includes(arg.$$typeof)) {
|
|
144
|
-
const matcherKey = SUPPORTED_ASYMMETRIC_MATCHER[arg.$$typeof];
|
|
145
|
-
const matcher = arg.inverse ? expect.not[matcherKey] : expect[matcherKey];
|
|
146
|
-
if (!matcher) {
|
|
147
|
-
throw new Error(`Matcher "${matcherKey}" is not supported by expect-webdriverio`);
|
|
148
|
-
}
|
|
149
|
-
return matcher(arg.sample);
|
|
150
|
-
}
|
|
151
|
-
return arg;
|
|
152
|
-
}
|
/package/{LICENSE-MIT → LICENSE}
RENAMED
|
File without changes
|