From f8a72484c53884a6bbd74ca0e6f070c7aa4d3dde Mon Sep 17 00:00:00 2001 From: Raymond Feng Date: Wed, 22 Aug 2018 13:06:27 -0700 Subject: [PATCH] fix(rest): make sure basePath is included in RestServer.url --- .../integration/rest.server.integration.ts | 88 +++++++++++++++---- packages/rest/src/rest.server.ts | 16 ++++ packages/testlab/src/client.ts | 3 +- 3 files changed, 90 insertions(+), 17 deletions(-) diff --git a/packages/rest/src/__tests__/integration/rest.server.integration.ts b/packages/rest/src/__tests__/integration/rest.server.integration.ts index c5ebdca63072..f968d8c334a3 100644 --- a/packages/rest/src/__tests__/integration/rest.server.integration.ts +++ b/packages/rest/src/__tests__/integration/rest.server.integration.ts @@ -6,12 +6,12 @@ import {Application} from '@loopback/core'; import { createClientForHandler, + createRestAppClient, expect, givenHttpServerConfig, httpsGetAsync, itSkippedOnTravis, supertest, - createRestAppClient, } from '@loopback/testlab'; import * as fs from 'fs'; import {IncomingMessage, ServerResponse} from 'http'; @@ -26,11 +26,11 @@ import { Request, requestBody, RequestContext, + RestApplication, RestBindings, RestComponent, RestServer, RestServerConfig, - RestApplication, } from '../..'; const readFileAsync = util.promisify(fs.readFile); @@ -38,20 +38,76 @@ const FIXTURES = path.resolve(__dirname, '../../../fixtures'); const ASSETS = path.resolve(FIXTURES, 'assets'); describe('RestServer (integration)', () => { - it('exports url property', async () => { - const server = await givenAServer(); - server.handler(dummyRequestHandler); - expect(server.url).to.be.undefined(); - await server.start(); - expect(server) - .to.have.property('url') - .which.is.a.String() - .match(/http|https\:\/\//); - await supertest(server.url) - .get('/') - .expect(200, 'Hello'); - await server.stop(); - expect(server.url).to.be.undefined(); + describe('url/rootUrl properties', () => { + let server: RestServer; + + afterEach('shuts down server', async () => { + if (!server) return; + await server.stop(); + expect(server.url).to.be.undefined(); + expect(server.rootUrl).to.be.undefined(); + }); + + describe('url', () => { + it('exports url property', async () => { + server = await givenAServer(); + server.handler(dummyRequestHandler); + expect(server.url).to.be.undefined(); + await server.start(); + expect(server) + .to.have.property('url') + .which.is.a.String() + .match(/http|https\:\/\//); + await supertest(server.url) + .get('/') + .expect(200, 'Hello'); + }); + + it('includes basePath in the url property', async () => { + server = await givenAServer({rest: {basePath: '/api'}}); + server.handler(dummyRequestHandler); + expect(server.url).to.be.undefined(); + await server.start(); + expect(server) + .to.have.property('url') + .which.is.a.String() + .match(/http|https\:\/\//); + expect(server.url).to.match(/api$/); + await supertest(server.url) + .get('/') + .expect(200, 'Hello'); + }); + }); + + describe('rootUrl', () => { + it('exports rootUrl property', async () => { + server = await givenAServer(); + server.handler(dummyRequestHandler); + expect(server.rootUrl).to.be.undefined(); + await server.start(); + expect(server) + .to.have.property('rootUrl') + .which.is.a.String() + .match(/http|https\:\/\//); + await supertest(server.rootUrl) + .get('/api') + .expect(200, 'Hello'); + }); + + it('does not include basePath in rootUrl', async () => { + server = await givenAServer({rest: {basePath: '/api'}}); + server.handler(dummyRequestHandler); + expect(server.rootUrl).to.be.undefined(); + await server.start(); + expect(server) + .to.have.property('rootUrl') + .which.is.a.String() + .match(/http|https\:\/\//); + await supertest(server.rootUrl) + .get('/api') + .expect(200, 'Hello'); + }); + }); }); it('parses query without decorated rest query params', async () => { diff --git a/packages/rest/src/rest.server.ts b/packages/rest/src/rest.server.ts index f64aaf93c25e..007f9420a601 100644 --- a/packages/rest/src/rest.server.ts +++ b/packages/rest/src/rest.server.ts @@ -151,7 +151,23 @@ export class RestServer extends Context implements Server, HttpServerLike { return this._httpServer ? this._httpServer.listening : false; } + /** + * The base url for the server, including the basePath if set. For example, + * the value will be 'http://localhost:3000/api' if `basePath` is set to + * '/api'. + */ get url(): string | undefined { + let serverUrl = this.rootUrl; + if (!serverUrl) return serverUrl; + serverUrl = serverUrl + (this._basePath || ''); + return serverUrl; + } + + /** + * The root url for the server without the basePath. For example, the value + * will be 'http://localhost:3000' regardless of the `basePath`. + */ + get rootUrl(): string | undefined { return this._httpServer && this._httpServer.url; } diff --git a/packages/testlab/src/client.ts b/packages/testlab/src/client.ts index 21ff87bc0c0a..ede41af880f4 100644 --- a/packages/testlab/src/client.ts +++ b/packages/testlab/src/client.ts @@ -33,7 +33,7 @@ export function createClientForHandler( * @param app A running (listening) instance of a RestApplication. */ export function createRestAppClient(app: RestApplicationLike) { - const url = app.restServer.url; + const url = app.restServer.rootUrl || app.restServer.url; if (!url) { throw new Error( `Cannot create client for ${app.constructor.name}, it is not listening.`, @@ -53,4 +53,5 @@ export interface RestApplicationLike { export interface RestServerLike { url?: string; + rootUrl?: string; }