Skip to content

Commit

Permalink
feat(server): server mode ws string option
Browse files Browse the repository at this point in the history
  • Loading branch information
knagaitsev committed Jul 1, 2019
1 parent f984e53 commit 4c12f80
Show file tree
Hide file tree
Showing 3 changed files with 224 additions and 102 deletions.
5 changes: 4 additions & 1 deletion lib/utils/getSocketServerImplementation.js
Expand Up @@ -9,6 +9,9 @@ function getSocketServerImplementation(options) {
if (options.serverMode === 'sockjs') {
// eslint-disable-next-line global-require
ServerImplementation = require('../servers/SockJSServer');
} else if (options.serverMode === 'ws') {
// eslint-disable-next-line global-require
ServerImplementation = require('../servers/WebsocketServer');
} else {
try {
// eslint-disable-next-line global-require, import/no-dynamic-require
Expand All @@ -29,7 +32,7 @@ function getSocketServerImplementation(options) {

if (!serverImplFound) {
throw new Error(
"serverMode must be a string denoting a default implementation (e.g. 'sockjs'), a full path to " +
"serverMode must be a string denoting a default implementation (e.g. 'sockjs', 'ws'), a full path to " +
'a JS file which exports a class extending BaseServer (webpack-dev-server/lib/servers/BaseServer) ' +
'via require.resolve(...), or the class itself which extends BaseServer'
);
Expand Down
278 changes: 180 additions & 98 deletions test/server/serverMode-option.test.js
Expand Up @@ -7,134 +7,216 @@ const request = require('supertest');
const sockjs = require('sockjs');
const SockJSServer = require('../../lib/servers/SockJSServer');
const config = require('../fixtures/simple-config/webpack.config');
const testServer = require('../helpers/test-server');
const BaseServer = require('../../lib/servers/BaseServer');
const port = require('../ports-map')['serverMode-option'];

describe('serverMode option', () => {
let mockedTestServer;
let testServer;
let server;
let req;
let getSocketServerImplementation;

const serverModes = [
{
title: 'as a string ("sockjs")',
serverMode: 'sockjs',
},
{
title: 'as a path ("sockjs")',
serverMode: require.resolve('../../lib/servers/SockJSServer'),
},
{
title: 'as a string ("ws")',
serverMode: 'ws',
},
{
title: 'as a path ("ws")',
serverMode: require.resolve('../../lib/servers/WebsocketServer'),
},
{
title: 'as a class (custom implementation)',
serverMode: class CustomServer {},
},
{
title: 'as a nonexistent path',
serverMode: '/bad/path/to/implementation',
},
];

describe('is passed to getSocketServerImplementation correctly', () => {
beforeEach(() => {
jest.mock('../../lib/utils/getSocketServerImplementation');
// eslint-disable-next-line global-require
getSocketServerImplementation = require('../../lib/utils/getSocketServerImplementation');
getSocketServerImplementation.mockImplementation(() => {
return class MockServer {
// eslint-disable-next-line no-empty-function
onConnection() {}
};
});
});

afterEach((done) => {
testServer.close(done);
req = null;
server = null;
});
afterEach((done) => {
jest.resetAllMocks();
jest.resetModules();

describe('as a string ("sockjs")', () => {
beforeEach((done) => {
server = testServer.start(
config,
{
serverMode: 'sockjs',
port,
},
done
);
req = request(`http://localhost:${port}`);
mockedTestServer.close(done);
});

it('sockjs path responds with a 200', (done) => {
req.get('/sockjs-node').expect(200, done);
serverModes.forEach((data) => {
it(data.title, (done) => {
// eslint-disable-next-line global-require
mockedTestServer = require('../helpers/test-server');
mockedTestServer.start(
config,
{
serverMode: data.serverMode,
port,
},
() => {
expect(getSocketServerImplementation.mock.calls.length).toEqual(1);
expect(getSocketServerImplementation.mock.calls[0].length).toEqual(
1
);
expect(
getSocketServerImplementation.mock.calls[0][0].serverMode
).toEqual(data.serverMode);
done();
}
);
});
});
});

describe('as a path ("sockjs")', () => {
beforeEach((done) => {
server = testServer.start(
config,
{
serverMode: require.resolve('../../lib/servers/SockJSServer'),
port,
},
done
);
req = request(`http://localhost:${port}`);
describe('passed to server', () => {
beforeAll(() => {
jest.unmock('../../lib/utils/getSocketServerImplementation');
// eslint-disable-next-line global-require
testServer = require('../helpers/test-server');
});

it('sockjs path responds with a 200', (done) => {
req.get('/sockjs-node').expect(200, done);
afterEach((done) => {
testServer.close(done);
req = null;
server = null;
});
});

describe('as a class ("sockjs")', () => {
beforeEach((done) => {
server = testServer.start(
config,
{
serverMode: SockJSServer,
port,
},
done
);
req = request(`http://localhost:${port}`);
describe('as a string ("sockjs")', () => {
beforeEach((done) => {
server = testServer.start(
config,
{
serverMode: 'sockjs',
port,
},
done
);
req = request(`http://localhost:${port}`);
});

it('sockjs path responds with a 200', (done) => {
req.get('/sockjs-node').expect(200, done);
});
});

it('sockjs path responds with a 200', (done) => {
req.get('/sockjs-node').expect(200, done);
describe('as a path ("sockjs")', () => {
beforeEach((done) => {
server = testServer.start(
config,
{
serverMode: require.resolve('../../lib/servers/SockJSServer'),
port,
},
done
);
req = request(`http://localhost:${port}`);
});

it('sockjs path responds with a 200', (done) => {
req.get('/sockjs-node').expect(200, done);
});
});
});

describe('as a class (custom "sockjs" implementation)', () => {
it('uses supplied server implementation', (done) => {
server = testServer.start(
config,
{
port,
sockPath: '/foo/test/bar/',
serverMode: class MySockJSServer extends BaseServer {
constructor(serv) {
super(serv);
this.socket = sockjs.createServer({
// Use provided up-to-date sockjs-client
sockjs_url: '/__webpack_dev_server__/sockjs.bundle.js',
// Limit useless logs
log: (severity, line) => {
if (severity === 'error') {
this.server.log.error(line);
} else {
this.server.log.debug(line);
}
},
});

this.socket.installHandlers(this.server.listeningApp, {
prefix: this.server.sockPath,
});

expect(server.options.sockPath).toEqual('/foo/test/bar/');
}

send(connection, message) {
connection.write(message);
}

close(connection) {
connection.close();
}

onConnection(f) {
this.socket.on('connection', f);
}
describe('as a class ("sockjs")', () => {
beforeEach((done) => {
server = testServer.start(
config,
{
serverMode: SockJSServer,
port,
},
},
done
);
done
);
req = request(`http://localhost:${port}`);
});

it('sockjs path responds with a 200', (done) => {
req.get('/sockjs-node').expect(200, done);
});
});
});

describe('as a path with nonexistent path', () => {
it('should throw an error', () => {
expect(() => {
describe('as a class (custom "sockjs" implementation)', () => {
it('uses supplied server implementation', (done) => {
server = testServer.start(
config,
{
serverMode: '/bad/path/to/implementation',
port,
sockPath: '/foo/test/bar/',
serverMode: class MySockJSServer extends BaseServer {
constructor(serv) {
super(serv);
this.socket = sockjs.createServer({
// Use provided up-to-date sockjs-client
sockjs_url: '/__webpack_dev_server__/sockjs.bundle.js',
// Limit useless logs
log: (severity, line) => {
if (severity === 'error') {
this.server.log.error(line);
} else {
this.server.log.debug(line);
}
},
});

this.socket.installHandlers(this.server.listeningApp, {
prefix: this.server.sockPath,
});

expect(server.options.sockPath).toEqual('/foo/test/bar/');
}

send(connection, message) {
connection.write(message);
}

close(connection) {
connection.close();
}

onConnection(f) {
this.socket.on('connection', f);
}
},
},
() => {}
done
);
}).toThrow(/serverMode must be a string/);
});
});

describe('as a path with nonexistent path', () => {
it('should throw an error', () => {
expect(() => {
server = testServer.start(
config,
{
serverMode: '/bad/path/to/implementation',
port,
},
() => {}
);
}).toThrow(/serverMode must be a string/);
});
});
});
});
43 changes: 40 additions & 3 deletions test/server/utils/getSocketServerImplementation.test.js
Expand Up @@ -2,9 +2,10 @@

const getSocketServerImplementation = require('../../../lib/utils/getSocketServerImplementation');
const SockJSServer = require('../../../lib/servers/SockJSServer');
const WebsocketServer = require('../../../lib/servers/WebsocketServer');

describe('getSocketServerImplementation util', () => {
it("should works with string serverMode ('sockjs')", () => {
it("should work with string serverMode ('sockjs')", () => {
let result;

expect(() => {
Expand All @@ -16,7 +17,7 @@ describe('getSocketServerImplementation util', () => {
expect(result).toEqual(SockJSServer);
});

it('should works with serverMode (SockJSServer class)', () => {
it('should work with serverMode (SockJSServer class)', () => {
let result;

expect(() => {
Expand All @@ -40,7 +41,43 @@ describe('getSocketServerImplementation util', () => {
expect(result).toEqual(SockJSServer);
});

it('should throws with serverMode (bad path)', () => {
it("should work with string serverMode ('ws')", () => {
let result;

expect(() => {
result = getSocketServerImplementation({
serverMode: 'ws',
});
}).not.toThrow();

expect(result).toEqual(WebsocketServer);
});

it('should work with serverMode (WebsocketServer class)', () => {
let result;

expect(() => {
result = getSocketServerImplementation({
serverMode: WebsocketServer,
});
}).not.toThrow();

expect(result).toEqual(WebsocketServer);
});

it('should work with serverMode (WebsocketServer full path)', () => {
let result;

expect(() => {
result = getSocketServerImplementation({
serverMode: require.resolve('../../../lib/servers/WebsocketServer'),
});
}).not.toThrow();

expect(result).toEqual(WebsocketServer);
});

it('should throw with serverMode (bad path)', () => {
expect(() => {
getSocketServerImplementation({
serverMode: '/bad/path/to/implementation',
Expand Down

0 comments on commit 4c12f80

Please sign in to comment.