Skip to content

Commit

Permalink
test(express): add a test to illstruate how to use express router
Browse files Browse the repository at this point in the history
To simulate expressApp.get(...), post(...), we can create an Express router.
add handlers, and register the router as an Express middleware to LoopBack.
  • Loading branch information
raymondfeng committed May 18, 2020
1 parent 5c4d10f commit 6d54aae
Show file tree
Hide file tree
Showing 4 changed files with 68 additions and 22 deletions.
21 changes: 21 additions & 0 deletions docs/site/Express-middleware.md
Original file line number Diff line number Diff line change
Expand Up @@ -333,6 +333,27 @@ export class MorganInterceptor extends ExpressMiddlewareInterceptorProvider<
}
```

## Use Express Router to enable

Express allows HTTP verbs to be used to set up routes, such as
`app.post('/hello', ...)`. See http://expressjs.com/en/4x/api.html#app.METHOD.

To allow a similar usage in LoopBack, we can create an Express router and
register it to LoopBack as follows:

```ts
import {ExpressRequestHandler, Router} from '@loopback/express';

const handler: ExpressRequestHandler = async (req, res, next) => {
res.send(req.path);
};

const router = Router();
router.post('/greet', handler);
router.get('/hello', handler);
const binding = server.expressMiddleware('middleware.express.greeting', router);
```

## What's behind the scenes

`Middleware` and `Interceptor` are key concepts that allow Express middleware
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@

import {config, Provider} from '@loopback/core';
import {Client, expect} from '@loopback/testlab';
import {Router} from 'express';
import {ExpressServer, Middleware} from '../../';
import {SpyAction} from '../fixtures/spy-config';
import {spy, SpyConfig, TestFunction, TestHelper} from './test-helpers';
Expand Down Expand Up @@ -42,12 +43,30 @@ describe('Express middleware registry', () => {
expect(binding.key).to.match(/^middleware\./);
return testFn(binding);
});

it('registers a middleware with router', async () => {
const router = Router();
router.post('/greet', spy(spyConfig));
const binding = server.expressMiddleware(
'middleware.express.spy',
router,
);
await testFn(binding, '/greet');
const res = await client
.post('/hello')
.send('"World"')
.set('content-type', 'application/json')
.expect(200, 'Hello, World');
['x-spy-log', 'x-spy-mock', 'x-spy-reject'].forEach(h =>
expect(res.get(h)).to.be.undefined(),
);
});
});
}

runTests('log', binding => helper.testSpyLog(binding));
runTests('mock', binding => helper.testSpyMock(binding));
runTests('reject', binding => helper.testSpyReject(binding));
runTests('log', (binding, path) => helper.testSpyLog(binding, path));
runTests('mock', (binding, path) => helper.testSpyMock(binding, path));
runTests('reject', (binding, path) => helper.testSpyReject(binding, path));

describe('LoopBack middleware registry', () => {
const spyMiddleware: Middleware = async (middlewareCtx, next) => {
Expand Down
42 changes: 24 additions & 18 deletions packages/express/src/__tests__/acceptance/test-helpers.ts
Original file line number Diff line number Diff line change
Expand Up @@ -12,12 +12,16 @@ import {
import {Client, givenHttpServerConfig, supertest} from '@loopback/testlab';
import bodyParser from 'body-parser';
import {ExpressApplication} from '../../express.application';
import {ExpressRequestHandler} from '../../types';
import {SpyAction, SpyConfig} from '../fixtures/spy-config';
import spyFactory from '../fixtures/spy.middleware';
export const spy = spyFactory;
export {SpyConfig} from '../fixtures/spy-config';

export type TestFunction = (spyBinding: Binding<unknown>) => Promise<unknown>;
export type TestFunction = (
spyBinding: Binding<unknown>,
path?: string,
) => Promise<unknown>;

export class TestHelper {
readonly app: ExpressApplication;
Expand Down Expand Up @@ -58,7 +62,7 @@ export class TestHelper {
}
}
const binding = this.app.controller(MyController);
this.app.expressServer.expressApp.post('/hello', async (req, res, next) => {
const handler: ExpressRequestHandler = async (req, res, next) => {
try {
const controller = await this.app.get<MyController>(binding.key);
const proxy = createProxyWithInterceptors(
Expand All @@ -74,7 +78,9 @@ export class TestHelper {
} catch (err) {
next(err);
}
});
};
this.app.expressServer.expressApp.post('/hello', handler);
this.app.expressServer.expressApp.post('/greet', handler);
}

private configureSpy(
Expand All @@ -84,46 +90,46 @@ export class TestHelper {
this.app.configure<SpyConfig>(spyBinding.key).to({action});
}

async testSpyLog(spyBinding: Binding<unknown>) {
async testSpyLog(spyBinding: Binding<unknown>, path = '/hello') {
this.configureSpy(spyBinding);

await this.assertSpyLog();
await this.assertSpyLog(path);
}

async assertSpyLog() {
async assertSpyLog(path = '/hello') {
await this.client
.post('/hello')
.post(path)
.send('"World"')
.set('content-type', 'application/json')
.expect(200, 'Hello, World')
.expect('x-spy-log', 'POST /hello');
.expect('x-spy-log', `POST ${path}`);
}

async testSpyMock(spyBinding: Binding<unknown>) {
async testSpyMock(spyBinding: Binding<unknown>, path = '/hello') {
this.configureSpy(spyBinding, 'mock');
await this.assertSpyMock();
await this.assertSpyMock(path);
}

async assertSpyMock() {
async assertSpyMock(path = '/hello') {
await this.client
.post('/hello')
.post(path)
.send('"World"')
.set('content-type', 'application/json')
.expect(200, 'Hello, Spy')
.expect('x-spy-mock', 'POST /hello');
.expect('x-spy-mock', `POST ${path}`);
}

async testSpyReject(spyBinding: Binding<unknown>) {
async testSpyReject(spyBinding: Binding<unknown>, path = '/hello') {
this.configureSpy(spyBinding, 'reject');
await this.assertSpyReject();
await this.assertSpyReject(path);
}

private async assertSpyReject() {
private async assertSpyReject(path = '/hello') {
await this.client
.post('/hello')
.post(path)
.send('"World"')
.set('content-type', 'application/json')
.expect(400)
.expect('x-spy-reject', 'POST /hello');
.expect('x-spy-reject', `POST ${path}`);
}
}
2 changes: 1 addition & 1 deletion packages/express/src/types.ts
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,7 @@ import {Request, RequestHandler, Response} from 'express';
import onFinished from 'on-finished';
import {MiddlewareBindings} from './keys';

export {Request, Response} from 'express';
export {Request, Response, Router, RouterOptions} from 'express';

/**
* An object holding HTTP request, response and other data
Expand Down

0 comments on commit 6d54aae

Please sign in to comment.