@modern-js/server 1.2.0 → 1.2.1-rc.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (70) hide show
  1. package/CHANGELOG.md +14 -0
  2. package/dist/js/modern/index.js +1 -7
  3. package/dist/js/modern/libs/context/context.js +3 -6
  4. package/dist/js/modern/libs/context/index.js +1 -7
  5. package/dist/js/modern/libs/hook-api/template.js +4 -4
  6. package/dist/js/modern/libs/proxy.js +1 -1
  7. package/dist/js/modern/libs/render/cache/__tests__/cache.test.js +1 -2
  8. package/dist/js/modern/libs/render/index.js +6 -2
  9. package/dist/js/modern/libs/render/reader.js +8 -11
  10. package/dist/js/modern/libs/render/ssr.js +2 -1
  11. package/dist/js/modern/libs/route/index.js +2 -1
  12. package/dist/js/modern/server/index.js +3 -1
  13. package/dist/js/modern/server/modern-server.js +21 -11
  14. package/dist/js/modern/utils.js +1 -9
  15. package/dist/js/node/index.js +1 -49
  16. package/dist/js/node/libs/context/context.js +3 -6
  17. package/dist/js/node/libs/context/index.js +1 -7
  18. package/dist/js/node/libs/hook-api/template.js +4 -4
  19. package/dist/js/node/libs/proxy.js +1 -1
  20. package/dist/js/node/libs/render/cache/__tests__/cache.test.js +1 -2
  21. package/dist/js/node/libs/render/index.js +6 -2
  22. package/dist/js/node/libs/render/reader.js +8 -11
  23. package/dist/js/node/libs/render/ssr.js +2 -1
  24. package/dist/js/node/libs/route/index.js +6 -0
  25. package/dist/js/node/server/index.js +3 -1
  26. package/dist/js/node/server/modern-server.js +21 -11
  27. package/dist/js/node/utils.js +2 -12
  28. package/dist/types/index.d.ts +1 -3
  29. package/dist/types/libs/context/context.d.ts +7 -7
  30. package/dist/types/libs/context/index.d.ts +1 -8
  31. package/dist/types/libs/hook-api/template.d.ts +4 -4
  32. package/dist/types/libs/render/index.d.ts +10 -1
  33. package/dist/types/libs/render/ssr.d.ts +2 -1
  34. package/dist/types/libs/render/type.d.ts +2 -21
  35. package/dist/types/libs/route/index.d.ts +2 -1
  36. package/dist/types/server/modern-server.d.ts +1 -1
  37. package/dist/types/type.d.ts +6 -0
  38. package/dist/types/utils.d.ts +1 -2
  39. package/package.json +14 -12
  40. package/src/index.ts +2 -8
  41. package/src/libs/context/context.ts +8 -7
  42. package/src/libs/context/index.ts +2 -6
  43. package/src/libs/hook-api/template.ts +4 -4
  44. package/src/libs/proxy.ts +1 -1
  45. package/src/libs/render/cache/__tests__/cache.test.ts +2 -2
  46. package/src/libs/render/index.ts +21 -11
  47. package/src/libs/render/reader.ts +8 -8
  48. package/src/libs/render/ssr.ts +4 -0
  49. package/src/libs/render/type.ts +2 -17
  50. package/src/libs/route/index.ts +2 -1
  51. package/src/server/index.ts +1 -1
  52. package/src/server/modern-server.ts +20 -12
  53. package/src/type.ts +7 -0
  54. package/src/utils.ts +0 -14
  55. package/tests/.eslintrc.js +6 -0
  56. package/tests/context.test.ts +41 -0
  57. package/tests/fixtures/hosting-files/static/index.js +1 -0
  58. package/tests/fixtures/pure/modern.config.js +5 -0
  59. package/tests/fixtures/pure/package.json +21 -0
  60. package/tests/fixtures/pure/src/App.css +119 -0
  61. package/tests/fixtures/pure/src/App.tsx +43 -0
  62. package/tests/fixtures/pure/tsconfig.json +13 -0
  63. package/tests/fixtures/route-spec/index.json +29 -0
  64. package/tests/helper.ts +8 -0
  65. package/tests/hook.test.ts +44 -0
  66. package/tests/middleware.test.ts +178 -0
  67. package/tests/route.test.ts +54 -0
  68. package/tests/server.test.ts +89 -0
  69. package/tests/tsconfig.json +14 -0
  70. package/tests/utils.test.ts +40 -0
@@ -135,7 +135,7 @@ export class Server {
135
135
  ...appContext,
136
136
  distDirectory: path.join(
137
137
  options.pwd,
138
- options.config.output.path || 'dist',
138
+ options.config.output?.path || 'dist',
139
139
  ),
140
140
  });
141
141
  });
@@ -87,12 +87,12 @@ export class ModernServer {
87
87
 
88
88
  private frameAPIHandler: Adapter | null = null;
89
89
 
90
+ private proxyHandler: ReturnType<typeof createProxyHandler> = null;
91
+
90
92
  private _handler!: (context: ModernServerContext, next: NextFunction) => void;
91
93
 
92
94
  private readonly staticGenerate: boolean = false;
93
95
 
94
- private proxyHandler: ReturnType<typeof createProxyHandler> = null;
95
-
96
96
  constructor({
97
97
  pwd,
98
98
  config,
@@ -107,7 +107,7 @@ export class ModernServer {
107
107
  this.isDev = Boolean(dev);
108
108
 
109
109
  this.pwd = pwd;
110
- this.distDir = path.join(pwd, config.output.path || 'dist');
110
+ this.distDir = path.join(pwd, config.output?.path || 'dist');
111
111
  this.workDir = this.isDev ? pwd : this.distDir;
112
112
  this.conf = config;
113
113
  this.logger = logger!;
@@ -162,7 +162,7 @@ export class ModernServer {
162
162
 
163
163
  await this.prepareFrameHandler();
164
164
 
165
- const { favicon, faviconByEntries } = this.conf.output;
165
+ const { favicon, faviconByEntries } = this.conf.output || {};
166
166
  const favicons = this.prepareFavicons(favicon, faviconByEntries);
167
167
  // Only work when without setting `assetPrefix`.
168
168
  // Setting `assetPrefix` means these resources should be uploaded to CDN.
@@ -229,6 +229,7 @@ export class ModernServer {
229
229
  }
230
230
 
231
231
  // add promisify request handler to server
232
+ // handler should do not do more things after invoke next
232
233
  protected addHandler(handler: ModernServerHandler) {
233
234
  if ((handler as any)[Symbol.toStringTag] === 'AsyncFunction') {
234
235
  this.handlers.push(handler as ModernServerAsyncHandler);
@@ -356,7 +357,11 @@ export class ModernServer {
356
357
  }
357
358
 
358
359
  protected async handleWeb(context: ModernServerContext, route: ModernRoute) {
359
- return this.routeRenderHandler(context, route);
360
+ return this.routeRenderHandler({
361
+ ctx: context,
362
+ route,
363
+ runner: this.runner,
364
+ });
360
365
  }
361
366
 
362
367
  protected verifyMatch(_c: ModernServerContext, _m: RouteMatcher) {
@@ -372,7 +377,7 @@ export class ModernServer {
372
377
  await this.emitRouteHook('beforeMatch', { context });
373
378
 
374
379
  // match routes in the route spec
375
- const matched = this.router.match(context.url);
380
+ const matched = this.router.match(context.path);
376
381
  if (!matched) {
377
382
  this.render404(context);
378
383
  return;
@@ -498,7 +503,7 @@ export class ModernServer {
498
503
  try {
499
504
  // Todo Safety xss
500
505
  const injection = JSON.stringify({ ...manifest, modules });
501
- templateAPI.afterHead(
506
+ templateAPI.appendHead(
502
507
  `<script>window.modern_manifest=${injection}</script>`,
503
508
  );
504
509
  } catch (e) {
@@ -546,10 +551,9 @@ export class ModernServer {
546
551
  },
547
552
  ) {
548
553
  res.statusCode = 200;
549
- const context: ModernServerContext = createContext(req, res, {
550
- logger: this.logger,
551
- metrics: this.metrics,
552
- });
554
+ req.logger = req.logger || this.logger;
555
+ req.metrics = req.metrics || this.metrics;
556
+ const context: ModernServerContext = createContext(req, res);
553
557
 
554
558
  try {
555
559
  this._handler(context, next);
@@ -580,7 +584,11 @@ export class ModernServer {
580
584
  // check entryName, aviod matched '/' route
581
585
  if (entryName === status.toString() || entryName === '_error') {
582
586
  try {
583
- const file = await this.routeRenderHandler(context, route);
587
+ const file = await this.routeRenderHandler({
588
+ route,
589
+ ctx: context,
590
+ runner: this.runner,
591
+ });
584
592
  if (file) {
585
593
  context.res.end(file.content);
586
594
  return;
package/src/type.ts CHANGED
@@ -5,6 +5,13 @@ import type { NormalizedConfig } from '@modern-js/core';
5
5
  import type { Metrics, Logger, NextFunction } from '@modern-js/types/server';
6
6
  import { ModernRouteInterface } from './libs/route';
7
7
 
8
+ declare module 'http' {
9
+ interface IncomingMessage {
10
+ logger: Logger;
11
+ metrics: Metrics;
12
+ }
13
+ }
14
+
8
15
  declare module '@modern-js/core' {
9
16
  interface UserConfig {
10
17
  bff: {
package/src/utils.ts CHANGED
@@ -49,17 +49,3 @@ export const createErrorDocument = (status: number, text: string) => {
49
49
  </html>
50
50
  `;
51
51
  };
52
-
53
- // This can live anywhere in your codebase:
54
- export function applyMixins(derivedCtor: any, constructors: any[]) {
55
- constructors.forEach(baseCtor => {
56
- Object.getOwnPropertyNames(baseCtor.prototype).forEach(name => {
57
- Object.defineProperty(
58
- derivedCtor.prototype,
59
- name,
60
- Object.getOwnPropertyDescriptor(baseCtor.prototype, name) ||
61
- Object.create(null),
62
- );
63
- });
64
- });
65
- }
@@ -0,0 +1,6 @@
1
+ module.exports = {
2
+ extends: ['@modern-js'],
3
+ parserOptions: {
4
+ project: require.resolve('./tsconfig.json'),
5
+ },
6
+ };
@@ -0,0 +1,41 @@
1
+ import EventEmitter from 'events';
2
+ import { Readable } from 'stream';
3
+ import httpMocks from 'node-mocks-http';
4
+ import { createContext } from '../src/libs/context';
5
+
6
+ describe('test server context', () => {
7
+ test('should route api work correctly', () => {
8
+ const req = httpMocks.createRequest({
9
+ url: '/pathname?foo=baz',
10
+ headers: {
11
+ host: 'modernjs.com',
12
+ },
13
+ eventEmitter: Readable,
14
+ method: 'GET',
15
+ });
16
+ const res = httpMocks.createResponse({ eventEmitter: EventEmitter });
17
+ const {
18
+ method,
19
+ url,
20
+ origin,
21
+ host,
22
+ path,
23
+ href,
24
+ query,
25
+ querystring,
26
+ protocol,
27
+ params,
28
+ } = createContext(req, res);
29
+
30
+ expect(method).toBe('GET');
31
+ expect(url).toBe('/pathname?foo=baz');
32
+ expect(origin).toBe('http://modernjs.com');
33
+ expect(host).toBe('modernjs.com');
34
+ expect(path).toBe('/pathname');
35
+ expect(href).toBe('http://modernjs.com/pathname?foo=baz');
36
+ expect(query).toEqual({ foo: 'baz' });
37
+ expect(querystring).toBe('foo=baz');
38
+ expect(protocol).toBe('http');
39
+ expect(params).toEqual({});
40
+ });
41
+ });
@@ -0,0 +1 @@
1
+ console.info('index.js');
@@ -0,0 +1,5 @@
1
+ module.exports = {
2
+ server: {
3
+ ssr: true,
4
+ },
5
+ };
@@ -0,0 +1,21 @@
1
+ {
2
+ "name": "deploy",
3
+ "version": "0.1.0",
4
+ "scripts": {
5
+ "reset": "del-cli node_modules",
6
+ "dev": "modern dev",
7
+ "build": "modern build",
8
+ "start": "modern start",
9
+ "new": "modern new",
10
+ "lint": "modern lint",
11
+ "deploy": "modern deploy"
12
+ },
13
+ "dependencies": {},
14
+ "devDependencies": {},
15
+ "modernConfig": {
16
+ "runtime": {
17
+ "router": true,
18
+ "state": true
19
+ }
20
+ }
21
+ }
@@ -0,0 +1,119 @@
1
+ html,
2
+ body {
3
+ padding: 0;
4
+ margin: 0;
5
+ font-family: nunito_for_arco, Helvetica Neue, Helvetica, PingFang SC,
6
+ Hiragino Sans GB, Microsoft YaHei, 微软雅黑, Arial, sans-serif;
7
+ }
8
+
9
+ * {
10
+ -webkit-font-smoothing: antialiased;
11
+ -moz-osx-font-smoothing: grayscale;
12
+ box-sizing: border-box;
13
+ }
14
+
15
+ .container {
16
+ min-height: 100vh;
17
+ max-width: 100%;
18
+ display: flex;
19
+ flex-direction: column;
20
+ justify-content: center;
21
+ align-items: center;
22
+ }
23
+
24
+ main {
25
+ padding: 5rem 0;
26
+ flex: 1;
27
+ display: flex;
28
+ flex-direction: column;
29
+ justify-content: center;
30
+ align-items: center;
31
+ }
32
+
33
+ .footer {
34
+ width: 100%;
35
+ height: 80px;
36
+ border-top: 1px solid #eaeaea;
37
+ display: flex;
38
+ justify-content: center;
39
+ align-items: center;
40
+ background-color: #470000;
41
+ }
42
+
43
+ .footer a {
44
+ display: flex;
45
+ justify-content: center;
46
+ align-items: center;
47
+ flex-grow: 1;
48
+ color: #f4f4f4;
49
+ text-decoration: none;
50
+ font-size: 1.1rem;
51
+ }
52
+
53
+ .logo {
54
+ margin-bottom: 2rem;
55
+ }
56
+
57
+ .logo svg {
58
+ width: 450px;
59
+ height: 132px;
60
+ }
61
+
62
+ .description {
63
+ text-align: center;
64
+ line-height: 1.5;
65
+ font-size: 1.5rem;
66
+ }
67
+
68
+ .code {
69
+ background: #fafafa;
70
+ border-radius: 5px;
71
+ padding: 0.75rem;
72
+ font-size: 1.1rem;
73
+ font-family: Menlo, Monaco, Lucida Console, Liberation Mono, DejaVu Sans Mono,
74
+ Bitstream Vera Sans Mono, Courier New, monospace;
75
+ }
76
+
77
+ @media (max-width: 600px) {
78
+ .grid {
79
+ width: 100%;
80
+ flex-direction: column;
81
+ }
82
+ }
83
+
84
+ .grid {
85
+ display: flex;
86
+ align-items: center;
87
+ justify-content: center;
88
+ flex-wrap: wrap;
89
+ width: 800px;
90
+ margin-top: 3rem;
91
+ }
92
+
93
+ .card {
94
+ margin: 1rem;
95
+ padding: 1.5rem;
96
+ display: flex;
97
+ align-items: center;
98
+ justify-content: center;
99
+ height: 100px;
100
+ color: inherit;
101
+ text-decoration: none;
102
+ border: 1px solid #470000;
103
+ color: #470000;
104
+ transition: color 0.15s ease, border-color 0.15s ease;
105
+ width: 45%;
106
+ }
107
+
108
+ .card:hover,
109
+ .card:focus,
110
+ .card:active {
111
+ transform: scale(1.05);
112
+ transition: 0.1s ease-in-out;
113
+ }
114
+
115
+ .card h2 {
116
+ font-size: 1.5rem;
117
+ margin: 0;
118
+ padding: 0;
119
+ }
@@ -0,0 +1,43 @@
1
+ import './App.css';
2
+
3
+ const App = () => (
4
+ <div className="container">
5
+ <main>
6
+ <div className="logo">
7
+ <img
8
+ src="https://lf3-static.bytednsdoc.com/obj/eden-cn/ylaelkeh7nuhfnuhf/modernjs-cover.png"
9
+ width="300"
10
+ alt="Modern.js Logo"
11
+ />
12
+ </div>
13
+ <p className="description">
14
+ Get started by editing <code className="code">src/home/App.tsx</code>
15
+ </p>
16
+ <div className="grid">
17
+ <a href="https://modernjs.dev/docs/start" className="card">
18
+ <h2>Quick Start Tencent</h2>
19
+ </a>
20
+ <a href="https://modernjs.dev/docs/guides" className="card">
21
+ <h2>Handbook</h2>
22
+ </a>
23
+ <a href="https://modernjs.dev/docs/apis" className="card">
24
+ <h2>API Reference </h2>
25
+ </a>
26
+ <a
27
+ href="https://modernjs.dev/coming-soon"
28
+ target="_blank"
29
+ rel="noopener noreferrer"
30
+ className="card">
31
+ <h2>Community </h2>
32
+ </a>
33
+ </div>
34
+ </main>
35
+ <footer className="footer">
36
+ <a href="https://modernjs.dev" target="_blank" rel="noopener noreferrer">
37
+ Powered by Modern.js
38
+ </a>
39
+ </footer>
40
+ </div>
41
+ );
42
+
43
+ export default App;
@@ -0,0 +1,13 @@
1
+ {
2
+ "extends": "@modern-js/tsconfig/base",
3
+ "compilerOptions": {
4
+ "declaration": false,
5
+ "jsx": "preserve",
6
+ "baseUrl": "./",
7
+ "paths": {
8
+ "@/*": ["./src/*"],
9
+ "@shared/*": ["./shared/*"]
10
+ }
11
+ },
12
+ "include": ["src", "shared", "config"]
13
+ }
@@ -0,0 +1,29 @@
1
+ {
2
+ "routes": [
3
+ {
4
+ "urlPath": "/entry",
5
+ "entryName": "entry",
6
+ "entryPath": "html/entry/index.html",
7
+ "isSPA": true,
8
+ "isSSR": true,
9
+ "enableModernMode": false,
10
+ "bundle": "bundles/entry.js"
11
+ },
12
+ {
13
+ "urlPath": "/home",
14
+ "entryName": "home",
15
+ "entryPath": "html/home/index.html",
16
+ "isSPA": true,
17
+ "isSSR": true,
18
+ "enableModernMode": false,
19
+ "bundle": "bundles/home.js"
20
+ },
21
+ {
22
+ "urlPath": "/api",
23
+ "isApi": true,
24
+ "entryPath": "",
25
+ "isSPA": false,
26
+ "isSSR": false
27
+ }
28
+ ]
29
+ }
@@ -0,0 +1,8 @@
1
+ export const createDoc = () => `<html>
2
+ <head>
3
+ <title>mock</title>
4
+ </head>
5
+ <body>
6
+ <div>hello</div>
7
+ </body>
8
+ </html>`;
@@ -0,0 +1,44 @@
1
+ import { createRouteAPI } from '../src/libs/hook-api/route';
2
+ import { createTemplateAPI } from '../src/libs/hook-api/template';
3
+ import { RouteMatchManager } from '../src/libs/route';
4
+ import { createDoc } from './helper';
5
+ import spec from './fixtures/route-spec/index.json';
6
+
7
+ describe('test hook api', () => {
8
+ test('should route api work correctly', () => {
9
+ const manager = new RouteMatchManager();
10
+ manager.reset(spec.routes);
11
+ const matcher = manager.match('/home');
12
+
13
+ const routeAPI = createRouteAPI(matcher!, manager);
14
+ expect(routeAPI.cur().entryName).toBe('home');
15
+ expect(routeAPI.get('entry')?.entryPath).toBe('html/entry/index.html');
16
+
17
+ expect(routeAPI.use('home')).toBeTruthy();
18
+ expect(routeAPI.cur().entryName).toBe('home');
19
+ });
20
+
21
+ test('should template api work correctly', () => {
22
+ const content = createDoc();
23
+ const templateAPI = createTemplateAPI(content);
24
+
25
+ expect(templateAPI.get()).toMatch(content);
26
+
27
+ templateAPI.replace('mock', 'replace');
28
+ expect(templateAPI.get()).toMatch('replace');
29
+
30
+ templateAPI.appendBody('after body');
31
+ templateAPI.prependBody('before body');
32
+ templateAPI.appendHead('after head');
33
+ templateAPI.prependHead('before head');
34
+
35
+ const newContent = templateAPI.get();
36
+ expect(newContent).toMatch('<head>before head');
37
+ expect(newContent).toMatch('<body>before body');
38
+ expect(newContent).toMatch('after head</head>');
39
+ expect(newContent).toMatch('after body</body>');
40
+
41
+ templateAPI.set('<div>empty</div>');
42
+ expect(templateAPI.get()).toBe('<div>empty</div>');
43
+ });
44
+ });
@@ -0,0 +1,178 @@
1
+ /* eslint-disable max-nested-callbacks */
2
+ import path from 'path';
3
+ import EventEmitter from 'events';
4
+ import { Readable } from 'stream';
5
+ import { createServer, Server } from 'http';
6
+ import httpMocks from 'node-mocks-http';
7
+ import portfinder from 'portfinder';
8
+ import axios from 'axios';
9
+ import { createContext } from '../src/libs/context';
10
+ import { createStaticFileHandler } from '../src/libs/serve-file';
11
+ import { createProxyHandler } from '../src/libs/proxy';
12
+
13
+ describe('test middleware create factory', () => {
14
+ describe('should create static-file handler correctly', () => {
15
+ const middleware = createStaticFileHandler([
16
+ {
17
+ path: /static\/|upload\//,
18
+ target: path.join(__dirname, './fixtures/hosting-files'),
19
+ },
20
+ ]);
21
+
22
+ test('should get static file correctly', resolve => {
23
+ const req = httpMocks.createRequest({
24
+ path: '/static/index.js',
25
+ eventEmitter: Readable,
26
+ });
27
+ const res = httpMocks.createResponse({ eventEmitter: EventEmitter });
28
+ const mockContext = createContext(req, res);
29
+ res.on('finish', () => {
30
+ expect(res._getBuffer().toString().trim()).toBe(
31
+ "console.info('index.js');",
32
+ );
33
+ resolve();
34
+ });
35
+
36
+ middleware(mockContext, () => {
37
+ throw new Error('should not happened');
38
+ });
39
+ });
40
+
41
+ test('should miss static file correctly', resolve => {
42
+ const req = httpMocks.createRequest({
43
+ path: '/static/index.css',
44
+ eventEmitter: Readable,
45
+ });
46
+ const res = httpMocks.createResponse({ eventEmitter: EventEmitter });
47
+ const mockContext = createContext(req, res);
48
+ res.on('finish', () => {
49
+ throw new Error('should not happened');
50
+ });
51
+
52
+ middleware(mockContext, () => {
53
+ req.destroy();
54
+ expect(true).toBeTruthy();
55
+ resolve();
56
+ });
57
+ });
58
+ });
59
+
60
+ jest.setTimeout(1000 * 10);
61
+ describe('should create proxy handler correctly', () => {
62
+ test('should return null if no options', () => {
63
+ expect(createProxyHandler(null as any)).toBeNull();
64
+ });
65
+
66
+ let sourceServerPort = 8080;
67
+ let sourceServer: Server | null = null;
68
+ beforeAll(async () => {
69
+ sourceServerPort = await portfinder.getPortPromise();
70
+ sourceServer = createServer((req, res) => {
71
+ res.setHeader('Access-Control-Allow-Origin', '*');
72
+ res.write(req.url?.slice(1));
73
+ res.end();
74
+ }).listen(sourceServerPort);
75
+ });
76
+
77
+ afterAll(() => {
78
+ if (sourceServer) {
79
+ sourceServer.close();
80
+ }
81
+ });
82
+
83
+ test('should proxy correctly use simply options', async () => {
84
+ const port = await portfinder.getPortPromise();
85
+ const middlewares = createProxyHandler({
86
+ '/simple': `http://127.0.0.1:${sourceServerPort}`,
87
+ });
88
+ const proxyHandler = middlewares![0];
89
+
90
+ const server = createServer((req, res) => {
91
+ const context = createContext(req, res);
92
+ proxyHandler(context, () => {
93
+ throw new Error('should not happened');
94
+ });
95
+ }).listen(port);
96
+
97
+ try {
98
+ const { data } = await axios.get(`http://127.0.0.1:${port}/simple`);
99
+ expect(data).toBe('simple');
100
+ } finally {
101
+ server.close();
102
+ }
103
+ });
104
+
105
+ test('should proxy correctly use simply obj options', async () => {
106
+ const port = await portfinder.getPortPromise();
107
+ const middlewares = createProxyHandler({
108
+ '/simple-obj': {
109
+ target: `http://127.0.0.1:${sourceServerPort}`,
110
+ },
111
+ });
112
+ const proxyHandler = middlewares![0];
113
+
114
+ const server = createServer((req, res) => {
115
+ const context = createContext(req, res);
116
+ proxyHandler(context, () => {
117
+ throw new Error('should not happened');
118
+ });
119
+ }).listen(port);
120
+
121
+ try {
122
+ const { data } = await axios.get(`http://127.0.0.1:${port}/simple-obj`);
123
+ expect(data).toBe('simple-obj');
124
+ } finally {
125
+ server.close();
126
+ }
127
+ });
128
+
129
+ test('should proxy correctly use context options', async () => {
130
+ const port = await portfinder.getPortPromise();
131
+ const middlewares = createProxyHandler({
132
+ context: '/context',
133
+ target: `http://127.0.0.1:${sourceServerPort}`,
134
+ });
135
+ const proxyHandler = middlewares![0];
136
+
137
+ const server = createServer((req, res) => {
138
+ const context = createContext(req, res);
139
+ proxyHandler(context, () => {
140
+ throw new Error('should not happened');
141
+ });
142
+ }).listen(port);
143
+
144
+ try {
145
+ const { data } = await axios.get(`http://127.0.0.1:${port}/context`);
146
+ expect(data).toBe('context');
147
+ } finally {
148
+ server.close();
149
+ }
150
+ });
151
+
152
+ test('should proxy correctly use array options', async () => {
153
+ const port = await portfinder.getPortPromise();
154
+ const middlewares = createProxyHandler([
155
+ {
156
+ context: '/array',
157
+ target: `http://127.0.0.1:${sourceServerPort}`,
158
+ },
159
+ ]);
160
+ const proxyHandler = middlewares![0];
161
+
162
+ const server = createServer((req, res) => {
163
+ const context = createContext(req, res);
164
+ proxyHandler(context, () => {
165
+ throw new Error('should not happened');
166
+ });
167
+ }).listen(port);
168
+
169
+ try {
170
+ const { data } = await axios.get(`http://127.0.0.1:${port}/array`);
171
+ expect(data).toBe('array');
172
+ } finally {
173
+ server.close();
174
+ }
175
+ });
176
+ });
177
+ });
178
+ /* eslint-enable max-nested-callbacks */