diff --git a/app/controllers/forms.server.controller.js b/app/controllers/forms.server.controller.js
index 005841bb..c511bcf0 100644
--- a/app/controllers/forms.server.controller.js
+++ b/app/controllers/forms.server.controller.js
@@ -88,17 +88,15 @@ exports.listSubmissions = function(req, res) {
}
res.json(_submissions);
});
-
};
/**
* Create a new form
*/
exports.create = function(req, res) {
- debugger;
-
+
if(!req.body.form){
- return res.status(401).send({
+ return res.status(400).send({
message: 'Invalid Input'
});
}
diff --git a/app/models/form.server.model.js b/app/models/form.server.model.js
index b20d1a9e..f9139f26 100644
--- a/app/models/form.server.model.js
+++ b/app/models/form.server.model.js
@@ -71,7 +71,6 @@ var VisitorDataSchema = new Schema({
userAgent: {
type: String
}
-
});
var formSchemaOptions = {
@@ -219,7 +218,7 @@ FormSchema.virtual('analytics.fields').get(function () {
var visitors = this.analytics.visitors;
var that = this;
- if(this.form_fields.length === 0) {
+ if(!this.form_fields || this.form_fields.length === 0) {
return null;
}
diff --git a/app/tests/form.server.routes.test.js b/app/tests/form.server.routes.test.js
index e1aa2654..93c5e6cb 100644
--- a/app/tests/form.server.routes.test.js
+++ b/app/tests/form.server.routes.test.js
@@ -9,7 +9,8 @@ var should = require('should'),
User = mongoose.model('User'),
Form = mongoose.model('Form'),
Field = mongoose.model('Field'),
- FormSubmission = mongoose.model('FormSubmission');
+ FormSubmission = mongoose.model('FormSubmission'),
+ async = require('async');
/**
* Globals
@@ -68,7 +69,7 @@ describe('Form Routes Unit tests', function() {
.send({form: myForm})
.expect(401)
.end(function(FormSaveErr, FormSaveRes) {
-
+ console.log(FormSaveRes.text);
// Call the assertion callback
done(FormSaveErr);
});
@@ -83,7 +84,7 @@ describe('Form Routes Unit tests', function() {
});
});
- it(' > should be able to read/get a Form if not signed in', function(done) {
+ it(' > should be able to read/get a live Form if not signed in', function(done) {
// Create new Form model instance
var FormObj = new Form(myForm);
@@ -105,6 +106,23 @@ describe('Form Routes Unit tests', function() {
});
});
+ it(' > should be able to read/get a non-live Form if not signed in', function(done) {
+ // Create new Form model instance
+ var FormObj = new Form(myForm);
+ FormObj.isLive = false;
+
+ // Save the Form
+ FormObj.save(function(err, form) {
+ if(err) return done(err);
+
+ userSession.get('/subdomain/' + credentials.username + '/forms/' + form._id + '/render')
+ .expect(401, {message: 'Form is Not Public'})
+ .end(function(err, res) {
+ done(err);
+ });
+ });
+ });
+
it(' > should not be able to delete an Form if not signed in', function(done) {
// Set Form user
myForm.admin = user;
@@ -146,6 +164,16 @@ describe('Form Routes Unit tests', function() {
});
});
+ it(' > should not be able to create a Form if body is empty', function(done) {
+ loginSession.post('/forms')
+ .send({form: null})
+ .expect(400, {"message":"Invalid Input"})
+ .end(function(FormSaveErr, FormSaveRes) {
+ // Call the assertion callback
+ done(FormSaveErr);
+ });
+ });
+
it(' > should not be able to save a Form if no title is provided', function(done) {
// Set Form with a invalid title field
myForm.title = '';
@@ -165,10 +193,22 @@ describe('Form Routes Unit tests', function() {
done();
});
-
});
- it(' > should be able to update a Form if signed in', function(done) {
+ it(' > should be able to create a Form if form_fields are undefined', function(done) {
+ myForm.analytics = null;
+ myForm.form_fields = null;
+
+ loginSession.post('/forms')
+ .send({form: myForm})
+ .expect(200)
+ .end(function(FormSaveErr, FormSaveRes) {
+ // Call the assertion callback
+ done(FormSaveErr);
+ });
+ });
+
+ it(' > should be able to update a Form if signed in and Form is valid', function(done) {
// Save a new Form
loginSession.post('/forms')
@@ -182,7 +222,7 @@ describe('Form Routes Unit tests', function() {
}
// Update Form title
- myForm.title = 'WHY YOU GOTTA BE SO MEAN?';
+ myForm.title = 'WHY YOU GOTTA BE SO FORMULAIC?';
// Update an existing Form
loginSession.put('/forms/' + FormSaveRes.body._id)
@@ -197,13 +237,12 @@ describe('Form Routes Unit tests', function() {
// Set assertions
(FormUpdateRes.body._id).should.equal(FormSaveRes.body._id);
- (FormUpdateRes.body.title).should.match('WHY YOU GOTTA BE SO MEAN?');
+ (FormUpdateRes.body.title).should.match(myForm.title);
// Call the assertion callback
done();
});
});
-
});
it(' > should be able to delete a Form if signed in', function(done) {
@@ -238,10 +277,9 @@ describe('Form Routes Unit tests', function() {
done();
});
});
-
});
- it('should be able to save new form while logged in', function(done){
+ it(' > should be able to save new form while logged in', function(done){
// Save a new Form
authenticatedSession.post('/forms')
.send({form: myForm})
@@ -271,12 +309,70 @@ describe('Form Routes Unit tests', function() {
});
});
+ it(' > should be able to get list of users\' forms sorted by date created while logged in', function(done) {
+ var myForm1 = {
+ title: 'First Form',
+ language: 'en',
+ admin: user.id,
+ form_fields: [
+ new Field({'fieldType':'textfield', 'title':'First Name', 'fieldValue': ''}),
+ new Field({'fieldType':'checkbox', 'title':'nascar', 'fieldValue': ''}),
+ new Field({'fieldType':'checkbox', 'title':'hockey', 'fieldValue': ''})
+ ],
+ isLive: true
+ };
+
+ var myForm2 = {
+ title: 'Second Form',
+ language: 'en',
+ admin: user.id,
+ form_fields: [
+ new Field({'fieldType':'textfield', 'title':'Last Name', 'fieldValue': ''}),
+ new Field({'fieldType':'checkbox', 'title':'formula one', 'fieldValue': ''}),
+ new Field({'fieldType':'checkbox', 'title':'football', 'fieldValue': ''})
+ ],
+ isLive: true
+ };
+
+ var FormObj1 = new Form(myForm1);
+ var FormObj2 = new Form(myForm2);
+
+ async.waterfall([
+ function(callback) {
+ FormObj1.save(function(err){
+ callback(err);
+ });
+ },
+ function(callback) {
+ FormObj2.save(function(err){
+ callback(err);
+ });
+ },
+ function(callback) {
+ loginSession.get('/forms')
+ .expect(200)
+ .end(function(err, res) {
+ res.body.length.should.equal(2);
+ res.body[0].title.should.equal('Second Form');
+ res.body[1].title.should.equal('First Form');
+
+ // Call the assertion callback
+ callback(err);
+ });
+ }
+ ], function (err) {
+ done(err);
+ });
+ });
+
afterEach('should be able to signout user', function(done){
authenticatedSession.get('/auth/signout')
.expect(200)
.end(function(signoutErr, signoutRes) {
// Handle signout error
- if (signoutErr) return done(signoutErr);
+ if (signoutErr) {
+ return done(signoutErr);
+ }
authenticatedSession.destroy();
done();
});
diff --git a/app/tests/form_submission.model.test.js b/app/tests/form_submission.model.test.js
index f60e599e..09442c81 100644
--- a/app/tests/form_submission.model.test.js
+++ b/app/tests/form_submission.model.test.js
@@ -199,6 +199,7 @@ describe('FormSubmission Model Unit Tests:', function() {
it('should preserve deleted form_fields that have submissions without any problems', function(done) {
+ var fieldPropertiesToOmit = ['deletePreserved', 'globalId', 'lastModified', 'created', '_id', 'submissionId', 'isSubmission', 'validFieldTypes', 'title'];
var old_fields = myForm.toObject().form_fields;
var new_form_fields = _.clone(myForm.toObject().form_fields);
new_form_fields.splice(0, 1);
@@ -210,8 +211,8 @@ describe('FormSubmission Model Unit Tests:', function() {
should.not.exist(err);
should.exist(_form.form_fields);
- var actual_fields = _.deepOmit(_form.toObject().form_fields, ['deletePreserved', 'globalId', 'lastModified', 'created', '_id', 'submissionId']);
- old_fields = _.deepOmit(old_fields, ['deletePreserved', 'globalId', 'lastModified', 'created', '_id', 'submissionId']);
+ var actual_fields = _.deepOmit(_form.toObject().form_fields, fieldPropertiesToOmit);
+ old_fields = _.deepOmit(old_fields, fieldPropertiesToOmit);
should.deepEqual(actual_fields, old_fields, 'old form_fields not equal to newly saved form_fields');
done();
diff --git a/app/views/500.server.view.pug b/app/views/500.server.view.pug
index 688a9af0..3c6fc1b1 100644
--- a/app/views/500.server.view.pug
+++ b/app/views/500.server.view.pug
@@ -5,7 +5,7 @@ block content
div.row.valign
h3.col-md-12.text-center=__('500_HEADER')
div.col-md-4.col-md-offset-4
- if process.env.NODE_ENV == 'development'
+ if process.env.NODE_ENV == 'development' || process.env.NODE_ENV == 'test'
div.col-md-12.text-center(style="padding-bottom: 50px;")
| #{error}
else
diff --git a/config/express.js b/config/express.js
index 1da3f4a1..902beb6f 100755
--- a/config/express.js
+++ b/config/express.js
@@ -148,8 +148,6 @@ module.exports = function(db) {
// reassign url
req.url = subdomainPath;
- req.userId = user._id;
-
// Q.E.D.
return next();
});
@@ -200,7 +198,7 @@ module.exports = function(db) {
app.use(morgan(logger.getLogFormat(), logger.getMorganOptions()));
// Environment dependent middleware
- if (process.env.NODE_ENV === 'development') {
+ if (process.env.NODE_ENV === 'development' || process.env.NODE_ENV === 'test') {
// Disable views cache
app.set('view cache', false);
} else if (process.env.NODE_ENV === 'production') {
@@ -263,9 +261,13 @@ module.exports = function(db) {
//Visitor Language Detection
app.use(function(req, res, next) {
var acceptLanguage = req.headers['accept-language'];
- var languages = acceptLanguage.match(/[a-z]{2}(?!-)/g) || [];
+ var languages, supportedLanguage;
+
+ if(acceptLanguage){
+ languages = acceptLanguage.match(/[a-z]{2}(?!-)/g) || [];
+ supportedLanguage = containsAnySupportedLanguages(languages);
+ }
- var supportedLanguage = containsAnySupportedLanguages(languages);
if(!req.user && supportedLanguage !== null){
var currLanguage = res.cookie('userLang');
@@ -288,7 +290,7 @@ module.exports = function(db) {
app.use(function (req, res, next) {
// Website you wish to allow to connect
- res.setHeader('Access-Control-Allow-Origin', 'https://sentry.polydaic.com');
+ res.setHeader('Access-Control-Allow-Origin', 'https://sentry.io');
// Request methods you wish to allow
res.setHeader('Access-Control-Allow-Methods', 'GET, POST, OPTIONS, PUT, PATCH, DELETE');
@@ -320,16 +322,10 @@ module.exports = function(db) {
// Log it
client.captureError(err);
- if(process.env.NODE_ENV === 'production'){
- res.status(500).render('500', {
- error: 'Internal Server Error'
- });
- } else {
- // Error page
- res.status(500).render('500', {
- error: err.stack
- });
- }
+ // Error page
+ res.status(500).render('500', {
+ error: err.stack
+ });
});
// Assume 404 since no middleware responded
diff --git a/config/strategies/local.js b/config/strategies/local.js
index 319324a6..174a0007 100755
--- a/config/strategies/local.js
+++ b/config/strategies/local.js
@@ -14,8 +14,6 @@ module.exports = function () {
passwordField: 'password'
},
function (username, password, done) {
- console.log('\n\n\n\n\nusername: '+username);
- console.log('password: '+password)
User.findOne({
$or: [
{'username': username.toLowerCase()},
diff --git a/package.json b/package.json
index 3700f6b0..1cb7e1f1 100644
--- a/package.json
+++ b/package.json
@@ -26,7 +26,6 @@
},
"dependencies": {
"async": "^1.4.2",
- "bcrypt": "^0.8.7",
"body-parser": "~1.14.1",
"bower": "~1.6.5",
"chalk": "^1.1.3",
@@ -74,9 +73,7 @@
"socket.io-redis": "^1.0.0",
"swig": "~1.4.1",
"uuid-token-generator": "^0.5.0",
- "wildcard-subdomains": "github:tellform/wildcard-subdomains",
- "winston": "^2.3.1",
- "winston-logrotate": "^1.2.0"
+ "winston": "^2.3.1"
},
"devDependencies": {
"all-contributors-cli": "^4.3.0",
diff --git a/public/dist/form_populate_template_cache.js b/public/dist/form_populate_template_cache.js
index 3e094dc7..7c806969 100644
--- a/public/dist/form_populate_template_cache.js
+++ b/public/dist/form_populate_template_cache.js
@@ -12,7 +12,7 @@ angular.module('TellForm-Form.form_templates', []).run(['$templateCache', functi
$templateCache.put("form_modules/forms/base/views/directiveViews/field/date.html",
"
{{index+1}} {{field.title}} {{ 'OPTIONAL' | translate }}
{{field.description}}
");
$templateCache.put("form_modules/forms/base/views/directiveViews/field/dropdown.html",
- " 0\">
{{index+1}} {{field.title}} {{ 'OPTIONAL' | translate }}
{{field.description}}
");
+ " 0\">
{{index+1}} {{field.title}} {{ 'OPTIONAL' | translate }}
{{field.description}}
");
$templateCache.put("form_modules/forms/base/views/directiveViews/field/hidden.html",
"");
$templateCache.put("form_modules/forms/base/views/directiveViews/field/legal.html",
diff --git a/public/form_modules/forms/base/views/directiveViews/field/dropdown.html b/public/form_modules/forms/base/views/directiveViews/field/dropdown.html
index 21151b22..64d2863c 100755
--- a/public/form_modules/forms/base/views/directiveViews/field/dropdown.html
+++ b/public/form_modules/forms/base/views/directiveViews/field/dropdown.html
@@ -26,8 +26,7 @@
ng-change="nextField()">
-
+
diff --git a/public/modules/core/img/loaders/page-loader.gif b/public/modules/core/img/loaders/page-loader.gif
new file mode 100644
index 00000000..ae90a507
Binary files /dev/null and b/public/modules/core/img/loaders/page-loader.gif differ
diff --git a/public/modules/core/tests/unit/controllers/header.client.controller.test.js b/public/modules/core/tests/unit/controllers/header.client.controller.test.js
index 76ee4fb4..f2cebdc1 100755
--- a/public/modules/core/tests/unit/controllers/header.client.controller.test.js
+++ b/public/modules/core/tests/unit/controllers/header.client.controller.test.js
@@ -6,9 +6,38 @@
var scope,
HeaderController;
+ var sampleUser = {
+ firstName: 'Full',
+ lastName: 'Name',
+ email: 'test@test.com',
+ username: 'test@test.com',
+ language: 'en',
+ password: 'password',
+ provider: 'local',
+ roles: ['user'],
+ _id: 'ed873933b1f1dea0ce12fab9'
+ };
+
// Load the main application module
beforeEach(module(ApplicationConfiguration.applicationModuleName));
+ //Mock Authentication Service
+ beforeEach(module(function($provide) {
+ $provide.service('Auth', function() {
+ return {
+ ensureHasCurrentUser: function() {
+ return sampleUser;
+ },
+ isAuthenticated: function() {
+ return true;
+ },
+ getUserState: function() {
+ return true;
+ }
+ };
+ });
+ }));
+
beforeEach(inject(function($controller, $rootScope) {
scope = $rootScope.$new();
diff --git a/public/modules/forms/admin/config/i18n/german.js b/public/modules/forms/admin/config/i18n/german.js
index 0ea8d351..77d40107 100644
--- a/public/modules/forms/admin/config/i18n/german.js
+++ b/public/modules/forms/admin/config/i18n/german.js
@@ -84,7 +84,6 @@ angular.module('forms').config(['$translateProvider', function ($translateProvid
ADD_OPTION: 'Option hinzufügen',
NUM_OF_STEPS: 'Anzahl der Schritte',
CLICK_FIELDS_FOOTER: 'Klicken Sie auf Felder, um sie hier hinzuzufügen',
- FORM: 'Formular',
IF_THIS_FIELD: 'Wenn dieses Feld',
IS_EQUAL_TO: 'ist gleich',
IS_NOT_EQUAL_TO: 'ist nicht gleich',
diff --git a/public/modules/forms/admin/directives/edit-submissions-form.client.directive.js b/public/modules/forms/admin/directives/edit-submissions-form.client.directive.js
index de630bfa..e405da62 100644
--- a/public/modules/forms/admin/directives/edit-submissions-form.client.directive.js
+++ b/public/modules/forms/admin/directives/edit-submissions-form.client.directive.js
@@ -10,13 +10,33 @@ angular.module('forms').directive('editSubmissionsFormDirective', ['$rootScope',
myform: '='
},
controller: function($scope){
-
$scope.table = {
masterChecker: false,
rows: []
};
- var getSubmissions = function(){
+ $scope.deletionInProgress = false;
+ $scope.waitingForDeletion = false;
+
+ //Waits until deletionInProgress is false before running getSubmissions
+ $scope.$watch("deletionInProgress",function(newVal, oldVal){
+ if(newVal === oldVal) return;
+
+ if(newVal === false && $scope.waitingForDeletion) {
+ $scope.getSubmissions();
+ $scope.waitingForDeletion = false;
+ }
+ });
+
+ $scope.handleSubmissionsRefresh = function(){
+ if(!$scope.deletionInProgress) {
+ $scope.getSubmissions();
+ } else {
+ $scope.waitingForDeletion = true;
+ }
+ };
+
+ $scope.getSubmissions = function(cb){
$http({
method: 'GET',
url: '/forms/'+$scope.myform._id+'/submissions'
@@ -36,10 +56,19 @@ angular.module('forms').directive('editSubmissionsFormDirective', ['$rootScope',
}
$scope.table.rows = submissions;
- });
+
+ if(cb && typeof cb === 'function'){
+ cb();
+ }
+ }, function errorCallback(err){
+ console.error(err);
+ if(cb && typeof cb === 'function'){
+ cb(err);
+ }
+ });
};
- var getVisitors = function(){
+ $scope.getVisitors = function(){
$http({
method: 'GET',
url: '/forms/'+$scope.myform._id+'/visitors'
@@ -52,8 +81,23 @@ angular.module('forms').directive('editSubmissionsFormDirective', ['$rootScope',
});
};
- getSubmissions();
- getVisitors();
+ $scope.handleSubmissionsRefresh();
+ $scope.getVisitors();
+
+ //Fetch submissions and visitor data every 1.67 min
+ var updateSubmissions = $interval($scope.handleSubmissionsRefresh, 100000);
+ var updateVisitors = $interval($scope.getVisitors, 1000000);
+
+ //Prevent $intervals from running after directive is destroyed
+ $scope.$on('$destroy', function() {
+ if (updateSubmissions) {
+ $interval.cancel($scope.updateSubmissions);
+ }
+
+ if (updateVisitors) {
+ $interval.cancel($scope.updateVisitors);
+ }
+ });
/*
** Analytics Functions
@@ -72,14 +116,48 @@ angular.module('forms').directive('editSubmissionsFormDirective', ['$rootScope',
return (totalTime/numSubmissions).toFixed(0);
})();
- var updateFields = $interval(getSubmissions, 100000);
- var updateFields = $interval(getVisitors, 1000000);
+ $scope.DeviceStatistics = (function(){
+ var newStatItem = function(){
+ return {
+ visits: 0,
+ responses: 0,
+ completion: 0,
+ average_time: 0,
+ total_time: 0
+ };
+ };
- $scope.$on('$destroy', function() {
- if (updateFields) {
- $interval.cancel($scope.updateFields);
+ var stats = {
+ desktop: newStatItem(),
+ tablet: newStatItem(),
+ phone: newStatItem(),
+ other: newStatItem()
+ };
+
+ if($scope.myform.analytics && $scope.myform.analytics.visitors) {
+ var visitors = $scope.myform.analytics.visitors;
+ for (var i = 0; i < visitors.length; i++) {
+ var visitor = visitors[i];
+ var deviceType = visitor.deviceType;
+
+ stats[deviceType].visits++;
+
+ if (visitor.isSubmitted) {
+ stats[deviceType].total_time = stats[deviceType].total_time + visitor.timeElapsed;
+ stats[deviceType].responses++;
+ }
+
+ if(stats[deviceType].visits) {
+ stats[deviceType].completion = 100*(stats[deviceType].responses / stats[deviceType].visits).toFixed(2);
+ }
+
+ if(stats[deviceType].responses){
+ stats[deviceType].average_time = (stats[deviceType].total_time / stats[deviceType].responses).toFixed(0);
+ }
+ }
}
- });
+ return stats;
+ })();
/*
** Table Functions
@@ -109,25 +187,24 @@ angular.module('forms').directive('editSubmissionsFormDirective', ['$rootScope',
//Delete selected submissions of Form
$scope.deleteSelectedSubmissions = function(){
+ $scope.deletionInProgress = true;
var delete_ids = _.chain($scope.table.rows).filter(function(row){
return !!row.selected;
}).pluck('_id').value();
- $http({ url: '/forms/'+$scope.myform._id+'/submissions',
+ return $http({ url: '/forms/'+$scope.myform._id+'/submissions',
method: 'DELETE',
data: {deleted_submissions: delete_ids},
headers: {'Content-Type': 'application/json;charset=utf-8'}
}).success(function(data, status){
+ $scope.deletionInProgress = true;
//Remove deleted ids from table
- var tmpArray = [];
- for(var i=0; i<$scope.table.rows.length; i++){
- if(!$scope.table.rows[i].selected){
- tmpArray.push($scope.table.rows[i]);
- }
- }
- $scope.table.rows = tmpArray;
+ $scope.table.rows = $scope.table.rows.filter(function(field){
+ return !field.selected;
+ });
})
.error(function(err){
+ $scope.deletionInProgress = true;
console.error(err);
});
};
diff --git a/public/modules/forms/tests/unit/controllers/admin-form.client.controller.test.js b/public/modules/forms/tests/unit/controllers/admin-form.client.controller.test.js
index ba92adaf..d49d8914 100644
--- a/public/modules/forms/tests/unit/controllers/admin-form.client.controller.test.js
+++ b/public/modules/forms/tests/unit/controllers/admin-form.client.controller.test.js
@@ -57,22 +57,7 @@
_id: '525a8422f6d0f87f0e407a33'
};
- var newFakeModal = function(){
- var result = {
- opened: true,
- close: function( item ) {
- //The user clicked OK on the modal dialog, call the stored confirm callback with the selected item
- this.opened = false;
- },
- dismiss: function( type ) {
- //The user clicked cancel on the modal dialog, call the stored cancel callback
- this.opened = false;
- }
- };
- return result;
- };
-
- //Mock Users Service
+ //Mock myForm Service
beforeEach(module(function($provide) {
$provide.service('myForm', function($q) {
return sampleForm;
@@ -159,6 +144,27 @@
});
}));
+ var newFakeModal = function(){
+ var modal = {
+ opened: true,
+ close: function( item ) {
+ //The user clicked OK on the modal dialog, call the stored confirm callback with the selected item
+ this.opened = false;
+ },
+ dismiss: function( type ) {
+ //The user clicked cancel on the modal dialog, call the stored cancel callback
+ this.opened = false;
+ },
+ result: {
+ then: function (cb) {
+ if(cb && typeof cb === 'function'){
+ cb();
+ }
+ }
+ }
+ };
+ return modal;
+ };
//Mock $uibModal
beforeEach(inject(function($uibModal) {
@@ -199,7 +205,7 @@
expect(scope.myform).toEqualData(sampleForm);
});
- it('$scope.removeCurrentForm() with valid form data should send a DELETE request with the id of form', function() {
+ it('$scope.removeCurrentForm() with valid form data should send a DELETE request with the id of form', inject(function($uibModal) {
var controller = createAdminFormController();
//Set $state transition
@@ -214,7 +220,7 @@
$httpBackend.flush();
$state.ensureAllTransitionsHappened();
- });
+ }));
it('$scope.update() should send a PUT request with the id of form', function() {
var controller = createAdminFormController();
diff --git a/public/modules/forms/tests/unit/controllers/list-forms.client.controller.test.js b/public/modules/forms/tests/unit/controllers/list-forms.client.controller.test.js
index 6f591280..2190264b 100644
--- a/public/modules/forms/tests/unit/controllers/list-forms.client.controller.test.js
+++ b/public/modules/forms/tests/unit/controllers/list-forms.client.controller.test.js
@@ -86,7 +86,6 @@
});
}));
-
// The injector ignores leading and trailing underscores here (i.e. _$httpBackend_).
// This allows us to inject a service but then attach it to a variable
// with the same name as the service.
@@ -106,25 +105,13 @@
// Initialize the Forms controller.
createListFormsController = function(){
- return $controller('ListFormsController', { $scope: scope });
+ return $controller('ListFormsController', {
+ $scope: scope,
+ myForms: sampleFormList
+ });
};
}));
- it('$scope.findAll() should query all User\'s Forms', inject(function() {
-
- var controller = createListFormsController();
-
- // Set GET response
- $httpBackend.expectGET(/^(\/forms)$/).respond(200, sampleFormList);
-
- // Run controller functionality
- scope.findAll();
- $httpBackend.flush();
-
- // Test scope value
- expect( scope.myforms ).toEqualData(sampleFormList);
- }));
-
it('$scope.duplicateForm() should duplicate a Form', inject(function() {
var dupSampleForm = sampleFormList[2],
@@ -135,12 +122,6 @@
var controller = createListFormsController();
- // Set GET response
- $httpBackend.expectGET(/^(\/forms)$/).respond(200, sampleFormList);
- // Run controller functionality
- scope.findAll();
- $httpBackend.flush();
-
// Set GET response
$httpBackend.expect('POST', '/forms').respond(200, dupSampleForm);
// Run controller functionality
@@ -164,13 +145,6 @@
var controller = createListFormsController();
- // Set GET response
- $httpBackend.expectGET(/^(\/forms)$/).respond(200, sampleFormList);
-
- // Run controller functionality
- scope.findAll();
- $httpBackend.flush();
-
// Set GET response
$httpBackend.expect('DELETE', /^(\/forms\/)([0-9a-fA-F]{24})$/).respond(200, delSampleForm);
diff --git a/public/modules/forms/tests/unit/directives/edit-form-submissions.client.directive.test.js b/public/modules/forms/tests/unit/directives/edit-form-submissions.client.directive.test.js
index d1418c2e..75ac6b0d 100644
--- a/public/modules/forms/tests/unit/directives/edit-form-submissions.client.directive.test.js
+++ b/public/modules/forms/tests/unit/directives/edit-form-submissions.client.directive.test.js
@@ -2,7 +2,7 @@
(function() {
// Forms Controller Spec
- describe('EditSubmissions Directive-Controller Tests', function() {
+ describe('EditFormSubmissions Directive-Controller Tests', function() {
// Initialize global variables
var el, scope, controller, $httpBackend;
@@ -10,13 +10,25 @@
firstName: 'Full',
lastName: 'Name',
email: 'test@test.com',
- username: 'test@test.com',
+ username: 'test1234',
password: 'password',
provider: 'local',
roles: ['user'],
_id: 'ed873933b1f1dea0ce12fab9'
};
+ var sampleVisitors = [{
+ socketId: '33b1f1dea0ce12fab9ed8739',
+ referrer: 'https://tellform.com/examples',
+ lastActiveField: 'ed873933b0ce121f1deafab9',
+ timeElapsed: 100000,
+ isSubmitted: true,
+ language: 'en',
+ ipAddr: '192.168.1.1',
+ deviceType: 'desktop',
+ userAgent: 'Mozilla/5.0 (iPhone; CPU iPhone OS 8_3 like Mac OS X) AppleWebKit/600.1.4 (KHTML, like Gecko) FxiOS/1.0 Mobile/12F69 Safari/600.1.4'
+ }]
+
var sampleForm = {
title: 'Form Title',
admin: 'ed873933b1f1dea0ce12fab9',
@@ -27,7 +39,18 @@
{fieldType:'checkbox', title:'hockey', fieldOptions: [], fieldValue: '', required: true, disabled: false, deletePreserved: false, _id: 'ed8317393deab0ce121ffab9'}
],
analytics: {
- visitors: []
+ visitors: sampleVisitors,
+ conversionRate: 80.5,
+ fields: [
+ {
+ dropoffViews: 0,
+ responses: 1,
+ totalViews: 1,
+ continueRate: 100,
+ dropoffRate: 0,
+ field: {fieldType:'textfield', title:'First Name', fieldOptions: [], fieldValue: '', required: true, disabled: false, deletePreserved: false, _id: 'ed873933b0ce121f1deafab9'}
+ }
+ ]
},
submissions: [],
startPage: {
@@ -61,7 +84,8 @@
],
admin: sampleUser,
form: sampleForm,
- timeElapsed: 10.33
+ timeElapsed: 10.33,
+ selected: false
},
{
form_fields: [
@@ -71,7 +95,8 @@
],
admin: sampleUser,
form: sampleForm,
- timeElapsed: 2.33
+ timeElapsed: 2.33,
+ selected: false
},
{
form_fields: [
@@ -81,7 +106,8 @@
],
admin: sampleUser,
form: sampleForm,
- timeElapsed: 11.11
+ timeElapsed: 11.11,
+ selected: false
}];
// The $resource service augments the response object with methods for updating and deleting the resource.
@@ -118,10 +144,12 @@
$httpBackend.whenGET(/^(\/forms\/)([0-9a-fA-F]{24})$/).respond(200, sampleForm);
$httpBackend.whenGET('/forms').respond(200, sampleForm);
$httpBackend.whenGET(/^(\/forms\/)([0-9a-fA-F]{24})$/).respond(200, sampleForm);
- //Instantiate directive.
+ $httpBackend.whenGET(/^(\/forms\/)([0-9a-fA-F]{24})\/submissions$/).respond(200, sampleSubmissions);
+ $httpBackend.whenGET(/^(\/forms\/)([0-9a-fA-F]{24})\/visitors$/).respond(200, sampleVisitors);
+
+ //Instantiate directive.
var tmp_scope = $rootScope.$new();
tmp_scope.myform = sampleForm;
- tmp_scope.myform.submissions = sampleSubmissions;
tmp_scope.user = sampleUser;
//gotacha: Controller and link functions will execute.
@@ -141,6 +169,7 @@
it('$scope.toggleAllCheckers should toggle all checkboxes in table', function(){
//Run Controller Logic to Test
+ scope.table.rows = sampleSubmissions;
scope.table.masterChecker = true;
scope.toggleAllCheckers();
@@ -151,6 +180,7 @@
});
it('$scope.isAtLeastOneChecked should return true when at least one checkbox is selected', function(){
+ scope.table.rows = sampleSubmissions;
scope.table.masterChecker = true;
scope.toggleAllCheckers();
@@ -161,16 +191,22 @@
});
it('$scope.deleteSelectedSubmissions should delete all submissions that are selected', function(){
+ $httpBackend.expect('GET', /^(\/forms\/)([0-9a-fA-F]{24})(\/submissions)$/).respond(200, sampleSubmissions);
scope.table.masterChecker = true;
- scope.toggleAllCheckers();
+ scope.getSubmissions(function(err){
+ scope.toggleAllCheckers();
- $httpBackend.expect('DELETE', /^(\/forms\/)([0-9a-fA-F]{24})(\/submissions)$/).respond(200);
+ $httpBackend.expect('DELETE', /^(\/forms\/)([0-9a-fA-F]{24})(\/submissions)$/).respond(200);
- //Run Controller Logic to Test
- scope.deleteSelectedSubmissions();
+ //Run Controller Logic to Test
+ scope.deleteSelectedSubmissions().then(function(){
+ expect(scope.table.rows.length).toEqual(0);
+ });
+ expect(err).not.toBeDefined();
+ });
$httpBackend.flush();
- expect(scope.table.rows.length).toEqual(0);
+
});
});
diff --git a/public/modules/forms/tests/unit/directives/edit-form.client.directive.test.js b/public/modules/forms/tests/unit/directives/edit-form.client.directive.test.js
index fe7e2452..5ad0047b 100644
--- a/public/modules/forms/tests/unit/directives/edit-form.client.directive.test.js
+++ b/public/modules/forms/tests/unit/directives/edit-form.client.directive.test.js
@@ -62,6 +62,52 @@
beforeEach(module('module-templates'));
beforeEach(module('stateMock'));
+ //Mock FormFields Service
+ beforeEach(module(function($provide) {
+ $provide.service('FormFields', function() {
+ return {
+ types: [
+ {
+ name : 'textfield',
+ value : 'Short Text'
+ },
+ {
+ name : 'email',
+ value : 'Email'
+ }
+ ]
+ };
+ });
+ }));
+
+ var newFakeModal = function(){
+ var modal = {
+ opened: true,
+ close: function( item ) {
+ //The user clicked OK on the modal dialog, call the stored confirm callback with the selected item
+ this.opened = false;
+ },
+ dismiss: function( type ) {
+ //The user clicked cancel on the modal dialog, call the stored cancel callback
+ this.opened = false;
+ },
+ result: {
+ then: function (cb) {
+ if(cb && typeof cb === 'function'){
+ cb();
+ }
+ }
+ }
+ };
+ return modal;
+ };
+
+ //Mock $uibModal
+ beforeEach(inject(function($uibModal) {
+ var modal = newFakeModal();
+ spyOn($uibModal, 'open').and.returnValue(modal);
+ }));
+
beforeEach(inject(function($compile, $controller, $rootScope, _$httpBackend_) {
//Instantiate directive.
var tmp_scope = $rootScope.$new();
@@ -97,26 +143,12 @@
scope.myform = _.cloneDeep(sampleForm);
});
- it('$scope.addNewField() should ADD a new field to $scope.myform.form_fields', function() {
+ it('$scope.addNewField() should open the new field modal', function() {
//Run controller methods
- scope.addNewField(true, 'textfield');
+ scope.addNewField('textfield');
- var expectedFormField = {
- title: 'Short Text2',
- fieldType: 'textfield',
- fieldValue: '',
- required: true,
- disabled: false,
- deletePreserved: false,
- logicJump: Object({ })
- };
-
- var actualFormField = _.cloneDeep(_.last(scope.myform.form_fields));
- delete actualFormField._id;
-
- expect(scope.myform.form_fields.length).toEqual(sampleForm.form_fields.length+1);
- expect(actualFormField).toEqualData(expectedFormField);
+ expect(scope.editFieldModal.opened).toBeTruthy();
});
it('$scope.deleteField() should DELETE a field to $scope.myform.form_fields', function() {
diff --git a/public/modules/forms/tests/unit/directives/field-icon.client.directive.test.js b/public/modules/forms/tests/unit/directives/field-icon.client.directive.test.js
index fbb89193..7dfc6823 100644
--- a/public/modules/forms/tests/unit/directives/field-icon.client.directive.test.js
+++ b/public/modules/forms/tests/unit/directives/field-icon.client.directive.test.js
@@ -5,7 +5,6 @@
describe('FieldIcon Directive Tests', function() {
// Initialize global variables
var scope,
- FormFields,
faClasses = {
'textfield': 'fa fa-pencil-square-o',
'dropdown': 'fa fa-th-list',
@@ -28,10 +27,68 @@
// Load the main application module
beforeEach(module(ApplicationConfiguration.applicationModuleName));
+ //Mock FormFields Service
+ var FormFields = {
+ types: [
+ {
+ name : 'textfield',
+ value : 'Short Text'
+ },
+ {
+ name : 'email',
+ value : 'Email'
+ },
+ {
+ name : 'radio',
+ value : 'Muliple Choice'
+ },
+ {
+ name : 'dropdown',
+ value : 'Dropdown'
+ },
+ {
+ name : 'date',
+ value : 'Date'
+ },
+ {
+ name : 'textarea',
+ value : 'Paragraph',
+ },
+ {
+ name : 'yes_no',
+ value : 'Yes/No',
+ },
+ {
+ name : 'legal',
+ value : 'Legal',
+ },
+ {
+ name : 'rating',
+ value : 'Rating',
+ },
+ {
+ name : 'link',
+ value : 'Link',
+ },
+ {
+ name : 'number',
+ value : 'Numbers',
+ },
+ {
+ name : 'statement',
+ value : 'Statement'
+ }
+ ]
+ };
+ beforeEach(module(function($provide) {
+ $provide.service('FormFields', function() {
+ return FormFields;
+ });
+ }));
+
beforeEach(inject(function ($rootScope, _FormFields_) {
scope = $rootScope.$new();
- FormFields = _FormFields_;
- }));
+ }));
it('should be able render all field-icon types', inject(function($compile) {
var currType, currClass;
diff --git a/public/modules/forms/tests/unit/directives/field.client.directive.test.js b/public/modules/forms/tests/unit/directives/field.client.directive.test.js
index 462951ca..d5d3c89d 100644
--- a/public/modules/forms/tests/unit/directives/field.client.directive.test.js
+++ b/public/modules/forms/tests/unit/directives/field.client.directive.test.js
@@ -5,11 +5,63 @@
describe('Field Directive Tests', function() {
// Initialize global variables
var scope,
- FormFields,
$templateCache,
$httpBackend,
$compile;
+ var FormFields = {
+ types: [
+ {
+ name : 'textfield',
+ value : 'Short Text'
+ },
+ {
+ name : 'email',
+ value : 'Email'
+ },
+ {
+ name : 'radio',
+ value : 'Muliple Choice'
+ },
+ {
+ name : 'dropdown',
+ value : 'Dropdown'
+ },
+ {
+ name : 'date',
+ value : 'Date'
+ },
+ {
+ name : 'textarea',
+ value : 'Paragraph',
+ },
+ {
+ name : 'yes_no',
+ value : 'Yes/No',
+ },
+ {
+ name : 'legal',
+ value : 'Legal',
+ },
+ {
+ name : 'rating',
+ value : 'Rating',
+ },
+ {
+ name : 'link',
+ value : 'Link',
+ },
+ {
+ name : 'number',
+ value : 'Numbers',
+ },
+ {
+ name : 'statement',
+ value : 'Statement'
+ }
+ ]
+ };
+
var sampleUser = {
firstName: 'Full',
lastName: 'Name',
@@ -65,9 +117,15 @@
beforeEach(module('ngSanitize', 'ui.select'));
+ //Mock FormFields Service
+ beforeEach(module(function($provide) {
+ $provide.service('FormFields', function() {
+ return FormFields;
+ });
+ }));
+
beforeEach(inject(function($rootScope, _FormFields_, _$compile_, _$httpBackend_) {
scope = $rootScope.$new();
- FormFields = _FormFields_;
// Point global variables to injected services
$httpBackend = _$httpBackend_;
@@ -76,6 +134,7 @@
$compile = _$compile_;
}));
+
it('should be able to render all field types in html', inject(function($rootScope) {
scope.fields = sampleFields;
diff --git a/public/modules/forms/tests/unit/directives/on-finish-render.client.directive.test.js b/public/modules/forms/tests/unit/directives/on-finish-render.client.directive.test.js
index 188022c4..9f48ab6a 100644
--- a/public/modules/forms/tests/unit/directives/on-finish-render.client.directive.test.js
+++ b/public/modules/forms/tests/unit/directives/on-finish-render.client.directive.test.js
@@ -4,15 +4,73 @@
// Forms Controller Spec
describe('onFinishRender Directive Tests', function() {
// Initialize global variables
- var scope,
- FormFields;
+ var scope;
+
+ var FormFields = {
+ types: [
+ {
+ name : 'textfield',
+ value : 'Short Text'
+ },
+ {
+ name : 'email',
+ value : 'Email'
+ },
+ {
+ name : 'radio',
+ value : 'Muliple Choice'
+ },
+ {
+ name : 'dropdown',
+ value : 'Dropdown'
+ },
+ {
+ name : 'date',
+ value : 'Date'
+ },
+ {
+ name : 'textarea',
+ value : 'Paragraph',
+ },
+ {
+ name : 'yes_no',
+ value : 'Yes/No',
+ },
+ {
+ name : 'legal',
+ value : 'Legal',
+ },
+ {
+ name : 'rating',
+ value : 'Rating',
+ },
+ {
+ name : 'link',
+ value : 'Link',
+ },
+ {
+ name : 'number',
+ value : 'Numbers',
+ },
+ {
+ name : 'statement',
+ value : 'Statement'
+ }
+ ]
+ };
// Load the main application module
beforeEach(module(ApplicationConfiguration.applicationModuleName));
- beforeEach(inject(function ($rootScope, _FormFields_) {
+ //Mock FormFields Service
+ beforeEach(module(function($provide) {
+ $provide.service('FormFields', function() {
+ return FormFields;
+ });
+ }));
+
+ beforeEach(inject(function ($rootScope) {
scope = $rootScope.$new();
- FormFields = _FormFields_;
spyOn($rootScope, '$broadcast');
}));
diff --git a/public/modules/users/tests/unit/controllers/authentication.client.controller.test.js b/public/modules/users/tests/unit/controllers/authentication.client.controller.test.js
deleted file mode 100644
index 363f1f37..00000000
--- a/public/modules/users/tests/unit/controllers/authentication.client.controller.test.js
+++ /dev/null
@@ -1,181 +0,0 @@
-'use strict';
-
-(function() {
- // Forms Controller Spec
- describe('Authentication Controller Tests', function() {
- // Initialize global variables
- var AuthenticationController,
- scope,
- $httpBackend,
- $stateParams,
- $location,
- $state;
-
- var sampleUser = {
- firstName: 'Full',
- lastName: 'Name',
- email: 'test@test.com',
- username: 'test@test.com',
- password: 'password',
- provider: 'local',
- roles: ['user'],
- _id: 'ed873933b1f1dea0ce12fab9'
- };
-
- var sampleForm = {
- title: 'Form Title',
- admin: 'ed873933b1f1dea0ce12fab9',
- language: 'english',
- form_fields: [
- {fieldType:'textfield', title:'First Name', fieldValue: '', deletePreserved: false},
- {fieldType:'checkbox', title:'nascar', fieldValue: '', deletePreserved: false},
- {fieldType:'checkbox', title:'hockey', fieldValue: '', deletePreserved: false}
- ],
- _id: '525a8422f6d0f87f0e407a33'
- };
-
- var expectedForm = {
- title: 'Form Title',
- admin: 'ed873933b1f1dea0ce12fab9',
- language: 'english',
- form_fields: [
- {fieldType:'textfield', title:'First Name', fieldValue: '', deletePreserved: false},
- {fieldType:'checkbox', title:'nascar', fieldValue: '', deletePreserved: false},
- {fieldType:'checkbox', title:'hockey', fieldValue: '', deletePreserved: false}
- ],
- visible_form_fields: [
- {fieldType:'textfield', title:'First Name', fieldValue: '', deletePreserved: false},
- {fieldType:'checkbox', title:'nascar', fieldValue: '', deletePreserved: false},
- {fieldType:'checkbox', title:'hockey', fieldValue: '', deletePreserved: false}
- ],
- _id: '525a8422f6d0f87f0e407a33'
- };
-
- var sampleCredentials = {
- username: sampleUser.username,
- password: sampleUser.password,
- };
-
-
-
- // The $resource service augments the response object with methods for updating and deleting the resource.
- // If we were to use the standard toEqual matcher, our tests would fail because the test values would not match
- // the responses exactly. To solve the problem, we define a new toEqualData Jasmine matcher.
- // When the toEqualData matcher compares two objects, it takes only object properties into
- // account and ignores methods.
- beforeEach(function() {
- jasmine.addMatchers({
- toEqualData: function(util, customEqualityTesters) {
- return {
- compare: function(actual, expected) {
- return {
- pass: angular.equals(actual, expected)
- };
- }
- };
- }
- });
- });
-
-
- // Load the main application module
- beforeEach(module(ApplicationConfiguration.applicationModuleName));
-
- beforeEach(module('stateMock'));
-
- // Mock Users Service
- beforeEach(module(function($provide) {
- $provide.service('User', function($q) {
- return {
- getCurrent: function() {
- var deferred = $q.defer();
- deferred.resolve( JSON.stringify(sampleUser) );
- return deferred.promise;
- },
- login: function(credentials) {
- var deferred = $q.defer();
- if( credentials.password === sampleUser.password && credentials.username === sampleUser.username){
- deferred.resolve( JSON.stringify(sampleUser) );
- }else {
- deferred.resolve('Error: User could not be loggedin');
- }
-
- return deferred.promise;
- },
- logout: function() {
- var deferred = $q.defer();
- deferred.resolve(null);
- return deferred.promise;
- },
- signup: function(credentials) {
- var deferred = $q.defer();
- if( credentials.password === sampleUser.password && credentials.username === sampleUser.username){
- deferred.resolve( JSON.stringify(sampleUser) );
- }else {
- deferred.resolve('Error: User could not be signed up');
- }
-
- return deferred.promise;
- }
- };
- });
- }));
-
- // Mock Authentication Service
- beforeEach(module(function($provide) {
- $provide.service('Auth', function() {
- return {
- ensureHasCurrentUser: function() {
- return sampleUser;
- },
- isAuthenticated: function() {
- return true;
- },
- getUserState: function() {
- return true;
- }
- };
- });
- }));
-
- // The injector ignores leading and trailing underscores here (i.e. _$httpBackend_).
- // This allows us to inject a service but then attach it to a variable
- // with the same name as the service.
- beforeEach(inject(function($controller, $rootScope, _$state_, _$location_, _$stateParams_, _$httpBackend_, CurrentForm, Forms) {
- // Set a new global scope
- scope = $rootScope.$new();
- scope.abc = 'hello';
-
- // Point global variables to injected services
- $stateParams = _$stateParams_;
- $httpBackend = _$httpBackend_;
- $location = _$location_;
- $state = _$state_;
-
- // $httpBackend.whenGET(/\.html$/).respond('');
- $httpBackend.whenGET('/users/me/').respond('');
-
- // Initialize the Forms controller.
- AuthenticationController = $controller('AuthenticationController', { $scope: scope });
- }));
-
- it('$scope.signin should sigin in user with valid credentials', inject(function(Auth) {
-
- //Set $state transition
- // $state.expectTransitionTo('listForms');
- //Set POST response
- // $httpBackend.expect('POST', '/auth/signin', sampleCredentials).respond(200, sampleUser);
-
- scope.abc = 'sampleCredentials';
- //Run Controller Logic to Test
- scope.signin();
-
- // $httpBackend.flush();
-
- // Test scope value
- // expect(Auth.ensureHasCurrentUser()).toEqualData(sampleUser);
- }));
-
-
- });
-}());
\ No newline at end of file