forked from codeceptjs/CodeceptJS
-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy pathactor.js
157 lines (136 loc) · 3.99 KB
/
actor.js
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
const Step = require('./step');
const { MetaStep } = require('./step');
const container = require('./container');
const { methodsOfObject } = require('./utils');
const recorder = require('./recorder');
const event = require('./event');
const store = require('./store');
const output = require('./output');
/**
* @interface
* @alias ActorStatic
*/
class Actor {
/**
* add print comment method`
* @param {string} msg
* @param {string} color
* @return {Promise<any> | undefined}
* @inner
*/
say(msg, color = 'cyan') {
return recorder.add(`say ${msg}`, () => {
event.emit(event.step.comment, msg);
output.say(msg, `${color}`);
});
}
/**
* set the maximum execution time for the next step
* @function
* @param {number} timeout - step timeout in seconds
* @return {this}
* @inner
*/
limitTime(timeout) {
if (!store.timeouts) return this;
event.dispatcher.prependOnceListener(event.step.before, (step) => {
output.log(`Timeout to ${step}: ${timeout}s`);
step.setTimeout(timeout * 1000, Step.TIMEOUT_ORDER.codeLimitTime);
});
return this;
}
/**
* @function
* @param {*} [opts]
* @return {this}
* @inner
*/
retry(opts) {
if (opts === undefined) opts = 1;
recorder.retry(opts);
// remove retry once the step passed
recorder.add(() => event.dispatcher.once(event.step.finished, () => recorder.retries.pop()));
return this;
}
}
/**
* Fetches all methods from all enabled helpers,
* and makes them available to use from I. object
* Wraps helper methods into promises.
* @ignore
*/
module.exports = function (obj = {}) {
if (!store.actor) {
store.actor = new Actor();
}
const actor = store.actor;
const translation = container.translation();
if (Object.keys(obj).length > 0) {
Object.keys(obj)
.forEach(action => {
const actionAlias = translation.actionAliasFor(action);
const currentMethod = obj[action];
const ms = new MetaStep('I', action);
if (translation.loaded) {
ms.name = actionAlias;
ms.actor = translation.I;
}
ms.setContext(actor);
actor[action] = actor[actionAlias] = ms.run.bind(ms, currentMethod);
});
}
const helpers = container.helpers();
// add methods from enabled helpers
Object.values(helpers)
.forEach((helper) => {
methodsOfObject(helper, 'Helper')
.filter(method => method !== 'constructor' && method[0] !== '_')
.forEach((action) => {
const actionAlias = translation.actionAliasFor(action);
if (!actor[action]) {
actor[action] = actor[actionAlias] = function () {
const step = new Step(helper, action);
if (translation.loaded) {
step.name = actionAlias;
step.actor = translation.I;
}
// add methods to promise chain
return recordStep(step, Array.from(arguments));
};
}
});
});
return actor;
};
function recordStep(step, args) {
step.status = 'queued';
step.setArguments(args);
// run async before step hooks
event.emit(event.step.before, step);
const task = `${step.name}: ${step.humanizeArgs()}`;
let val;
// run step inside promise
recorder.add(task, () => {
if (!step.startTime) { // step can be retries
event.emit(event.step.started, step);
step.startTime = Date.now();
}
return val = step.run(...args);
}, false, undefined, step.getTimeout());
event.emit(event.step.after, step);
recorder.add('step passed', () => {
step.endTime = Date.now();
event.emit(event.step.passed, step, val);
event.emit(event.step.finished, step);
});
recorder.catchWithoutStop((err) => {
step.status = 'failed';
step.endTime = Date.now();
event.emit(event.step.failed, step);
event.emit(event.step.finished, step);
throw err;
});
recorder.add('return result', () => val);
// run async after step hooks
return recorder.promise();
}