77 */
88
99/* eslint-disable import/no-extraneous-dependencies */
10- import { Architect , BuilderRun } from '@angular-devkit/architect' ;
1110import { tags } from '@angular-devkit/core' ;
1211import { createServer } from 'http' ;
1312import { createProxyServer } from 'http-proxy' ;
1413import { AddressInfo } from 'net' ;
1514import puppeteer , { Browser , Page } from 'puppeteer' ;
16- import { debounceTime , switchMap , take } from 'rxjs/operators' ;
17- import { createArchitect , host } from '../../../testing/test-utils' ;
15+ import { count , debounceTime , finalize , switchMap , take , timeout } from 'rxjs/operators' ;
16+ import { serveWebpackBrowser } from '../../index' ;
17+ import {
18+ BASE_OPTIONS ,
19+ BUILD_TIMEOUT ,
20+ DEV_SERVER_BUILDER_INFO ,
21+ describeBuilder ,
22+ setupBrowserTarget ,
23+ } from '../setup' ;
1824
1925// eslint-disable-next-line @typescript-eslint/no-explicit-any
2026declare const document : any ;
@@ -132,135 +138,159 @@ async function goToPageAndWaitForWS(page: Page, url: string): Promise<void> {
132138 } ) ,
133139 page . goto ( url ) ,
134140 ] ) ;
141+
135142 await client . detach ( ) ;
136143}
137144
138- describe ( 'Dev Server Builder live-reload' , ( ) => {
139- const target = { project : 'app' , target : 'serve' } ;
140- // TODO: check if the below is still true.
141- // Avoid using port `0` as these tests will behave differrently and tests will pass when they shouldn't.
142- // Port 0 and host 0.0.0.0 have special meaning in dev-server.
143- const overrides = { hmr : false , watch : true , port : 4202 , liveReload : true } ;
144- let architect : Architect ;
145- let browser : Browser ;
146- let page : Page ;
147- let runs : BuilderRun [ ] ;
148-
149- beforeAll ( async ( ) => {
150- browser = await puppeteer . launch ( {
151- // MacOSX users need to set the local binary manually because Chrome has lib files with
152- // spaces in them which Bazel does not support in runfiles
153- // See: https://github.com/angular/angular-cli/pull/17624
154- // eslint-disable-next-line max-len
155- // executablePath: '/Users/<USERNAME>/git/angular-cli/node_modules/puppeteer/.local-chromium/mac-818858/chrome-mac/Chromium.app/Contents/MacOS/Chromium',
156- ignoreHTTPSErrors : true ,
157- args : [ '--no-sandbox' , '--disable-gpu' ] ,
145+ describeBuilder ( serveWebpackBrowser , DEV_SERVER_BUILDER_INFO , ( harness ) => {
146+ describe ( 'Behavior: "Dev-server builder live-reload with proxies"' , ( ) => {
147+ let browser : Browser ;
148+ let page : Page ;
149+
150+ const SERVE_OPTIONS = Object . freeze ( {
151+ ...BASE_OPTIONS ,
152+ hmr : false ,
153+ watch : true ,
154+ liveReload : true ,
158155 } ) ;
159- } ) ;
160156
161- afterAll ( async ( ) => {
162- await browser . close ( ) ;
163- } ) ;
157+ beforeAll ( async ( ) => {
158+ browser = await puppeteer . launch ( {
159+ // MacOSX users need to set the local binary manually because Chrome has lib files with
160+ // spaces in them which Bazel does not support in runfiles
161+ // See: https://github.com/angular/angular-cli/pull/17624
162+ // eslint-disable-next-line max-len
163+ // executablePath: '/Users/<USERNAME>/git/angular-cli/node_modules/puppeteer/.local-chromium/mac-818858/chrome-mac/Chromium.app/Contents/MacOS/Chromium',
164+ ignoreHTTPSErrors : true ,
165+ args : [ '--no-sandbox' , '--disable-gpu' ] ,
166+ } ) ;
167+ } ) ;
164168
165- beforeEach ( async ( ) => {
166- await host . initialize ( ) . toPromise ( ) ;
167- architect = ( await createArchitect ( host . root ( ) ) ) . architect ;
169+ afterAll ( async ( ) => {
170+ await browser . close ( ) ;
171+ } ) ;
172+
173+ beforeEach ( async ( ) => {
174+ setupBrowserTarget ( harness , {
175+ polyfills : 'src/polyfills.ts' ,
176+ } ) ;
168177
169- host . writeMultipleFiles ( {
170- 'src/app/app.component.html' : `
171- <p>{{ title }}</p>
172- ` ,
178+ page = await browser . newPage ( ) ;
173179 } ) ;
174180
175- runs = [ ] ;
176- page = await browser . newPage ( ) ;
177- } ) ;
181+ afterEach ( async ( ) => {
182+ await page . close ( ) ;
183+ } ) ;
178184
179- afterEach ( async ( ) => {
180- await host . restore ( ) . toPromise ( ) ;
181- await page . close ( ) ;
182- await Promise . all ( runs . map ( ( r ) => r . stop ( ) ) ) ;
183- } ) ;
185+ it ( 'works without proxy' , async ( ) => {
186+ harness . useTarget ( 'serve' , {
187+ ...SERVE_OPTIONS ,
188+ } ) ;
184189
185- it ( 'works without proxy' , async ( ) => {
186- const run = await architect . scheduleTarget ( target , overrides ) ;
187- runs . push ( run ) ;
188-
189- await run . output
190- . pipe (
191- debounceTime ( 1000 ) ,
192- switchMap ( async ( buildEvent , buildCount ) => {
193- expect ( buildEvent . success ) . toBe ( true ) ;
194- const url = buildEvent . baseUrl as string ;
195- switch ( buildCount ) {
196- case 0 :
197- await goToPageAndWaitForWS ( page , url ) ;
198- host . replaceInFile ( 'src/app/app.component.ts' , `'app'` , `'app-live-reload'` ) ;
199- break ;
200- case 1 :
201- const innerText = await page . evaluate ( ( ) => document . querySelector ( 'p' ) . innerText ) ;
202- expect ( innerText ) . toBe ( 'app-live-reload' ) ;
203- break ;
204- }
205- } ) ,
206- take ( 2 ) ,
207- )
208- . toPromise ( ) ;
209- } ) ;
190+ await harness . writeFile ( 'src/app/app.component.html' , '<p>{{ title }}</p>' ) ;
210191
211- it ( 'works without http -> http proxy' , async ( ) => {
212- const run = await architect . scheduleTarget ( target , overrides ) ;
213- runs . push ( run ) ;
192+ const buildCount = await harness
193+ . execute ( )
194+ . pipe (
195+ debounceTime ( 1000 ) ,
196+ timeout ( BUILD_TIMEOUT * 2 ) ,
197+ switchMap ( async ( { result } , index ) => {
198+ expect ( result ?. success ) . toBeTrue ( ) ;
199+ if ( typeof result ?. baseUrl !== 'string' ) {
200+ throw new Error ( 'Expected "baseUrl" to be a string.' ) ;
201+ }
214202
215- let proxy : ProxyInstance | undefined ;
216- let buildCount = 0 ;
217- try {
218- await run . output
203+ switch ( index ) {
204+ case 0 :
205+ await goToPageAndWaitForWS ( page , result . baseUrl ) ;
206+ await harness . modifyFile ( 'src/app/app.component.ts' , ( content ) =>
207+ content . replace ( `'app'` , `'app-live-reload'` ) ,
208+ ) ;
209+ break ;
210+ case 1 :
211+ const innerText = await page . evaluate ( ( ) => document . querySelector ( 'p' ) . innerText ) ;
212+ expect ( innerText ) . toBe ( 'app-live-reload' ) ;
213+ break ;
214+ }
215+ } ) ,
216+ take ( 2 ) ,
217+ count ( ) ,
218+ )
219+ . toPromise ( ) ;
220+
221+ expect ( buildCount ) . toBe ( 2 ) ;
222+ } ) ;
223+
224+ it ( 'works without http -> http proxy' , async ( ) => {
225+ harness . useTarget ( 'serve' , {
226+ ...SERVE_OPTIONS ,
227+ } ) ;
228+
229+ await harness . writeFile ( 'src/app/app.component.html' , '<p>{{ title }}</p>' ) ;
230+
231+ let proxy : ProxyInstance | undefined ;
232+ const buildCount = await harness
233+ . execute ( )
219234 . pipe (
220235 debounceTime ( 1000 ) ,
221- switchMap ( async ( buildEvent ) => {
222- expect ( buildEvent . success ) . toBe ( true ) ;
223- const url = buildEvent . baseUrl as string ;
224- switch ( buildCount ) {
236+ timeout ( BUILD_TIMEOUT * 2 ) ,
237+ switchMap ( async ( { result } , index ) => {
238+ expect ( result ?. success ) . toBeTrue ( ) ;
239+ if ( typeof result ?. baseUrl !== 'string' ) {
240+ throw new Error ( 'Expected "baseUrl" to be a string.' ) ;
241+ }
242+
243+ switch ( index ) {
225244 case 0 :
226- proxy = await createProxy ( url , false ) ;
245+ proxy = await createProxy ( result . baseUrl , false ) ;
227246 await goToPageAndWaitForWS ( page , proxy . url ) ;
228- host . replaceInFile ( 'src/app/app.component.ts' , `'app'` , `'app-live-reload'` ) ;
247+ await harness . modifyFile ( 'src/app/app.component.ts' , ( content ) =>
248+ content . replace ( `'app'` , `'app-live-reload'` ) ,
249+ ) ;
229250 break ;
230251 case 1 :
231252 const innerText = await page . evaluate ( ( ) => document . querySelector ( 'p' ) . innerText ) ;
232253 expect ( innerText ) . toBe ( 'app-live-reload' ) ;
233254 break ;
234255 }
235-
236- buildCount ++ ;
237256 } ) ,
238257 take ( 2 ) ,
258+ count ( ) ,
259+ finalize ( ( ) => {
260+ proxy ?. server . close ( ) ;
261+ } ) ,
239262 )
240263 . toPromise ( ) ;
241- } finally {
242- proxy ?. server . close ( ) ;
243- }
244- } ) ;
245264
246- it ( 'works without https -> http proxy' , async ( ) => {
247- const run = await architect . scheduleTarget ( target , overrides ) ;
248- runs . push ( run ) ;
265+ expect ( buildCount ) . toBe ( 2 ) ;
266+ } ) ;
267+
268+ it ( 'works without https -> http proxy' , async ( ) => {
269+ harness . useTarget ( 'serve' , {
270+ ...SERVE_OPTIONS ,
271+ } ) ;
249272
250- let proxy : ProxyInstance | undefined ;
273+ await harness . writeFile ( 'src/app/app.component.html' , '<p>{{ title }}</p>' ) ;
251274
252- try {
253- await run . output
275+ let proxy : ProxyInstance | undefined ;
276+ const buildCount = await harness
277+ . execute ( )
254278 . pipe (
255279 debounceTime ( 1000 ) ,
256- switchMap ( async ( buildEvent , buildCount ) => {
257- expect ( buildEvent . success ) . toBe ( true ) ;
258- const url = buildEvent . baseUrl as string ;
259- switch ( buildCount ) {
280+ timeout ( BUILD_TIMEOUT * 2 ) ,
281+ switchMap ( async ( { result } , index ) => {
282+ expect ( result ?. success ) . toBeTrue ( ) ;
283+ if ( typeof result ?. baseUrl !== 'string' ) {
284+ throw new Error ( 'Expected "baseUrl" to be a string.' ) ;
285+ }
286+
287+ switch ( index ) {
260288 case 0 :
261- proxy = await createProxy ( url , true ) ;
289+ proxy = await createProxy ( result . baseUrl , true ) ;
262290 await goToPageAndWaitForWS ( page , proxy . url ) ;
263- host . replaceInFile ( 'src/app/app.component.ts' , `'app'` , `'app-live-reload'` ) ;
291+ await harness . modifyFile ( 'src/app/app.component.ts' , ( content ) =>
292+ content . replace ( `'app'` , `'app-live-reload'` ) ,
293+ ) ;
264294 break ;
265295 case 1 :
266296 const innerText = await page . evaluate ( ( ) => document . querySelector ( 'p' ) . innerText ) ;
@@ -269,10 +299,14 @@ describe('Dev Server Builder live-reload', () => {
269299 }
270300 } ) ,
271301 take ( 2 ) ,
302+ count ( ) ,
303+ finalize ( ( ) => {
304+ proxy ?. server . close ( ) ;
305+ } ) ,
272306 )
273307 . toPromise ( ) ;
274- } finally {
275- proxy ?. server . close ( ) ;
276- }
308+
309+ expect ( buildCount ) . toBe ( 2 ) ;
310+ } ) ;
277311 } ) ;
278312} ) ;
0 commit comments