Skip to content

Commit 7b97a55

Browse files
DavertMikDavertMik
andauthored
Improved passing step options (#4733)
* initial implementation for step params * refactored steps * refactored steps * fixed refactoring * fixed typings * fixed typings * added steps to export * added step timeouts tests * deprecated I.limitTime and I.retry * fix failed timeout tests * added test for case insensitive opt * fixed flakiness of timeout tests --------- Co-authored-by: DavertMik <[email protected]>
1 parent f5cbe20 commit 7b97a55

32 files changed

+1108
-756
lines changed

docs/helpers/Appium.md

Lines changed: 291 additions & 295 deletions
Large diffs are not rendered by default.

lib/actor.js

Lines changed: 47 additions & 92 deletions
Original file line numberDiff line numberDiff line change
@@ -1,11 +1,13 @@
1-
const Step = require('./step');
2-
const { MetaStep } = require('./step');
3-
const container = require('./container');
4-
const { methodsOfObject } = require('./utils');
5-
const recorder = require('./recorder');
6-
const event = require('./event');
7-
const store = require('./store');
8-
const output = require('./output');
1+
const Step = require('./step')
2+
const MetaStep = require('./step/meta')
3+
const recordStep = require('./step/record')
4+
const container = require('./container')
5+
const { methodsOfObject } = require('./utils')
6+
const { TIMEOUT_ORDER } = require('./step/timeout')
7+
const recorder = require('./recorder')
8+
const event = require('./event')
9+
const store = require('./store')
10+
const output = require('./output')
911

1012
/**
1113
* @interface
@@ -21,13 +23,13 @@ class Actor {
2123
* ⚠️ returns a promise which is synchronized internally by recorder
2224
*/
2325
async say(msg, color = 'cyan') {
24-
const step = new Step('say', 'say');
25-
step.status = 'passed';
26+
const step = new Step('say', 'say')
27+
step.status = 'passed'
2628
return recordStep(step, [msg]).then(() => {
2729
// this is backward compatibility as this event may be used somewhere
28-
event.emit(event.step.comment, msg);
29-
output.say(msg, `${color}`);
30-
});
30+
event.emit(event.step.comment, msg)
31+
output.say(msg, `${color}`)
32+
})
3133
}
3234

3335
/**
@@ -38,14 +40,16 @@ class Actor {
3840
* @inner
3941
*/
4042
limitTime(timeout) {
41-
if (!store.timeouts) return this;
43+
if (!store.timeouts) return this
44+
45+
console.log('I.limitTime() is deprecated, use step.timeout() instead')
4246

4347
event.dispatcher.prependOnceListener(event.step.before, step => {
44-
output.log(`Timeout to ${step}: ${timeout}s`);
45-
step.setTimeout(timeout * 1000, Step.TIMEOUT_ORDER.codeLimitTime);
46-
});
48+
output.log(`Timeout to ${step}: ${timeout}s`)
49+
step.setTimeout(timeout * 1000, TIMEOUT_ORDER.codeLimitTime)
50+
})
4751

48-
return this;
52+
return this
4953
}
5054

5155
/**
@@ -55,11 +59,10 @@ class Actor {
5559
* @inner
5660
*/
5761
retry(opts) {
58-
if (opts === undefined) opts = 1;
59-
recorder.retry(opts);
60-
// remove retry once the step passed
61-
recorder.add(() => event.dispatcher.once(event.step.finished, () => recorder.retries.pop()));
62-
return this;
62+
console.log('I.retry() is deprecated, use step.retry() instead')
63+
const retryStep = require('./step/retry')
64+
retryStep(opts)
65+
return this
6366
}
6467
}
6568

@@ -70,102 +73,54 @@ class Actor {
7073
* @ignore
7174
*/
7275
module.exports = function (obj = {}) {
73-
const actor = container.actor() || new Actor();
76+
const actor = container.actor() || new Actor()
7477

7578
// load all helpers once container initialized
7679
container.started(() => {
77-
const translation = container.translation();
78-
const helpers = container.helpers();
80+
const translation = container.translation()
81+
const helpers = container.helpers()
7982

8083
// add methods from enabled helpers
8184
Object.values(helpers).forEach(helper => {
8285
methodsOfObject(helper, 'Helper')
8386
.filter(method => method !== 'constructor' && method[0] !== '_')
8487
.forEach(action => {
85-
const actionAlias = translation.actionAliasFor(action);
88+
const actionAlias = translation.actionAliasFor(action)
8689
if (!actor[action]) {
8790
actor[action] = actor[actionAlias] = function () {
88-
const step = new Step(helper, action);
91+
const step = new Step(helper, action)
8992
if (translation.loaded) {
90-
step.name = actionAlias;
91-
step.actor = translation.I;
93+
step.name = actionAlias
94+
step.actor = translation.I
9295
}
9396
// add methods to promise chain
94-
return recordStep(step, Array.from(arguments));
95-
};
97+
return recordStep(step, Array.from(arguments))
98+
}
9699
}
97-
});
98-
});
100+
})
101+
})
99102

100103
// add translated custom steps from actor
101104
Object.keys(obj).forEach(key => {
102-
const actionAlias = translation.actionAliasFor(key);
105+
const actionAlias = translation.actionAliasFor(key)
103106
if (!actor[actionAlias]) {
104-
actor[actionAlias] = actor[key];
107+
actor[actionAlias] = actor[key]
105108
}
106-
});
109+
})
107110

108111
container.append({
109112
support: {
110113
I: actor,
111114
},
112-
});
113-
});
115+
})
116+
})
114117
// store.actor = actor;
115118
// add custom steps from actor
116119
Object.keys(obj).forEach(key => {
117-
const ms = new MetaStep('I', key);
118-
ms.setContext(actor);
119-
actor[key] = ms.run.bind(ms, obj[key]);
120-
});
121-
122-
return actor;
123-
};
124-
125-
function recordStep(step, args) {
126-
step.status = 'queued';
127-
step.setArguments(args);
128-
129-
// run async before step hooks
130-
event.emit(event.step.before, step);
131-
132-
const task = `${step.name}: ${step.humanizeArgs()}`;
133-
let val;
134-
135-
// run step inside promise
136-
recorder.add(
137-
task,
138-
() => {
139-
if (!step.startTime) {
140-
// step can be retries
141-
event.emit(event.step.started, step);
142-
step.startTime = Date.now();
143-
}
144-
return (val = step.run(...args));
145-
},
146-
false,
147-
undefined,
148-
step.getTimeout(),
149-
);
150-
151-
event.emit(event.step.after, step);
152-
153-
recorder.add('step passed', () => {
154-
step.endTime = Date.now();
155-
event.emit(event.step.passed, step, val);
156-
event.emit(event.step.finished, step);
157-
});
158-
159-
recorder.catchWithoutStop(err => {
160-
step.status = 'failed';
161-
step.endTime = Date.now();
162-
event.emit(event.step.failed, step);
163-
event.emit(event.step.finished, step);
164-
throw err;
165-
});
166-
167-
recorder.add('return result', () => val);
168-
// run async after step hooks
120+
const ms = new MetaStep('I', key)
121+
ms.setContext(actor)
122+
actor[key] = ms.run.bind(ms, obj[key])
123+
})
169124

170-
return recorder.promise();
125+
return actor
171126
}

lib/helper/Playwright.js

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3509,6 +3509,11 @@ async function proceedSee(assertType, text, context, strict = false) {
35093509
allText = await Promise.all(els.map(el => el.innerText()))
35103510
}
35113511

3512+
if (store?.currentStep?.opts?.ignoreCase === true) {
3513+
text = text.toLowerCase()
3514+
allText = allText.map(elText => elText.toLowerCase())
3515+
}
3516+
35123517
if (strict) {
35133518
return allText.map(elText => equals(description)[assertType](text, elText))
35143519
}

lib/helper/Puppeteer.js

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2769,6 +2769,11 @@ async function proceedSee(assertType, text, context, strict = false) {
27692769
allText = await Promise.all(els.map(el => el.getProperty('innerText').then(p => p.jsonValue())))
27702770
}
27712771

2772+
if (store?.currentStep?.opts?.ignoreCase === true) {
2773+
text = text.toLowerCase()
2774+
allText = allText.map(elText => elText.toLowerCase())
2775+
}
2776+
27722777
if (strict) {
27732778
return allText.map(elText => equals(description)[assertType](text, elText))
27742779
}

lib/helper/WebDriver.js

Lines changed: 9 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,7 @@ const Helper = require('@codeceptjs/helper')
77
const promiseRetry = require('promise-retry')
88
const stringIncludes = require('../assert/include').includes
99
const { urlEquals, equals } = require('../assert/equal')
10+
const store = require('../store')
1011
const { debug } = require('../output')
1112
const { empty } = require('../assert/empty')
1213
const { truth } = require('../assert/truth')
@@ -2698,7 +2699,14 @@ async function proceedSee(assertType, text, context, strict = false) {
26982699
const smartWaitEnabled = assertType === 'assert'
26992700
const res = await this._locate(withStrictLocator(context), smartWaitEnabled)
27002701
assertElementExists(res, context)
2701-
const selected = await forEachAsync(res, async el => this.browser.getElementText(getElementId(el)))
2702+
let selected = await forEachAsync(res, async el => this.browser.getElementText(getElementId(el)))
2703+
2704+
// apply ignoreCase option
2705+
if (store?.currentStep?.opts?.ignoreCase === true) {
2706+
text = text.toLowerCase()
2707+
selected = selected.map(elText => elText.toLowerCase())
2708+
}
2709+
27022710
if (strict) {
27032711
if (Array.isArray(selected) && selected.length !== 0) {
27042712
return selected.map(elText => equals(description)[assertType](text, elText))

lib/listener/globalTimeout.js

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,7 @@ const output = require('../output')
33
const recorder = require('../recorder')
44
const Config = require('../config')
55
const { timeouts } = require('../store')
6-
const TIMEOUT_ORDER = require('../step').TIMEOUT_ORDER
6+
const { TIMEOUT_ORDER } = require('../step/timeout')
77

88
module.exports = function () {
99
let timeout

lib/listener/steps.js

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -73,6 +73,7 @@ module.exports = function () {
7373
event.dispatcher.on(event.step.started, step => {
7474
step.startedAt = +new Date()
7575
step.test = currentTest
76+
store.currentStep = step
7677
if (currentHook && Array.isArray(currentHook.steps)) {
7778
return currentHook.steps.push(step)
7879
}
@@ -84,5 +85,7 @@ module.exports = function () {
8485
step.finishedAt = +new Date()
8586
if (step.startedAt) step.duration = step.finishedAt - step.startedAt
8687
debug(`Step '${step}' finished; Duration: ${step.duration || 0}ms`)
88+
store.currentStep = null
89+
store.stepOptions = null
8790
})
8891
}

lib/plugin/stepTimeout.js

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
const event = require('../event')
2-
const TIMEOUT_ORDER = require('../step').TIMEOUT_ORDER
2+
const { TIMEOUT_ORDER } = require('../step/timeout')
33

44
const defaultConfig = {
55
timeout: 150,

lib/recorder.js

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -179,7 +179,7 @@ module.exports = {
179179
}
180180
if (retry === undefined) retry = true
181181
if (!running && !force) {
182-
return
182+
return Promise.resolve()
183183
}
184184
tasks.push(taskName)
185185
debug(chalk.gray(`${currentQueue()} Queued | ${taskName}`))

0 commit comments

Comments
 (0)