|
1 | 1 | import * as http from 'http';
|
2 |
| -import * as express from 'express'; |
3 | 2 | import * as WebSocket from 'ws';
|
4 |
| -// tslint:disable-next-line: no-duplicate-imports |
5 | 3 | import { Server as WebSocketServer } from 'ws';
|
6 |
| -import { createProxyMiddleware } from './test-kit'; |
| 4 | +import { createProxyMiddleware, createApp } from './test-kit'; |
| 5 | +import type { RequestHandler } from '../../src/types'; |
| 6 | + |
| 7 | +/******************************************************************** |
| 8 | + * - Not possible to use `supertest` to test WebSockets |
| 9 | + * - Make sure to use different port for each test to avoid flakiness |
| 10 | + ********************************************************************/ |
7 | 11 |
|
8 | 12 | describe('E2E WebSocket proxy', () => {
|
9 | 13 | let proxyServer: http.Server;
|
10 |
| - let ws; |
11 |
| - let wss; |
12 |
| - let responseMessage; |
13 |
| - let proxy; |
| 14 | + let ws: WebSocket; |
| 15 | + let wss: WebSocketServer; |
| 16 | + let proxyMiddleware: RequestHandler; |
| 17 | + const WS_SERVER_PORT = 9000; |
14 | 18 |
|
15 | 19 | beforeEach(() => {
|
16 |
| - proxy = createProxyMiddleware('/', { |
17 |
| - target: 'http://localhost:9000', |
18 |
| - ws: true, |
19 |
| - pathRewrite: { '^/socket': '' }, |
20 |
| - }); |
21 |
| - |
22 |
| - proxyServer = express().use(proxy).listen(3000); |
23 |
| - |
24 |
| - wss = new WebSocketServer({ port: 9000 }); |
| 20 | + wss = new WebSocketServer({ port: WS_SERVER_PORT }); |
25 | 21 |
|
26 |
| - wss.on('connection', function connection(websocket) { |
27 |
| - websocket.on('message', function incoming(message) { |
| 22 | + wss.on('connection', (websocket) => { |
| 23 | + websocket.on('message', (message) => { |
28 | 24 | websocket.send(message); // echo received message
|
29 | 25 | });
|
30 | 26 | });
|
31 | 27 | });
|
32 | 28 |
|
33 |
| - afterEach((done) => { |
34 |
| - proxyServer.close(() => { |
35 |
| - done(); |
| 29 | + beforeEach(() => { |
| 30 | + proxyMiddleware = createProxyMiddleware('/', { |
| 31 | + target: `http://localhost:${WS_SERVER_PORT}`, |
| 32 | + ws: true, |
| 33 | + pathRewrite: { '^/socket': '' }, |
36 | 34 | });
|
37 |
| - wss.close(); |
38 |
| - ws = null; |
| 35 | + }); |
| 36 | + |
| 37 | + afterEach(async () => { |
| 38 | + return Promise.all([ |
| 39 | + new Promise((resolve) => proxyServer.close(resolve)), |
| 40 | + new Promise((resolve) => wss.close(resolve)), |
| 41 | + new Promise((resolve) => resolve(ws.close())), |
| 42 | + ]); |
39 | 43 | });
|
40 | 44 |
|
41 | 45 | describe('option.ws', () => {
|
42 |
| - beforeEach((done) => { |
43 |
| - // need to make a normal http request, |
44 |
| - // so http-proxy-middleware can catch the upgrade request |
45 |
| - http.get('http://localhost:3000/', () => { |
46 |
| - // do a second http request to make |
47 |
| - // sure only 1 listener subscribes to upgrade request |
48 |
| - http.get('http://localhost:3000/', () => { |
49 |
| - ws = new WebSocket('ws://localhost:3000/socket'); |
50 |
| - |
51 |
| - ws.on('message', function incoming(message) { |
52 |
| - responseMessage = message; |
53 |
| - done(); |
54 |
| - }); |
55 |
| - |
56 |
| - ws.on('open', function open() { |
57 |
| - ws.send('foobar'); |
58 |
| - }); |
59 |
| - }); |
60 |
| - }); |
| 46 | + beforeEach(async (done) => { |
| 47 | + const SERVER_PORT = 31000; |
| 48 | + proxyServer = createApp(proxyMiddleware).listen(SERVER_PORT); |
| 49 | + |
| 50 | + // quick & dirty Promise version of http.get (don't care about correctness) |
| 51 | + const get = async (uri) => new Promise((resolve, reject) => http.get(uri, resolve)); |
| 52 | + |
| 53 | + // need to make a normal http request, so http-proxy-middleware can catch the upgrade request |
| 54 | + await get(`http://localhost:${SERVER_PORT}/`); |
| 55 | + // do a second http request to make sure only 1 listener subscribes to upgrade request |
| 56 | + await get(`http://localhost:${SERVER_PORT}/`); |
| 57 | + |
| 58 | + ws = new WebSocket(`ws://localhost:${SERVER_PORT}/socket`); |
| 59 | + ws.on('open', done); |
61 | 60 | });
|
62 | 61 |
|
63 |
| - it('should proxy to path', () => { |
64 |
| - expect(responseMessage).toBe('foobar'); |
| 62 | + it('should proxy to path', (done) => { |
| 63 | + ws.on('message', (message) => { |
| 64 | + expect(message).toBe('foobar'); |
| 65 | + done(); |
| 66 | + }); |
| 67 | + ws.send('foobar'); |
65 | 68 | });
|
66 | 69 | });
|
67 | 70 |
|
68 | 71 | describe('option.ws with external server "upgrade"', () => {
|
69 | 72 | beforeEach((done) => {
|
70 |
| - proxyServer.on('upgrade', proxy.upgrade); |
| 73 | + const SERVER_PORT = 32000; |
| 74 | + proxyServer = createApp(proxyMiddleware).listen(SERVER_PORT); |
| 75 | + proxyServer.on('upgrade', proxyMiddleware.upgrade); |
71 | 76 |
|
72 |
| - ws = new WebSocket('ws://localhost:3000/socket'); |
| 77 | + ws = new WebSocket(`ws://localhost:${SERVER_PORT}/socket`); |
| 78 | + ws.on('open', done); |
| 79 | + }); |
73 | 80 |
|
74 |
| - ws.on('message', function incoming(message) { |
75 |
| - responseMessage = message; |
| 81 | + it('should proxy to path', async (done) => { |
| 82 | + ws.on('message', (message) => { |
| 83 | + expect(message).toBe('foobar'); |
76 | 84 | done();
|
77 | 85 | });
|
78 |
| - |
79 |
| - ws.on('open', function open() { |
80 |
| - ws.send('foobar'); |
81 |
| - }); |
82 |
| - }); |
83 |
| - |
84 |
| - it('should proxy to path', () => { |
85 |
| - expect(responseMessage).toBe('foobar'); |
| 86 | + ws.send('foobar'); |
86 | 87 | });
|
87 | 88 | });
|
88 | 89 |
|
89 | 90 | describe('option.ws with external server "upgrade" and shorthand usage', () => {
|
90 |
| - beforeEach(() => { |
91 |
| - proxyServer.close(); |
| 91 | + const SERVER_PORT = 33000; |
92 | 92 |
|
93 |
| - // override |
94 |
| - proxy = createProxyMiddleware('ws://localhost:9000', { |
95 |
| - pathRewrite: { '^/socket': '' }, |
96 |
| - }); |
| 93 | + beforeEach(() => { |
| 94 | + proxyServer = createApp( |
| 95 | + createProxyMiddleware(`ws://localhost:${WS_SERVER_PORT}`, { |
| 96 | + pathRewrite: { '^/socket': '' }, |
| 97 | + }) |
| 98 | + ).listen(SERVER_PORT); |
97 | 99 |
|
98 |
| - proxyServer = express().use(proxy).listen(3000); |
| 100 | + proxyServer.on('upgrade', proxyMiddleware.upgrade); |
99 | 101 | });
|
100 | 102 |
|
101 | 103 | beforeEach((done) => {
|
102 |
| - proxyServer.on('upgrade', proxy.upgrade); |
103 |
| - |
104 |
| - ws = new WebSocket('ws://localhost:3000/socket'); |
| 104 | + ws = new WebSocket(`ws://localhost:${SERVER_PORT}/socket`); |
| 105 | + ws.on('open', done); |
| 106 | + }); |
105 | 107 |
|
106 |
| - ws.on('message', function incoming(message) { |
107 |
| - responseMessage = message; |
| 108 | + it('should proxy to path', (done) => { |
| 109 | + ws.on('message', (message) => { |
| 110 | + expect(message).toBe('foobar'); |
108 | 111 | done();
|
109 | 112 | });
|
110 |
| - |
111 |
| - ws.on('open', function open() { |
112 |
| - ws.send('foobar'); |
113 |
| - }); |
114 |
| - }); |
115 |
| - |
116 |
| - it('should proxy to path', () => { |
117 |
| - expect(responseMessage).toBe('foobar'); |
| 113 | + ws.send('foobar'); |
118 | 114 | });
|
119 | 115 | });
|
120 | 116 |
|
121 | 117 | describe('with router and pathRewrite', () => {
|
122 |
| - beforeEach(() => { |
123 |
| - proxyServer.close(); |
| 118 | + const SERVER_PORT = 34000; |
124 | 119 |
|
| 120 | + beforeEach(() => { |
125 | 121 | // override
|
126 |
| - proxy = createProxyMiddleware('ws://notworkinghost:6789', { |
127 |
| - router: { '/socket': 'ws://localhost:9000' }, |
128 |
| - pathRewrite: { '^/socket': '' }, |
129 |
| - }); |
130 |
| - |
131 |
| - proxyServer = express().use(proxy).listen(3000); |
| 122 | + proxyServer = createApp( |
| 123 | + createProxyMiddleware('ws://notworkinghost:6789', { |
| 124 | + router: { '/socket': `ws://localhost:${WS_SERVER_PORT}` }, |
| 125 | + pathRewrite: { '^/socket': '' }, |
| 126 | + }) |
| 127 | + ).listen(SERVER_PORT); |
| 128 | + |
| 129 | + proxyServer.on('upgrade', proxyMiddleware.upgrade); |
132 | 130 | });
|
133 | 131 |
|
134 | 132 | beforeEach((done) => {
|
135 |
| - proxyServer.on('upgrade', proxy.upgrade); |
136 |
| - |
137 |
| - ws = new WebSocket('ws://localhost:3000/socket'); |
| 133 | + ws = new WebSocket(`ws://localhost:${SERVER_PORT}/socket`); |
| 134 | + ws.on('open', done); |
| 135 | + }); |
138 | 136 |
|
139 |
| - ws.on('message', function incoming(message) { |
140 |
| - responseMessage = message; |
| 137 | + it('should proxy to path', (done) => { |
| 138 | + ws.on('message', (message) => { |
| 139 | + expect(message).toBe('foobar'); |
141 | 140 | done();
|
142 | 141 | });
|
143 |
| - |
144 |
| - ws.on('open', function open() { |
145 |
| - ws.send('foobar'); |
146 |
| - }); |
147 |
| - }); |
148 |
| - |
149 |
| - it('should proxy to path', () => { |
150 |
| - expect(responseMessage).toBe('foobar'); |
| 142 | + ws.send('foobar'); |
151 | 143 | });
|
152 | 144 | });
|
153 | 145 | });
|
0 commit comments