Commit 3716ff04 authored by Sami BENHAMICHE's avatar Sami BENHAMICHE
Browse files

Merge branch 'issue-7' into 'master'

Implement robot injector mechanism

Closes #7

See merge request !2
parents 48723b83 43a5f415
'use strict';
/**
* This file defines a mock for the mz/fs lib.
*
* It allows us to mock filesystem access during tests.
*
* To use it, call the `__setup` method before your tests and pass it a
* dictionary of { "filepath": "content"} that represent the filesystem to mock.
*
*/
const path = require('path');
const fs = jest.genMockFromModule('mz/fs');
let mockFiles = Object.create(null);
// This is a custom function that our tests can use during setup to specify
// what the files on the "mock" filesystem should look like when any of the
// `moz/fs` APIs are used.
fs.__setup = function(newMockFiles){
mockFiles = newMockFiles;
}
fs.readFile = function(filePath, ...rest) {
if(Object.keys(mockFiles).includes(filePath)){
return Promise.resolve(mockFiles[filePath]);
} else {
return Promise.reject(new Error('no such file or directory'));
}
};
fs.readdir = function(dirPath, ...rest) {
const res = Object.keys(mockFiles)
.filter(f => path.dirname(f) == dirPath)
.map(f => path.basename(f));
if(res.length != 0) {
return Promise.resolve(res);
} else {
return Promise.reject(new Error('no such file or directory')) ;
}
};
module.exports = fs;
const config = require('./config.json');
const webdriverio = require('webdriverio');
const fs = require('fs');
const runner = require('./lib/runner.js')(config.runner);
const controller = require('./lib/controller.js')('./client');
fs.readFile('robotClientController.js', 'utf8', (err,data) => {
if (err) {
controller.loadAll('controller', 'lib', 'robot')
.then(modules => {
let client = runner.run(modules, config.visio.url, 'test-bot');
})
.catch(err => {
console.error(err);
return;
}
let client = runner.run(data, config.visio.url, 'test-bot');
});
});
var room = arguments[0];
var name = arguments[1];
// This file is used to define the global `robotController` object that is used
// to expose the hubl.in services as an unified API to be used by the robot.
//
// It is the first file of the `controller` folder to be loaded in the client.
controller = {
const room = arguments[0];
const name = arguments[1];
robotController = {
$scope: angular.element(document.body).scope().$root,
chatService: angular.element(document.body).injector().get('chat'),
......@@ -15,12 +20,12 @@ controller = {
},
getRemoteStreams: () => {
let participants = controller.getParticipants();
let participants = robotController.getParticipants();
let res = {};
for(let i = 0; i < participants.length; i++){
let participant = participants[i];
try{
let mediaStream = controller.getRemoteStream(participant);
let mediaStream = robotController.getRemoteStream(participant);
if(mediaStream !== null){
res[participant] = mediaStream;
}
......@@ -33,17 +38,17 @@ controller = {
}
};
controller.$scope.$on('conferencestate:attendees:push', function(event, data) {
robotController.$scope.$on('conferencestate:attendees:push', function(event, data) {
console.log('### someone connected %j %j', event, data);
console.log('RemoteMediaStream %j', controller.getRemoteStream(data.easyrtcid));
controller.chatService.sendMessage({author: name, displayName: name, message: 'Hello!'});
console.log('RemoteMediaStream %j', robotController.getRemoteStream(data.easyrtcid));
robotController.chatService.sendMessage({author: name, displayName: name, message: 'Hello!'});
});
controller.$scope.$on('conferencestate:attendees:remove', function(event, data) {
robotController.$scope.$on('conferencestate:attendees:remove', function(event, data) {
console.log('### someone leaved %j %j', event, data);
controller.chatService.sendMessage({author: name, displayName: name, message: 'Goodbye!'});
robotController.chatService.sendMessage({author: name, displayName: name, message: 'Goodbye!'});
});
controller.$scope.$on('attendee:update', function(event, data){
robotController.$scope.$on('attendee:update', function(event, data){
console.log('### received update %j %j', event, data);
});
// populated by the different libraries loaded into the client.
//
// It is the first file of the `lib` folder to be loaded in the client.
robotLib = {
// populated at runtime
};
// This file is used to define the structure and the behavior of the robot.
//
// It is the first file of the `robot` folder to be loaded in the client.
robot = {
// TODO
};
'use strict';
const fs = require('mz/fs');
module.exports = root => {
const controller = {
load: (module) => new Promise((resolve, reject) => {
// first we read the file with the same name than the folder
fs.readFile(root + '/' + module + '/' + module + '.js', 'utf8')
.then(content => {
// then we read all the other files in the folder
fs.readdir(root + '/' + module)
.then(files => {
// remove the file we already read
files.splice(files.indexOf(module + '.js'), 1);
Promise.all(files.map(
f => fs.readFile(root + '/' + module + '/' + f, 'utf8')
))
.then(contents => {
// concatenate all the files and resolve
resolve([content].concat(contents));
})
.catch(err => { reject(err); });
})
.catch(err => { reject(err); });
})
.catch(err => { reject(err); });
}),
loadAll: (...modules) => new Promise((resolve, reject) => {
// load all the passed modules
Promise.all(
modules.map(f => controller.load(f)))
.then(values => {
// concatenate all the arrays into a single one
resolve(Array.prototype.concat.apply([], values));
}).catch(err => {
reject(err);
});
})
};
return controller;
};
'use strict';
jest.mock('mz/fs');
describe('loadModules', () => {
const MOCK_FILES = {
'/test/controller/controller.js': '1',
'/test/controller/test.js': '2',
'/test/lib/lib.js': '3',
'/test/robot/robot.js': '4',
'/test/notavalidmodule/test.js':'5'
};
beforeEach(() => {
require('mz/fs').__setup(MOCK_FILES);
});
describe('loading a module', () => {
test('should include all (and only) files in its dir.', (done) => {
const controller = require('./controller.js')('/test');
controller.load('controller')
.then(res => {
expect(res.length).toBe(2);
expect(res.includes('1')).toBeTruthy();
expect(res.includes('2')).toBeTruthy();
done();
});
});
test('should return the files in the correct order', (done) => {
const controller = require('./controller.js')('/test');
controller.load('controller')
.then(res => {
expect(res[0]).toBe('1');
expect(res[1]).toBe('2');
done();
});
});
test('should fail for a nonexistent module', (done) => {
const controller = require('./controller.js')('/test');
controller.load('nonexistent')
.catch(() => done());
});
test('should fail for a module missing its base file', (done) => {
const controller = require('./controller.js')('/test');
controller.load('notavalidmodule')
.catch(() => done());
});
});
describe('loading several modules', () => {
test('should include all files from all modules', (done) => {
const controller = require('./controller.js')('/test');
controller.loadAll('controller', 'lib', 'robot')
.then(res => {
expect(res.length).toBe(4);
expect(res.includes('1')).toBeTruthy();
expect(res.includes('2')).toBeTruthy();
expect(res.includes('3')).toBeTruthy();
expect(res.includes('4')).toBeTruthy();
done();
});
});
test('should return files in correct order', (done) => {
const controller = require('./controller.js')('/test');
controller.loadAll('controller', 'lib', 'robot')
.then(res => {
expect(res[0]).toBe('1');
expect(res[1]).toBe('2');
expect(res[2]).toBe('3');
expect(res[3]).toBe('4');
done();
});
});
test('should fail when trying to load a non-existent module ', (done) => {
const controller = require('./controller.js')('/test');
controller.loadAll('controller', 'lib', 'robot', 'nonexistent')
.catch(() => done());
});
test('should fail when trying to load an invalid module', (done) => {
const controller = require('./controller.js')('/test');
controller.loadAll('controller', 'lib', 'robot', 'invalid')
.catch(() => done());
});
});
});
let webdriverio = require('webdriverio');
const webdriverio = require('webdriverio');
module.exports = (config) => ({
run: (controller, server, room) => {
let client = webdriverio.remote(config.driver);
client.init()
run: (controllerFilesList, server, room) => {
const client = webdriverio.remote(config.driver);
return client.init()
.url(server + '/' + room)
.execute(controller, room, config.name) // injecting our controller
.then(() =>
Promise.all(controllerFilesList.map(f => client.execute(f, room, config.name))))
.waitForVisible('#displayname', 30000)
.setValue('#displayname', config.name)
.click('.btn')
.waitForExist('//div[@video-id="video-thumb8"]', 30000);
return client;
}
});
......@@ -5,10 +5,15 @@
"version": "0.0.1",
"main": "app.js",
"scripts":{
"start": "node app.js"
"start": "node app.js",
"test": "jest",
},
"dependencies":{
"webdriverio": "4.7.1"
"webdriverio": "4.7.1",
"mz": "2.6.0"
},
"devDependencies":{
"jest": "20.0.0"
},
"author": "Linagora Folks",
"license": "AGPL-3.0"
......
Markdown is supported
0% or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment