9
9
/* eslint-disable import/no-extraneous-dependencies */
10
10
import { Architect , BuilderRun } from '@angular-devkit/architect' ;
11
11
import { tags } from '@angular-devkit/core' ;
12
+ import { createServer } from 'http' ;
12
13
import { createProxyServer } from 'http-proxy' ;
14
+ import { AddressInfo } from 'net' ;
13
15
import puppeteer , { Browser , Page } from 'puppeteer' ;
14
- import { debounceTime , finalize , switchMap , take } from 'rxjs/operators' ;
16
+ import { debounceTime , switchMap , take } from 'rxjs/operators' ;
15
17
import { createArchitect , host } from '../../../testing/test-utils' ;
16
18
17
19
// eslint-disable-next-line @typescript-eslint/no-explicit-any
@@ -22,10 +24,20 @@ interface ProxyInstance {
22
24
url : string ;
23
25
}
24
26
25
- let proxyPort = 9100 ;
26
- function createProxy ( target : string , secure : boolean , ws = true ) : ProxyInstance {
27
- proxyPort ++ ;
27
+ function findFreePort ( ) : Promise < number > {
28
+ return new Promise < number > ( ( resolve , reject ) => {
29
+ const server = createServer ( ) ;
30
+ server . once ( 'listening' , ( ) => {
31
+ const port = ( server . address ( ) as AddressInfo ) . port ;
32
+ server . close ( ( e ) => ( e ? reject ( e ) : resolve ( port ) ) ) ;
33
+ } ) ;
34
+ server . once ( 'error' , ( e ) => server . close ( ( ) => reject ( e ) ) ) ;
35
+ server . listen ( ) ;
36
+ } ) ;
37
+ }
28
38
39
+ async function createProxy ( target : string , secure : boolean , ws = true ) : Promise < ProxyInstance > {
40
+ const proxyPort = await findFreePort ( ) ;
29
41
const server = createProxyServer ( {
30
42
ws,
31
43
target,
@@ -125,6 +137,7 @@ async function goToPageAndWaitForWS(page: Page, url: string): Promise<void> {
125
137
126
138
describe ( 'Dev Server Builder live-reload' , ( ) => {
127
139
const target = { project : 'app' , target : 'serve' } ;
140
+ // TODO: check if the below is still true.
128
141
// Avoid using port `0` as these tests will behave differrently and tests will pass when they shouldn't.
129
142
// Port 0 and host 0.0.0.0 have special meaning in dev-server.
130
143
const overrides = { hmr : false , watch : true , port : 4202 , liveReload : true } ;
@@ -155,7 +168,7 @@ describe('Dev Server Builder live-reload', () => {
155
168
156
169
host . writeMultipleFiles ( {
157
170
'src/app/app.component.html' : `
158
- <p>{{title}}</p>
171
+ <p>{{ title }}</p>
159
172
` ,
160
173
} ) ;
161
174
@@ -173,11 +186,10 @@ describe('Dev Server Builder live-reload', () => {
173
186
const run = await architect . scheduleTarget ( target , overrides ) ;
174
187
runs . push ( run ) ;
175
188
176
- let buildCount = 0 ;
177
189
await run . output
178
190
. pipe (
179
191
debounceTime ( 1000 ) ,
180
- switchMap ( async ( buildEvent ) => {
192
+ switchMap ( async ( buildEvent , buildCount ) => {
181
193
expect ( buildEvent . success ) . toBe ( true ) ;
182
194
const url = buildEvent . baseUrl as string ;
183
195
switch ( buildCount ) {
@@ -190,8 +202,6 @@ describe('Dev Server Builder live-reload', () => {
190
202
expect ( innerText ) . toBe ( 'app-live-reload' ) ;
191
203
break ;
192
204
}
193
-
194
- buildCount ++ ;
195
205
} ) ,
196
206
take ( 2 ) ,
197
207
)
@@ -204,65 +214,65 @@ describe('Dev Server Builder live-reload', () => {
204
214
205
215
let proxy : ProxyInstance | undefined ;
206
216
let buildCount = 0 ;
207
- await run . output
208
- . pipe (
209
- debounceTime ( 1000 ) ,
210
- switchMap ( async ( buildEvent ) => {
211
- expect ( buildEvent . success ) . toBe ( true ) ;
212
- const url = buildEvent . baseUrl as string ;
213
- switch ( buildCount ) {
214
- case 0 :
215
- proxy = createProxy ( url , false ) ;
216
- await goToPageAndWaitForWS ( page , proxy . url ) ;
217
- host . replaceInFile ( 'src/app/app.component.ts' , `'app'` , `'app-live-reload'` ) ;
218
- break ;
219
- case 1 :
220
- const innerText = await page . evaluate ( ( ) => document . querySelector ( 'p' ) . innerText ) ;
221
- expect ( innerText ) . toBe ( 'app-live-reload' ) ;
222
- break ;
223
- }
217
+ try {
218
+ await run . output
219
+ . pipe (
220
+ debounceTime ( 1000 ) ,
221
+ switchMap ( async ( buildEvent ) => {
222
+ expect ( buildEvent . success ) . toBe ( true ) ;
223
+ const url = buildEvent . baseUrl as string ;
224
+ switch ( buildCount ) {
225
+ case 0 :
226
+ proxy = await createProxy ( url , false ) ;
227
+ await goToPageAndWaitForWS ( page , proxy . url ) ;
228
+ host . replaceInFile ( 'src/app/app.component.ts' , `'app'` , `'app-live-reload'` ) ;
229
+ break ;
230
+ case 1 :
231
+ const innerText = await page . evaluate ( ( ) => document . querySelector ( 'p' ) . innerText ) ;
232
+ expect ( innerText ) . toBe ( 'app-live-reload' ) ;
233
+ break ;
234
+ }
224
235
225
- buildCount ++ ;
226
- } ) ,
227
- take ( 2 ) ,
228
- finalize ( ( ) => {
229
- proxy ?. server . close ( ) ;
230
- } ) ,
231
- )
232
- . toPromise ( ) ;
236
+ buildCount ++ ;
237
+ } ) ,
238
+ take ( 2 ) ,
239
+ )
240
+ . toPromise ( ) ;
241
+ } finally {
242
+ proxy ?. server . close ( ) ;
243
+ }
233
244
} ) ;
234
245
235
246
it ( 'works without https -> http proxy' , async ( ) => {
236
247
const run = await architect . scheduleTarget ( target , overrides ) ;
237
248
runs . push ( run ) ;
238
249
239
250
let proxy : ProxyInstance | undefined ;
240
- let buildCount = 0 ;
241
- await run . output
242
- . pipe (
243
- debounceTime ( 1000 ) ,
244
- switchMap ( async ( buildEvent ) => {
245
- expect ( buildEvent . success ) . toBe ( true ) ;
246
- const url = buildEvent . baseUrl as string ;
247
- switch ( buildCount ) {
248
- case 0 :
249
- proxy = createProxy ( url , true ) ;
250
- await goToPageAndWaitForWS ( page , proxy . url ) ;
251
- host . replaceInFile ( 'src/app/app.component.ts' , `'app'` , `'app-live-reload'` ) ;
252
- break ;
253
- case 1 :
254
- const innerText = await page . evaluate ( ( ) => document . querySelector ( 'p' ) . innerText ) ;
255
- expect ( innerText ) . toBe ( 'app-live-reload' ) ;
256
- break ;
257
- }
258
251
259
- buildCount ++ ;
260
- } ) ,
261
- take ( 2 ) ,
262
- finalize ( ( ) => {
263
- proxy ?. server . close ( ) ;
264
- } ) ,
265
- )
266
- . toPromise ( ) ;
252
+ try {
253
+ await run . output
254
+ . pipe (
255
+ debounceTime ( 1000 ) ,
256
+ switchMap ( async ( buildEvent , buildCount ) => {
257
+ expect ( buildEvent . success ) . toBe ( true ) ;
258
+ const url = buildEvent . baseUrl as string ;
259
+ switch ( buildCount ) {
260
+ case 0 :
261
+ proxy = await createProxy ( url , true ) ;
262
+ await goToPageAndWaitForWS ( page , proxy . url ) ;
263
+ host . replaceInFile ( 'src/app/app.component.ts' , `'app'` , `'app-live-reload'` ) ;
264
+ break ;
265
+ case 1 :
266
+ const innerText = await page . evaluate ( ( ) => document . querySelector ( 'p' ) . innerText ) ;
267
+ expect ( innerText ) . toBe ( 'app-live-reload' ) ;
268
+ break ;
269
+ }
270
+ } ) ,
271
+ take ( 2 ) ,
272
+ )
273
+ . toPromise ( ) ;
274
+ } finally {
275
+ proxy ?. server . close ( ) ;
276
+ }
267
277
} ) ;
268
278
} ) ;
0 commit comments