-
-
Notifications
You must be signed in to change notification settings - Fork 751
Expand file tree
/
Copy pathrerun.js
More file actions
128 lines (114 loc) · 3.94 KB
/
Copy pathrerun.js
File metadata and controls
128 lines (114 loc) · 3.94 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
import fsPath from 'path'
import store from './store.js'
import container from './container.js'
import event from './event.js'
import BaseCodecept from './codecept.js'
import output from './output.js'
import { createRequire } from 'module'
import { resolveImportModulePath } from './utils.js'
const require = createRequire(import.meta.url)
class CodeceptRerunner extends BaseCodecept {
async runOnce(test) {
await container.started()
// Ensure translations are loaded for Gherkin features
try {
const { loadTranslations } = await import('./mocha/gherkin.js')
await loadTranslations()
} catch (e) {
// Ignore if gherkin module not available
}
return new Promise(async (resolve, reject) => {
try {
// Create a fresh Mocha instance for each run
// @ts-ignore
container.createMocha()
const mocha = container.mocha()
let filesToRun = this.testFiles
if (test) {
if (!fsPath.isAbsolute(test)) {
test = fsPath.join(store.codeceptDir, test)
}
filesToRun = this.testFiles.filter(t => fsPath.basename(t, '.js') === test || t === test)
}
// Clear any existing tests/suites
mocha.suite.suites = []
mocha.suite.tests = []
// Manually load each test file by importing it
for (const file of filesToRun) {
try {
// Clear CommonJS cache if available (for mixed environments)
try {
delete require.cache[file]
} catch (e) {
// ESM modules don't have require.cache, ignore
}
// Force reload the module by using a cache-busting query parameter
const fileUrl = `${fsPath.resolve(file)}`
const resolvedPath = resolveImportModulePath(fileUrl)
await import(resolvedPath)
} catch (e) {
console.error(`Error loading test file ${file}:`, e)
}
}
const done = () => {
event.emit(event.all.result, container.result())
event.emit(event.all.after, this)
// Check if there were any failures
if (container.result().hasFailed) {
reject(new Error('Test run failed'))
} else {
resolve(undefined)
}
}
event.emit(event.all.before, this)
mocha.run(() => done())
} catch (e) {
output.error(e.stack)
reject(e)
}
})
}
async runTests(test) {
const configRerun = this.config.rerun || {}
const minSuccess = configRerun.minSuccess || 1
const maxReruns = configRerun.maxReruns || 1
if (minSuccess > maxReruns) {
process.exitCode = 1
throw new Error(`run-rerun Configuration Error: minSuccess must be less than maxReruns. Current values: minSuccess=${minSuccess} maxReruns=${maxReruns}`)
}
if (maxReruns === 1) {
await this.runOnce(test)
return
}
let successCounter = 0
let rerunsCounter = 0
while (rerunsCounter < maxReruns && successCounter < minSuccess) {
container.result().reset() // reset result
rerunsCounter++
try {
await this.runOnce(test)
successCounter++
output.success(`\nProcess run ${rerunsCounter} of max ${maxReruns}, success runs ${successCounter}/${minSuccess}\n`)
} catch (e) {
output.error(`\nFail run ${rerunsCounter} of max ${maxReruns}, success runs ${successCounter}/${minSuccess} \n`)
console.error(e)
}
}
if (successCounter < minSuccess) {
throw new Error(`Flaky tests detected! ${successCounter} success runs achieved instead of ${minSuccess} success runs expected`)
}
}
async run(test) {
event.emit(event.all.before, this)
try {
await this.runTests(test)
} catch (e) {
output.error(e.stack)
throw e
} finally {
event.emit(event.all.result, this)
event.emit(event.all.after, this)
}
}
}
export default CodeceptRerunner