-
-
Notifications
You must be signed in to change notification settings - Fork 1.1k
/
world.ts
137 lines (128 loc) · 3.64 KB
/
world.ts
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
import { Cli, setWorldConstructor } from '../../'
import { execFile } from 'child_process'
import { expect } from 'chai'
import toString from 'stream-to-string'
import { PassThrough, pipeline, Writable } from 'stream'
import stripAnsi from 'strip-ansi'
import fs from 'fs'
import path from 'path'
import VError from 'verror'
import * as messages from '@cucumber/messages'
import * as messageStreams from '@cucumber/message-streams'
import FakeReportServer from '../../test/fake_report_server'
import { doesHaveValue } from '../../src/value_checker'
import util from 'util'
const asyncPipeline = util.promisify(pipeline)
interface ILastRun {
error: any
errorOutput: string
envelopes: messages.Envelope[]
output: string
}
interface IRunResult {
error: any
stderr: string
stdout: string
}
export class World {
public tmpDir: string
public sharedEnv: NodeJS.ProcessEnv
public spawn: boolean = false
public debug: boolean = false
public lastRun: ILastRun
public verifiedLastRunError: boolean
public localExecutablePath: string
public reportServer: FakeReportServer
parseEnvString(str: string): NodeJS.ProcessEnv {
const result: NodeJS.ProcessEnv = {}
if (doesHaveValue(str)) {
str
.split(/\s+/)
.map((keyValue) => keyValue.split('='))
.forEach((pair) => (result[pair[0]] = pair[1]))
}
return result
}
async run(
executablePath: string,
inputArgs: string[],
envOverride: NodeJS.ProcessEnv = null
): Promise<void> {
const messageFilename = 'message.ndjson'
const args = ['node', executablePath].concat(inputArgs, [
'--backtrace',
'--format',
`message:${messageFilename}`,
])
const env = { ...process.env, ...this.sharedEnv, ...envOverride }
const cwd = this.tmpDir
let result: IRunResult
if (this.spawn) {
result = await new Promise((resolve) => {
execFile(
args[0],
args.slice(1),
{ cwd, env },
(error, stdout, stderr) => {
resolve({ error, stdout, stderr })
}
)
})
} else {
const stdout = new PassThrough()
const stderr = new PassThrough()
const cli = new Cli({
argv: args,
cwd,
stdout,
stderr,
env,
})
let error: any
try {
const { success } = await cli.run()
if (!success) {
error = new Error('CLI exited with non-zero')
error.code = 42
}
} catch (err) {
error = err
}
stdout.end()
stderr.end()
const stderrSuffix = error != null ? VError.fullStack(error) : ''
result = {
error,
stdout: await toString(stdout),
stderr: (await toString(stderr)) + stderrSuffix,
}
}
const envelopes: messages.Envelope[] = []
const messageOutputPath = path.join(cwd, messageFilename)
if (fs.existsSync(messageOutputPath)) {
await asyncPipeline(
fs.createReadStream(messageOutputPath, { encoding: 'utf-8' }),
new messageStreams.NdjsonToMessageStream(),
new Writable({
objectMode: true,
write(envelope: messages.Envelope, _: BufferEncoding, callback) {
envelopes.push(envelope)
callback()
},
})
)
}
if (this.debug) {
console.log(result.stdout + result.stderr) // eslint-disable-line no-console
}
this.lastRun = {
error: result.error,
errorOutput: result.stderr,
envelopes,
output: stripAnsi(result.stdout),
}
this.verifiedLastRunError = false
expect(this.lastRun.output).to.not.include('Unhandled rejection')
}
}
setWorldConstructor(World)