Skip to content

Commit dfec1d9

Browse files
feat(run-workers) : Add support of multiple browsers for run-workers (#3606)
* feat(run-workers) : Add support of multiple for run-workers * Fix multiple array not defined error * Fix unit test case * Update parallel.md
1 parent 11109b6 commit dfec1d9

File tree

5 files changed

+146
-11
lines changed

5 files changed

+146
-11
lines changed

bin/codecept.js

+1-1
Original file line numberDiff line numberDiff line change
@@ -130,7 +130,7 @@ program.command('run [test]')
130130
.option('--child <string>', 'option for child processes')
131131
.action(errorHandler(require('../lib/command/run')));
132132

133-
program.command('run-workers <workers>')
133+
program.command('run-workers <workers> [selectedRuns...]')
134134
.description('Executes tests in workers')
135135
.option('-c, --config [file]', 'configuration file to be used')
136136
.option('-g, --grep <pattern>', 'only run tests matching <pattern>')

docs/parallel.md

+56
Original file line numberDiff line numberDiff line change
@@ -32,6 +32,62 @@ By default the tests are assigned one by one to the available workers this may l
3232
npx codeceptjs run-workers --suites 2
3333
```
3434

35+
## Parallel Execution by Workers on Multiple Browsers
36+
37+
To run tests in parallel across multiple browsers, modify your `codecept.conf.js` file to configure multiple browsers on which you want to run your tests and your tests will run across multiple browsers.
38+
39+
Start with modifying the `codecept.conf.js` file. Add multiple key inside the config which will be used to configure multiple profiles.
40+
41+
```
42+
exports.config = {
43+
helpers: {
44+
WebDriver: {
45+
url: 'http://localhost:3000',
46+
desiredCapabilties: {}
47+
}
48+
},
49+
multiple: {
50+
profile1: {
51+
browsers: [
52+
{
53+
browser: "firefox",
54+
desiredCapabilties: {
55+
// override capabilties related to firefox
56+
}
57+
},
58+
{
59+
browser: "chrome",
60+
desiredCapabilties: {
61+
// override capabilties related to chrome
62+
}
63+
}
64+
]
65+
},
66+
profile2: {
67+
browsers: [
68+
{
69+
browser: "safari",
70+
desiredCapabilties: {
71+
// override capabilties related to safari
72+
}
73+
}
74+
]
75+
}
76+
}
77+
};
78+
```
79+
To trigger tests on all the profiles configured, you can use the following command:
80+
```
81+
npx codeceptjs run-workers 3 all -c codecept.conf.js
82+
```
83+
This will run your tests across all browsers configured from profile1 & profile2 on 3 workers.
84+
85+
To trigger tests on specific profile, you can use the following command:
86+
```
87+
npx codeceptjs run-workers 2 profile1 -c codecept.conf.js
88+
```
89+
This will run your tests across 2 browsers from profile1 on 2 workers.
90+
3591
## Custom Parallel Execution
3692

3793
To get a full control of parallelization create a custom execution script to match your needs.

lib/command/run-workers.js

+2-1
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,7 @@ const output = require('../output');
44
const event = require('../event');
55
const Workers = require('../workers');
66

7-
module.exports = async function (workerCount, options) {
7+
module.exports = async function (workerCount, selectedRuns, options) {
88
process.env.profile = options.profile;
99

1010
const { config: testConfig, override = '' } = options;
@@ -15,6 +15,7 @@ module.exports = async function (workerCount, options) {
1515
by,
1616
testConfig,
1717
options,
18+
selectedRuns,
1819
};
1920

2021
const numberOfWorkers = parseInt(workerCount, 10);

lib/workers.js

+57-9
Original file line numberDiff line numberDiff line change
@@ -10,12 +10,14 @@ const MochaFactory = require('./mochaFactory');
1010
const Container = require('./container');
1111
const { getTestRoot } = require('./command/utils');
1212
const { isFunction, fileExists } = require('./utils');
13+
const { replaceValueDeep, deepClone } = require('./utils');
1314
const mainConfig = require('./config');
1415
const output = require('./output');
1516
const event = require('./event');
1617
const recorder = require('./recorder');
1718
const runHook = require('./hooks');
1819
const WorkerStorage = require('./workerStorage');
20+
const collection = require('./command/run-multiple/collection');
1921

2022
const pathToWorker = path.join(__dirname, 'command', 'workers', 'runTests.js');
2123

@@ -79,15 +81,39 @@ const repackTest = (test) => {
7981
return test;
8082
};
8183

82-
const createWorkerObjects = (testGroups, config, testRoot, options) => {
83-
return testGroups.map((tests, index) => {
84-
const workerObj = new WorkerObject(index);
85-
workerObj.addConfig(config);
86-
workerObj.addTests(tests);
87-
workerObj.setTestRoot(testRoot);
88-
workerObj.addOptions(options);
89-
return workerObj;
84+
const createWorkerObjects = (testGroups, config, testRoot, options, selectedRuns) => {
85+
selectedRuns = options && options.all && config.multiple ? Object.keys(config.multiple) : selectedRuns;
86+
if (selectedRuns === undefined || !selectedRuns.length || config.multiple === undefined) {
87+
return testGroups.map((tests, index) => {
88+
const workerObj = new WorkerObject(index);
89+
workerObj.addConfig(config);
90+
workerObj.addTests(tests);
91+
workerObj.setTestRoot(testRoot);
92+
workerObj.addOptions(options);
93+
return workerObj;
94+
});
95+
}
96+
const workersToExecute = [];
97+
collection.createRuns(selectedRuns, config).forEach((worker) => {
98+
const workerName = worker.getOriginalName() || worker.getName();
99+
const workerConfig = worker.getConfig();
100+
workersToExecute.push(getOverridenConfig(workerName, workerConfig, config));
101+
});
102+
const workers = [];
103+
let index = 0;
104+
testGroups.forEach((tests) => {
105+
const testWorkerArray = [];
106+
workersToExecute.forEach((finalConfig) => {
107+
const workerObj = new WorkerObject(index++);
108+
workerObj.addConfig(finalConfig);
109+
workerObj.addTests(tests);
110+
workerObj.setTestRoot(testRoot);
111+
workerObj.addOptions(options);
112+
testWorkerArray.push(workerObj);
113+
});
114+
workers.push(...testWorkerArray);
90115
});
116+
return workers;
91117
};
92118

93119
const indexOfSmallestElement = (groups) => {
@@ -115,6 +141,28 @@ const convertToMochaTests = (testGroup) => {
115141
return group;
116142
};
117143

144+
const getOverridenConfig = (workerName, workerConfig, config) => {
145+
// clone config
146+
const overriddenConfig = deepClone(config);
147+
148+
// get configuration
149+
const browserConfig = workerConfig.browser;
150+
151+
for (const key in browserConfig) {
152+
overriddenConfig.helpers = replaceValueDeep(overriddenConfig.helpers, key, browserConfig[key]);
153+
}
154+
155+
// override tests configuration
156+
if (overriddenConfig.tests) {
157+
overriddenConfig.tests = workerConfig.tests;
158+
}
159+
160+
if (overriddenConfig.gherkin && workerConfig.gherkin && workerConfig.gherkin.features) {
161+
overriddenConfig.gherkin.features = workerConfig.gherkin.features;
162+
}
163+
return overriddenConfig;
164+
};
165+
118166
class WorkerObject {
119167
/**
120168
* @param {Number} workerIndex - Unique ID for worker
@@ -183,7 +231,7 @@ class Workers extends EventEmitter {
183231

184232
_initWorkers(numberOfWorkers, config) {
185233
this.splitTestsByGroups(numberOfWorkers, config);
186-
this.workers = createWorkerObjects(this.testGroups, this.codecept.config, config.testConfig, config.options);
234+
this.workers = createWorkerObjects(this.testGroups, this.codecept.config, config.testConfig, config.options, config.selectedRuns);
187235
this.numberOfWorkers = this.workers.length;
188236
}
189237

test/unit/worker_test.js

+30
Original file line numberDiff line numberDiff line change
@@ -240,4 +240,34 @@ describe('Workers', () => {
240240
done();
241241
});
242242
});
243+
244+
it('should run worker with multiple config', (done) => {
245+
const workerConfig = {
246+
by: 'test',
247+
testConfig: './test/data/sandbox/codecept.multiple.js',
248+
options: {},
249+
selectedRuns: ['mobile'],
250+
};
251+
252+
const workers = new Workers(2, workerConfig);
253+
254+
for (const worker of workers.getWorkers()) {
255+
worker.addConfig({
256+
helpers: {
257+
FileSystem: {},
258+
Workers: {
259+
require: './custom_worker_helper',
260+
},
261+
},
262+
});
263+
}
264+
265+
workers.run();
266+
267+
workers.on(event.all.result, (status) => {
268+
expect(workers.getWorkers().length).equal(8);
269+
expect(status).equal(true);
270+
done();
271+
});
272+
});
243273
});

0 commit comments

Comments
 (0)