diff --git a/package.json b/package.json index ce8cb30..2d4e529 100644 --- a/package.json +++ b/package.json @@ -81,6 +81,9 @@ "karma-chrome-launcher": "^0.2.2", "karma-firefox-launcher": "^0.1.7", "karma-jasmine": "^0.3.7", + "karma-jasmine-html-reporter": "^0.2.0", + "karma-jasmine-html-reporter-livereload": "^1.0.0", + "karma-jasmine-style-specrunner-reporter": "^1.0.3", "karma-junit-reporter": "^0.3.8", "karma-sourcemap-loader": "^0.3.7", "karma-webpack": "^1.7.0", diff --git a/src/js/game.js b/src/js/game.js index 96bbc45..90b28ac 100644 --- a/src/js/game.js +++ b/src/js/game.js @@ -91,13 +91,15 @@ var Game = module.exports =(function (Helpers, GameObjects, ObjectStorage,Rules, // deal new initial cards that follow the rule this.lastCards.splice(0,this.lastCards.length); this.lastCards.push(_.sample(this.cards)); - for (var i = 0; i < 52; i++) { + var error,i; + for (i = 0; i < 52; i++) { if (this.lastCards.length>2) break; // stop here var card = _.sample(this.cards); var res; try{ res = this.rule.test(card,this.lastCards,this.cards); } catch(e){ + error=e; // in case of an error just add a random card // this is probobly because it is looking back 2 or 3 cards // yet we only have 1 @@ -105,7 +107,23 @@ var Game = module.exports =(function (Helpers, GameObjects, ObjectStorage,Rules, } if (res) this.lastCards.push(_.sample(this.cards)); } - if (this.lastCards.length<3) console.error('Could not deal cards for rule',this.rule.key,this.rule.options); + if (this.lastCards.length<3) { + console.warn( + 'Could not deal cards for rule after:', + i, + this.rule.key, + this.rule.options, + this.rule.describe(), + _.map(this.lastCards,'key'), + error?error.message:'' + ); + // feck, just deal 3 random then + this.lastCards.splice(0,this.lastCards.length); + this.lastCards.push(_.sample(this.cards)); + this.lastCards.push(_.sample(this.cards)); + this.lastCards.push(_.sample(this.cards)); + + } // this.lastCards.push.apply(this.lastCards,_.sampleSize(this.cards,3)); this.ruleInfo.splice(0,this.ruleInfo.length); diff --git a/src/js/rules.js b/src/js/rules.js index 2eebd45..b0354e9 100644 --- a/src/js/rules.js +++ b/src/js/rules.js @@ -15,6 +15,21 @@ if (!chai){ */ var Rules = module.exports = (function functionName(_,chai) { + var Simulation = function(rules,cards){ + this.results=[]; + this.cards=cards; + this.rules=rules; + }; + Simulation.prototype.run = function () { + var allPromises = []; + for (var i = 0; i < this.rules.length; i++) { + var rule = this.rules[i]; + var promises = rule.simulate(); + allPromises.push(promises); + } + return Promise.all(allPromises).then(function(data){return _.concat(data);}); + }; + /** Generate all combination of arguments from array using functional programming instead of recursive * @param {Object} opts - An array or arrays with keys describing options [['Ben','Jade','Darren'],['Smith','Miller']] @@ -306,21 +321,24 @@ var Rules = module.exports = (function functionName(_,chai) { $.extend(this.state, state); }; Rule.prototype.simulateOne = function (options,cards,n) { + var self = this; + // return new Promise(function(resolve, reject) { if (!n) n=52*2; var t0=new Date(); var rights=[]; var wrongs=[]; var errors=[]; var lastCards = _.sampleSize(cards,3); - this.setOptions(options); + self.setOptions(options); for (var i = 0; i < n; i++) { var res=undefined; var error=undefined; var card = _.sample(cards); try{ - var res = this.testAndTell(card,lastCards,cards); + var res = self.testAndTell(card,lastCards,cards); } catch(e){ + console.error('simulateOne',err); error=e; } @@ -339,6 +357,7 @@ var Rules = module.exports = (function functionName(_,chai) { } } var ratioRight = rights.length/(rights.length+wrongs.length); + if (isNaN(ratioRight)) ratioRight = 0; var ok = ratioRight>0.1&&ratioRight<0.66; return { wrongs:wrongs, @@ -347,9 +366,9 @@ var Rules = module.exports = (function functionName(_,chai) { rights:rights, error:errors.length, errors:errors, - key:this.key, - description:this.describe(), - options:this.options, + key:self.key, + description:self.describe(), + options:self.options, n:n, time:new Date()-t0, ok:ok, @@ -360,8 +379,8 @@ var Rules = module.exports = (function functionName(_,chai) { Rule.prototype.simulate = function (cards) { var results = []; for (var i = 0; i < this.optionsPossible.length; i++) { - var res = this.simulateOne(this.optionsPossible[i],cards); - results.push(res); + var result = this.simulateOne(this.optionsPossible[i],cards); + results.push(result); } return results; }; @@ -656,6 +675,7 @@ var Rules = module.exports = (function functionName(_,chai) { return { Rule: Rule, rules: rules, + Simulation: Simulation, }; diff --git a/src/tmpl/detector.html b/src/tmpl/detector.html deleted file mode 100644 index e69de29..0000000 diff --git a/test/e2e/scenarios.js b/test/e2e/scenarios.js index 79b5b6e..3546b77 100644 --- a/test/e2e/scenarios.js +++ b/test/e2e/scenarios.js @@ -2,100 +2,24 @@ /* http://docs.angularjs.org/guide/dev_guide.e2e-testing */ -describe('PhoneCat App', function() { - - it('should redirect index.html to index.html#/phones', function() { - browser.get('app/index.html'); - browser.getLocationAbsUrl().then(function(url) { - expect(url).toEqual('/phones'); - }); - }); +describe('cards for science', function() { describe('Phone list view', function() { beforeEach(function() { - browser.get('app/index.html#/phones'); + browser.get('index.html'); }); - it('should filter the phone list as a user types into the search box', function() { - - var phoneList = element.all(by.repeater('phone in phones')); - var query = element(by.model('query')); - - expect(phoneList.count()).toBe(20); - - query.sendKeys('nexus'); - expect(phoneList.count()).toBe(1); - - query.clear(); - query.sendKeys('motorola'); - expect(phoneList.count()).toBe(8); - }); - - - it('should be possible to control phone order via the drop down select box', function() { - - var phoneNameColumn = element.all(by.repeater('phone in phones').column('phone.name')); - var query = element(by.model('query')); - - function getNames() { - return phoneNameColumn.map(function(elm) { - return elm.getText(); - }); - } - - query.sendKeys('tablet'); //let's narrow the dataset to make the test assertions shorter - - expect(getNames()).toEqual([ - "Motorola XOOM\u2122 with Wi-Fi", - "MOTOROLA XOOM\u2122" - ]); - - element(by.model('orderProp')).element(by.css('option[value="name"]')).click(); - - expect(getNames()).toEqual([ - "MOTOROLA XOOM\u2122", - "Motorola XOOM\u2122 with Wi-Fi" - ]); - }); - - - it('should render phone specific links', function() { - var query = element(by.model('query')); - query.sendKeys('nexus'); - element.all(by.css('.phones li a')).first().click(); - browser.getLocationAbsUrl().then(function(url) { - expect(url).toEqual('/phones/nexus-s'); - }); - }); - }); - - - describe('Phone detail view', function() { - - beforeEach(function() { - browser.get('app/index.html#/phones/nexus-s'); - }); - - - it('should display nexus-s page', function() { - expect(element(by.binding('phone.name')).getText()).toBe('Nexus S'); - }); - - - it('should display the first phone image as the main phone image', function() { - expect(element(by.css('img.phone.active')).getAttribute('src')).toMatch(/img\/phones\/nexus-s.0.jpg/); - }); - - - it('should swap main image if a thumbnail image is clicked on', function() { - element(by.css('.phone-thumbs li:nth-child(3) img')).click(); - expect(element(by.css('img.phone.active')).getAttribute('src')).toMatch(/img\/phones\/nexus-s.2.jpg/); - - element(by.css('.phone-thumbs li:nth-child(1) img')).click(); - expect(element(by.css('img.phone.active')).getAttribute('src')).toMatch(/img\/phones\/nexus-s.0.jpg/); - }); + // it('should filter the phone list as a user types into the search box', function() { + // + // var lastCards = element.all(by.css('#lastCards .card')); + // expect(lastCards.count()).toBe(3); + // + // var query = element(by.repeater('r in rc.cards')); + // query.click(); + // expect(lastCards.count()).toBe(4); + // }); }); }); diff --git a/test/karma.conf.js b/test/karma.conf.js index 1cd2bb8..79d5874 100644 --- a/test/karma.conf.js +++ b/test/karma.conf.js @@ -29,7 +29,15 @@ module.exports = function (config) { // test results reporter to use // possible values: 'dots', 'progress' // available reporters: https://npmjs.org/browse/keyword/karma-reporter - reporters: ['progress','html','junit'], + reporters: ['dots','html'], + + htmlReporter: { + outputFile: 'tests/units.html', + + // Optional + pageTitle: 'Unit Tests', + subPageTitle: 'A sample project description' + }, frameworks: ['jasmine'], @@ -50,12 +58,9 @@ module.exports = function (config) { require('karma-ng-html2js-preprocessor'), require('karma-chrome-launcher'), require('karma-firefox-launcher'), + "karma-jasmine-html-reporter-livereload" // displays html summary on debug page ], - junitReporter: { - outputFile: 'test_out/unit.xml', - suite: 'unit' - }, preprocessors: { // './build/clientapp.bundle.js': ['webpack','sourcemap'], @@ -80,10 +85,6 @@ module.exports = function (config) { '/json/': '/base/json/' }, - // test results reporter to use - // possible values: 'dots', 'progress' - // available reporters: https://npmjs.org/browse/keyword/karma-reporter - reporters: ['progress'], // list of files / patterns to load in the browser files: [ diff --git a/test/protractor-conf.js b/test/protractor-conf.js index 30c78c8..06af1cc 100644 --- a/test/protractor-conf.js +++ b/test/protractor-conf.js @@ -12,7 +12,7 @@ exports.config = { chromeOnly: true, - baseUrl: 'http://localhost:8000/', + baseUrl: 'http://localhost:8080/', framework: 'jasmine', diff --git a/test/unit/ruleSpec.js b/test/unit/ruleSpec.js index c271251..07fa591 100644 --- a/test/unit/ruleSpec.js +++ b/test/unit/ruleSpec.js @@ -17,27 +17,27 @@ describe('Rules', function () { describe('Rule', function () { it('should test false on false', function () { - var rule = new Rule('1',function(){return false;},{},{},[]); + var rule = new Rule('1','1',function(){return false;},{},{},[]); var res = rule.test(card,lastCards,allCards); expect(res).toBe(false); }); it('should test false on assertion error', function () { - var rule = new Rule('2',function(){return chai.expect(1).to.equal(0);},{},{},[]); + var rule = new Rule('2','2',function(){return chai.expect(1).to.equal(0);},{},{},[]); var res = rule.test(card,lastCards,allCards); expect(res).toBe(false); }); it('should test true on assertion', function () { - var rule = new Rule('3',function(){return chai.expect(1).to.equal(1);},{},{},[]); + var rule = new Rule('3','3',function(){return chai.expect(1).to.equal(1);},{},{},[]); var res = rule.test(card,lastCards,allCards); expect(res).toBe(true); }); it('should test true on true', function () { - var rule = new Rule('4',function(){return true;},{},{},[]); + var rule = new Rule('4','4',function(){return true;},{},{},[]); var res = rule.test(card,lastCards,allCards); expect(res).toBe(true); }); it('should throw test on error', function () { - var rule = new Rule('5',function(){throw new Error('test');return true;},{},{},[]); + var rule = new Rule('5','5',function(){throw new Error('test');return true;},{},{},[]); expect(function(){ rule.test(card,lastCards,allCards); }).toThrow(); @@ -45,31 +45,18 @@ describe('Rules', function () { }); describe('Each rule', function () { Rules.rules.forEach(function(rule){ - describe('rule: "'+rule.describe()+'"', function () { - it('should test', function () { - var res = rule.test(card,lastCards,allCards); - Boolean(res); - }); - it('should describe itself', function () { - var desc = rule.describe(); - expect(typeof desc).toBe('string'); - expect(desc).not.toContain(/[{}]+/); - }); - it('should describeOptions', function () { - var desc = rule.describeOptions(); - expect(typeof desc).toBe('string'); - expect(desc).not.toContain(/[{}]+/); - }); + describe('rule: "'+rule.key+'"', function () { + it('should describeVariations', function () { var desc = rule.describeVariations(); expect(desc instanceof Array).toBe(true); expect(desc).not.toContain(/[{}]+/); }); - it('should genHints', function () { - var hints = rule.genHints(); - expect(hints instanceof Array).toBe(true); - expect(hints.length).toBeGreaterThan(0); - expect(hints.join('')).not.toContain(/[{}]+/); + + it('should describeOptions', function () { + var desc = rule.describeOptions(); + expect(typeof desc).toBe('string'); + expect(desc).not.toContain(/[{}]+/); }); it('should set options', function () { var opts1 = rule.options; @@ -84,31 +71,56 @@ describe('Rules', function () { expect(opts).not.toEqual(opts1); }); - - // now check each rule permutation - var options=Object.keys(rule.optionDesc); - options.forEach(function(option){ - var vals = rule.optionDesc[option].possibleVals; - var def = rule.optionDefaults[option]; - describe('option: '+option, function () { - for (var i = 0; i < vals.length; i++) { - it('should test with val: '+vals[i],function(){ - var options={}; - options[option]=vals[i]; - rule.setOptions(options); - var res = rule.test(card,lastCards,allCards); - expect(typeof res).toBe('boolean'); - }); - } - - it('default should be in possible vals '+option+' = '+vals[i],function(){ + for (var option in rule.optionDefaults) { + if (rule.optionDefaults.hasOwnProperty(option)) { + var def = rule.optionDefaults[option]; + var vals = rule.optionDesc[option].possibleVals; + it('defaults should be in possible vals '+option,function(){ expect(vals).toEqual(jasmine.arrayContaining([def])); }); + } + } + + }); + + // now check each rule permutation + rule.optionsPossible.forEach(function(options){ + + describe('rule: "'+rule.describe()+'"', function () { + beforeEach(function () { + rule.setOptions(options); }); + it('should describe itself', function () { + var desc = rule.describe(); + expect(typeof desc).toBe('string'); + expect(desc).not.toContain(/[{}]+/); + }); + it('should test', function () { + var res = rule.test(card,lastCards,allCards); + Boolean(res); + }); + it('should genHints', function () { + var hints = rule.genHints(); + expect(hints instanceof Array).toBe(true); + expect(hints.length).toBeGreaterThan(0); + expect(hints.join('')).not.toContain(/[{}]+/); + }); + describe('simulation',function(){ + it('should have more than 10% right and less than 60%',function(){ + var simulation=rule.simulateOne(options,allCards,52*2); + expect(simulation).not.toEqual(undefined); + expect(simulation.ratioRight).toBeLessThan(0.6); + expect(simulation.ratioRight).toBeGreaterThan(0.1); + expect(simulation.error).toBe(0); + // if (simulation.wrong){ + // expect(_.uniq(simulation.wrongs)[0].length).toBeGreaterThan(0); + // } + }); + }); + // it should give reasons + // it should not give errors }); - - }); }); });