@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/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
- }
File without changes