Skip to content

Commit

Permalink
test(websocket): fix flaky tests (#584)
Browse files Browse the repository at this point in the history
  • Loading branch information
chimurai committed May 2, 2021
1 parent 76ce96e commit 9d5a4fd
Showing 1 changed file with 89 additions and 97 deletions.
186 changes: 89 additions & 97 deletions test/e2e/websocket.spec.ts
Original file line number Diff line number Diff line change
@@ -1,153 +1,145 @@
import * as http from 'http';
import * as express from 'express';
import * as WebSocket from 'ws';
// tslint:disable-next-line: no-duplicate-imports
import { Server as WebSocketServer } from 'ws';
import { createProxyMiddleware } from './test-kit';
import { createProxyMiddleware, createApp } from './test-kit';
import type { RequestHandler } from '../../src/types';

/********************************************************************
* - Not possible to use `supertest` to test WebSockets
* - Make sure to use different port for each test to avoid flakiness
********************************************************************/

describe('E2E WebSocket proxy', () => {
let proxyServer: http.Server;
let ws;
let wss;
let responseMessage;
let proxy;
let ws: WebSocket;
let wss: WebSocketServer;
let proxyMiddleware: RequestHandler;
const WS_SERVER_PORT = 9000;

beforeEach(() => {
proxy = createProxyMiddleware('/', {
target: 'http://localhost:9000',
ws: true,
pathRewrite: { '^/socket': '' },
});

proxyServer = express().use(proxy).listen(3000);

wss = new WebSocketServer({ port: 9000 });
wss = new WebSocketServer({ port: WS_SERVER_PORT });

wss.on('connection', function connection(websocket) {
websocket.on('message', function incoming(message) {
wss.on('connection', (websocket) => {
websocket.on('message', (message) => {
websocket.send(message); // echo received message
});
});
});

afterEach((done) => {
proxyServer.close(() => {
done();
beforeEach(() => {
proxyMiddleware = createProxyMiddleware('/', {
target: `http://localhost:${WS_SERVER_PORT}`,
ws: true,
pathRewrite: { '^/socket': '' },
});
wss.close();
ws = null;
});

afterEach(async () => {
return Promise.all([
new Promise((resolve) => proxyServer.close(resolve)),
new Promise((resolve) => wss.close(resolve)),
new Promise((resolve) => resolve(ws.close())),
]);
});

describe('option.ws', () => {
beforeEach((done) => {
// need to make a normal http request,
// so http-proxy-middleware can catch the upgrade request
http.get('http://localhost:3000/', () => {
// do a second http request to make
// sure only 1 listener subscribes to upgrade request
http.get('http://localhost:3000/', () => {
ws = new WebSocket('ws://localhost:3000/socket');

ws.on('message', function incoming(message) {
responseMessage = message;
done();
});

ws.on('open', function open() {
ws.send('foobar');
});
});
});
beforeEach(async (done) => {
const SERVER_PORT = 31000;
proxyServer = createApp(proxyMiddleware).listen(SERVER_PORT);

// quick & dirty Promise version of http.get (don't care about correctness)
const get = async (uri) => new Promise((resolve, reject) => http.get(uri, resolve));

// need to make a normal http request, so http-proxy-middleware can catch the upgrade request
await get(`http://localhost:${SERVER_PORT}/`);
// do a second http request to make sure only 1 listener subscribes to upgrade request
await get(`http://localhost:${SERVER_PORT}/`);

ws = new WebSocket(`ws://localhost:${SERVER_PORT}/socket`);
ws.on('open', done);
});

it('should proxy to path', () => {
expect(responseMessage).toBe('foobar');
it('should proxy to path', (done) => {
ws.on('message', (message) => {
expect(message).toBe('foobar');
done();
});
ws.send('foobar');
});
});

describe('option.ws with external server "upgrade"', () => {
beforeEach((done) => {
proxyServer.on('upgrade', proxy.upgrade);
const SERVER_PORT = 32000;
proxyServer = createApp(proxyMiddleware).listen(SERVER_PORT);
proxyServer.on('upgrade', proxyMiddleware.upgrade);

ws = new WebSocket('ws://localhost:3000/socket');
ws = new WebSocket(`ws://localhost:${SERVER_PORT}/socket`);
ws.on('open', done);
});

ws.on('message', function incoming(message) {
responseMessage = message;
it('should proxy to path', async (done) => {
ws.on('message', (message) => {
expect(message).toBe('foobar');
done();
});

ws.on('open', function open() {
ws.send('foobar');
});
});

it('should proxy to path', () => {
expect(responseMessage).toBe('foobar');
ws.send('foobar');
});
});

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

// override
proxy = createProxyMiddleware('ws://localhost:9000', {
pathRewrite: { '^/socket': '' },
});
beforeEach(() => {
proxyServer = createApp(
createProxyMiddleware(`ws://localhost:${WS_SERVER_PORT}`, {
pathRewrite: { '^/socket': '' },
})
).listen(SERVER_PORT);

proxyServer = express().use(proxy).listen(3000);
proxyServer.on('upgrade', proxyMiddleware.upgrade);
});

beforeEach((done) => {
proxyServer.on('upgrade', proxy.upgrade);

ws = new WebSocket('ws://localhost:3000/socket');
ws = new WebSocket(`ws://localhost:${SERVER_PORT}/socket`);
ws.on('open', done);
});

ws.on('message', function incoming(message) {
responseMessage = message;
it('should proxy to path', (done) => {
ws.on('message', (message) => {
expect(message).toBe('foobar');
done();
});

ws.on('open', function open() {
ws.send('foobar');
});
});

it('should proxy to path', () => {
expect(responseMessage).toBe('foobar');
ws.send('foobar');
});
});

describe('with router and pathRewrite', () => {
beforeEach(() => {
proxyServer.close();
const SERVER_PORT = 34000;

beforeEach(() => {
// override
proxy = createProxyMiddleware('ws://notworkinghost:6789', {
router: { '/socket': 'ws://localhost:9000' },
pathRewrite: { '^/socket': '' },
});

proxyServer = express().use(proxy).listen(3000);
proxyServer = createApp(
createProxyMiddleware('ws://notworkinghost:6789', {
router: { '/socket': `ws://localhost:${WS_SERVER_PORT}` },
pathRewrite: { '^/socket': '' },
})
).listen(SERVER_PORT);

proxyServer.on('upgrade', proxyMiddleware.upgrade);
});

beforeEach((done) => {
proxyServer.on('upgrade', proxy.upgrade);

ws = new WebSocket('ws://localhost:3000/socket');
ws = new WebSocket(`ws://localhost:${SERVER_PORT}/socket`);
ws.on('open', done);
});

ws.on('message', function incoming(message) {
responseMessage = message;
it('should proxy to path', (done) => {
ws.on('message', (message) => {
expect(message).toBe('foobar');
done();
});

ws.on('open', function open() {
ws.send('foobar');
});
});

it('should proxy to path', () => {
expect(responseMessage).toBe('foobar');
ws.send('foobar');
});
});
});

0 comments on commit 9d5a4fd

Please sign in to comment.