From 119256f72b2d928e5f5df9f1215d956b69a4cd63 Mon Sep 17 00:00:00 2001 From: Charles Lyding <19598772+clydin@users.noreply.github.com> Date: Tue, 6 Apr 2021 10:14:48 -0400 Subject: [PATCH] test(@angular-devkit/build-angular): add dev-server builder port option tests This change adds expanded unit tests for the dev-server builder's `port` option using the builder test harness. --- .../src/dev-server/tests/options/port_spec.ts | 101 ++++++++++++++++++ .../src/dev-server/works_spec.ts | 37 +------ 2 files changed, 102 insertions(+), 36 deletions(-) create mode 100644 packages/angular_devkit/build_angular/src/dev-server/tests/options/port_spec.ts diff --git a/packages/angular_devkit/build_angular/src/dev-server/tests/options/port_spec.ts b/packages/angular_devkit/build_angular/src/dev-server/tests/options/port_spec.ts new file mode 100644 index 000000000000..9811860d88e0 --- /dev/null +++ b/packages/angular_devkit/build_angular/src/dev-server/tests/options/port_spec.ts @@ -0,0 +1,101 @@ +/** + * @license + * Copyright Google Inc. All Rights Reserved. + * + * Use of this source code is governed by an MIT-style license that can be + * found in the LICENSE file at https://angular.io/license + */ +import { URL } from 'url'; +import { serveWebpackBrowser } from '../../index'; +import { executeOnceAndFetch } from '../execute-fetch'; +import { + BASE_OPTIONS, + DEV_SERVER_BUILDER_INFO, + describeBuilder, + setupBrowserTarget, +} from '../setup'; + +function getResultPort(result: Record | undefined): string | undefined { + if (typeof result?.baseUrl !== 'string') { + fail(`Expected builder result with a string 'baseUrl' property. Received: ${result?.baseUrl}`); + + return; + } + + try { + return new URL(result.baseUrl).port; + } catch { + fail(`Expected a valid URL in builder result 'baseUrl' property. Received: ${result.baseUrl}`); + } +} + +describeBuilder(serveWebpackBrowser, DEV_SERVER_BUILDER_INFO, (harness) => { + describe('option: "port"', () => { + beforeEach(async () => { + setupBrowserTarget(harness); + + // Application code is not needed for these tests + await harness.writeFile('src/main.ts', ''); + }); + + it('uses default port (4200) when not present', async () => { + harness.useTarget('serve', { + ...BASE_OPTIONS, + // Base options set port to zero + port: undefined, + }); + + const { result, response, logs } = await executeOnceAndFetch(harness, '/'); + + expect(result?.success).toBeTrue(); + expect(getResultPort(result)).toBe('4200'); + expect(await response?.text()).toContain(''); + + expect(logs).toContain( + jasmine.objectContaining({ + message: jasmine.stringMatching(/:4200/), + }), + ); + }); + + it('uses a random free port when set to 0 (zero)', async () => { + harness.useTarget('serve', { + ...BASE_OPTIONS, + port: 0, + }); + + const { result, response, logs } = await executeOnceAndFetch(harness, '/'); + + expect(result?.success).toBeTrue(); + const port = getResultPort(result); + expect(port).not.toBe('4200'); + expect(port).toMatch(/\d{4,6}/); + expect(await response?.text()).toContain('<title>'); + + expect(logs).toContain( + jasmine.objectContaining({ + message: jasmine.stringMatching(':' + port), + }), + ); + }); + + it('uses specific port when a non-zero number is specified', async () => { + harness.useTarget('serve', { + ...BASE_OPTIONS, + port: 8000, + }); + + const { result, response, logs } = await executeOnceAndFetch(harness, '/'); + + expect(result?.success).toBeTrue(); + expect(getResultPort(result)).toBe('8000'); + expect(await response?.text()).toContain('<title>'); + + expect(logs).toContain( + jasmine.objectContaining({ + message: jasmine.stringMatching(':8000'), + }), + ); + }); + }); +}); diff --git a/packages/angular_devkit/build_angular/src/dev-server/works_spec.ts b/packages/angular_devkit/build_angular/src/dev-server/works_spec.ts index 50a738128af4..58ba3612baff 100644 --- a/packages/angular_devkit/build_angular/src/dev-server/works_spec.ts +++ b/packages/angular_devkit/build_angular/src/dev-server/works_spec.ts @@ -7,7 +7,7 @@ */ import { Architect, BuilderRun } from '@angular-devkit/architect'; import { DevServerBuilderOutput } from '@angular-devkit/build-angular'; -import { logging, normalize, virtualFs } from '@angular-devkit/core'; +import { normalize, virtualFs } from '@angular-devkit/core'; import fetch from 'node-fetch'; // tslint:disable-line:no-implicit-dependencies import { createArchitect, host } from '../test-utils'; @@ -27,17 +27,6 @@ describe('Dev Server Builder', () => { await Promise.all(runs.map(r => r.stop())); }); - it('works', async () => { - const run = await architect.scheduleTarget(target); - runs.push(run); - const output = await run.result as DevServerBuilderOutput; - expect(output.success).toBe(true); - expect(output.baseUrl).toBe('http://localhost:4200/'); - - const response = await fetch('http://localhost:4200/index.html'); - expect(await response.text()).toContain('<title>HelloWorldApp'); - }); - it(`doesn't serve files on the cwd directly`, async () => { const run = await architect.scheduleTarget(target); runs.push(run); @@ -56,30 +45,6 @@ describe('Dev Server Builder', () => { expect(res).toContain('HelloWorldApp'); }); - it('works with port 0', async () => { - const logger = new logging.Logger(''); - const logs: string[] = []; - logger.subscribe(e => logs.push(e.message)); - - const run = await architect.scheduleTarget(target, { port: 0 }, { logger }); - runs.push(run); - const output = await run.result as DevServerBuilderOutput; - expect(output.success).toBe(true); - - const groups = logs.join().match(/\:(\d+){4,6}/g); - if (!groups) { - throw new Error('Expected log to contain port number.'); - } - - // tests that both the ports in the logs are the same. - const [firstPort, secondPort] = groups; - expect(firstPort).toBe(secondPort); - - expect(output.baseUrl).toBe(`http://localhost${firstPort}/`); - const response = await fetch(`http://localhost${firstPort}/index.html`); - expect(await response.text()).toContain('HelloWorldApp'); - }); - it('should not generate sourcemaps when running prod build', async () => { // Production builds have sourcemaps turned off. const run = await architect.scheduleTarget({ ...target, configuration: 'production' });