Skip to content

Commit 68c07ba

Browse files
committed
test(server): added mock server implementation tests
1 parent f29ef95 commit 68c07ba

File tree

2 files changed

+236
-75
lines changed

2 files changed

+236
-75
lines changed

test/server/__snapshots__/serverMode-option.test.js.snap

Lines changed: 75 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -8,10 +8,84 @@ Array [
88
]
99
`;
1010

11-
exports[`serverMode option without a header results in an error 1`] = `
11+
exports[`serverMode option passed to server without a header results in an error 1`] = `
1212
Array [
1313
"open",
1414
"{\\"type\\":\\"error\\",\\"data\\":\\"Invalid Host/Origin header\\"}",
1515
"close",
1616
]
1717
`;
18+
19+
exports[`serverMode option server should close client with bad headers 1`] = `
20+
Array [
21+
Array [
22+
[Function],
23+
],
24+
]
25+
`;
26+
27+
exports[`serverMode option server should close client with bad headers 2`] = `
28+
Array [
29+
Array [
30+
Object {
31+
"foo": "bar",
32+
},
33+
"{\\"type\\":\\"error\\",\\"data\\":\\"Invalid Host/Origin header\\"}",
34+
],
35+
]
36+
`;
37+
38+
exports[`serverMode option server should close client with bad headers 3`] = `
39+
Array [
40+
Array [
41+
Object {
42+
"foo": "bar",
43+
},
44+
],
45+
]
46+
`;
47+
48+
exports[`serverMode option server should use server implementation correctly 1`] = `
49+
Array [
50+
Object {
51+
"foo": "bar",
52+
},
53+
]
54+
`;
55+
56+
exports[`serverMode option server should use server implementation correctly 2`] = `
57+
Array [
58+
Array [
59+
[Function],
60+
],
61+
]
62+
`;
63+
64+
exports[`serverMode option server should use server implementation correctly 3`] = `
65+
Array [
66+
Object {
67+
"foo": "bar",
68+
},
69+
"{\\"type\\":\\"liveReload\\"}",
70+
]
71+
`;
72+
73+
exports[`serverMode option server should use server implementation correctly 4`] = `
74+
Array [
75+
Object {
76+
"foo": "bar",
77+
},
78+
"{\\"type\\":\\"ok\\"}",
79+
]
80+
`;
81+
82+
exports[`serverMode option server should use server implementation correctly 5`] = `
83+
Array [
84+
Array [
85+
Object {
86+
"foo": "bar",
87+
},
88+
[Function],
89+
],
90+
]
91+
`;

test/server/serverMode-option.test.js

Lines changed: 161 additions & 74 deletions
Original file line numberDiff line numberDiff line change
@@ -224,12 +224,103 @@ describe('serverMode option', () => {
224224
serverMode: '/bad/path/to/implementation',
225225
port,
226226
},
227-
() => {}
227+
() => { }
228228
);
229229
}).toThrow(/serverMode must be a string/);
230230
});
231231
});
232232

233+
describe('without a header', () => {
234+
let mockWarn;
235+
beforeAll((done) => {
236+
server = testServer.start(
237+
config,
238+
{
239+
port,
240+
serverMode: class MySockJSServer extends BaseServer {
241+
constructor(serv) {
242+
super(serv);
243+
this.socket = sockjs.createServer({
244+
// Use provided up-to-date sockjs-client
245+
sockjs_url: '/__webpack_dev_server__/sockjs.bundle.js',
246+
// Limit useless logs
247+
log: (severity, line) => {
248+
if (severity === 'error') {
249+
this.server.log.error(line);
250+
} else {
251+
this.server.log.debug(line);
252+
}
253+
},
254+
});
255+
256+
this.socket.installHandlers(this.server.listeningApp, {
257+
prefix: this.server.sockPath,
258+
});
259+
}
260+
261+
send(connection, message) {
262+
connection.write(message);
263+
}
264+
265+
close(connection) {
266+
connection.close();
267+
}
268+
269+
onConnection(f) {
270+
this.socket.on('connection', (connection) => {
271+
f(connection);
272+
});
273+
}
274+
275+
onConnectionClose(connection, f) {
276+
connection.on('close', f);
277+
}
278+
},
279+
},
280+
done
281+
);
282+
283+
mockWarn = jest.spyOn(server.log, 'warn').mockImplementation(() => { });
284+
});
285+
286+
it('results in an error', (done) => {
287+
const data = [];
288+
const client = new SockJS(`http://localhost:${port}/sockjs-node`);
289+
290+
client.onopen = () => {
291+
data.push('open');
292+
};
293+
294+
client.onmessage = (e) => {
295+
data.push(e.data);
296+
};
297+
298+
client.onclose = () => {
299+
data.push('close');
300+
};
301+
302+
setTimeout(() => {
303+
expect(data).toMatchSnapshot();
304+
const calls = mockWarn.mock.calls;
305+
mockWarn.mockRestore();
306+
307+
let foundWarning = false;
308+
const regExp = /serverMode implementation must pass headers to the callback of onConnection\(f\)/;
309+
calls.every((call) => {
310+
if (regExp.test(call)) {
311+
foundWarning = true;
312+
return false;
313+
}
314+
return true;
315+
});
316+
317+
expect(foundWarning).toBeTruthy();
318+
319+
done();
320+
}, 5000);
321+
});
322+
});
323+
233324
describe('with a bad host header', () => {
234325
beforeAll((done) => {
235326
server = testServer.start(
@@ -306,94 +397,90 @@ describe('serverMode option', () => {
306397
});
307398
});
308399

309-
describe('without a header', () => {
310-
let mockWarn;
311-
beforeAll((done) => {
312-
server = testServer.start(
400+
describe('server', () => {
401+
let MockSockJSServer;
402+
beforeEach((done) => {
403+
jest.mock('../../lib/servers/SockJSServer');
404+
// eslint-disable-next-line global-require
405+
mockedTestServer = require('../helpers/test-server');
406+
// eslint-disable-next-line global-require
407+
MockSockJSServer = require('../../lib/servers/SockJSServer');
408+
409+
server = mockedTestServer.start(
313410
config,
314411
{
315412
port,
316-
serverMode: class MySockJSServer extends BaseServer {
317-
constructor(serv) {
318-
super(serv);
319-
this.socket = sockjs.createServer({
320-
// Use provided up-to-date sockjs-client
321-
sockjs_url: '/__webpack_dev_server__/sockjs.bundle.js',
322-
// Limit useless logs
323-
log: (severity, line) => {
324-
if (severity === 'error') {
325-
this.server.log.error(line);
326-
} else {
327-
this.server.log.debug(line);
328-
}
329-
},
330-
});
331-
332-
this.socket.installHandlers(this.server.listeningApp, {
333-
prefix: this.server.sockPath,
334-
});
335-
}
336-
337-
send(connection, message) {
338-
connection.write(message);
339-
}
340-
341-
close(connection) {
342-
connection.close();
343-
}
344-
345-
onConnection(f) {
346-
this.socket.on('connection', (connection) => {
347-
f(connection);
348-
});
349-
}
350-
351-
onConnectionClose(connection, f) {
352-
connection.on('close', f);
353-
}
354-
},
355413
},
356414
done
357415
);
358-
359-
mockWarn = jest.spyOn(server.log, 'warn').mockImplementation(() => {});
360416
});
361417

362-
it('results in an error', (done) => {
363-
const data = [];
364-
const client = new SockJS(`http://localhost:${port}/sockjs-node`);
418+
afterEach((done) => {
419+
mockedTestServer.close(done);
420+
jest.resetAllMocks();
421+
jest.resetModules();
365422

366-
client.onopen = () => {
367-
data.push('open');
368-
};
423+
server = null;
424+
});
369425

370-
client.onmessage = (e) => {
371-
data.push(e.data);
372-
};
426+
it('should use server implementation correctly', () => {
427+
const mockServerInstance = MockSockJSServer.mock.instances[0];
373428

374-
client.onclose = () => {
375-
data.push('close');
429+
const connectionObj = {
430+
foo: 'bar',
376431
};
432+
// this simulates a client connecting to the server
433+
mockServerInstance.onConnection.mock.calls[0][0](connectionObj, {
434+
host: `localhost:${port}`,
435+
origin: `http://localhost:${port}`,
436+
});
377437

378-
setTimeout(() => {
379-
expect(data).toMatchSnapshot();
380-
const calls = mockWarn.mock.calls;
381-
mockWarn.mockRestore();
382-
383-
let foundWarning = false;
384-
const regExp = /serverMode implementation must pass headers to the callback of onConnection\(f\)/;
385-
calls.every((call) => {
386-
if (regExp.test(call)) {
387-
foundWarning = true;
388-
return false;
389-
}
390-
return true;
391-
});
438+
expect(server.sockets.length).toEqual(1);
439+
expect(server.sockets).toMatchSnapshot();
440+
441+
// this simulates a client leaving the server
442+
mockServerInstance.onConnectionClose.mock.calls[0][1](connectionObj);
443+
444+
expect(server.sockets.length).toEqual(0);
445+
446+
// check that the dev server was passed to the socket server implementation constructor
447+
expect(MockSockJSServer.mock.calls[0].length).toEqual(1);
448+
expect(MockSockJSServer.mock.calls[0][0].options.port).toEqual(port);
449+
450+
expect(mockServerInstance.onConnection.mock.calls).toMatchSnapshot();
451+
expect(mockServerInstance.send.mock.calls.length).toEqual(3);
452+
// call 0 to the send() method is liveReload
453+
expect(mockServerInstance.send.mock.calls[0]).toMatchSnapshot();
454+
// call 1 to the send() method is hash data, so we skip it
455+
// call 2 to the send() method is the "ok" message
456+
expect(mockServerInstance.send.mock.calls[2]).toMatchSnapshot();
457+
// close should not be called because the server never forcefully closes
458+
// a successful client connection
459+
expect(mockServerInstance.close.mock.calls.length).toEqual(0);
460+
expect(mockServerInstance.onConnectionClose.mock.calls).toMatchSnapshot();
461+
});
392462

393-
expect(foundWarning).toBeTruthy();
463+
it('should close client with bad headers', () => {
464+
const mockServerInstance = MockSockJSServer.mock.instances[0];
394465

395-
done();
396-
}, 5000);
466+
// this simulates a client connecting to the server
467+
mockServerInstance.onConnection.mock.calls[0][0](
468+
{
469+
foo: 'bar',
470+
},
471+
{
472+
host: null,
473+
}
474+
);
475+
expect(server.sockets.length).toEqual(0);
476+
expect(MockSockJSServer.mock.calls[0].length).toEqual(1);
477+
expect(MockSockJSServer.mock.calls[0][0].options.port).toEqual(port);
478+
expect(mockServerInstance.onConnection.mock.calls).toMatchSnapshot();
479+
// the only call to send() here should be an invalid header message
480+
expect(mockServerInstance.send.mock.calls).toMatchSnapshot();
481+
expect(mockServerInstance.close.mock.calls).toMatchSnapshot();
482+
// onConnectionClose should never get called since the client should be closed first
483+
expect(mockServerInstance.onConnectionClose.mock.calls.length).toEqual(0);
397484
});
398485
});
399486
});

0 commit comments

Comments
 (0)