Skip to content

Commit 9d5a4fd

Browse files
authored
test(websocket): fix flaky tests (#584)
1 parent 76ce96e commit 9d5a4fd

File tree

1 file changed

+89
-97
lines changed

1 file changed

+89
-97
lines changed

test/e2e/websocket.spec.ts

Lines changed: 89 additions & 97 deletions
Original file line numberDiff line numberDiff line change
@@ -1,153 +1,145 @@
11
import * as http from 'http';
2-
import * as express from 'express';
32
import * as WebSocket from 'ws';
4-
// tslint:disable-next-line: no-duplicate-imports
53
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+
********************************************************************/
711

812
describe('E2E WebSocket proxy', () => {
913
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;
1418

1519
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 });
2521

26-
wss.on('connection', function connection(websocket) {
27-
websocket.on('message', function incoming(message) {
22+
wss.on('connection', (websocket) => {
23+
websocket.on('message', (message) => {
2824
websocket.send(message); // echo received message
2925
});
3026
});
3127
});
3228

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': '' },
3634
});
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+
]);
3943
});
4044

4145
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);
6160
});
6261

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');
6568
});
6669
});
6770

6871
describe('option.ws with external server "upgrade"', () => {
6972
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);
7176

72-
ws = new WebSocket('ws://localhost:3000/socket');
77+
ws = new WebSocket(`ws://localhost:${SERVER_PORT}/socket`);
78+
ws.on('open', done);
79+
});
7380

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');
7684
done();
7785
});
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');
8687
});
8788
});
8889

8990
describe('option.ws with external server "upgrade" and shorthand usage', () => {
90-
beforeEach(() => {
91-
proxyServer.close();
91+
const SERVER_PORT = 33000;
9292

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);
9799

98-
proxyServer = express().use(proxy).listen(3000);
100+
proxyServer.on('upgrade', proxyMiddleware.upgrade);
99101
});
100102

101103
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+
});
105107

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');
108111
done();
109112
});
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');
118114
});
119115
});
120116

121117
describe('with router and pathRewrite', () => {
122-
beforeEach(() => {
123-
proxyServer.close();
118+
const SERVER_PORT = 34000;
124119

120+
beforeEach(() => {
125121
// 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);
132130
});
133131

134132
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+
});
138136

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');
141140
done();
142141
});
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');
151143
});
152144
});
153145
});

0 commit comments

Comments
 (0)