Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

fix(workers): event improvements #3953

Merged
merged 33 commits into from
Dec 5, 2023
Merged
Show file tree
Hide file tree
Changes from 31 commits
Commits
Show all changes
33 commits
Select commit Hold shift + click to select a range
3c6c221
fix(workers): improve events
kobenguyent Oct 26, 2023
081e11c
fix(workers): improve events
kobenguyent Oct 26, 2023
d072254
expose env var
kobenguyent Oct 27, 2023
b7430b7
some improvements
kobenguyent Oct 27, 2023
58514ae
emit step events in workers
kobenguyent Oct 28, 2023
1245816
Update internal-api.md
kobenguyent Oct 29, 2023
bf70dfc
Update workers.js
kobenguyent Oct 29, 2023
f346f3d
remove duplicate events
kobenguyent Oct 29, 2023
4436a91
Update internal-api.md
kobenguyent Oct 29, 2023
24baf51
Update package.json
kobenguyent Oct 29, 2023
62ea8e8
Update worker_test.js
kobenguyent Oct 29, 2023
9ed686d
fix: expose test stats when run-workers finished
kobenguyent Oct 30, 2023
00d385b
fix: attach step object to test object
kobenguyent Oct 31, 2023
c86f5ef
resolve conflict
kobenguyent Nov 7, 2023
7df2d9f
fix(workers): improve events
kobenguyent Oct 26, 2023
a579605
resolve conflict
kobenguyent Nov 7, 2023
61457c8
some improvements
kobenguyent Oct 27, 2023
c5713b6
emit step events in workers
kobenguyent Oct 28, 2023
45c37cc
Update internal-api.md
kobenguyent Oct 29, 2023
c9391a2
Update workers.js
kobenguyent Oct 29, 2023
26f8b8d
remove duplicate events
kobenguyent Oct 29, 2023
18a93e9
Update package.json
kobenguyent Oct 29, 2023
a727708
Update worker_test.js
kobenguyent Oct 29, 2023
ee47cd2
fix: expose test stats when run-workers finished
kobenguyent Oct 30, 2023
a8d153b
fix: attach step object to test object
kobenguyent Oct 31, 2023
082ba93
fix: conflict
kobenguyent Oct 31, 2023
c78345d
fix: update docs
kobenguyent Oct 31, 2023
8c2212b
fix: add err object to step
kobenguyent Oct 31, 2023
06fcded
remove redundant
kobenguyent Nov 7, 2023
b71b01f
remove redundant
kobenguyent Nov 7, 2023
97a7e4a
Merge branch '3.x' into worker-event-improvements
kobenguyent Nov 30, 2023
0f284da
address CR
kobenguyent Dec 5, 2023
1f776b1
Merge branch '3.x' into worker-event-improvements
kobenguyent Dec 5, 2023
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
111 changes: 111 additions & 0 deletions docs/internal-api.md
Original file line number Diff line number Diff line change
Expand Up @@ -96,7 +96,117 @@ module.exports = function() {
});
}
```
You could get test stats when running with workers
kobenguyent marked this conversation as resolved.
Show resolved Hide resolved

```js
const { event } = require('codeceptjs');

module.exports = function() {

event.dispatcher.on(event.workers.result, function (result) {

console.log(result);

});
}

// in console log
FAIL | 7 passed, 1 failed, 1 skipped // 2s
{
"tests": {
"passed": [
{
"type": "test",
"title": "Assert @C3",
"body": "() => { }",
"async": 0,
"sync": true,
"_timeout": 2000,
"_slow": 75,
"_retries": -1,
"timedOut": false,
"_currentRetry": 0,
"pending": false,
"opts": {},
"tags": [
"@C3"
],
"uid": "xe4q1HdqpRrZG5dPe0JG+A",
"workerIndex": 3,
"retries": -1,
"duration": 493,
"err": null,
"parent": {
"title": "My",
"ctx": {},
"suites": [],
"tests": [],
"root": false,
"pending": false,
"_retries": -1,
"_beforeEach": [],
"_beforeAll": [],
"_afterEach": [],
"_afterAll": [],
"_timeout": 2000,
"_slow": 75,
"_bail": false,
"_onlyTests": [],
"_onlySuites": [],
"delayed": false
},
"steps": [
{
"actor": "I",
"name": "amOnPage",
"status": "success",
"agrs": [
"https://developer.mozilla.org/en-US/docs/Web/HTTP/Methods/POST"
],
"startedAt": 1698760652610,
"startTime": 1698760652611,
"endTime": 1698760653098,
"finishedAt": 1698760653098,
"duration": 488
},
{
"actor": "I",
"name": "grabCurrentUrl",
"status": "success",
"agrs": [],
"startedAt": 1698760653098,
"startTime": 1698760653098,
"endTime": 1698760653099,
"finishedAt": 1698760653099,
"duration": 1
}
]
}
],
"failed": [],
"skipped": []
}
}
```

CodeceptJS also exposes the env var `process.env.RUNS_WITH_WORKERS` when running tests with `run-workers` command so that you could handle the events better in your plugins/helpers

```js
const { event } = require('codeceptjs');

module.exports = function() {
// this event would trigger the `_publishResultsToTestrail` when running `run-workers` command
event.dispatcher.on(event.workers.result, async () => {
await _publishResultsToTestrail();
});

// this event would not trigger the `_publishResultsToTestrail` multiple times when running `run-workers` command
event.dispatcher.on(event.all.result, async () => {
// when running `run` command, this env var is undefined
if (!process.env.RUNS_WITH_WORKERS) await _publishResultsToTestrail();
});
}
```
Available events:

* `event.test.before(test)` - *async* when `Before` hooks from helpers and from test is executed
Expand All @@ -119,6 +229,7 @@ Available events:
* `event.all.result` - when results are printed
* `event.workers.before` - before spawning workers in parallel run
* `event.workers.after` - after workers finished in parallel run
* `event.workers.result` - test results after workers finished in parallel run


> *sync* - means that event is fired in the moment of the action happening.
Expand Down
34 changes: 30 additions & 4 deletions lib/command/run-workers.js
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,11 @@ const Workers = require('../workers');
module.exports = async function (workerCount, selectedRuns, options) {
process.env.profile = options.profile;

const suiteArr = [];
const passedTestArr = [];
const failedTestArr = [];
const skippedTestArr = [];

const { config: testConfig, override = '' } = options;
const overrideConfigs = tryOrDefault(() => JSON.parse(override), {});
const by = options.suites ? 'suite' : 'test';
Expand All @@ -26,15 +31,36 @@ module.exports = async function (workerCount, selectedRuns, options) {

const workers = new Workers(numberOfWorkers, config);
workers.overrideConfig(overrideConfigs);
workers.on(event.test.failed, (failedTest) => {
output.test.failed(failedTest);

workers.on(event.suite.before, (suite) => {
suiteArr.push(suite);
});

workers.on(event.test.failed, (test) => {
failedTestArr.push(test);
output.test.failed(test);
});

workers.on(event.test.passed, (test) => {
passedTestArr.push(test);
output.test.passed(test);
});

workers.on(event.test.passed, (successTest) => {
output.test.passed(successTest);
workers.on(event.test.skipped, (test) => {
skippedTestArr.push(test);
output.test.passed(test);
});

workers.on(event.all.result, () => {
// expose test stats after all workers finished their execution
event.dispatcher.emit(event.workers.result, {
suites: suiteArr,
tests: {
passed: passedTestArr,
failed: failedTestArr,
skipped: skippedTestArr,
},
});
workers.printResults();
});

Expand Down
23 changes: 23 additions & 0 deletions lib/command/workers/runTests.js
Original file line number Diff line number Diff line change
Expand Up @@ -132,9 +132,32 @@ function initializeListeners() {
duration: test.duration || 0,
err,
parent,
steps: test.steps ? simplifyStepsInTestObject(test.steps, err) : [],
};
}

function simplifyStepsInTestObject(steps, err) {
steps = [...steps];
const _steps = [];

for (step of steps) {
_steps.push({
actor: step.actor,
name: step.name,
status: step.status,
agrs: step.args,
startedAt: step.startedAt,
startTime: step.startTime,
endTime: step.endTime,
finishedAt: step.finishedAt,
duration: step.duration,
err,
});
}

return _steps;
}

function simplifyStep(step, err = null) {
step = { ...step };

Expand Down
2 changes: 2 additions & 0 deletions lib/event.js
Original file line number Diff line number Diff line change
Expand Up @@ -127,10 +127,12 @@ module.exports = {
* @inner
* @property {'workers.before'} before
* @property {'workers.after'} after
* @property {'workers.result'} result
*/
workers: {
before: 'workers.before',
after: 'workers.after',
result: 'workers.result',
},

/**
Expand Down
2 changes: 2 additions & 0 deletions lib/workers.js
Original file line number Diff line number Diff line change
Expand Up @@ -359,6 +359,7 @@ class Workers extends EventEmitter {
this.stats.start = new Date();
recorder.startUnlessRunning();
event.dispatcher.emit(event.workers.before);
process.env.RUNS_WITH_WORKERS = 'true';
recorder.add('starting workers', () => {
for (const worker of this.workers) {
const workerThread = createWorker(worker);
Expand Down Expand Up @@ -492,6 +493,7 @@ class Workers extends EventEmitter {
}

output.result(this.stats.passes, this.stats.failures, this.stats.pending, ms(this.stats.duration));
process.env.RUNS_WITH_WORKERS = 'false';
}
}

Expand Down
4 changes: 0 additions & 4 deletions test/unit/worker_test.js
Original file line number Diff line number Diff line change
Expand Up @@ -9,10 +9,6 @@ describe('Workers', function () {
global.codecept_dir = path.join(__dirname, '/../data/sandbox');
});

beforeEach(function () {
this.timeout(40000);
});

it('should run simple worker', (done) => {
const workerConfig = {
by: 'test',
Expand Down