prool 0.0.4 → 0.0.5

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (50) hide show
  1. package/CHANGELOG.md +8 -0
  2. package/_lib/exports/index.d.ts +1 -1
  3. package/_lib/exports/processes.d.ts +2 -0
  4. package/_lib/exports/processes.d.ts.map +1 -0
  5. package/_lib/exports/processes.js +2 -0
  6. package/_lib/exports/processes.js.map +1 -0
  7. package/_lib/instance.d.ts +4 -4
  8. package/_lib/instance.d.ts.map +1 -1
  9. package/_lib/instance.js +3 -2
  10. package/_lib/instance.js.map +1 -1
  11. package/_lib/instances/anvil.d.ts +1 -5
  12. package/_lib/instances/anvil.d.ts.map +1 -1
  13. package/_lib/instances/anvil.js +18 -44
  14. package/_lib/instances/anvil.js.map +1 -1
  15. package/_lib/instances/stackup.d.ts +86 -0
  16. package/_lib/instances/stackup.d.ts.map +1 -0
  17. package/_lib/instances/stackup.js +89 -0
  18. package/_lib/instances/stackup.js.map +1 -0
  19. package/_lib/pool.d.ts +6 -6
  20. package/_lib/pool.d.ts.map +1 -1
  21. package/_lib/pool.js +5 -2
  22. package/_lib/pool.js.map +1 -1
  23. package/_lib/processes/execa.d.ts +27 -0
  24. package/_lib/processes/execa.d.ts.map +1 -0
  25. package/_lib/processes/execa.js +63 -0
  26. package/_lib/processes/execa.js.map +1 -0
  27. package/_lib/server.d.ts +3 -3
  28. package/_lib/server.d.ts.map +1 -1
  29. package/_lib/utils.d.ts +4 -3
  30. package/_lib/utils.d.ts.map +1 -1
  31. package/_lib/utils.js +2 -2
  32. package/_lib/utils.js.map +1 -1
  33. package/exports/index.ts +2 -2
  34. package/exports/processes.test.ts +10 -0
  35. package/exports/processes.ts +8 -0
  36. package/instance.test.ts +2 -2
  37. package/instance.ts +15 -10
  38. package/instances/anvil.test.ts +5 -3
  39. package/instances/anvil.ts +21 -49
  40. package/instances/stackup.test.ts +106 -0
  41. package/instances/stackup.ts +162 -0
  42. package/package.json +6 -2
  43. package/pool.test.ts +195 -171
  44. package/pool.ts +18 -9
  45. package/processes/execa.test.ts +143 -0
  46. package/processes/execa.ts +100 -0
  47. package/server.test.ts +91 -97
  48. package/server.ts +4 -4
  49. package/tsconfig.build.tsbuildinfo +1 -1
  50. package/utils.ts +11 -9
package/pool.test.ts CHANGED
@@ -1,9 +1,15 @@
1
1
  import getPort from 'get-port'
2
- import { afterEach, describe, expect, test } from 'vitest'
2
+ import { afterEach, beforeAll, describe, expect, test } from 'vitest'
3
+
4
+ import { stackupOptions } from '../test/utils.js'
3
5
  import { anvil } from './instances/anvil.js'
6
+ import { stackup } from './instances/stackup.js'
4
7
  import { definePool } from './pool.js'
5
8
 
6
9
  let pool: ReturnType<typeof definePool>
10
+ const port = await getPort()
11
+
12
+ beforeAll(() => anvil({ port }).start())
7
13
 
8
14
  afterEach(async () => {
9
15
  try {
@@ -13,238 +19,256 @@ afterEach(async () => {
13
19
  }
14
20
  })
15
21
 
16
- describe.each([{ instance: anvil() }])(
17
- 'instance: $instance.name',
18
- ({ instance }) => {
19
- test('default', async () => {
20
- pool = definePool({
21
- instance,
22
- })
22
+ describe.each([
23
+ { instance: anvil() },
24
+ {
25
+ instance: stackup(stackupOptions({ port })),
26
+ },
27
+ ])('instance: $instance.name', ({ instance }) => {
28
+ test('default', async () => {
29
+ pool = definePool({
30
+ instance,
31
+ })
32
+
33
+ expect(pool).toBeDefined()
34
+ })
23
35
 
24
- expect(pool).toBeDefined()
36
+ test('start', async () => {
37
+ pool = definePool({
38
+ instance,
25
39
  })
26
40
 
27
- test('start', async () => {
28
- pool = definePool({
29
- instance,
30
- })
41
+ expect(pool.size).toEqual(0)
42
+
43
+ const instance_1 = await pool.start(1)
44
+ expect(instance_1.status).toBe('started')
45
+ expect(pool.size).toEqual(1)
46
+
47
+ const instance_2 = await pool.start(2)
48
+ expect(instance_2.status).toBe('started')
49
+ expect(pool.size).toEqual(2)
50
+
51
+ const instance_3 = await pool.start(1337)
52
+ expect(instance_3.status).toBe('started')
53
+ expect(pool.size).toEqual(3)
54
+ })
31
55
 
32
- expect(pool.size).toEqual(0)
56
+ test('callback instance', async () => {
57
+ const keys: (number | string)[] = []
58
+ pool = definePool({
59
+ instance(key) {
60
+ keys.push(key)
61
+ return instance
62
+ },
63
+ })
33
64
 
34
- const instance_1 = await pool.start(1)
35
- expect(instance_1.status).toBe('started')
36
- expect(pool.size).toEqual(1)
65
+ await pool.start(1)
66
+ await pool.start(2)
67
+ await pool.start(1337)
37
68
 
38
- const instance_2 = await pool.start(2)
39
- expect(instance_2.status).toBe('started')
40
- expect(pool.size).toEqual(2)
69
+ expect(keys).toStrictEqual([1, 2, 1337])
70
+ })
41
71
 
42
- const instance_3 = await pool.start(1337)
43
- expect(instance_3.status).toBe('started')
44
- expect(pool.size).toEqual(3)
72
+ test('stop / destroy', async () => {
73
+ pool = definePool({
74
+ instance,
45
75
  })
46
76
 
47
- test('stop / destroy', async () => {
48
- pool = definePool({
49
- instance,
50
- })
77
+ const instance_1 = await pool.start(1)
78
+ const instance_2 = await pool.start(2)
79
+ const instance_3 = await pool.start(3)
51
80
 
52
- const instance_1 = await pool.start(1)
53
- const instance_2 = await pool.start(2)
54
- const instance_3 = await pool.start(3)
81
+ expect(instance_1.status).toBe('started')
82
+ expect(instance_2.status).toBe('started')
83
+ expect(instance_3.status).toBe('started')
84
+ expect(pool.size).toEqual(3)
55
85
 
56
- expect(instance_1.status).toBe('started')
57
- expect(instance_2.status).toBe('started')
58
- expect(instance_3.status).toBe('started')
59
- expect(pool.size).toEqual(3)
86
+ await pool.stop(1)
87
+ expect(instance_1.status).toBe('stopped')
60
88
 
61
- await pool.stop(1)
62
- expect(instance_1.status).toBe('stopped')
89
+ await pool.stop(2)
90
+ expect(instance_2.status).toBe('stopped')
63
91
 
64
- await pool.stop(2)
65
- expect(instance_2.status).toBe('stopped')
92
+ await pool.stop(3)
93
+ expect(instance_3.status).toBe('stopped')
66
94
 
67
- await pool.stop(3)
68
- expect(instance_3.status).toBe('stopped')
95
+ await pool.stop(1)
96
+ await pool.stop(2)
97
+ await pool.stop(3)
98
+ await pool.stop(4)
69
99
 
70
- await pool.stop(1)
71
- await pool.stop(2)
72
- await pool.stop(3)
73
- await pool.stop(4)
100
+ expect(pool.size).toEqual(3)
74
101
 
75
- expect(pool.size).toEqual(3)
102
+ await pool.destroy(1)
103
+ expect(pool.size).toEqual(2)
104
+ await pool.destroy(2)
105
+ expect(pool.size).toEqual(1)
106
+ await pool.destroy(3)
107
+ expect(pool.size).toEqual(0)
108
+ })
76
109
 
77
- await pool.destroy(1)
78
- expect(pool.size).toEqual(2)
79
- await pool.destroy(2)
80
- expect(pool.size).toEqual(1)
81
- await pool.destroy(3)
82
- expect(pool.size).toEqual(0)
110
+ test('restart', async () => {
111
+ pool = definePool({
112
+ instance,
83
113
  })
84
114
 
85
- test('restart', async () => {
86
- pool = definePool({
87
- instance,
88
- })
115
+ const instance_1 = await pool.start(1)
116
+ const instance_2 = await pool.start(2)
117
+ const instance_3 = await pool.start(3)
89
118
 
90
- const instance_1 = await pool.start(1)
91
- const instance_2 = await pool.start(2)
92
- const instance_3 = await pool.start(3)
119
+ expect(instance_1.status).toBe('started')
120
+ expect(instance_2.status).toBe('started')
121
+ expect(instance_3.status).toBe('started')
122
+ expect(pool.size).toEqual(3)
93
123
 
94
- expect(instance_1.status).toBe('started')
95
- expect(instance_2.status).toBe('started')
96
- expect(instance_3.status).toBe('started')
97
- expect(pool.size).toEqual(3)
124
+ const promise_1 = pool.restart(1)
125
+ expect(instance_1.status).toBe('restarting')
126
+ await promise_1
127
+ expect(instance_1.status).toBe('started')
128
+ })
98
129
 
99
- const promise_1 = pool.restart(1)
100
- expect(instance_1.status).toBe('restarting')
101
- await promise_1
102
- expect(instance_1.status).toBe('started')
130
+ test('start > stop > start', async () => {
131
+ pool = definePool({
132
+ instance,
103
133
  })
104
134
 
105
- test('start > stop > start', async () => {
106
- pool = definePool({
107
- instance,
108
- })
135
+ const instance_1 = await pool.start(1)
136
+ expect(instance_1.status).toBe('started')
109
137
 
110
- const instance_1 = await pool.start(1)
111
- expect(instance_1.status).toBe('started')
138
+ await pool.stop(1)
139
+ expect(instance_1.status).toBe('stopped')
112
140
 
113
- await pool.stop(1)
114
- expect(instance_1.status).toBe('stopped')
141
+ await pool.start(1)
142
+ expect(instance_1.status).toBe('started')
143
+ })
115
144
 
116
- await pool.start(1)
117
- expect(instance_1.status).toBe('started')
145
+ test('stopAll / destroyAll', async () => {
146
+ pool = definePool({
147
+ instance,
118
148
  })
119
149
 
120
- test('stopAll / destroyAll', async () => {
121
- pool = definePool({
122
- instance,
123
- })
150
+ await pool.start(1)
151
+ await pool.start(2)
152
+ await pool.start(3)
124
153
 
125
- await pool.start(1)
126
- await pool.start(2)
127
- await pool.start(3)
154
+ expect(pool.size).toEqual(3)
128
155
 
129
- expect(pool.size).toEqual(3)
156
+ await pool.stopAll()
157
+ expect(pool.size).toEqual(3)
130
158
 
131
- await pool.stopAll()
132
- expect(pool.size).toEqual(3)
159
+ await pool.destroyAll()
160
+ expect(pool.size).toEqual(0)
161
+ })
133
162
 
134
- await pool.destroyAll()
135
- expect(pool.size).toEqual(0)
163
+ test('get', async () => {
164
+ pool = definePool({
165
+ instance,
136
166
  })
137
167
 
138
- test('get', async () => {
139
- pool = definePool({
140
- instance,
141
- })
168
+ const instance_1 = await pool.start(1)
169
+ const instance_2 = await pool.start(2)
170
+ const instance_3 = await pool.start(3)
142
171
 
143
- const instance_1 = await pool.start(1)
144
- const instance_2 = await pool.start(2)
145
- const instance_3 = await pool.start(3)
172
+ expect(pool.get(1)).toStrictEqual(instance_1)
173
+ expect(pool.get(2)).toStrictEqual(instance_2)
174
+ expect(pool.get(3)).toStrictEqual(instance_3)
175
+ })
146
176
 
147
- expect(pool.get(1)).toStrictEqual(instance_1)
148
- expect(pool.get(2)).toStrictEqual(instance_2)
149
- expect(pool.get(3)).toStrictEqual(instance_3)
177
+ test('behavior: start more than once', async () => {
178
+ pool = definePool({
179
+ instance,
150
180
  })
151
181
 
152
- test('behavior: start more than once', async () => {
153
- pool = definePool({
154
- instance,
155
- })
182
+ const promise_1 = pool.start(1)
183
+ const promise_2 = pool.start(1)
184
+ expect(promise_1).toStrictEqual(promise_2)
156
185
 
157
- const promise_1 = pool.start(1)
158
- const promise_2 = pool.start(1)
159
- expect(promise_1).toStrictEqual(promise_2)
186
+ const instance_1 = await promise_1
187
+ const instance_2 = await promise_2
188
+ expect(instance_1).toStrictEqual(instance_2)
189
+ })
160
190
 
161
- const instance_1 = await promise_1
162
- const instance_2 = await promise_2
163
- expect(instance_1).toStrictEqual(instance_2)
191
+ test('behavior: clear more than once', async () => {
192
+ pool = definePool({
193
+ instance,
164
194
  })
165
195
 
166
- test('behavior: clear more than once', async () => {
167
- pool = definePool({
168
- instance,
169
- })
196
+ await pool.start(1)
197
+ await pool.start(2)
198
+ await pool.start(3)
170
199
 
171
- await pool.start(1)
172
- await pool.start(2)
173
- await pool.start(3)
200
+ const promise_1 = pool.stopAll()
201
+ const promise_2 = pool.stopAll()
202
+ expect(promise_1).toStrictEqual(promise_2)
174
203
 
175
- const promise_1 = pool.stopAll()
176
- const promise_2 = pool.stopAll()
177
- expect(promise_1).toStrictEqual(promise_2)
204
+ await promise_1
205
+ await promise_2
206
+ })
178
207
 
179
- await promise_1
180
- await promise_2
208
+ test('behavior: restart more than once', async () => {
209
+ pool = definePool({
210
+ instance,
181
211
  })
182
212
 
183
- test('behavior: restart more than once', async () => {
184
- pool = definePool({
185
- instance,
186
- })
213
+ const instance_1 = await pool.start(1)
214
+ expect(instance_1.status).toBe('started')
187
215
 
188
- const instance_1 = await pool.start(1)
189
- expect(instance_1.status).toBe('started')
216
+ const promise_1 = pool.restart(1)
217
+ expect(instance_1.status).toBe('restarting')
218
+ const promise_2 = pool.restart(1)
219
+ expect(instance_1.status).toBe('restarting')
190
220
 
191
- const promise_1 = pool.restart(1)
192
- expect(instance_1.status).toBe('restarting')
193
- const promise_2 = pool.restart(1)
194
- expect(instance_1.status).toBe('restarting')
221
+ expect(promise_1).toStrictEqual(promise_2)
195
222
 
196
- expect(promise_1).toStrictEqual(promise_2)
223
+ await promise_1
224
+ expect(instance_1.status).toBe('started')
225
+ await promise_2
226
+ expect(instance_1.status).toBe('started')
227
+ })
197
228
 
198
- await promise_1
199
- expect(instance_1.status).toBe('started')
200
- await promise_2
201
- expect(instance_1.status).toBe('started')
229
+ test('behavior: stop more than once', async () => {
230
+ pool = definePool({
231
+ instance,
202
232
  })
203
233
 
204
- test('behavior: stop more than once', async () => {
205
- pool = definePool({
206
- instance,
207
- })
234
+ await pool.start(1)
208
235
 
209
- await pool.start(1)
236
+ const promise_1 = pool.stop(1)
237
+ const promise_2 = pool.stop(1)
238
+ expect(promise_1).toStrictEqual(promise_2)
210
239
 
211
- const promise_1 = pool.stop(1)
212
- const promise_2 = pool.stop(1)
213
- expect(promise_1).toStrictEqual(promise_2)
240
+ await promise_1
241
+ await promise_2
242
+ })
214
243
 
215
- await promise_1
216
- await promise_2
217
- })
244
+ test('error: start more than once on same port', async () => {
245
+ const port = await getPort()
218
246
 
219
- test('error: start more than once on same port', async () => {
220
- const port = await getPort()
247
+ pool = definePool({
248
+ instance,
249
+ })
221
250
 
222
- pool = definePool({
223
- instance,
224
- })
251
+ await pool.start(1, { port })
225
252
 
226
- await pool.start(1, { port })
253
+ const promise_1 = pool.start(2, { port })
254
+ const promise_2 = pool.start(2, { port })
255
+ expect(promise_1).toStrictEqual(promise_2)
227
256
 
228
- const promise_1 = pool.start(2, { port })
229
- const promise_2 = pool.start(2, { port })
230
- expect(promise_1).toStrictEqual(promise_2)
257
+ await expect(() => promise_1).rejects.toThrowError()
258
+ await expect(() => promise_2).rejects.toThrowError()
259
+ })
231
260
 
232
- await expect(() => promise_1).rejects.toThrowError()
233
- await expect(() => promise_2).rejects.toThrowError()
261
+ test('error: instance limit reached', async () => {
262
+ pool = definePool({
263
+ instance,
264
+ limit: 2,
234
265
  })
235
266
 
236
- test('error: instance limit reached', async () => {
237
- pool = definePool({
238
- instance,
239
- limit: 2,
240
- })
267
+ await pool.start(1)
268
+ await pool.start(2)
241
269
 
242
- await pool.start(1)
243
- await pool.start(2)
244
-
245
- await expect(() => pool.start(3)).rejects.toThrowError(
246
- 'Instance limit of 2 reached.',
247
- )
248
- })
249
- },
250
- )
270
+ await expect(() => pool.start(3)).rejects.toThrowError(
271
+ 'Instance limit of 2 reached.',
272
+ )
273
+ })
274
+ })
package/pool.ts CHANGED
@@ -4,12 +4,12 @@ import type { Instance } from './instance.js'
4
4
 
5
5
  type Instance_ = Omit<Instance, 'create'>
6
6
 
7
- export type Pool<key = number> = Pick<
7
+ export type Pool<key extends number | string = number | string> = Pick<
8
8
  Map<key, Instance_>,
9
9
  'entries' | 'keys' | 'forEach' | 'get' | 'has' | 'size' | 'values'
10
10
  > & {
11
11
  _internal: {
12
- instance: Instance_
12
+ instance: Instance_ | ((key: key) => Instance_)
13
13
  }
14
14
  destroy(key: key): Promise<void>
15
15
  destroyAll(): Promise<void>
@@ -19,14 +19,18 @@ export type Pool<key = number> = Pick<
19
19
  stopAll(): Promise<void>
20
20
  }
21
21
 
22
- export type DefinePoolParameters = {
22
+ export type DefinePoolParameters<
23
+ key extends number | string = number | string,
24
+ > = {
23
25
  /** Instance for the pool. */
24
- instance: Instance
26
+ instance: Instance | ((key: key) => Instance)
25
27
  /** The maximum number of instances that can be started. */
26
28
  limit?: number | number
27
29
  }
28
30
 
29
- export type DefinePoolReturnType<key = number> = Pool<key>
31
+ export type DefinePoolReturnType<
32
+ key extends number | string = number | string,
33
+ > = Pool<key>
30
34
 
31
35
  /**
32
36
  * Defines an instance pool. Instances can be started, cached, and stopped against an identifier.
@@ -42,10 +46,10 @@ export type DefinePoolReturnType<key = number> = Pool<key>
42
46
  * const instance_3 = await pool.start(3)
43
47
  * ```
44
48
  */
45
- export function definePool<key = number>(
46
- parameters: DefinePoolParameters,
49
+ export function definePool<key extends number | string = number>(
50
+ parameters: DefinePoolParameters<key>,
47
51
  ): DefinePoolReturnType<key> {
48
- const { instance, limit } = parameters
52
+ const { limit } = parameters
49
53
 
50
54
  type Instance_ = Omit<Instance, 'create'>
51
55
  const instances = new Map<key, Instance_>()
@@ -65,7 +69,7 @@ export function definePool<key = number>(
65
69
 
66
70
  return {
67
71
  _internal: {
68
- instance,
72
+ instance: parameters.instance,
69
73
  },
70
74
  async destroy(key) {
71
75
  const destroyPromise = promises.destroy.get(key)
@@ -130,7 +134,12 @@ export function definePool<key = number>(
130
134
 
131
135
  promises.start.set(key, resolver.promise)
132
136
 
137
+ const instance =
138
+ typeof parameters.instance === 'function'
139
+ ? parameters.instance(key)
140
+ : parameters.instance
133
141
  const { port = await getPort() } = options
142
+
134
143
  const instance_ = instances.get(key) || instance.create({ port })
135
144
  instance_
136
145
  .start()
@@ -0,0 +1,143 @@
1
+ import { EventEmitter } from 'eventemitter3'
2
+ import { afterEach, expect, test } from 'vitest'
3
+ import { type ExecaProcess, execa } from './execa.js'
4
+
5
+ const processes: ExecaProcess[] = []
6
+ function createProcess() {
7
+ const process = execa({ name: 'foo' })
8
+ processes.push(process)
9
+ return process
10
+ }
11
+
12
+ afterEach(async () => {
13
+ for (const process of processes) await process.stop().catch(() => {})
14
+ })
15
+
16
+ test('default', async () => {
17
+ const process = createProcess()
18
+ expect(process).toMatchInlineSnapshot(`
19
+ {
20
+ "_internal": {
21
+ "process": undefined,
22
+ },
23
+ "name": "foo",
24
+ "start": [Function],
25
+ "stop": [Function],
26
+ }
27
+ `)
28
+ })
29
+
30
+ test('start', async () => {
31
+ const emitter = new EventEmitter<any>()
32
+ const process = createProcess()
33
+
34
+ const resolvers = {
35
+ listening: Promise.withResolvers<void>(),
36
+ message: Promise.withResolvers<void>(),
37
+ stdout: Promise.withResolvers<void>(),
38
+ }
39
+ emitter.on('listening', resolvers.listening.resolve)
40
+ emitter.on('message', resolvers.message.resolve)
41
+ emitter.on('stdout', resolvers.stdout.resolve)
42
+
43
+ await process.start(($) => $`anvil --port 1337`, {
44
+ emitter,
45
+ status: 'idle',
46
+ resolver({ process, resolve }) {
47
+ process.stdout.on('data', (data) => {
48
+ const message = data.toString()
49
+ if (message.includes('Listening on')) resolve()
50
+ })
51
+ },
52
+ })
53
+ expect(process._internal.process).toBeDefined()
54
+ await expect(resolvers.listening.promise).resolves.toBeUndefined()
55
+ await expect(resolvers.message.promise).resolves.toBeDefined()
56
+ await expect(resolvers.stdout.promise).resolves.toBeDefined()
57
+ })
58
+
59
+ test('start (error)', async () => {
60
+ const emitter = new EventEmitter<any>()
61
+ const process = createProcess()
62
+
63
+ const resolvers = {
64
+ listening: Promise.withResolvers<void>(),
65
+ message: Promise.withResolvers<void>(),
66
+ stderr: Promise.withResolvers<void>(),
67
+ }
68
+ emitter.on('listening', resolvers.listening.resolve)
69
+ emitter.on('message', resolvers.message.resolve)
70
+ emitter.on('stderr', resolvers.stderr.resolve)
71
+
72
+ // Invalid argument
73
+ await expect(() =>
74
+ process.start(($) => $`anvil --lol`, {
75
+ emitter,
76
+ status: 'idle',
77
+ resolver({ process, reject, resolve }) {
78
+ process.stdout.on('data', (data) => {
79
+ const message = data.toString()
80
+ if (message.includes('Listening on')) resolve()
81
+ })
82
+ process.stderr.on('data', reject)
83
+ },
84
+ }),
85
+ ).rejects.toThrowErrorMatchingInlineSnapshot(`
86
+ [Error: Failed to start process "foo": error: unexpected argument '--lol' found
87
+
88
+ Usage: anvil [OPTIONS] [COMMAND]
89
+
90
+ For more information, try '--help'.
91
+ ]
92
+ `)
93
+ await expect(resolvers.message.promise).resolves.toBeDefined()
94
+ await expect(resolvers.stderr.promise).resolves.toBeDefined()
95
+ })
96
+
97
+ test('behavior: exit', async () => {
98
+ const emitter = new EventEmitter<any>()
99
+ const process = createProcess()
100
+
101
+ const resolvers = {
102
+ exit: Promise.withResolvers<void>(),
103
+ }
104
+ emitter.on('exit', resolvers.exit.resolve)
105
+
106
+ // Invalid argument
107
+ await process.start(($) => $`anvil --port 1338`, {
108
+ emitter,
109
+ status: 'idle',
110
+ resolver({ process, resolve }) {
111
+ process.stdout.on('data', (data) => {
112
+ const message = data.toString()
113
+ if (message.includes('Listening on')) resolve()
114
+ })
115
+ },
116
+ })
117
+ process._internal.process.kill()
118
+ await expect(resolvers.exit.promise).resolves.toBeDefined()
119
+ })
120
+
121
+ test('behavior: exit when status is starting', async () => {
122
+ const emitter = new EventEmitter<any>()
123
+ const process = createProcess()
124
+
125
+ const resolvers = {
126
+ exit: Promise.withResolvers<void>(),
127
+ }
128
+ emitter.on('exit', resolvers.exit.resolve)
129
+
130
+ // Invalid argument
131
+ await process.start(($) => $`anvil`, {
132
+ emitter,
133
+ status: 'starting',
134
+ resolver({ process, resolve }) {
135
+ process.stdout.on('data', (data) => {
136
+ const message = data.toString()
137
+ if (message.includes('Listening on')) resolve()
138
+ })
139
+ },
140
+ })
141
+ process._internal.process.kill()
142
+ await expect(resolvers.exit.promise).resolves.toBeDefined()
143
+ })