Jean-Yves Didier

introduction off mocha testing infrastructure

This diff is collapsed. Click to expand it.
This diff is collapsed. Click to expand it.
......@@ -9,7 +9,9 @@
},
"main": "build/arcs.js",
"scripts": {
"test": "echo \"Error: no test specified\" && exit 1"
"build": "webpack --config-name core",
"doc": "webpack --config-name doc",
"test": "npx mocha"
},
"keywords": [
"Augmented Reality"
......@@ -29,13 +31,12 @@
"author": "Jean-Yves Didier",
"license": "GPL-3.0-or-later",
"devDependencies": {
"chai": "4.3.4",
"copy-webpack-plugin": "^9.0.1",
"eslint": "^8.7.0",
"eslint-webpack-plugin": "^3.0.1",
"jsdoc-webpack-plugin": "^0.3.0",
"mocha": "^9.1.4",
"val-loader": "^4.0.0"
},
"scripts": {
"build": "webpack --config-name core",
"doc": "webpack --config-name doc"
}
}
......
......@@ -26,7 +26,7 @@ var Component = {
* <li>A method returnung the signal list;</li>
* <li>An emit method, to trigger signals by their names;</li>
* <li>A slot method to cast an internal method to a slot;</li>
* <li>A signal mehtod to register a possible signal.</li>
* <li>A signal method to register a possible signal.</li>
* </ul>
* @param name {string} Class name to transform to a component
* @param sltList {string[]} names of functions designated as slots, may be empty.
......@@ -44,11 +44,11 @@ var Component = {
return name.prototype.slots;
};
name.prototype.slotList = function () {
return name.prototype.slots;
return this.slots;
};
name.prototype.signalList = function () {
var res = [], i;
for (i in name.prototype.signals) {
for (i in this.signals) {
res.push(i);
}
return res;
......@@ -65,6 +65,23 @@ var Component = {
func.apply(obj, args);
}
};
name.prototype.slot = function(slot, func) {
if (!this.hasOwnProperty('slots')) {
this.slots = name.prototype.slots.map(s => s);
}
this.slots.push(slot);
this[slot]= func;
};
name.prototype.signal = function(signal) {
if (!this.hasOwnProperty('signals')) {
this.signals = {};
Object.assign(this.signals, name.prototype.signals);
}
this.signals[signal]= 1;
};
name.slot = function (slot, func) {
var i;
if (slot instanceof Array) {
......@@ -127,10 +144,14 @@ var Component = {
throw Component.SourceIsNotComponent;
}
if (source.signals[signal] === undefined) {
throw Component.UndefinedSignal;
let e = Object.assign({}, Component.UndefinedSignal);
e.message = e.message + ": \"" + signal + "\"";
throw e;
}
if (destination[slt] === undefined) {
throw Component.UndefinedSlot;
let e = Object.assign({}, Component.UndefinedSlot);
e.message = e.message + ": \"" + slt + "\"";
throw e;
}
// we must also check if the signals dispose of their own implementation
if (!source.hasOwnProperty('signals')) {
......
......@@ -23,12 +23,11 @@ let StateMachine = Component.create(function (obj) {
var addToken = function(t) {
if ( self.slots.indexOf(t) < 0 ) {
self.slots.push(t);
self[t] = function( s ) {
self.slot(t, function( s ) {
return function() {
self.setToken(s);
};
} (t);
} (t));
}
};
......
import chai from 'chai';
import ARCS from '../build/arcs.js';
const expect = chai.expect;
let signalHandler = function(chai, utils) {
const MODULE = 'signalHandler';
const FLAG_EXPECTED_SIGNALS = MODULE + "#expectedSignals";
let isComponent = function(obj) {
return Array.isArray(obj.slots) &&
typeof obj.signals === 'object' &&
typeof obj.emit === 'function';
};
chai.Assertion.addProperty('component', function() {
this.assert(
isComponent(this._obj),
"expected #{this} to have signals and slots",
"expected #{this} no to have signals and slots"
);
});
chai.Assertion.addMethod('emit', function(signal) {
const registeredSignals = utils.flag(this, FLAG_EXPECTED_SIGNALS)
?? utils.flag(this, FLAG_EXPECTED_SIGNALS, [])
?? utils.flag(this, FLAG_EXPECTED_SIGNALS);
registeredSignals.push(signal);
});
chai.Assertion.addMethod('when',function(slot) {
const self = this;
const expectedSignals = utils.flag(this, FLAG_EXPECTED_SIGNALS);
if (!expectedSignals || !expectedSignals.length) {
throw new AssertionError("No signals registered. Use '.emit' before calling '.when'");
}
let obj = this._obj;
expectedSignals.forEach( function(signal) {
let Handler = new ARCS.Component.create(
function() {
this.triggered = false;
this.trigger = function() {
this.triggered = true;
};
}, ['trigger']
);
let handler = new Handler();
ARCS.Component.connect(obj, signal, handler, "trigger");
obj[slot].call(obj);
self.assert(
handler.triggered,
"expected #{this} to emit signal "+signal,
"expected #{this} not to emit signal "+signal
);
});
});
};
chai.use(signalHandler);
describe('components', function() {
it('should have property slots', function() {
let C = ARCS.Component.create(function() {});
let c = new C();
expect(c).to.have.property('slots');
});
it('should have property signals', function() {
let C = ARCS.Component.create(function() {});
let c = new C();
expect(c).to.have.property('signals');
});
it ('should return correct slot list', function() {
let C = ARCS.Component.create(function() {
this.mySlot= ()=>{};
}, ['mySlot']);
let c = new C();
expect(c.slotList()).to.deep.equal(["mySlot"]);
});
it ('should return correct signal list', function() {
let C = ARCS.Component.create(function() {}, [], ['mySignal']);
let c = new C();
expect(c.signalList()).to.deep.equal(["mySignal"]);
});
it ('should accept creating local slots', function() {
let C = ARCS.Component.create(function() {});
let c = new C();
c.slot('mySlot', () => {});
expect(C.prototype.slots).to.deep.equal([]);
expect(c.slots).to.deep.equal(['mySlot']);
});
it ('should accept creating local signals', function() {
let C = ARCS.Component.create(function() {});
let c = new C();
c.signal('mySignal');
expect(C.prototype.signals).to.deep.equal({});
expect(c.signals).to.have.property('mySignal');
});
it ('should be a component', function() {
let C = ARCS.Component.create(function() {});
let c = new C();
expect(c).to.be.a.component;
});
it ('should emit signal', function() {
let A = ARCS.Component.create(function() {
const self = this;
this.slotA = function() {
self.emit('signalA');
}
},['slotA'],['signalA']
);
let a = new A();
expect(a).to.emit('signalA').when('slotA');
});
});
describe('statemachine', function() {
it ('should create slots for tokens', function() {
let sm = new ARCS.StateMachine();
sm.setTransitions({
start: {next:"end"}
});
expect(ARCS.StateMachine.prototype.slots).to.deep.equal(['setToken']);
expect(sm.slots).to.deep.equal(['setToken', 'next']);
});
// it ('should trigger a single transition', function() {
// let sm = new ARCS.StateMachine();
// sm.setTransitions({
// start: {next:"end"}
// });
// sm.start();
// expect(sm).to.emit('requestSheet').when('next');
//
// // here we should be able to capture the right signal emission and
// // its params.
//
// });
});