Browse Source

add socket.io jasmine tests

romanmatiasko 9 years ago
parent
commit
1a63b49f1f
10 changed files with 245 additions and 20 deletions
  1. 1 1
      bin/www
  2. 0 0
      dist/js/play.js
  3. 17 11
      io.js
  4. 2 1
      package.json
  5. 209 0
      spec/io-spec.js
  6. 9 0
      spec/support/jasmine.json
  7. 1 1
      src/js/components/Chessboard.js
  8. 1 1
      src/js/components/Clock.js
  9. 2 2
      src/js/components/GameInterface.js
  10. 3 3
      winston.js

+ 1 - 1
bin/www

@@ -4,7 +4,7 @@
 
 require('babel/register');
 const app = require('../app');
-const io = require('../io');
+const io = require('../io').io;
 const debug = require('debug')('reti-chess:server');
 const port = process.env.PORT || '3000';
 const ip = process.env.IP || '127.0.0.1';

File diff suppressed because it is too large
+ 0 - 0
dist/js/play.js


+ 17 - 11
io.js

@@ -1,10 +1,11 @@
 'use strict';
 
-import IO from 'socket.io';
-import winston from './winston';
-import {Map, List} from 'immutable';
+const io = require('socket.io').listen();
+const winston = require('./winston');
+const Immutable = require('immutable');
+const Map = Immutable.Map;
+const List = Immutable.List;
 
-const io = IO.listen();
 var _games = Map();
 
 io.sockets.on('connection', socket => {
@@ -14,13 +15,13 @@ io.sockets.on('connection', socket => {
     const b = new Buffer(Math.random() + new Date().getTime() + socket.id);
     token = b.toString('base64').slice(12, 32);
 
-    // token is valid for 5 minutes
+    // token is valid for 3 minutes
     const timeout = setTimeout(() => {
       if (_games.getIn([token, 'players']).isEmpty()) {
         _games = _games.delete(token);
         socket.emit('token-expired');
       }
-    }, 5 * 60 * 1000);
+    }, 3 * 60 * 1000);
 
     _games = _games.set(token, Map({
       creator: socket,
@@ -91,6 +92,9 @@ io.sockets.on('connection', socket => {
     }
   });
 
+  socket.on('send-message', data =>
+    maybeEmit('receive-message', data, data.token, socket));
+
   socket.on('resign', data => {
     if (!_games.has(data.token)) return;
     clearInterval(_games.getIn([data.token, 'interval']));
@@ -106,7 +110,7 @@ io.sockets.on('connection', socket => {
   socket.on('rematch-decline', data =>
     maybeEmit('rematch-declined', {}, data.token, socket));
 
-  socket.on('rematch-confirm', data => {
+  socket.on('rematch-accept', data => {
     if (!_games.has(data.token)) return;
 
     _games = _games.updateIn([data.token, 'players'], players =>
@@ -115,7 +119,7 @@ io.sockets.on('connection', socket => {
         .set('inc', data.inc)
         .update('color', color => color === 'black' ? 'white' : 'black')));
 
-    io.sockets.in(data.token).emit('rematch-confirmed');
+    io.sockets.in(data.token).emit('rematch-accepted');
   });
 
   socket.on('disconnect', data => {
@@ -138,8 +142,6 @@ io.sockets.on('connection', socket => {
     }
   });
 
-  socket.on('send-message', data =>
-    maybeEmit('receive-message', data, data.token, socket));
 });
 
 function maybeEmit(event, data, token, socket) {
@@ -202,4 +204,8 @@ function getOpponent(token, socket) {
   }
 }
 
-export default io;
+module.exports = {
+  io: io,
+  // used for jasmine tests
+  getGames: () => _games
+};

+ 2 - 1
package.json

@@ -3,7 +3,7 @@
   "version": "0.3.0",
   "scripts": {
     "start": "node --harmony ./bin/www",
-    "test": "jest",
+    "test": "node --harmony ./node_modules/jasmine/bin/jasmine.js && jest",
     "build": "NODE_ENV=development gulp",
     "deploy": "NODE_ENV=production gulp"
   },
@@ -38,6 +38,7 @@
     "gulp-streamify": "0.0.5",
     "gulp-uglify": "^1.1.0",
     "gulp-util": "^3.0.4",
+    "jasmine": "^2.2.1",
     "jest-cli": "^0.4.0",
     "lodash.omit": "^3.0.0",
     "react": "^0.13.0",

+ 209 - 0
spec/io-spec.js

@@ -0,0 +1,209 @@
+const server = require('../io');
+const client = require('socket.io-client');
+const url = 'http://127.0.0.1:5000';
+const options = {
+  transports: ['websocket'],
+  'force new connection': true
+};
+
+server.io.listen(5000);
+
+var p1, p2, p3, c1, c2, games, token;
+
+function getGames() {
+  games = server.getGames();
+}
+
+describe('Socket.IO', () => {
+  
+  it('should create new game', done => {
+    p1 = client.connect(url, options);
+
+    p1.on('connect', data => {
+      p1.emit('start');
+    });
+
+    p1.on('created', data => {
+      getGames();
+      token = data.token;
+      expect(games.has(token)).toBeTruthy();
+      expect(games.getIn([token, 'players']).isEmpty()).toBeTruthy();
+      expect(games.getIn([token, 'timeout'])).toBeDefined();
+      done();
+    });
+  });
+
+  it('should join player to the game and emit events to both of them', done => {
+    p2 = client.connect(url, options);
+
+    p2.on('connect', data => {
+      p2.emit('join', {
+        token: token,
+        time: 10 * 60,
+        inc: 5
+      });
+    });
+
+    p1.on('ready', () => {
+      p1.emit('join', {
+        token: token,
+        time: 10 * 60,
+        inc: 5
+      });
+    });
+
+    p1.on('joined', data => {
+      c1 = data.color;
+      expect(data.color === 'white' || data.color === 'black').toBeTruthy();
+    });
+
+    p2.on('joined', data => {
+      c2 = data.color;
+      expect(data.color === 'white' || data.color === 'black').toBeTruthy();
+    });
+
+    p1.on('both-joined', data => {
+      getGames();
+      var players = games.getIn([token, 'players']);
+      expect(games.size).toBe(1);
+      expect(players.size).toBe(2);
+      expect(players.getIn([0, 'color']) !== players.getIn([1, 'color']))
+        .toBeTruthy();
+      expect(players.getIn([0, 'inc'])).toBe(5);
+      done();
+    });
+  });
+
+  it('should emit that game is full to third player', done => {
+    p3 = client.connect(url, options);
+
+    p3.on('connect', data => {
+      p3.emit('join', {
+        token: token,
+        time: 10,
+        inc: 5
+      });
+    });
+
+    p3.on('full', () => {
+      getGames();
+      expect(games.getIn([token, 'players']).size).toBe(2);
+      done();
+    });
+  });
+
+  it('should run clock', done => {
+    p1.emit('clock-run', {
+      token: token,
+      color: c1
+    });
+
+    p1.on('countdown', data => {
+      expect(data.color).toBe(c1);
+      expect(data.time).toBe(600);
+      done();
+    });
+  });
+
+  it('should make new move', done => {
+    p1.emit('new-move', {
+      token: token,
+      color: c1,
+      move: {
+        from: 'd2',
+        to: 'd4',
+        capture: undefined,
+        gameOver: false
+      },
+    });
+
+    p2.on('move', data => {
+      expect(data.from).toBe('d2');
+      expect(data.to).toBe('d4');
+      expect(data.gameOver).toBeFalsy();
+      done();
+    });
+  });
+
+  it('should send and receive messages', done => {
+    p1.emit('send-message', {
+      token: token,
+      color: c1,
+      message: 'hi there'
+    });
+
+    p2.on('receive-message', data => {
+      expect(data.message).toBe('hi there');
+      p2.emit('send-message', {
+        token: token,
+        color: c2,
+        message: 'hello!'
+      });
+    });
+
+    p1.on('receive-message', data => {
+      expect(data.message).toBe('hello!');
+      done();
+    });
+  });
+
+  it('should resign the game', done => {
+    p2.emit('resign', {
+      token: token,
+      color: c2
+    });
+
+    p1.on('player-resigned', data => {
+      expect(data.color).toBe(c2);
+      done();
+    });
+  });
+
+  it('should offer rematch and decline', done => {
+    p1.emit('rematch-offer', {
+      token: token
+    });
+
+    p2.on('rematch-offered', () => {
+      p2.emit('rematch-decline', {
+        token: token
+      });
+    });
+
+    p1.on('rematch-declined', () => {
+      done();
+    });
+  });
+
+  it('should offer rematch and accept', done => {
+    p1.emit('rematch-offer', {
+      token: token
+    });
+
+    p2.on('rematch-offered', () => {
+      p2.emit('rematch-accept', {
+        token: token,
+        time: 10 * 60,
+        inc: 5
+      });
+    });
+
+    p1.on('rematch-accepted', () => {
+      getGames();
+      expect(games.getIn([token, 'players', 0, 'time'])).toBe(600 - 5 + 1);
+      expect(games.getIn([token, 'players', 1, 'time'])).toBe(600 - 5 + 1);
+      done();
+    });
+  });
+
+  it('should disconnect player and delete game', done => {
+    p2.disconnect();
+
+    p1.on('opponent-disconnected', () => {
+      getGames();
+      expect(games.size).toBe(0);
+      done();
+    });
+  });
+
+});

+ 9 - 0
spec/support/jasmine.json

@@ -0,0 +1,9 @@
+{
+  "spec_dir": "spec",
+  "spec_files": [
+    "**/*[sS]pec.js"
+  ],
+  "helpers": [
+    "helpers/**/*.js"
+  ]
+}

+ 1 - 1
src/js/components/Chessboard.js

@@ -55,7 +55,7 @@ const Chessboard = React.createClass({
       }
     });
 
-    io.on('rematch-confirmed', () => this.setState({moveFrom: null}));
+    io.on('rematch-accepted', () => this.setState({moveFrom: null}));
   },
   componentWillUnmount() {
     GameStore.off('change', this._onGameChange);

+ 1 - 1
src/js/components/Clock.js

@@ -39,7 +39,7 @@ const Clock = React.createClass({
       });
     });
 
-    io.on('rematch-confirmed', () => {
+    io.on('rematch-accepted', () => {
       this.setState({
         white: this.props.params[1] * 60,
         black: this.props.params[1] * 60

+ 2 - 2
src/js/components/GameInterface.js

@@ -85,7 +85,7 @@ const GameInterface = React.createClass({
     io.on('rematch-declined', () =>
       this._openModal('info', 'Rematch offer has been declined.'));
 
-    io.on('rematch-confirmed', () => {
+    io.on('rematch-accepted', () => {
       GameActions.rematch();
       this.setState({
         color: this.state.color === 'white' ? 'black' : 'white',
@@ -169,7 +169,7 @@ const GameInterface = React.createClass({
   _acceptRematch() {
     const {io, params} = this.props;
 
-    io.emit('rematch-confirm', {
+    io.emit('rematch-accept', {
       token: params[0],
       time: params[1] * 60,
       inc: params[2]

+ 3 - 3
winston.js

@@ -1,7 +1,7 @@
 'use strict';
 
-import path from 'path';
-import winston from 'winston';
+const path = require('path');
+const winston = require('winston');
  
 winston.add(winston.transports.File, {
   filename: path.join(__dirname, 'logs/games.log'),
@@ -13,4 +13,4 @@ winston.remove(winston.transports.Console);
 winston.handleExceptions(new winston.transports.Console());
 winston.exitOnError = false;
 
-export default winston;
+module.exports = winston;

Some files were not shown because too many files changed in this diff