99/* eslint-disable import/no-extraneous-dependencies */
1010import { Architect , BuilderRun } from '@angular-devkit/architect' ;
1111import { tags } from '@angular-devkit/core' ;
12+ import { createServer } from 'http' ;
1213import { createProxyServer } from 'http-proxy' ;
14+ import { AddressInfo } from 'net' ;
1315import puppeteer , { Browser , Page } from 'puppeteer' ;
14- import { debounceTime , finalize , switchMap , take } from 'rxjs/operators' ;
16+ import { debounceTime , switchMap , take } from 'rxjs/operators' ;
1517import { createArchitect , host } from '../../../testing/test-utils' ;
1618
1719// eslint-disable-next-line @typescript-eslint/no-explicit-any
@@ -22,10 +24,20 @@ interface ProxyInstance {
2224 url : string ;
2325}
2426
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+ }
2838
39+ async function createProxy ( target : string , secure : boolean , ws = true ) : Promise < ProxyInstance > {
40+ const proxyPort = await findFreePort ( ) ;
2941 const server = createProxyServer ( {
3042 ws,
3143 target,
@@ -125,6 +137,7 @@ async function goToPageAndWaitForWS(page: Page, url: string): Promise<void> {
125137
126138describe ( 'Dev Server Builder live-reload' , ( ) => {
127139 const target = { project : 'app' , target : 'serve' } ;
140+ // TODO: check if the below is still true.
128141 // Avoid using port `0` as these tests will behave differrently and tests will pass when they shouldn't.
129142 // Port 0 and host 0.0.0.0 have special meaning in dev-server.
130143 const overrides = { hmr : false , watch : true , port : 4202 , liveReload : true } ;
@@ -155,7 +168,7 @@ describe('Dev Server Builder live-reload', () => {
155168
156169 host . writeMultipleFiles ( {
157170 'src/app/app.component.html' : `
158- <p>{{title}}</p>
171+ <p>{{ title }}</p>
159172 ` ,
160173 } ) ;
161174
@@ -173,11 +186,10 @@ describe('Dev Server Builder live-reload', () => {
173186 const run = await architect . scheduleTarget ( target , overrides ) ;
174187 runs . push ( run ) ;
175188
176- let buildCount = 0 ;
177189 await run . output
178190 . pipe (
179191 debounceTime ( 1000 ) ,
180- switchMap ( async ( buildEvent ) => {
192+ switchMap ( async ( buildEvent , buildCount ) => {
181193 expect ( buildEvent . success ) . toBe ( true ) ;
182194 const url = buildEvent . baseUrl as string ;
183195 switch ( buildCount ) {
@@ -190,8 +202,6 @@ describe('Dev Server Builder live-reload', () => {
190202 expect ( innerText ) . toBe ( 'app-live-reload' ) ;
191203 break ;
192204 }
193-
194- buildCount ++ ;
195205 } ) ,
196206 take ( 2 ) ,
197207 )
@@ -204,65 +214,65 @@ describe('Dev Server Builder live-reload', () => {
204214
205215 let proxy : ProxyInstance | undefined ;
206216 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+ }
224235
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+ }
233244 } ) ;
234245
235246 it ( 'works without https -> http proxy' , async ( ) => {
236247 const run = await architect . scheduleTarget ( target , overrides ) ;
237248 runs . push ( run ) ;
238249
239250 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- }
258251
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+ }
267277 } ) ;
268278} ) ;
0 commit comments