Skip to content

Commit 4f28c4d

Browse files
alan-agius4dgp1130
authored andcommitted
test: update live-reload test to reduce flakes
- assign dynamic port to proxy server - remove RXJS `finalize` in favor of `finally` (cherry picked from commit 449be88)
1 parent 4d848c4 commit 4f28c4d

File tree

1 file changed

+70
-60
lines changed

1 file changed

+70
-60
lines changed

packages/angular_devkit/build_angular/src/builders/dev-server/specs/live-reload_spec.ts

+70-60
Original file line numberDiff line numberDiff line change
@@ -9,9 +9,11 @@
99
/* eslint-disable import/no-extraneous-dependencies */
1010
import { Architect, BuilderRun } from '@angular-devkit/architect';
1111
import { tags } from '@angular-devkit/core';
12+
import { createServer } from 'http';
1213
import { createProxyServer } from 'http-proxy';
14+
import { AddressInfo } from 'net';
1315
import puppeteer, { Browser, Page } from 'puppeteer';
14-
import { debounceTime, finalize, switchMap, take } from 'rxjs/operators';
16+
import { debounceTime, switchMap, take } from 'rxjs/operators';
1517
import { 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

126138
describe('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

Comments
 (0)