1
0
mirror of https://github.com/Unleash/unleash.git synced 2025-02-09 00:18:00 +01:00

#108 Add eslint-config-spt and remove jshint (#111)

* #108 Add eslint-config-spt

* #108 Ignore bundle.js file

* #108 Change eslint ignore path to a glob file

* Remove jshint and follow more of eslint rules
This commit is contained in:
Anders Olsen Sandvik 2016-04-24 22:41:37 +02:00 committed by Ivar Conradi Østhus
parent 89c35135ec
commit a96a9f38ce
55 changed files with 340 additions and 351 deletions

24
.eslintrc Normal file
View File

@ -0,0 +1,24 @@
{
"extends": [
"spt",
"spt/env-node",
"spt/env-es6-false",
"spt/env-react"
],
"env": {
"browser": true
},
"rules": {
"quotes": 0,
"strict": 0,
"vars-on-top": 0,
"no-use-before-define": 0,
"dot-notation": 0,
"eqeqeq": 0,
"no-eq-null": 0,
"no-undefined": 0,
"no-else-return": 0,
"no-shadow": 0,
"consistent-this": 0
}
}

View File

@ -1,83 +0,0 @@
{
"globals": {
"jQuery" : false,
"$" : false,
"sinon" : false,
"describe" : false,
"it" : false,
"xit" : false,
"expect" : false,
"before" : false,
"after" : false,
"beforeEach": false,
"afterEach" : false,
"contain" : false
},
"bitwise" : true,
"camelcase" : true,
"curly" : true,
"eqeqeq" : false,
"es3" : false,
"forin" : false,
"freeze" : false,
"immed" : true,
"indent" : 4,
"latedef" : "nofunc",
"newcap" : false,
"noarg" : true,
"noempty" : true,
"nonbsp" : true,
"nonew" : true,
"plusplus" : false,
"quotmark" : false,
"undef" : true,
"unused" : true,
"strict" : false,
"trailing" : true,
"maxparams" : 3,
"maxdepth" : 4,
"maxstatements" : 20,
"maxcomplexity" : 10,
"maxlen" : 120,
"predef": [ "-Promise" ],
"asi" : false,
"boss" : false,
"debug" : false,
"eqnull" : true,
"esnext" : false,
"evil" : false,
"expr" : false,
"funcscope" : false,
"globalstrict" : false,
"iterator" : false,
"lastsemic" : false,
"laxbreak" : false,
"laxcomma" : false,
"loopfunc" : false,
"maxerr" : 100,
"moz" : false,
"multistr" : true,
"notypeof" : false,
"proto" : false,
"scripturl" : false,
"smarttabs" : false,
"shadow" : false,
"sub" : false,
"supernew" : false,
"validthis" : false,
"noyield" : false,
"browser" : true,
"devel" : false,
"node" : true,
"jquery" : false,
"nonstandard" : false,
"prototypejs" : false,
"nomen" : false,
"onevar" : false,
"passfail" : false,
"white" : false
}

6
app.js
View File

@ -10,10 +10,10 @@ var express = require('express'),
strategyApi = require('./lib/strategyApi'), strategyApi = require('./lib/strategyApi'),
validator = require('express-validator'), validator = require('express-validator'),
app = express(), app = express(),
router = express.Router(), router = express.Router(), // eslint-disable-line
baseUriPath = process.env.BASE_URI_PATH || ''; baseUriPath = process.env.BASE_URI_PATH || '';
if(app.get('env') === 'development') { if (app.get('env') === 'development') {
app.use(require('errorhandler')()); app.use(require('errorhandler')());
var webpack = require('webpack'), var webpack = require('webpack'),
@ -41,7 +41,7 @@ app.use(log4js.connectLogger(logger, {
app.set('port', process.env.HTTP_PORT || process.env.PORT || 4242); app.set('port', process.env.HTTP_PORT || process.env.PORT || 4242);
app.use(baseUriPath, express.static(__dirname + '/public')); app.use(baseUriPath, express.static(__dirname + '/public'));
app.use(bodyParser.json({strict: false})); app.use(bodyParser.json({ strict: false }));
app.use(cookieParser()); app.use(cookieParser());

View File

@ -42,7 +42,7 @@ function createDbPool() {
return knex({ return knex({
client: 'pg', client: 'pg',
connection: isTestEnv() ? getTestDatabaseUrl() : getDatabaseUrl(), connection: isTestEnv() ? getTestDatabaseUrl() : getDatabaseUrl(),
pool: {min: 2, max: 20} pool: { min: 2, max: 20 }
}); });
} }

View File

@ -2,11 +2,10 @@ var eventDb = require('./eventDb');
var eventDiffer = require('./eventDiffer'); var eventDiffer = require('./eventDiffer');
module.exports = function (app) { module.exports = function (app) {
app.get('/events', function (req, res) { app.get('/events', function (req, res) {
eventDb.getEvents().then(function (events) { eventDb.getEvents().then(function (events) {
eventDiffer.addDiffs(events); eventDiffer.addDiffs(events);
res.json({events: events}); res.json({ events: events });
}); });
}); });
@ -16,9 +15,8 @@ module.exports = function (app) {
eventDiffer.addDiffs(events); eventDiffer.addDiffs(events);
res.json(events); res.json(events);
} else { } else {
res.status(404).json({error: 'Could not find events'}); res.status(404).json({ error: 'Could not find events' });
} }
}); });
}); });
}; };

View File

@ -4,7 +4,7 @@ var EVENT_COLUMNS = ['id', 'type', 'created_by', 'created_at', 'data'];
function storeEvent(event) { function storeEvent(event) {
return knex('events').insert({ return knex('events').insert({
type: event.type, type: event.type,
created_by: event.createdBy, // jshint ignore:line created_by: event.createdBy, // eslint-disable-line
data: event.data data: event.data
}); });
} }
@ -30,8 +30,8 @@ function rowToEvent(row) {
return { return {
id: row.id, id: row.id,
type: row.type, type: row.type,
createdBy: row.created_by, // jshint ignore:line createdBy: row.created_by,
createdAt: row.created_at, // jshint ignore:line createdAt: row.created_at,
data: row.data data: row.data
}; };
} }

View File

@ -1,8 +1,8 @@
module.exports = { module.exports = {
featureCreated : 'feature-created', featureCreated: 'feature-created',
featureUpdated : 'feature-updated', featureUpdated: 'feature-updated',
featureArchived : 'feature-archived', featureArchived: 'feature-archived',
featureRevived : 'feature-revived', featureRevived: 'feature-revived',
strategyCreated: 'strategy-created', strategyCreated: 'strategy-created',
strategyDeleted: 'strategy-deleted' strategyDeleted: 'strategy-deleted'
}; };

View File

@ -10,18 +10,19 @@ var validateRequest = require('./error/validateRequest');
var extractUser = require('./extractUser'); var extractUser = require('./extractUser');
module.exports = function (app) { module.exports = function (app) {
app.get('/features', function (req, res) { app.get('/features', function (req, res) {
featureDb.getFeatures().then(function (features) { featureDb.getFeatures().then(function (features) {
res.json({features: features}); res.json({ features: features });
}); });
}); });
app.get('/features/:featureName', function (req, res) { app.get('/features/:featureName', function (req, res) {
featureDb.getFeature(req.params.featureName) featureDb.getFeature(req.params.featureName)
.then(function (feature) { res.json(feature); }) .then(function (feature) {
res.json(feature);
})
.catch(function () { .catch(function () {
res.status(404).json({error: 'Could not find feature'}); res.status(404).json({ error: 'Could not find feature' });
}); });
}); });

View File

@ -6,10 +6,9 @@ var ValidationError = require('./error/ValidationError');
var validateRequest = require('./error/validateRequest'); var validateRequest = require('./error/validateRequest');
module.exports = function (app) { module.exports = function (app) {
app.get('/archive/features', function (req, res) { app.get('/archive/features', function (req, res) {
featureDb.getArchivedFeatures().then(function (archivedFeatures) { featureDb.getArchivedFeatures().then(function (archivedFeatures) {
res.json({'features': archivedFeatures}); res.json({ 'features': archivedFeatures });
}); });
}); });
@ -34,4 +33,3 @@ module.exports = function (app) {
}); });
}); });
}; };

View File

@ -25,7 +25,7 @@ function getFeatures() {
return knex return knex
.select(FEATURE_COLUMNS) .select(FEATURE_COLUMNS)
.from('features') .from('features')
.where({archived: 0}) .where({ archived: 0 })
.orderBy('name', 'asc') .orderBy('name', 'asc')
.map(rowToFeature); .map(rowToFeature);
} }
@ -34,7 +34,7 @@ function getFeature(name) {
return knex return knex
.first(FEATURE_COLUMNS) .first(FEATURE_COLUMNS)
.from('features') .from('features')
.where({name: name}) .where({ name: name })
.then(rowToFeature); .then(rowToFeature);
} }
@ -42,7 +42,7 @@ function getArchivedFeatures() {
return knex return knex
.select(FEATURE_COLUMNS) .select(FEATURE_COLUMNS)
.from('features') .from('features')
.where({archived: 1}) .where({ archived: 1 })
.orderBy('name', 'asc') .orderBy('name', 'asc')
.map(rowToFeature); .map(rowToFeature);
} }
@ -57,7 +57,7 @@ function rowToFeature(row) {
name: row.name, name: row.name,
description: row.description, description: row.description,
enabled: row.enabled > 0, enabled: row.enabled > 0,
strategy: row.strategy_name, // jshint ignore: line strategy: row.strategy_name, // eslint-disable-line
parameters: row.parameters parameters: row.parameters
}; };
} }
@ -68,7 +68,7 @@ function eventDataToRow(data) {
description: data.description, description: data.description,
enabled: data.enabled ? 1 : 0, enabled: data.enabled ? 1 : 0,
archived: data.archived ? 1 :0, archived: data.archived ? 1 :0,
strategy_name: data.strategy, // jshint ignore: line strategy_name: data.strategy, // eslint-disable-line
parameters: data.parameters parameters: data.parameters
}; };
} }
@ -83,7 +83,7 @@ function createFeature(data) {
function updateFeature(data) { function updateFeature(data) {
return knex('features') return knex('features')
.where({name: data.name}) .where({ name: data.name })
.update(eventDataToRow(data)) .update(eventDataToRow(data))
.catch(function (err) { .catch(function (err) {
logger.error('Could not update feature, error was: ', err); logger.error('Could not update feature, error was: ', err);
@ -92,8 +92,8 @@ function updateFeature(data) {
function archiveFeature(data) { function archiveFeature(data) {
return knex('features') return knex('features')
.where({name: data.name}) .where({ name: data.name })
.update({archived: 1}) .update({ archived: 1 })
.catch(function (err) { .catch(function (err) {
logger.error('Could not archive feature, error was: ', err); logger.error('Could not archive feature, error was: ', err);
}); });
@ -101,8 +101,8 @@ function archiveFeature(data) {
function reviveFeature(data) { function reviveFeature(data) {
return knex('features') return knex('features')
.where({name: data.name}) .where({ name: data.name })
.update({archived: 0, enabled: 0}) .update({ archived: 0, enabled: 0 })
.catch(function (err) { .catch(function (err) {
logger.error('Could not archive feature, error was: ', err); logger.error('Could not archive feature, error was: ', err);
}); });

View File

@ -3,7 +3,7 @@ var util = require('util');
var path = require('path'); var path = require('path');
var runMigration = function(path, db, callback) { var runMigration = function(path, db, callback) {
db.runSql(fs.readFileSync(path, {encoding: 'utf8'}), callback); db.runSql(fs.readFileSync(path, { encoding: 'utf8' }), callback);
}; };
module.exports = { module.exports = {

View File

@ -2,17 +2,15 @@ var knex = require('./dbPool');
var logger = require('./logger'); var logger = require('./logger');
module.exports = function (app) { module.exports = function (app) {
app.get('/health', function (req, res) { app.get('/health', function (req, res) {
knex.select(1) knex.select(1)
.from('features') .from('features')
.then(function() { .then(function() {
res.json({health: 'GOOD'}); res.json({ health: 'GOOD' });
}) })
.catch(function(err) { .catch(function(err) {
logger.error('Could not select from features, error was: ', err); logger.error('Could not select from features, error was: ', err);
res.status(500).json({health: 'BAD'}); res.status(500).json({ health: 'BAD' });
}); });
}); });
}; };

View File

@ -10,17 +10,20 @@ var validateRequest = require('./error/validateRequest');
var extractUser = require('./extractUser'); var extractUser = require('./extractUser');
module.exports = function (app) { module.exports = function (app) {
app.get('/strategies', function (req, res) { app.get('/strategies', function (req, res) {
strategyDb.getStrategies().then(function (strategies) { strategyDb.getStrategies().then(function (strategies) {
res.json({strategies: strategies}); res.json({ strategies: strategies });
}); });
}); });
app.get('/strategies/:name', function (req, res) { app.get('/strategies/:name', function (req, res) {
strategyDb.getStrategy(req.params.name) strategyDb.getStrategy(req.params.name)
.then(function (strategy) { res.json(strategy); }) .then(function (strategy) {
.catch(function () { res.status(404).json({error: 'Could not find strategy'}); }); res.json(strategy);
})
.catch(function () {
res.status(404).json({ error: 'Could not find strategy' });
});
}); });
app.delete('/strategies/:name', function (req, res) { app.delete('/strategies/:name', function (req, res) {
@ -67,7 +70,7 @@ module.exports = function (app) {
res.status(201).end(); res.status(201).end();
}) })
.catch(NameExistsError, function() { .catch(NameExistsError, function() {
res.status(403).json([{msg: "A strategy named '" + req.body.name + "' already exists."}]).end(); res.status(403).json([{ msg: "A strategy named '" + req.body.name + "' already exists." }]).end();
}) })
.catch(ValidationError, function() { .catch(ValidationError, function() {
res.status(400).json(req.validationErrors()); res.status(400).json(req.validationErrors());
@ -88,5 +91,4 @@ module.exports = function (app) {
}); });
}); });
} }
}; };

View File

@ -30,7 +30,7 @@ function getStrategy(name) {
return knex return knex
.first(STRATEGY_COLUMNS) .first(STRATEGY_COLUMNS)
.from('strategies') .from('strategies')
.where({name: name}) .where({ name: name })
.then(rowToStrategy); .then(rowToStrategy);
} }
@ -42,7 +42,7 @@ function rowToStrategy(row) {
return { return {
name: row.name, name: row.name,
description: row.description, description: row.description,
parametersTemplate: row.parameters_template // jshint ignore: line parametersTemplate: row.parameters_template
}; };
} }
@ -50,7 +50,7 @@ function eventDataToRow(data) {
return { return {
name: data.name, name: data.name,
description: data.description, description: data.description,
parameters_template: data.parametersTemplate // jshint ignore: line parameters_template: data.parametersTemplate // eslint-disable-line
}; };
} }

View File

@ -1,2 +1 @@
module.exports = require('../lib/migrationRunner').create('002-add-description-to-features'); module.exports = require('../lib/migrationRunner').create('002-add-description-to-features');

View File

@ -1 +1,2 @@
module.exports = require('../lib/migrationRunner').create('003-add-parameters-template-to-strategies'); module.exports = require('../lib/migrationRunner').create('003-add-parameters-template-to-strategies');

View File

@ -35,7 +35,7 @@
"coverage-report": "cat ./coverage/lcov.info | ./node_modules/coveralls/bin/coveralls.js && rm -rf ./coverage", "coverage-report": "cat ./coverage/lcov.info | ./node_modules/coveralls/bin/coveralls.js && rm -rf ./coverage",
"postinstall": "npm run build", "postinstall": "npm run build",
"jest": "jest", "jest": "jest",
"lint": "jshint server.js lib test && jsxhint public/js/**/*.jsx" "lint": "eslint . --ignore-path .gitignore"
}, },
"dependencies": { "dependencies": {
"bluebird": "2.9.14", "bluebird": "2.9.14",
@ -65,9 +65,11 @@
"devDependencies": { "devDependencies": {
"chai": "2.1.2", "chai": "2.1.2",
"coveralls": "^2.11.2", "coveralls": "^2.11.2",
"eslint": "^2.7.0",
"eslint-config-spt": "^2.0.0",
"eslint-plugin-react": "^4.3.0",
"istanbul": "^0.3.5", "istanbul": "^0.3.5",
"jest-cli": "0.5.4", "jest-cli": "0.5.4",
"jshint": "^2.6.0",
"mocha": "^2.1.0", "mocha": "^2.1.0",
"mocha-lcov-reporter": "0.0.2", "mocha-lcov-reporter": "0.0.2",
"nsp": "^1.0.0", "nsp": "^1.0.0",

View File

@ -0,0 +1,25 @@
{
"extends": [
"spt",
"spt/env-node",
"spt/env-es6-false"
],
"env": {
"browser": true
},
"globals": {
"it": false,
"jest": false,
"beforeEach": false,
"expect": false,
"describe": false,
"afterEach": false
},
"rules": {
"quotes": 0,
"strict": 0,
"vars-on-top": 0,
"no-undefined": 0,
"no-shadow": 0
}
}

View File

@ -6,7 +6,6 @@ var React = require("react/addons");
var TestUtils = React.addons.TestUtils; var TestUtils = React.addons.TestUtils;
var FeatureArchive = require("../../../components/feature/ArchiveFeatureComponent"); var FeatureArchive = require("../../../components/feature/ArchiveFeatureComponent");
var FeatureActions = require("../../../stores/FeatureToggleActions"); var FeatureActions = require("../../../stores/FeatureToggleActions");
var FeatureToggleStore = require("../../../stores/ArchivedToggleStore");
describe("FeatureForm", function () { describe("FeatureForm", function () {
var Component; var Component;

View File

@ -7,7 +7,7 @@ var FeatureForm = require("../../../components/feature/FeatureForm");
describe("FeatureForm", function () { describe("FeatureForm", function () {
var Component; var Component;
var strategies = [ var strategies = [
{ name: "default"} { name: "default" }
]; ];
afterEach(function() { afterEach(function() {
React.unmountComponentAtNode(document.body); React.unmountComponentAtNode(document.body);
@ -22,7 +22,7 @@ describe("FeatureForm", function () {
}); });
describe("edit", function () { describe("edit", function () {
var feature = {name: "Test", strategy: "unknown"}; var feature = { name: "Test", strategy: "unknown" };
it("should show unknown strategy as default", function () { it("should show unknown strategy as default", function () {
Component = TestUtils .renderIntoDocument(<FeatureForm feature={feature} strategies={strategies} />); Component = TestUtils .renderIntoDocument(<FeatureForm feature={feature} strategies={strategies} />);
@ -31,5 +31,4 @@ describe("FeatureForm", function () {
expect(strategySelect.value).toEqual("default"); expect(strategySelect.value).toEqual("default");
}); });
}); });
}); });

View File

@ -14,7 +14,7 @@ describe("FeatureList", function () {
{ name: "group.featureY", strategy: "default" } { name: "group.featureY", strategy: "default" }
]; ];
var strategies=[ var strategies=[
{ name: "default"} { name: "default" }
]; ];
Component = TestUtils .renderIntoDocument(<FeatureList features={features} strategies={strategies} />); Component = TestUtils .renderIntoDocument(<FeatureList features={features} strategies={strategies} />);
}); });
@ -30,7 +30,7 @@ describe("FeatureList", function () {
it("should filter list of features", function() { it("should filter list of features", function() {
var filterNode = Component.refs.filter.getDOMNode(); var filterNode = Component.refs.filter.getDOMNode();
TestUtils.Simulate.change(filterNode, {target: {value: "group"}}); TestUtils.Simulate.change(filterNode, { target: { value: "group" } });
var features = Component.getDOMNode().querySelectorAll(".feature"); var features = Component.getDOMNode().querySelectorAll(".feature");
expect(features.length).toEqual(1); expect(features.length).toEqual(1);
@ -38,7 +38,7 @@ describe("FeatureList", function () {
it("should filter list of features ignoring case", function() { it("should filter list of features ignoring case", function() {
var filterNode = Component.refs.filter.getDOMNode(); var filterNode = Component.refs.filter.getDOMNode();
TestUtils.Simulate.change(filterNode, {target: {value: "GROUP"}}); TestUtils.Simulate.change(filterNode, { target: { value: "GROUP" } });
var features = Component.getDOMNode().querySelectorAll(".feature"); var features = Component.getDOMNode().querySelectorAll(".feature");
expect(features.length).toEqual(1); expect(features.length).toEqual(1);
@ -48,11 +48,10 @@ describe("FeatureList", function () {
it("should filter list of features by strategy name", function() { it("should filter list of features by strategy name", function() {
var searchString = "other"; var searchString = "other";
var filterNode = Component.refs.filter.getDOMNode(); var filterNode = Component.refs.filter.getDOMNode();
TestUtils.Simulate.change(filterNode, {target: {value: searchString}}); TestUtils.Simulate.change(filterNode, { target: { value: searchString } });
var features = Component.getDOMNode().querySelectorAll(".feature"); var features = Component.getDOMNode().querySelectorAll(".feature");
expect(features.length).toEqual(1); expect(features.length).toEqual(1);
expect(features[0].textContent).toMatch(searchString); expect(features[0].textContent).toMatch(searchString);
}); });
}); });

View File

@ -1,16 +1,15 @@
jest.autoMockOff() jest.autoMockOff();
jest.dontMock('../../stores/FeatureToggleActions'); jest.dontMock('../../stores/FeatureToggleActions');
jest.dontMock('../../stores/FeatureToggleStore'); jest.dontMock('../../stores/FeatureToggleStore');
describe('FeatureToggleStore', function() { describe('FeatureToggleStore', function() {
var Actions, Store, toggles; var Actions, Store, toggles;
beforeEach(function() { beforeEach(function() {
Actions = require('../../stores/FeatureToggleActions'); Actions = require('../../stores/FeatureToggleActions');
Store = require('../../stores/FeatureToggleStore'); Store = require('../../stores/FeatureToggleStore');
toggles = [ toggles = [
{name: "app.feature", enabled: true, strategy: "default"} { name: "app.feature", enabled: true, strategy: "default" }
]; ];
}); });
@ -29,7 +28,7 @@ describe('FeatureToggleStore', function() {
it('should add a another toggle', function() { it('should add a another toggle', function() {
Actions.init.completed(toggles); Actions.init.completed(toggles);
var newToggle = {name: "app.featureB", enabled: true, strategy: "default"}; var newToggle = { name: "app.featureB", enabled: true, strategy: "default" };
Actions.create.completed(newToggle); Actions.create.completed(newToggle);
@ -47,15 +46,14 @@ describe('FeatureToggleStore', function() {
expect(Store.getFeatureToggles().length).toBe(0); expect(Store.getFeatureToggles().length).toBe(0);
}); });
it('should keep toggles in sorted order', function() { it('should keep toggles in sorted order', function() {
Actions.init.completed([ Actions.init.completed([
{name: "A"}, { name: "A" },
{name: "B"}, { name: "B" },
{name: "C"} { name: "C" }
]); ]);
Actions.create.completed({name: "AA"}); Actions.create.completed({ name: "AA" });
jest.runAllTimers(); jest.runAllTimers();
expect(Store.getFeatureToggles()[0].name).toEqual("A"); expect(Store.getFeatureToggles()[0].name).toEqual("A");
@ -74,8 +72,4 @@ describe('FeatureToggleStore', function() {
jest.runAllTimers(); jest.runAllTimers();
expect(Store.getFeatureToggles()[0].enabled).toEqual(false); expect(Store.getFeatureToggles()[0].enabled).toEqual(false);
}); });
}); });

View File

@ -13,7 +13,6 @@ var FeatureStore = Reflux.createStore({
this.listenTo(FeatureActions.initArchive.completed, this.onInit); this.listenTo(FeatureActions.initArchive.completed, this.onInit);
this.listenTo(FeatureActions.archive.completed, this.onArchive); this.listenTo(FeatureActions.archive.completed, this.onArchive);
this.listenTo(FeatureActions.revive.completed, this.onRevive); this.listenTo(FeatureActions.revive.completed, this.onRevive);
}, },
onInit: function(toggles) { onInit: function(toggles) {

View File

@ -19,7 +19,9 @@ var FeatureStore = Reflux.createStore({
onError: function (error) { onError: function (error) {
if (this.isClientError(error)) { if (this.isClientError(error)) {
var errors = JSON.parse(error.responseText); var errors = JSON.parse(error.responseText);
errors.forEach(function(e) { this.addError(e.msg); }.bind(this)); errors.forEach(function(e) {
this.addError(e.msg);
}.bind(this));
} else if (error.status === 0) { } else if (error.status === 0) {
this.addError("server unreachable"); this.addError("server unreachable");
} else { } else {

View File

@ -1,7 +1,6 @@
var reqwest = require('reqwest'); var reqwest = require('reqwest');
var TYPE = 'json'; var TYPE = 'json';
var CONTENT_TYPE = 'application/json';
var EventStore = { var EventStore = {
getEvents: function () { getEvents: function () {

View File

@ -3,16 +3,16 @@ var Server = require('./FeatureToggleServerFacade');
var FeatureToggleActions = Reflux.createActions({ var FeatureToggleActions = Reflux.createActions({
'init': { asyncResult: true }, 'init': { asyncResult: true },
'initArchive':{ asyncResult: true }, 'initArchive': { asyncResult: true },
'create': { asyncResult: true }, 'create': { asyncResult: true },
'update': { asyncResult: true }, 'update': { asyncResult: true },
'archive': { asyncResult: true }, 'archive': { asyncResult: true },
'revive': { asyncResult: true } 'revive': { asyncResult: true }
}); });
FeatureToggleActions.init.listen(function(){ FeatureToggleActions.init.listen(function() {
Server.getFeatures(function(error, features) { Server.getFeatures(function(error, features) {
if(error) { if (error) {
this.failed(error); this.failed(error);
} else { } else {
this.completed(features); this.completed(features);
@ -20,9 +20,9 @@ FeatureToggleActions.init.listen(function(){
}.bind(this)); }.bind(this));
}); });
FeatureToggleActions.initArchive.listen(function(){ FeatureToggleActions.initArchive.listen(function() {
Server.getArchivedFeatures(function(error, archivedToggles) { Server.getArchivedFeatures(function(error, archivedToggles) {
if(error) { if (error) {
this.failed(error); this.failed(error);
} else { } else {
this.completed(archivedToggles); this.completed(archivedToggles);
@ -30,9 +30,9 @@ FeatureToggleActions.initArchive.listen(function(){
}.bind(this)); }.bind(this));
}); });
FeatureToggleActions.create.listen(function(feature){ FeatureToggleActions.create.listen(function(feature) {
Server.createFeature(feature, function(error) { Server.createFeature(feature, function(error) {
if(error) { if (error) {
this.failed(error); this.failed(error);
} else { } else {
this.completed(feature); this.completed(feature);
@ -40,9 +40,9 @@ FeatureToggleActions.create.listen(function(feature){
}.bind(this)); }.bind(this));
}); });
FeatureToggleActions.update.listen(function(feature){ FeatureToggleActions.update.listen(function(feature) {
Server.updateFeature(feature, function(error) { Server.updateFeature(feature, function(error) {
if(error) { if (error) {
this.failed(error); this.failed(error);
} else { } else {
this.completed(feature); this.completed(feature);
@ -50,9 +50,9 @@ FeatureToggleActions.update.listen(function(feature){
}.bind(this)); }.bind(this));
}); });
FeatureToggleActions.archive.listen(function(feature){ FeatureToggleActions.archive.listen(function(feature) {
Server.archiveFeature(feature, function(error) { Server.archiveFeature(feature, function(error) {
if(error) { if (error) {
this.failed(error); this.failed(error);
} else { } else {
this.completed(feature); this.completed(feature);
@ -60,9 +60,9 @@ FeatureToggleActions.archive.listen(function(feature){
}.bind(this)); }.bind(this));
}); });
FeatureToggleActions.revive.listen(function(feature){ FeatureToggleActions.revive.listen(function(feature) {
Server.reviveFeature(feature, function(error) { Server.reviveFeature(feature, function(error) {
if(error) { if (error) {
this.failed(error); this.failed(error);
} else { } else {
this.completed(feature); this.completed(feature);

View File

@ -7,9 +7,9 @@ var StrategyActions = Reflux.createActions({
'remove': { asyncResult: true }, 'remove': { asyncResult: true },
}); });
StrategyActions.init.listen(function(){ StrategyActions.init.listen(function() {
StrategyAPI.getStrategies(function(err, strategies) { StrategyAPI.getStrategies(function(err, strategies) {
if(err) { if (err) {
this.failed(err); this.failed(err);
} else { } else {
this.completed(strategies); this.completed(strategies);
@ -17,9 +17,9 @@ StrategyActions.init.listen(function(){
}.bind(this)); }.bind(this));
}); });
StrategyActions.create.listen(function(feature){ StrategyActions.create.listen(function(feature) {
StrategyAPI.createStrategy(feature, function(err) { StrategyAPI.createStrategy(feature, function(err) {
if(err) { if (err) {
this.failed(err); this.failed(err);
} else { } else {
this.completed(feature); this.completed(feature);
@ -27,9 +27,9 @@ StrategyActions.create.listen(function(feature){
}.bind(this)); }.bind(this));
}); });
StrategyActions.remove.listen(function(feature){ StrategyActions.remove.listen(function(feature) {
StrategyAPI.removeStrategy(feature, function(err) { StrategyAPI.removeStrategy(feature, function(err) {
if(err) { if (err) {
this.failed(err); this.failed(err);
} else { } else {
this.completed(feature); this.completed(feature);

View File

@ -1,16 +1,16 @@
var _username; var _username;
//Ref: http://stackoverflow.com/questions/10730362/get-cookie-by-name // Ref: http://stackoverflow.com/questions/10730362/get-cookie-by-name
function readCookie(name) { function readCookie(name) {
var nameEQ = name + "="; var nameEQ = name + "=";
var ca = document.cookie.split(';'); var ca = document.cookie.split(';');
for(var i=0;i < ca.length;i++) { for (var i=0;i < ca.length;i++) {
var c = ca[i]; var c = ca[i];
while (c.charAt(0)==' ') { while (c.charAt(0)==' ') {
c = c.substring(1,c.length); c = c.substring(1, c.length);
} }
if (c.indexOf(nameEQ) === 0) { if (c.indexOf(nameEQ) === 0) {
return c.substring(nameEQ.length,c.length); return c.substring(nameEQ.length, c.length);
} }
} }
return null; return null;

View File

@ -20,7 +20,9 @@ changeLog.att('xsi:schemaLocation',
'http://www.liquibase.org/xml/ns/dbchangelog/dbchangelog-ext.xsd'); 'http://www.liquibase.org/xml/ns/dbchangelog/dbchangelog-ext.xsd');
fs.readdir(sqlRoot, function (err, files) { fs.readdir(sqlRoot, function (err, files) {
if (err) { throw err; } if (err) {
throw err;
}
var changes = {}; var changes = {};
@ -37,23 +39,23 @@ fs.readdir(sqlRoot, function (err, files) {
var direction = match[2]; var direction = match[2];
changes[name] = changes[name] || {}; changes[name] = changes[name] || {};
changes[name][direction] = fs.readFileSync(path.resolve(sqlRoot, sqlFile), {encoding: encoding}); changes[name][direction] = fs.readFileSync(path.resolve(sqlRoot, sqlFile), { encoding: encoding });
}); });
Object.keys(changes).forEach(function (name) { Object.keys(changes).forEach(function (name) {
var change = changes[name]; var change = changes[name];
var el = changeLog.ele('changeSet', {id: name, author: 'unleash'}); var el = changeLog.ele('changeSet', { id: name, author: 'unleash' });
el.ele('sql', {}, change.up); el.ele('sql', {}, change.up);
el.ele('rollback', {}, change.down); el.ele('rollback', {}, change.down);
}); });
util.puts(changeLog.end({pretty: true})); util.puts(changeLog.end({ pretty: true }));
}); });
function initialInit(changes) { function initialInit(changes) {
changes["init-prepare"] = {}; changes["init-prepare"] = {};
changes["init-prepare"]["up"] = fs.readFileSync(path.resolve(__dirname, './init.up.sql'), {encoding: encoding}); changes["init-prepare"]["up"] = fs.readFileSync(path.resolve(__dirname, './init.up.sql'), { encoding: encoding });
changes["init-prepare"]["down"] = fs.readFileSync(path.resolve(__dirname, './init.down.sql'), {encoding: encoding}); changes["init-prepare"]["down"] = fs.readFileSync(path.resolve(__dirname, './init.down.sql'), { encoding: encoding });
} }

20
test/.eslintrc Normal file
View File

@ -0,0 +1,20 @@
{
"extends": [
"spt",
"spt/env-node",
"spt/env-es6-false"
],
"env": {
"browser": true
},
"globals": {
"it": false,
"beforeEach": false,
"describe": false
},
"rules": {
"quotes": 0,
"vars-on-top": 0,
"max-nested-callbacks": 0
}
}

View File

@ -1,3 +1,4 @@
'use strict';
var request = require('./specHelper').request; var request = require('./specHelper').request;
describe('The event api', function () { describe('The event api', function () {
@ -14,5 +15,4 @@ describe('The event api', function () {
.expect('Content-Type', /json/) .expect('Content-Type', /json/)
.expect(200, done); .expect(200, done);
}); });
}); });

View File

@ -1,3 +1,4 @@
'use strict';
var eventDiffer = require('../lib/eventDiffer'); var eventDiffer = require('../lib/eventDiffer');
var eventType = require('../lib/eventType'); var eventType = require('../lib/eventType');
var assert = require('assert'); var assert = require('assert');
@ -5,8 +6,8 @@ var assert = require('assert');
describe('eventDiffer', function () { describe('eventDiffer', function () {
it('fails if events include an unknown event type', function () { it('fails if events include an unknown event type', function () {
var events = [ var events = [
{type: eventType.featureCreated, data: {}}, { type: eventType.featureCreated, data: {} },
{type: 'unknown-type', data: {}} { type: 'unknown-type', data: {} }
]; ];
assert.throws(function () { assert.throws(function () {
@ -21,19 +22,19 @@ describe('eventDiffer', function () {
var events = [ var events = [
{ {
type: eventType.featureUpdated, type: eventType.featureUpdated,
data: {name: name, description: desc, strategy: 'default', enabled: true, parameters: {value: 2 }} data: { name: name, description: desc, strategy: 'default', enabled: true, parameters: { value: 2 } }
}, },
{ {
type: eventType.featureCreated, type: eventType.featureCreated,
data: {name: name, description: desc, strategy: 'default', enabled: false, parameters: {value: 1}} data: { name: name, description: desc, strategy: 'default', enabled: false, parameters: { value: 1 } }
} }
]; ];
eventDiffer.addDiffs(events); eventDiffer.addDiffs(events);
assert.deepEqual(events[0].diffs, [ assert.deepEqual(events[0].diffs, [
{kind: 'E', path: ["enabled"], lhs: false, rhs: true}, { kind: 'E', path: ["enabled"], lhs: false, rhs: true },
{kind: 'E', path: ["parameters", "value"], lhs: 1, rhs: 2} { kind: 'E', path: ["parameters", "value"], lhs: 1, rhs: 2 }
]); ]);
assert.strictEqual(events[1].diffs, null); assert.strictEqual(events[1].diffs, null);
@ -43,19 +44,19 @@ describe('eventDiffer', function () {
var events = [ var events = [
{ {
type: eventType.featureUpdated, type: eventType.featureUpdated,
data: {name: 'bar', description: 'desc', strategy: 'default', enabled: true, parameters: {}} data: { name: 'bar', description: 'desc', strategy: 'default', enabled: true, parameters: {} }
}, },
{ {
type: eventType.featureUpdated, type: eventType.featureUpdated,
data: {name: 'foo', description: 'desc', strategy: 'default', enabled: false, parameters: {}} data: { name: 'foo', description: 'desc', strategy: 'default', enabled: false, parameters: {} }
}, },
{ {
type: eventType.featureCreated, type: eventType.featureCreated,
data: {name: 'bar', description: 'desc', strategy: 'default', enabled: false, parameters: {}} data: { name: 'bar', description: 'desc', strategy: 'default', enabled: false, parameters: {} }
}, },
{ {
type: eventType.featureCreated, type: eventType.featureCreated,
data: {name: 'foo', description: 'desc', strategy: 'default', enabled: true, parameters: {}} data: { name: 'foo', description: 'desc', strategy: 'default', enabled: true, parameters: {} }
} }
]; ];
@ -71,11 +72,11 @@ describe('eventDiffer', function () {
var events = [ var events = [
{ {
type: eventType.featureUpdated, type: eventType.featureUpdated,
data: {name: 'foo', description: 'desc', strategy: 'default', enabled: true, parameters: {}} data: { name: 'foo', description: 'desc', strategy: 'default', enabled: true, parameters: {} }
}, },
{ {
type: eventType.featureCreated, type: eventType.featureCreated,
data: {name: 'foo', description: 'desc', strategy: 'default', enabled: true, parameters: {}} data: { name: 'foo', description: 'desc', strategy: 'default', enabled: true, parameters: {} }
} }
]; ];
@ -87,7 +88,7 @@ describe('eventDiffer', function () {
var events = [ var events = [
{ {
type: eventType.featureUpdated, type: eventType.featureUpdated,
data: {name: 'foo', description: 'desc', strategy: 'default', enabled: true, parameters: {}} data: { name: 'foo', description: 'desc', strategy: 'default', enabled: true, parameters: {} }
} }
]; ];

View File

@ -1,7 +1,10 @@
'use strict';
var assert = require('assert'); var assert = require('assert');
var specHelper = require('./specHelper'); var specHelper = require('./specHelper');
var request = specHelper.request; var request = specHelper.request;
var stringify = function (o) { return JSON.stringify(o, null, ' '); }; var stringify = function (o) {
return JSON.stringify(o, null, ' ');
};
describe('The features api', function () { describe('The features api', function () {
beforeEach(function (done) { beforeEach(function (done) {
@ -38,7 +41,7 @@ describe('The features api', function () {
it('creates new feature toggle', function (done) { it('creates new feature toggle', function (done) {
request request
.post('/features') .post('/features')
.send({name: 'com.test.feature', enabled: false}) .send({ name: 'com.test.feature', enabled: false })
.set('Content-Type', 'application/json') .set('Content-Type', 'application/json')
.expect(201, done); .expect(201, done);
}); });
@ -46,10 +49,10 @@ describe('The features api', function () {
it('creates new feature toggle with createdBy', function (done) { it('creates new feature toggle with createdBy', function (done) {
request request
.post('/features') .post('/features')
.send({name: 'com.test.Username', enabled: false}) .send({ name: 'com.test.Username', enabled: false })
.set('Cookie', ['username=ivaosthu']) .set('Cookie', ['username=ivaosthu'])
.set('Content-Type', 'application/json') .set('Content-Type', 'application/json')
.end(function(){ .end(function() {
request request
.get('/events') .get('/events')
.end(function (err, res) { .end(function (err, res) {
@ -62,7 +65,7 @@ describe('The features api', function () {
it('require new feature toggle to have a name', function (done) { it('require new feature toggle to have a name', function (done) {
request request
.post('/features') .post('/features')
.send({name: ''}) .send({ name: '' })
.set('Content-Type', 'application/json') .set('Content-Type', 'application/json')
.expect(400, done); .expect(400, done);
}); });
@ -70,7 +73,7 @@ describe('The features api', function () {
it('can not change status of feature toggle that does not exist', function (done) { it('can not change status of feature toggle that does not exist', function (done) {
request request
.put('/features/should-not-exist') .put('/features/should-not-exist')
.send({name: 'should-not-exist', enabled: false}) .send({ name: 'should-not-exist', enabled: false })
.set('Content-Type', 'application/json') .set('Content-Type', 'application/json')
.expect(404, done); .expect(404, done);
}); });
@ -78,7 +81,7 @@ describe('The features api', function () {
it('can change status of feature toggle that does exist', function (done) { it('can change status of feature toggle that does exist', function (done) {
request request
.put('/features/featureY') .put('/features/featureY')
.send({name: 'featureY', enabled: true}) .send({ name: 'featureY', enabled: true })
.set('Content-Type', 'application/json') .set('Content-Type', 'application/json')
.expect(200, done); .expect(200, done);
}); });
@ -98,9 +101,8 @@ describe('The features api', function () {
it('refuses to create a feature with an existing name', function (done) { it('refuses to create a feature with an existing name', function (done) {
request request
.post('/features') .post('/features')
.send({name: 'featureX'}) .send({ name: 'featureX' })
.set('Content-Type', 'application/json') .set('Content-Type', 'application/json')
.expect(403, done); .expect(403, done);
}); });
}); });

View File

@ -1,7 +1,10 @@
'use strict';
var assert = require('assert'); var assert = require('assert');
var specHelper = require('./specHelper'); var specHelper = require('./specHelper');
var request = specHelper.request; var request = specHelper.request;
var stringify = function (o) { return JSON.stringify(o, null, ' '); }; var stringify = function (o) {
return JSON.stringify(o, null, ' ');
};
describe('The archive features api', function () { describe('The archive features api', function () {
beforeEach(function (done) { beforeEach(function (done) {
@ -24,7 +27,7 @@ describe('The archive features api', function () {
it('revives a feature by name', function (done) { it('revives a feature by name', function (done) {
request request
.post('/archive/revive') .post('/archive/revive')
.send({name: 'featureArchivedX'}) .send({ name: 'featureArchivedX' })
.set('Content-Type', 'application/json') .set('Content-Type', 'application/json')
.expect(200, done); .expect(200, done);
}); });
@ -34,5 +37,4 @@ describe('The archive features api', function () {
.post('/archive/revive') .post('/archive/revive')
.expect(400, done); .expect(400, done);
}); });
}); });

View File

@ -1,8 +1,8 @@
'use strict';
var specHelper = require('./specHelper'); var specHelper = require('./specHelper');
var request = specHelper.request; var request = specHelper.request;
describe('The routes', function () { describe('The routes', function () {
describe('healthcheck', function () { describe('healthcheck', function () {
it('returns health good', function (done) { it('returns health good', function (done) {
request.get('/health') request.get('/health')
@ -11,5 +11,4 @@ describe('The routes', function () {
.expect('{"health":"GOOD"}', done); .expect('{"health":"GOOD"}', done);
}); });
}); });
}); });

View File

@ -1,3 +1,4 @@
'use strict';
process.env.NODE_ENV = 'test'; process.env.NODE_ENV = 'test';
var Promise = require('bluebird'); var Promise = require('bluebird');
@ -23,7 +24,9 @@ function createStrategies() {
emails: "String" emails: "String"
} }
} }
], function (strategy) { return strategyDb._createStrategy(strategy); }); ], function (strategy) {
return strategyDb._createStrategy(strategy);
});
} }
function createFeatures() { function createFeatures() {
@ -79,7 +82,9 @@ function createFeatures() {
"foo": "rab" "foo": "rab"
} }
} }
], function (feature) { return featureDb._createFeature(feature); }); ], function (feature) {
return featureDb._createFeature(feature);
});
} }
function destroyStrategies() { function destroyStrategies() {
@ -103,6 +108,8 @@ module.exports = {
db: { db: {
reset: resetDatabase, reset: resetDatabase,
setup: setupDatabase, setup: setupDatabase,
resetAndSetup: function () { return resetDatabase().then(setupDatabase); } resetAndSetup: function () {
return resetDatabase().then(setupDatabase);
}
} }
}; };

View File

@ -1,3 +1,4 @@
'use strict';
var specHelper = require('./specHelper'); var specHelper = require('./specHelper');
var request = specHelper.request; var request = specHelper.request;
@ -32,7 +33,7 @@ describe('The strategy api', function () {
it('creates a new strategy', function (done) { it('creates a new strategy', function (done) {
request request
.post('/strategies') .post('/strategies')
.send({name: 'myCustomStrategy', description: 'Best strategy ever.'}) .send({ name: 'myCustomStrategy', description: 'Best strategy ever.' })
.set('Content-Type', 'application/json') .set('Content-Type', 'application/json')
.expect(201, done); .expect(201, done);
}); });
@ -40,7 +41,7 @@ describe('The strategy api', function () {
it('requires new strategies to have a name', function (done) { it('requires new strategies to have a name', function (done) {
request request
.post('/strategies') .post('/strategies')
.send({name: ''}) .send({ name: '' })
.set('Content-Type', 'application/json') .set('Content-Type', 'application/json')
.expect(400, done); .expect(400, done);
}); });
@ -48,7 +49,7 @@ describe('The strategy api', function () {
it('refuses to create a strategy with an existing name', function (done) { it('refuses to create a strategy with an existing name', function (done) {
request request
.post('/strategies') .post('/strategies')
.send({name: 'default'}) .send({ name: 'default' })
.set('Content-Type', 'application/json') .set('Content-Type', 'application/json')
.expect(403, done); .expect(403, done);
}); });
@ -64,5 +65,4 @@ describe('The strategy api', function () {
.delete('/strategies/unknown') .delete('/strategies/unknown')
.expect(404, done); .expect(404, done);
}); });
}); });

View File

@ -2,21 +2,21 @@
var path = require('path'); var path = require('path');
var root = path.normalize(path.join(__dirname, '.')); var root = path.normalize(path.join(__dirname, '.'));
var js_root = path.join(path.join(root, 'public'), 'js'); var jsroot = path.join(path.join(root, 'public'), 'js');
module.exports = { module.exports = {
context: js_root, context: jsroot,
entry: 'app', entry: 'app',
output: { output: {
path: js_root, path: jsroot,
filename: 'bundle.js', filename: 'bundle.js',
publicPath: '/js/' publicPath: '/js/'
}, },
resolve: { resolve: {
root: [js_root], root: [jsroot],
extensions: ['', '.js', '.jsx'], extensions: ['', '.js', '.jsx'],
modulesDirectories: ["web_modules", "node_modules"] modulesDirectories: ["web_modules", "node_modules"]
}, },