mirror of
https://github.com/darkwire/darkwire.io.git
synced 2025-07-18 10:49:02 +00:00
Better sanitation of chat messages, support for multiline messages, updated username change method
This commit is contained in:
parent
383999b766
commit
57cef2f44f
1
.gitignore
vendored
1
.gitignore
vendored
@ -1,3 +1,4 @@
|
|||||||
|
.DS_Store
|
||||||
node_modules
|
node_modules
|
||||||
npm-debug.log
|
npm-debug.log
|
||||||
src/public/main.js
|
src/public/main.js
|
||||||
|
@ -20,6 +20,6 @@ before_script:
|
|||||||
- "/sbin/start-stop-daemon --start --quiet --pidfile /tmp/custom_xvfb_99.pid --make-pidfile --background --exec /usr/bin/Xvfb -- :99 -ac -screen 0 1280x1024x16"
|
- "/sbin/start-stop-daemon --start --quiet --pidfile /tmp/custom_xvfb_99.pid --make-pidfile --background --exec /usr/bin/Xvfb -- :99 -ac -screen 0 1280x1024x16"
|
||||||
- sleep 5 # give xvfb some time to start
|
- sleep 5 # give xvfb some time to start
|
||||||
- gulp bundle
|
- gulp bundle
|
||||||
- node index.js &
|
- npm start &
|
||||||
- sleep 5
|
- sleep 5
|
||||||
script: node_modules/mocha/bin/mocha test/unit --compilers js:babel-core/register && node_modules/nightwatch/bin/nightwatch --test test/acceptance/index.js --config test/acceptance/nightwatch.json -e chrome
|
script: npm run test-travis
|
||||||
|
@ -62,7 +62,7 @@ gulp.task('test', function() {
|
|||||||
|
|
||||||
let acceptanceTest = spawn(
|
let acceptanceTest = spawn(
|
||||||
'node_modules/nightwatch/bin/nightwatch',
|
'node_modules/nightwatch/bin/nightwatch',
|
||||||
['--test', 'test/acceptance/index.js', '--config', 'test/acceptance/nightwatch.json'],
|
['--test', 'test/acceptance/index.js', '--config', 'test/acceptance/nightwatch-local.json'],
|
||||||
{stdio: 'inherit'}
|
{stdio: 'inherit'}
|
||||||
);
|
);
|
||||||
|
|
||||||
|
10
package.json
10
package.json
@ -12,6 +12,7 @@
|
|||||||
"forever": "^0.15.1",
|
"forever": "^0.15.1",
|
||||||
"gulp": "^3.9.0",
|
"gulp": "^3.9.0",
|
||||||
"gulp-uglify": "^1.5.1",
|
"gulp-uglify": "^1.5.1",
|
||||||
|
"he": "^0.5.0",
|
||||||
"moment": "^2.11.2",
|
"moment": "^2.11.2",
|
||||||
"mustache-express": "^1.2.2",
|
"mustache-express": "^1.2.2",
|
||||||
"sanitize-html": "^1.11.3",
|
"sanitize-html": "^1.11.3",
|
||||||
@ -39,13 +40,10 @@
|
|||||||
"vinyl-source-stream": "^1.1.0"
|
"vinyl-source-stream": "^1.1.0"
|
||||||
},
|
},
|
||||||
"scripts": {
|
"scripts": {
|
||||||
"dev": "gulp start",
|
"start": "npm run bundle && gulp start",
|
||||||
"test": "gulp test"
|
|
||||||
},
|
|
||||||
"scripts": {
|
|
||||||
"start": "gulp start",
|
|
||||||
"bundle": "gulp bundle",
|
"bundle": "gulp bundle",
|
||||||
"test": "gulp test"
|
"test": "npm run bundle && gulp test",
|
||||||
|
"test-travis": "node_modules/mocha/bin/mocha test/unit --compilers js:babel-core/register && node_modules/nightwatch/bin/nightwatch --test test/acceptance/index.js --config test/acceptance/nightwatch.json -e chrome"
|
||||||
},
|
},
|
||||||
"author": "Daniel Seripap",
|
"author": "Daniel Seripap",
|
||||||
"license": "MIT"
|
"license": "MIT"
|
||||||
|
@ -1,5 +1,7 @@
|
|||||||
# Darkwire.io
|
# Darkwire.io
|
||||||
|
|
||||||
|
[](https://travis-ci.org/seripap/darkwire.io) []()
|
||||||
|
|
||||||
Simple encrypted web chat. Powered by [socket.io](http://socket.io) and the [web cryptography API](https://developer.mozilla.org/en-US/docs/Web/API/Window/crypto).
|
Simple encrypted web chat. Powered by [socket.io](http://socket.io) and the [web cryptography API](https://developer.mozilla.org/en-US/docs/Web/API/Window/crypto).
|
||||||
|
|
||||||
### Installation
|
### Installation
|
||||||
@ -10,11 +12,12 @@ Simple encrypted web chat. Powered by [socket.io](http://socket.io) and the [web
|
|||||||
|
|
||||||
# Bundle JS files (for deployment)
|
# Bundle JS files (for deployment)
|
||||||
npm bundle
|
npm bundle
|
||||||
# Start a local instance of darkwire
|
# Running tests locally
|
||||||
|
brew install chromedriver # Installs chromedriver to /usr/local/bin
|
||||||
|
npm test
|
||||||
|
# Start a local instance of darkwire / for dev
|
||||||
npm start
|
npm start
|
||||||
|
|
||||||
Create a **.secret** file in the **/src** folder with a your session secret. It doesn't matter what it is- just keep it private.
|
|
||||||
|
|
||||||
Darkwire is now running on `http://localhost:3000`
|
Darkwire is now running on `http://localhost:3000`
|
||||||
|
|
||||||
### Deployment
|
### Deployment
|
||||||
|
@ -1,5 +1,6 @@
|
|||||||
import _ from 'underscore';
|
import _ from 'underscore';
|
||||||
import sanitizeHtml from 'sanitize-html';
|
import sanitizeHtml from 'sanitize-html';
|
||||||
|
import he from 'he';
|
||||||
|
|
||||||
export default class Chat {
|
export default class Chat {
|
||||||
constructor(darkwire, socket) {
|
constructor(darkwire, socket) {
|
||||||
@ -172,11 +173,10 @@ export default class Chat {
|
|||||||
return this.log('Username must start with a letter or number.', {error: true});
|
return this.log('Username must start with a letter or number.', {error: true});
|
||||||
}
|
}
|
||||||
|
|
||||||
this.darkwire.updateUsername(newUsername).then((socketData) => {
|
this.darkwire.updateUsername(window.username, newUsername).then((socketData) => {
|
||||||
let modifiedSocketData = {
|
let modifiedSocketData = {
|
||||||
username: window.username,
|
username: window.username,
|
||||||
newUsername: socketData.username,
|
newUsername: socketData.username
|
||||||
publicKey: socketData.publicKey
|
|
||||||
};
|
};
|
||||||
|
|
||||||
this.socket.emit('update user', modifiedSocketData);
|
this.socket.emit('update user', modifiedSocketData);
|
||||||
@ -302,7 +302,10 @@ export default class Chat {
|
|||||||
if (messageType === 'action') {
|
if (messageType === 'action') {
|
||||||
$usernameDiv.css('color','').prepend('*');
|
$usernameDiv.css('color','').prepend('*');
|
||||||
}
|
}
|
||||||
$messageBodyDiv.html(unescape(data.message));
|
let unescapedMessage = unescape(data.message);
|
||||||
|
let lineBreaks = /<br \/>/g;
|
||||||
|
unescapedMessage = unescapedMessage.replace(lineBreaks, '<br />');
|
||||||
|
$messageBodyDiv.html(unescapedMessage);
|
||||||
} else {
|
} else {
|
||||||
$messageBodyDiv.html(this.darkwire.addFileToQueue(data));
|
$messageBodyDiv.html(this.darkwire.addFileToQueue(data));
|
||||||
}
|
}
|
||||||
|
@ -51,12 +51,35 @@ export default class Darkwire {
|
|||||||
return this._connected;
|
return this._connected;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
get audio() {
|
||||||
|
return this._audio;
|
||||||
|
}
|
||||||
|
|
||||||
get users() {
|
get users() {
|
||||||
return this._users;
|
return this._users;
|
||||||
}
|
}
|
||||||
|
|
||||||
get audio() {
|
getUserById(id) {
|
||||||
return this._audio;
|
return _.findWhere(this._users, {id: id});
|
||||||
|
}
|
||||||
|
|
||||||
|
getUserByName(username) {
|
||||||
|
return _.findWhere(this._users, {username: username});
|
||||||
|
}
|
||||||
|
|
||||||
|
updateUser(data) {
|
||||||
|
return new Promise((resolve, reject) => {
|
||||||
|
let user = this.getUserById(data.id);
|
||||||
|
|
||||||
|
if (!user) {
|
||||||
|
return reject();
|
||||||
|
}
|
||||||
|
|
||||||
|
let oldUsername = user.username;
|
||||||
|
|
||||||
|
user.username = data.username;
|
||||||
|
resolve(oldUsername);
|
||||||
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
addUser(data) {
|
addUser(data) {
|
||||||
@ -97,9 +120,16 @@ export default class Darkwire {
|
|||||||
return this._users;
|
return this._users;
|
||||||
}
|
}
|
||||||
|
|
||||||
updateUsername(username) {
|
updateUsername(username, newUsername) {
|
||||||
|
let user = null;
|
||||||
|
|
||||||
return new Promise((resolve, reject) => {
|
return new Promise((resolve, reject) => {
|
||||||
|
if (newUsername) {
|
||||||
|
user = this.getUserByName(username);
|
||||||
|
}
|
||||||
|
|
||||||
if (username) {
|
if (username) {
|
||||||
|
if (!user) {
|
||||||
Promise.all([
|
Promise.all([
|
||||||
this._cryptoUtil.createPrimaryKeys()
|
this._cryptoUtil.createPrimaryKeys()
|
||||||
])
|
])
|
||||||
@ -118,6 +148,12 @@ export default class Darkwire {
|
|||||||
publicKey: exportedKeys[0]
|
publicKey: exportedKeys[0]
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
} else {
|
||||||
|
resolve({
|
||||||
|
username: newUsername,
|
||||||
|
publicKey: user.publicKey
|
||||||
|
});
|
||||||
|
}
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
@ -5,6 +5,7 @@ import CryptoUtil from './crypto';
|
|||||||
import Chat from './chat';
|
import Chat from './chat';
|
||||||
import moment from 'moment';
|
import moment from 'moment';
|
||||||
import sanitizeHtml from 'sanitize-html';
|
import sanitizeHtml from 'sanitize-html';
|
||||||
|
import he from 'he';
|
||||||
|
|
||||||
let fs = window.RequestFileSystem || window.webkitRequestFileSystem;
|
let fs = window.RequestFileSystem || window.webkitRequestFileSystem;
|
||||||
|
|
||||||
@ -61,25 +62,21 @@ $(function() {
|
|||||||
|
|
||||||
// Prevents input from having injected markup
|
// Prevents input from having injected markup
|
||||||
function cleanInput(input) {
|
function cleanInput(input) {
|
||||||
let message = sanitizeHtml(_.escape(input), {
|
input = input.replace(/\r?\n/g, '<br />');
|
||||||
allowedTags: ['b', 'i', 'em', 'strong', 'a'],
|
let sanitized = he.encode(input);
|
||||||
allowedAttributes: {
|
sanitized = Autolinker.link(sanitized);
|
||||||
'a': ['href']
|
return sanitized;
|
||||||
}
|
|
||||||
});
|
|
||||||
// let message = $('<div/>').html(input).text();
|
|
||||||
message = Autolinker.link(message);
|
|
||||||
return _.escape(message);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// Keyboard events
|
// Keyboard events
|
||||||
|
|
||||||
$window.keydown(function(event) {
|
$window.keydown(function(event) {
|
||||||
// When the client hits ENTER on their keyboard and chat message input is focused
|
// When the client hits ENTER on their keyboard and chat message input is focused
|
||||||
if (event.which === 13 && $('.inputMessage').is(':focus')) {
|
if (event.which === 13 && !event.shiftKey && $('.inputMessage').is(':focus')) {
|
||||||
handleMessageSending();
|
handleMessageSending();
|
||||||
socket.emit('stop typing');
|
socket.emit('stop typing');
|
||||||
chat.typing = false;
|
chat.typing = false;
|
||||||
|
event.preventDefault();
|
||||||
}
|
}
|
||||||
|
|
||||||
});
|
});
|
||||||
@ -107,7 +104,10 @@ $(function() {
|
|||||||
});
|
});
|
||||||
|
|
||||||
socket.on('user update', (data) => {
|
socket.on('user update', (data) => {
|
||||||
updateUser(data);
|
darkwire.updateUser(data).then((oldUsername) => {
|
||||||
|
chat.log(oldUsername + ' changed name to ' + data.username);
|
||||||
|
renderParticipantsList();
|
||||||
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
// Whenever the server emits 'new message', update the chat body
|
// Whenever the server emits 'new message', update the chat body
|
||||||
@ -227,20 +227,6 @@ $(function() {
|
|||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
function updateUser(data) {
|
|
||||||
let logMessage = data.username + ' changed name to ';
|
|
||||||
darkwire.removeUser(data);
|
|
||||||
|
|
||||||
data.username = data.newUsername;
|
|
||||||
logMessage += data.username;
|
|
||||||
let importKeysPromises = darkwire.addUser(data);
|
|
||||||
Promise.all(importKeysPromises).then(() => {
|
|
||||||
chat.log(logMessage);
|
|
||||||
renderParticipantsList();
|
|
||||||
});
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
window.triggerFileTransfer = function(context) {
|
window.triggerFileTransfer = function(context) {
|
||||||
const fileId = context.getAttribute('data-file');
|
const fileId = context.getAttribute('data-file');
|
||||||
if (fileId) {
|
if (fileId) {
|
||||||
|
@ -31,7 +31,6 @@ export default class WindowHandler {
|
|||||||
|
|
||||||
enableFileTransfer() {
|
enableFileTransfer() {
|
||||||
if (this.fileHandler.isSupported) {
|
if (this.fileHandler.isSupported) {
|
||||||
console.log('enabled');
|
|
||||||
$('#send-file').click((e) => {
|
$('#send-file').click((e) => {
|
||||||
e.preventDefault();
|
e.preventDefault();
|
||||||
$('#fileInput').trigger('click');
|
$('#fileInput').trigger('click');
|
||||||
|
@ -9,7 +9,7 @@ html {
|
|||||||
-webkit-font-smoothing: antialiased;
|
-webkit-font-smoothing: antialiased;
|
||||||
}
|
}
|
||||||
|
|
||||||
html, body, input {
|
html, body, input, textarea {
|
||||||
font-family:
|
font-family:
|
||||||
"SourceCodePro-Regular",
|
"SourceCodePro-Regular",
|
||||||
"HelveticaNeue-Light",
|
"HelveticaNeue-Light",
|
||||||
@ -160,6 +160,10 @@ input {
|
|||||||
font-size: 16px;
|
font-size: 16px;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
textarea {
|
||||||
|
font-size: 20px;
|
||||||
|
}
|
||||||
|
|
||||||
.log {
|
.log {
|
||||||
color: gray;
|
color: gray;
|
||||||
font-size: 70%;
|
font-size: 70%;
|
||||||
@ -196,19 +200,24 @@ input {
|
|||||||
|
|
||||||
/* Input */
|
/* Input */
|
||||||
|
|
||||||
|
.inputContainer {
|
||||||
|
position: fixed;
|
||||||
|
right: 0;
|
||||||
|
left: 0;
|
||||||
|
bottom: 0;
|
||||||
|
width: 100%;
|
||||||
|
padding-bottom: 10px;
|
||||||
|
}
|
||||||
|
|
||||||
.inputMessage{
|
.inputMessage{
|
||||||
background: black !important;
|
background: black !important;
|
||||||
color: white !important;
|
color: white !important;
|
||||||
border: none;
|
border: none;
|
||||||
border-top: 1px solid #282828;
|
border-top: 1px solid #282828;
|
||||||
bottom: 0;
|
|
||||||
height: 60px;
|
height: 60px;
|
||||||
left: 0;
|
|
||||||
outline: none;
|
outline: none;
|
||||||
padding-left: 10px;
|
|
||||||
position: fixed;
|
|
||||||
right: 0;
|
|
||||||
width: 100%;
|
width: 100%;
|
||||||
|
padding: 10px 75px 10px 10px;
|
||||||
/*Fix for inner shadow on iOS*/
|
/*Fix for inner shadow on iOS*/
|
||||||
-webkit-appearance: none;
|
-webkit-appearance: none;
|
||||||
border-radius: 0px;
|
border-radius: 0px;
|
||||||
@ -218,7 +227,7 @@ input {
|
|||||||
position: fixed;
|
position: fixed;
|
||||||
bottom: 0px;
|
bottom: 0px;
|
||||||
right: 0px;
|
right: 0px;
|
||||||
padding: 15px;
|
padding: 22px;
|
||||||
cursor: pointer;
|
cursor: pointer;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
76
src/public/vendor/autogrow.js
vendored
Normal file
76
src/public/vendor/autogrow.js
vendored
Normal file
@ -0,0 +1,76 @@
|
|||||||
|
(function($)
|
||||||
|
{
|
||||||
|
/**
|
||||||
|
* Auto-growing textareas; technique ripped from Facebook
|
||||||
|
*
|
||||||
|
*
|
||||||
|
* http://github.com/jaz303/jquery-grab-bag/tree/master/javascripts/jquery.autogrow-textarea.js
|
||||||
|
*/
|
||||||
|
$.fn.autogrow = function(options)
|
||||||
|
{
|
||||||
|
return this.filter('textarea').each(function()
|
||||||
|
{
|
||||||
|
var self = this;
|
||||||
|
var $self = $(self);
|
||||||
|
var minHeight = $self.height();
|
||||||
|
var noFlickerPad = $self.hasClass('autogrow-short') ? 0 : parseInt($self.css('lineHeight')) || 0;
|
||||||
|
var settings = $.extend({
|
||||||
|
preGrowCallback: null,
|
||||||
|
postGrowCallback: null
|
||||||
|
}, options );
|
||||||
|
|
||||||
|
var shadow = $('<div></div>').css({
|
||||||
|
position: 'absolute',
|
||||||
|
top: -10000,
|
||||||
|
left: -10000,
|
||||||
|
width: $self.width(),
|
||||||
|
fontSize: $self.css('fontSize'),
|
||||||
|
fontFamily: $self.css('fontFamily'),
|
||||||
|
fontWeight: $self.css('fontWeight'),
|
||||||
|
lineHeight: $self.css('lineHeight'),
|
||||||
|
resize: 'none',
|
||||||
|
'word-wrap': 'break-word'
|
||||||
|
}).appendTo(document.body);
|
||||||
|
|
||||||
|
var update = function(event)
|
||||||
|
{
|
||||||
|
var times = function(string, number)
|
||||||
|
{
|
||||||
|
for (var i=0, r=''; i<number; i++) r += string;
|
||||||
|
return r;
|
||||||
|
};
|
||||||
|
|
||||||
|
var val = self.value.replace(/&/g, '&')
|
||||||
|
.replace(/</g, '<')
|
||||||
|
.replace(/>/g, '>')
|
||||||
|
.replace(/\n$/, '<br/> ')
|
||||||
|
.replace(/\n/g, '<br/>')
|
||||||
|
.replace(/ {2,}/g, function(space){ return times(' ', space.length - 1) + ' ' });
|
||||||
|
|
||||||
|
// Did enter get pressed? Resize in this keydown event so that the flicker doesn't occur.
|
||||||
|
if (event && event.data && event.data.event === 'keydown' && event.keyCode === 13) {
|
||||||
|
val += '<br />';
|
||||||
|
}
|
||||||
|
|
||||||
|
shadow.css('width', $self.width());
|
||||||
|
shadow.html(val + (noFlickerPad === 0 ? '...' : '')); // Append '...' to resize pre-emptively.
|
||||||
|
|
||||||
|
var newHeight=Math.max(shadow.height() + noFlickerPad, minHeight);
|
||||||
|
if(settings.preGrowCallback!=null){
|
||||||
|
newHeight=settings.preGrowCallback($self,shadow,newHeight,minHeight);
|
||||||
|
}
|
||||||
|
|
||||||
|
$self.height(newHeight);
|
||||||
|
|
||||||
|
if(settings.postGrowCallback!=null){
|
||||||
|
settings.postGrowCallback($self);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
$self.change(update).keyup(update).keydown({event:'keydown'},update);
|
||||||
|
$(window).resize(update);
|
||||||
|
|
||||||
|
update();
|
||||||
|
});
|
||||||
|
};
|
||||||
|
})(jQuery);
|
23
src/room.js
23
src/room.js
@ -93,26 +93,21 @@ class Room {
|
|||||||
if (data.newUsername.length > 16) {
|
if (data.newUsername.length > 16) {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
this.users = _.without(this.users, socket.user);
|
let user = _.find(this.users, (users) => {
|
||||||
let modifiedUser = {
|
return users === socket.user;
|
||||||
id: socket.user.id,
|
});
|
||||||
username: data.newUsername,
|
|
||||||
publicKey: data.publicKey
|
|
||||||
};
|
|
||||||
|
|
||||||
this.users.push(modifiedUser);
|
if (user) {
|
||||||
|
user.username = data.newUsername;
|
||||||
socket.username = data.newUsername;
|
socket.username = user.username;
|
||||||
socket.user = modifiedUser;
|
socket.user = user;
|
||||||
|
|
||||||
thisIO.emit('user update', {
|
thisIO.emit('user update', {
|
||||||
|
username: socket.username,
|
||||||
id: socket.user.id,
|
id: socket.user.id,
|
||||||
username: data.username,
|
|
||||||
newUsername: data.newUsername,
|
|
||||||
publicKey: data.publicKey,
|
|
||||||
users: this.users,
|
|
||||||
timestamp: new Date()
|
timestamp: new Date()
|
||||||
});
|
});
|
||||||
|
}
|
||||||
|
|
||||||
});
|
});
|
||||||
|
|
||||||
|
@ -53,12 +53,14 @@
|
|||||||
</li>
|
</li>
|
||||||
</ul>
|
</ul>
|
||||||
</div>
|
</div>
|
||||||
<input class="inputMessage" placeholder="Type here..."/>
|
<div class="inputContainer">
|
||||||
|
<textarea class="inputMessage" placeholder="Type here..."/></textarea>
|
||||||
<div id="input-icons">
|
<div id="input-icons">
|
||||||
<span class="glyphicon glyphicon-file" id="send-file"></span>
|
<span class="glyphicon glyphicon-file" id="send-file"></span>
|
||||||
<input type="file" id="fileInput">
|
<input type="file" name="fileUploader" id="fileInput">
|
||||||
<span class="glyphicon glyphicon-send" id="send-message-btn" aria-hidden="true"></span>
|
<span class="glyphicon glyphicon-send" id="send-message-btn" aria-hidden="true"></span>
|
||||||
</div>
|
</div>
|
||||||
|
</div>
|
||||||
</li>
|
</li>
|
||||||
</ul>
|
</ul>
|
||||||
|
|
||||||
@ -173,6 +175,7 @@
|
|||||||
<script src="/vendor/bootstrap-switch.min.js"></script>
|
<script src="/vendor/bootstrap-switch.min.js"></script>
|
||||||
<script src="/vendor/web-crypto-shim.js"></script>
|
<script src="/vendor/web-crypto-shim.js"></script>
|
||||||
<script src="/vendor/fastclick-1.0.6.min.js"></script>
|
<script src="/vendor/fastclick-1.0.6.min.js"></script>
|
||||||
|
<script src="/vendor/autogrow.js"></script>
|
||||||
<script src="/main.js"></script>
|
<script src="/main.js"></script>
|
||||||
</body>
|
</body>
|
||||||
</html>
|
</html>
|
||||||
|
@ -1,7 +1,11 @@
|
|||||||
|
/*jshint -W030 */
|
||||||
|
import App from '../../package.json';
|
||||||
|
|
||||||
describe('Darkwire', () => {
|
describe('Darkwire', () => {
|
||||||
|
|
||||||
describe('starting a room', () => {
|
describe('Creating a room', () => {
|
||||||
|
|
||||||
|
var testingRoom = null;
|
||||||
let browser;
|
let browser;
|
||||||
|
|
||||||
before((client, done) => {
|
before((client, done) => {
|
||||||
@ -25,31 +29,31 @@ describe('Darkwire', () => {
|
|||||||
done();
|
done();
|
||||||
});
|
});
|
||||||
|
|
||||||
it('should show welcome modal', () => {
|
it('Should show welcome modal', () => {
|
||||||
browser
|
browser
|
||||||
.waitForElementVisible('#first-modal', 5000)
|
.waitForElementVisible('#first-modal', 5000)
|
||||||
.assert.containsText('#first-modal .modal-title', 'Welcome to darkwire.io');
|
.expect.element('#first-modal').to.be.visible;
|
||||||
});
|
});
|
||||||
|
|
||||||
it('should have correct header', () => {
|
it('Should be started with NPM', () => {
|
||||||
browser.expect.element('#first-modal .modal-title').text.to.equal('Welcome to darkwire.io');
|
browser.expect.element('#first-modal .modal-title').text.to.equal('Welcome to darkwire.io v' + App.version);
|
||||||
});
|
});
|
||||||
|
|
||||||
describe('opening a second window', () => {
|
describe('Joining chat room', () => {
|
||||||
|
|
||||||
before((client, done) => {
|
before((client, done) => {
|
||||||
browser.url((result) => {
|
browser.url((result) => {
|
||||||
let urlSplit = result.value.split('/');
|
let urlSplit = result.value.split('/');
|
||||||
let roomId = urlSplit[urlSplit.length - 1];
|
testingRoom = urlSplit[urlSplit.length - 1];
|
||||||
let url = 'http://localhost:3000/' + roomId;
|
let url = 'http://localhost:3000/' + testingRoom;
|
||||||
browser.execute(() => {
|
browser.execute(() => {
|
||||||
window.open('http://localhost:3000/', '_blank');
|
window.open('http://localhost:3000/', '_blank');
|
||||||
}, [], () => {
|
}, [], () => {
|
||||||
browser.window_handles((result) => {
|
browser.windowHandles((result) => {
|
||||||
browser.switchWindow(result.value[1], () => {
|
browser.switchWindow(result.value[1], () => {
|
||||||
browser.execute((id) => {
|
browser.execute((id) => {
|
||||||
window.open('http://localhost:3000/' + id, '_self');
|
window.open('http://localhost:3000/' + id, '_self');
|
||||||
}, [roomId], () => {
|
}, [testingRoom], () => {
|
||||||
done();
|
done();
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
@ -58,25 +62,26 @@ describe('Darkwire', () => {
|
|||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
it('should not show welcome modal', () => {
|
it('Should not show welcome modal', () => {
|
||||||
browser.assert.hidden('#first-modal');
|
browser.assert.hidden('#first-modal');
|
||||||
});
|
});
|
||||||
|
|
||||||
describe('sending messages', () => {
|
describe('Sending chat message', () => {
|
||||||
|
|
||||||
before((client, done) => {
|
before((client, done) => {
|
||||||
browser.waitForElementPresent('ul.users li:nth-child(2)', 5000, () => {
|
browser.waitForElementPresent('ul.users li:nth-child(2)', 5000, () => {
|
||||||
browser.setValue('input.inputMessage', ['Hello world', browser.Keys.RETURN], () => {
|
browser.setValue('textarea.inputMessage', ['Hello world!', browser.Keys.RETURN], () => {
|
||||||
done();
|
done();
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
it('should work', () => {
|
it('Should send a message', () => {
|
||||||
browser.window_handles((result) => {
|
browser.windowHandles((result) => {
|
||||||
browser.switchWindow(result.value[0], () => {
|
browser.switchWindow(result.value[0], () => {
|
||||||
browser.waitForElementPresent('span.messageBody', 5000, () => {
|
browser.waitForElementPresent('span.messageBody', 5000, () => {
|
||||||
browser.assert.containsText('span.messageBody', 'Hello world');
|
browser.pause(2000);
|
||||||
|
browser.assert.containsText('span.messageBody', 'Hello world!');
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
@ -86,5 +91,129 @@ describe('Darkwire', () => {
|
|||||||
|
|
||||||
});
|
});
|
||||||
|
|
||||||
|
describe('Slash Commands', () => {
|
||||||
|
|
||||||
|
before((client, done) => {
|
||||||
|
let url = 'http://localhost:3000/' + testingRoom;
|
||||||
|
browser.url(url, () => {
|
||||||
|
browser.windowHandles((result) => {
|
||||||
|
browser.switchWindow(result.value[0], () => {
|
||||||
|
browser.execute((id) => {
|
||||||
|
window.open('http://localhost:3000/' + id, '_self');
|
||||||
|
}, [testingRoom], () => {
|
||||||
|
done();
|
||||||
|
});
|
||||||
|
});
|
||||||
|
});
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
describe('/me', () => {
|
||||||
|
|
||||||
|
before((client, done) => {
|
||||||
|
browser.windowHandles((result) => {
|
||||||
|
browser.switchWindow(result.value[0], () => {
|
||||||
|
browser.waitForElementPresent('ul.users li:nth-child(2)', 5000, () => {
|
||||||
|
browser.setValue('textarea.inputMessage', ['/me is no stranger to love', browser.Keys.RETURN], () => {
|
||||||
|
done();
|
||||||
|
});
|
||||||
|
});
|
||||||
|
});
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
it('Should express an interactive action', () => {
|
||||||
|
browser.windowHandles((result) => {
|
||||||
|
browser.switchWindow(result.value[0], () => {
|
||||||
|
browser.waitForElementPresent('span.messageBody', 5000, () => {
|
||||||
|
browser.pause(5000);
|
||||||
|
browser.assert.containsText('.action span.messageBody', 'is no stranger to love');
|
||||||
|
});
|
||||||
|
});
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
});
|
||||||
|
|
||||||
|
describe('/nick', () => {
|
||||||
|
|
||||||
|
before((client, done) => {
|
||||||
|
browser.url('http://localhost:3000/' + testingRoom, () => {
|
||||||
|
browser.waitForElementPresent('ul.users li:nth-child(2)', 5000, () => {
|
||||||
|
browser.setValue('textarea.inputMessage', ['/nick rickAnsley', browser.Keys.RETURN], () => {
|
||||||
|
done();
|
||||||
|
});
|
||||||
|
});
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
it('Should change username', () => {
|
||||||
|
browser.windowHandles((result) => {
|
||||||
|
browser.switchWindow(result.value[3], () => {
|
||||||
|
browser.pause(5000);
|
||||||
|
browser.assert.containsText('.log:last-child', 'rickAnsley');
|
||||||
|
});
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
});
|
||||||
|
|
||||||
|
});
|
||||||
|
|
||||||
|
describe('Before file transfer: Image: Confirm sending', () => {
|
||||||
|
|
||||||
|
before((client, done) => {
|
||||||
|
let url = 'http://localhost:3000/' + testingRoom;
|
||||||
|
browser.url(url, () => {
|
||||||
|
browser.windowHandles((result) => {
|
||||||
|
browser.switchWindow(result.value[0], () => {
|
||||||
|
browser.execute((id) => {
|
||||||
|
window.open('http://localhost:3000/' + id, '_self');
|
||||||
|
}, [testingRoom], () => {
|
||||||
|
browser.waitForElementPresent('#send-file', 5000, () => {
|
||||||
|
browser.execute(() => {
|
||||||
|
$('input[name="fileUploader"]').show();
|
||||||
|
}, [], () => {
|
||||||
|
browser.waitForElementPresent('input[name="fileUploader"]', 5000, () => {
|
||||||
|
let testFile = __dirname + '/ricky.jpg';
|
||||||
|
browser.setValue('input[name="fileUploader"]', testFile, (result) => {
|
||||||
|
done();
|
||||||
|
});
|
||||||
|
});
|
||||||
|
});
|
||||||
|
});
|
||||||
|
});
|
||||||
|
});
|
||||||
|
});
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
it('Should prompt user confirmation', () => {
|
||||||
|
browser.windowHandles((result) => {
|
||||||
|
browser.switchWindow(result.value[0], () => {
|
||||||
|
browser.waitForElementPresent('span.messageBody', 5000, () => {
|
||||||
|
browser.pause(5000);
|
||||||
|
browser.assert.containsText('span.messageBody', 'You are about to send ricky.jpg to all parties in this chat. Confirm | Cancel');
|
||||||
|
});
|
||||||
|
});
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
it('Should show sent confirmation message', () => {
|
||||||
|
browser.windowHandles((result) => {
|
||||||
|
browser.switchWindow(result.value[0], () => {
|
||||||
|
browser.waitForElementPresent('span.messageBody a:first-child', 5000, () => {
|
||||||
|
browser.click('span.messageBody a:first-child', () => {
|
||||||
|
browser.waitForElementNotPresent('span.messageBody a:first-child', 5000, () => {
|
||||||
|
browser.assert.containsText('span.messageBody', 'Sent ricky.jpg');
|
||||||
|
});
|
||||||
|
});
|
||||||
|
});
|
||||||
|
});
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
});
|
||||||
|
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
1
test/acceptance/fileUtility.js
Normal file
1
test/acceptance/fileUtility.js
Normal file
@ -0,0 +1 @@
|
|||||||
|
($('#fileInput').show)();
|
52
test/acceptance/nightwatch-local.json
Normal file
52
test/acceptance/nightwatch-local.json
Normal file
@ -0,0 +1,52 @@
|
|||||||
|
{
|
||||||
|
"src_folders" : ["test"],
|
||||||
|
"output_folder" : "reports",
|
||||||
|
"custom_commands_path" : "",
|
||||||
|
"custom_assertions_path" : "",
|
||||||
|
"page_objects_path" : "",
|
||||||
|
"globals_path" : "",
|
||||||
|
"test_runner" : "mocha",
|
||||||
|
"selenium" : {
|
||||||
|
"start_process" : true,
|
||||||
|
"server_path" : "test/acceptance/bin/selenium-server-standalone-2.52.0.jar",
|
||||||
|
"log_path" : false,
|
||||||
|
"host" : "127.0.0.1",
|
||||||
|
"port" : 4444,
|
||||||
|
"cli_args" : {
|
||||||
|
"webdriver.chrome.driver" : "/usr/local/bin/chromedriver",
|
||||||
|
"webdriver.ie.driver" : ""
|
||||||
|
}
|
||||||
|
},
|
||||||
|
|
||||||
|
"test_settings" : {
|
||||||
|
"default" : {
|
||||||
|
"launch_url" : "http://localhost",
|
||||||
|
"selenium_port" : 4444,
|
||||||
|
"selenium_host" : "localhost",
|
||||||
|
"silent": true,
|
||||||
|
"screenshots" : {
|
||||||
|
"enabled" : false,
|
||||||
|
"path" : ""
|
||||||
|
},
|
||||||
|
"desiredCapabilities": {
|
||||||
|
"browserName": "chrome",
|
||||||
|
"javascriptEnabled": true,
|
||||||
|
"acceptSslCerts": true,
|
||||||
|
"chromeOptions" : {
|
||||||
|
"binary": "/Applications/Google Chrome.app/Contents/MacOS/Google Chrome"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
|
||||||
|
"chrome" : {
|
||||||
|
"desiredCapabilities": {
|
||||||
|
"browserName": "chrome",
|
||||||
|
"javascriptEnabled": true,
|
||||||
|
"acceptSslCerts": true,
|
||||||
|
"chromeOptions" : {
|
||||||
|
"args" : ["-e", "--no-sandbox"]
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
BIN
test/acceptance/ricky.jpg
Normal file
BIN
test/acceptance/ricky.jpg
Normal file
Binary file not shown.
After Width: | Height: | Size: 44 KiB |
Loading…
x
Reference in New Issue
Block a user