-
-
Notifications
You must be signed in to change notification settings - Fork 752
Expand file tree
/
Copy pathsession.js
More file actions
140 lines (123 loc) · 4.17 KB
/
Copy pathsession.js
File metadata and controls
140 lines (123 loc) · 4.17 KB
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
import recorder from './recorder.js'
import container from './container.js'
import event from './event.js'
import output from './output.js'
import store from './store.js'
import { isAsyncFunction } from './utils.js'
const sessionColors = ['cyan', 'blue', 'red', 'magenta', 'yellow']
const savedSessions = {}
/**
* @param {CodeceptJS.LocatorOrString} sessionName
* @param {Function | Object<string, *>} config
* @param {Function} [fn]
* @return {any}
*/
function session(sessionName, config, fn) {
if (typeof config === 'function') {
if (typeof fn === 'function') {
config = config()
} else {
// no config but with function
fn = config
config = {}
}
}
// session helpers won't use beforeSuite and afterSuite hooks...
// restart: false options are not allowed as well
// but those helpers should be already started so inside listener/helpers.js the `_init` method should already be called
const helpers = container.helpers()
if (!savedSessions[sessionName]) {
for (const helper in helpers) {
if (!helpers[helper]._session) continue
savedSessions[sessionName] = {
start: () => null,
stop: () => null,
loadVars: () => null,
restoreVars: () => null,
...(store.dryRun ? {} : helpers[helper]._session()),
}
break
}
const closeBrowsers = () => {
const session = savedSessions[sessionName]
if (!session) return
session.stop(session.vars)
delete savedSessions[sessionName]
}
event.dispatcher.once(event.test.after, () => {
recorder.add('close session browsers', closeBrowsers)
})
if (!savedSessions[sessionName]) {
throw new Error('Configured helpers do not support starting sessions. Please use a helper with session support.')
}
recorder.add('save vars', async () => {
savedSessions[sessionName].vars = await savedSessions[sessionName].start(sessionName, config)
})
}
// pick random color
const color = sessionColors[Object.keys(savedSessions).indexOf(sessionName) % sessionColors.length]
const addContextToStep = step => {
step.actor = `${output.colors[color](sessionName)}: I`
}
if (!fn) return // no current session steps
return recorder.add(
'register session wrapper',
async () => {
const session = savedSessions[sessionName]
if (!session) {
throw new Error(`Session "${sessionName}" not found. It may have been closed already.`)
}
recorder.session.start(`session:${sessionName}`)
event.dispatcher.on(event.step.after, addContextToStep)
recorder.add('switch to browser', () => {
const session = savedSessions[sessionName]
return session.loadVars(session.vars)
})
const finalize = () => {
recorder.add('Finalize session', async () => {
output.stepShift = 0
event.dispatcher.removeListener(event.step.after, addContextToStep)
await session.restoreVars()
recorder.session.restore(`session:${sessionName}`)
})
}
// Indicate when executing this function that we are in a session
if (isAsyncFunction(fn)) {
return fn
.apply(null)
.then(async res => {
finalize()
await recorder.promise()
return res
})
.catch(e => {
output.stepShift = 0
session.restoreVars(sessionName)
event.dispatcher.removeListener(event.step.after, addContextToStep)
recorder.add('restore session on error', () => recorder.session.restore(`session:${sessionName}`))
recorder.throw(e)
return recorder.promise()
})
}
let res
try {
res = fn.apply(null)
} catch (err) {
recorder.throw(err)
} finally {
recorder.catch(e => {
session.restoreVars(sessionName)
output.stepShift = 0
event.dispatcher.removeListener(event.step.after, addContextToStep)
recorder.session.restore(`session:${sessionName}`)
throw e
})
}
finalize()
return recorder.promise().then(() => res)
},
false,
false,
)
}
export default session