http://git-wip-us.apache.org/repos/asf/ignite/blob/4c295f8f/modules/web-console/backend/package.json
----------------------------------------------------------------------
diff --git a/modules/web-console/backend/package.json 
b/modules/web-console/backend/package.json
index 0aa56c9..d08cd78 100644
--- a/modules/web-console/backend/package.json
+++ b/modules/web-console/backend/package.json
@@ -1,31 +1,24 @@
 {
   "name": "ignite-web-console",
-  "version": "1.0.0",
+  "version": "2.6.0",
   "description": "Interactive Web console for configuration, executing SQL 
queries and monitoring of Apache Ignite Cluster",
   "private": true,
+  "main": "index.js",
   "scripts": {
     "ci-test": "cross-env NODE_ENV=test MOCHA_REPORTER=mocha-teamcity-reporter 
node ./test/index.js",
     "test": "cross-env NODE_ENV=test CONFIG_PATH='./test/config/settings.json' 
node ./test/index.js",
     "eslint": "eslint --env node --format 
node_modules/eslint-friendly-formatter ./ -- --eff-by-issue",
     "start": "node ./index.js",
-    "build": "pkg . --out-path build",
-    "mongodb-download": "./node_modules/.bin/mongodb-download"
+    "build": "pkg . --out-path build"
   },
-  "author": "",
-  "contributors": [
-    {
-      "name": "",
-      "email": ""
-    }
-  ],
   "license": "Apache-2.0",
   "keywords": [
     "Apache Ignite Web console"
   ],
   "homepage": "https://ignite.apache.org/";,
   "engines": {
-    "npm": "^3.x.x",
-    "node": "^6.5.x"
+    "npm": ">=5.x.x",
+    "node": ">=8.x.x <10.x.x"
   },
   "os": [
     "darwin",
@@ -35,49 +28,52 @@
   "bin": "index.js",
   "pkg": {
     "assets": [
+      "app/*",
+      "errors/*",
+      "middlewares/*",
+      "migrations/*",
+      "routes/*",
+      "services/*",
+      "node_modules/getos/logic/*",
+      "node_modules/mongodb-download/node_modules/getos/logic/*"
+    ],
+    "scripts": [
       "app/*.js",
       "errors/*.js",
-      "ignite_modules/*",
-      "injector.js",
       "middlewares/*.js",
-      "migrations/*",
-      "node_modules/getos/logic/*.js",
+      "migrations/*.js",
       "routes/*.js",
-      "routes/**/*.json",
       "services/*.js"
     ]
   },
   "dependencies": {
     "app-module-path": "2.2.0",
     "body-parser": "1.17.2",
-    "common-tags": "1.4.0",
     "connect-mongo": "1.3.2",
     "cookie-parser": "1.4.3",
     "express": "4.15.3",
     "express-session": "1.15.4",
     "fire-up": "1.0.0",
     "glob": "7.1.2",
-    "getos": "3.1.0",
     "jszip": "3.1.3",
     "lodash": "4.17.4",
     "migrate-mongoose": "3.2.2",
     "mongodb-prebuilt": "6.3.3",
     "mongoose": "4.11.4",
     "morgan": "1.8.2",
-    "nexmo": "2.0.2",
     "nconf": "0.8.4",
     "nodemailer": "4.0.1",
     "passport": "0.3.2",
     "passport-local": "1.0.0",
     "passport-local-mongoose": "4.0.0",
     "passport.socketio": "3.7.0",
+    "pkg": "4.3.1",
     "socket.io": "1.7.3",
-    "uuid": "3.1.0",
-    "pkg": "4.2.4"
+    "uuid": "3.1.0"
   },
   "devDependencies": {
     "chai": "4.1.0",
-    "cross-env": "5.0.1",
+    "cross-env": "5.1.6",
     "eslint": "4.3.0",
     "eslint-friendly-formatter": "3.0.0",
     "mocha": "3.4.2",

http://git-wip-us.apache.org/repos/asf/ignite/blob/4c295f8f/modules/web-console/backend/services/clusters.js
----------------------------------------------------------------------
diff --git a/modules/web-console/backend/services/clusters.js 
b/modules/web-console/backend/services/clusters.js
index 0cc2b9f..470b9a3 100644
--- a/modules/web-console/backend/services/clusters.js
+++ b/modules/web-console/backend/services/clusters.js
@@ -94,8 +94,11 @@ module.exports.factory = (mongo, spacesService, 
cachesService, modelsService, ig
      * @returns {Promise.<RemoveResult>} - that resolves results of remove 
operation.
      */
     const removeAllBySpaces = (spaceIds) => {
-        return mongo.Cache.update({space: {$in: spaceIds}}, {clusters: []}, 
{multi: true}).exec()
-            .then(() => mongo.Igfs.update({space: {$in: spaceIds}}, {clusters: 
[]}, {multi: true}).exec())
+        return Promise.all([
+            mongo.DomainModel.remove({space: {$in: spaceIds}}).exec(),
+            mongo.Cache.remove({space: {$in: spaceIds}}).exec(),
+            mongo.Igfs.remove({space: {$in: spaceIds}}).exec()
+        ])
             .then(() => mongo.Cluster.remove({space: {$in: spaceIds}}).exec());
     };
 
@@ -245,14 +248,18 @@ module.exports.factory = (mongo, spacesService, 
cachesService, modelsService, ig
             return Promise.all(_.map(ids, (id) => {
                 return mongo.Cluster.findByIdAndRemove(id).exec()
                     .then((cluster) => {
+                        if (_.isNil(cluster))
+                            return 0;
+
                         return Promise.all([
                             mongo.DomainModel.remove({_id: {$in: 
cluster.models}}).exec(),
                             mongo.Cache.remove({_id: {$in: 
cluster.caches}}).exec(),
                             mongo.Igfs.remove({_id: {$in: 
cluster.igfss}}).exec()
-                        ]);
+                        ])
+                            .then(() => 1);
                     });
             }))
-                .then(() => ({rowsAffected: ids.length}));
+                .then((res) => ({rowsAffected: _.sum(res)}));
         }
 
         /**

http://git-wip-us.apache.org/repos/asf/ignite/blob/4c295f8f/modules/web-console/backend/test/app/db.js
----------------------------------------------------------------------
diff --git a/modules/web-console/backend/test/app/db.js 
b/modules/web-console/backend/test/app/db.js
index e07f887..68a75f3 100644
--- a/modules/web-console/backend/test/app/db.js
+++ b/modules/web-console/backend/test/app/db.js
@@ -19,6 +19,8 @@
 
 // Fire me up!
 
+const _ = require('lodash');
+
 const testAccounts = require('../data/accounts.json');
 const testClusters = require('../data/clusters.json');
 const testCaches = require('../data/caches.json');
@@ -28,10 +30,10 @@ const testSpaces = require('../data/spaces.json');
 
 module.exports = {
     implements: 'dbHelper',
-    inject: ['require(lodash)', 'mongo', 'mongoose']
+    inject: ['mongo', 'mongoose']
 };
 
-module.exports.factory = (_, mongo, mongoose) => {
+module.exports.factory = (mongo, mongoose) => {
     const prepareUserSpaces = () => 
Promise.all([mongo.Account.create(testAccounts), 
mongo.Space.create(testSpaces)]);
     const prepareClusters = () => mongo.Cluster.create(testClusters);
     const prepareDomains = () => mongo.DomainModel.create(testDomains);

http://git-wip-us.apache.org/repos/asf/ignite/blob/4c295f8f/modules/web-console/backend/test/app/httpAgent.js
----------------------------------------------------------------------
diff --git a/modules/web-console/backend/test/app/httpAgent.js 
b/modules/web-console/backend/test/app/httpAgent.js
index 76b191e..2b660fa 100644
--- a/modules/web-console/backend/test/app/httpAgent.js
+++ b/modules/web-console/backend/test/app/httpAgent.js
@@ -35,7 +35,7 @@ module.exports.factory = (apiSrv, http, request) => {
 
             return new Promise((resolve, reject) => {
                 authAgentInstance = request.agent(express);
-                authAgentInstance.post('/signin')
+                authAgentInstance.post('/api/v1/signin')
                     .send({email, password})
                     .end((err, res) => {
                         if (res.status === 401 || err)

http://git-wip-us.apache.org/repos/asf/ignite/blob/4c295f8f/modules/web-console/backend/test/data/caches.json
----------------------------------------------------------------------
diff --git a/modules/web-console/backend/test/data/caches.json 
b/modules/web-console/backend/test/data/caches.json
index 697d414..dd14b4e 100644
--- a/modules/web-console/backend/test/data/caches.json
+++ b/modules/web-console/backend/test/data/caches.json
@@ -16,7 +16,7 @@
       }
     },
     "domains": ["000000000000000000000001", "000000000000000000000002", 
"000000000000000000000003", "000000000000000000000004", 
"000000000000000000000005"],
-    "clusters": ["000000000000000000000001", "000000000000000000000002"]
+    "clusters": ["000000000000000000000001"]
   },
   {
     "_id" : "000000000000000000000002",
@@ -35,10 +35,48 @@
       }
     },
     "domains": ["000000000000000000000001", "000000000000000000000002", 
"000000000000000000000003", "000000000000000000000004", 
"000000000000000000000005"],
-    "clusters": ["000000000000000000000001", "000000000000000000000002"]
+    "clusters": ["000000000000000000000001"]
   },
   {
-    "_id" : "000000000000000000000003",
+    "_id" : "000000000000000000000021",
+    "space": "000000000000000000000001",
+    "name": "CarCache",
+    "cacheMode": "PARTITIONED",
+    "atomicityMode": "ATOMIC",
+    "readThrough": true,
+    "writeThrough": true,
+    "sqlFunctionClasses": [],
+    "cacheStoreFactory": {
+      "kind": "CacheJdbcPojoStoreFactory",
+      "CacheJdbcPojoStoreFactory": {
+        "dataSourceBean": "dsH2",
+        "dialect": "H2"
+      }
+    },
+    "domains": ["000000000000000000000023", "000000000000000000000024", 
"000000000000000000000025"],
+    "clusters": ["000000000000000000000020"]
+  },
+  {
+    "_id" : "000000000000000000000022",
+    "space": "000000000000000000000001",
+    "name": "ParkingCache",
+    "cacheMode": "PARTITIONED",
+    "atomicityMode": "ATOMIC",
+    "readThrough": true,
+    "writeThrough": true,
+    "sqlFunctionClasses": [],
+    "cacheStoreFactory": {
+      "kind": "CacheJdbcPojoStoreFactory",
+      "CacheJdbcPojoStoreFactory": {
+        "dataSourceBean": "dsH2",
+        "dialect": "H2"
+      }
+    },
+    "domains": ["000000000000000000000023", "000000000000000000000024", 
"000000000000000000000025"],
+    "clusters": ["000000000000000000000020"]
+  },
+  {
+    "_id" : "000000000000000000000023",
     "space": "000000000000000000000001",
     "name": "CountryCache",
     "cacheMode": "PARTITIONED",
@@ -53,11 +91,11 @@
         "dialect": "H2"
       }
     },
-    "domains": ["000000000000000000000001", "000000000000000000000002", 
"000000000000000000000003", "000000000000000000000004", 
"000000000000000000000005"],
-    "clusters": ["000000000000000000000002"]
+    "domains": ["000000000000000000000023", "000000000000000000000024", 
"000000000000000000000025"],
+    "clusters": ["000000000000000000000020"]
   },
   {
-    "_id" : "000000000000000000000004",
+    "_id" : "000000000000000000000024",
     "space": "000000000000000000000001",
     "name": "DepartmentCache",
     "cacheMode": "PARTITIONED",
@@ -72,11 +110,11 @@
         "dialect": "H2"
       }
     },
-    "domains": ["000000000000000000000001", "000000000000000000000002", 
"000000000000000000000003", "000000000000000000000004", 
"000000000000000000000005"],
-    "clusters": ["000000000000000000000002"]
+    "domains": ["000000000000000000000023", "000000000000000000000024", 
"000000000000000000000025"],
+    "clusters": ["000000000000000000000020"]
   },
   {
-    "_id" : "000000000000000000000005",
+    "_id" : "000000000000000000000025",
     "space": "000000000000000000000001",
     "name": "EmployeeCache",
     "cacheMode": "PARTITIONED",
@@ -91,7 +129,7 @@
         "dialect": "H2"
       }
     },
-    "domains": ["000000000000000000000001", "000000000000000000000002", 
"000000000000000000000003", "000000000000000000000004", 
"000000000000000000000005"],
-    "clusters": ["000000000000000000000002"]
+    "domains": ["000000000000000000000023", "000000000000000000000024", 
"000000000000000000000025"],
+    "clusters": ["000000000000000000000020"]
   }
 ]

http://git-wip-us.apache.org/repos/asf/ignite/blob/4c295f8f/modules/web-console/backend/test/data/clusters.json
----------------------------------------------------------------------
diff --git a/modules/web-console/backend/test/data/clusters.json 
b/modules/web-console/backend/test/data/clusters.json
index 8e16e76..55e05ce 100644
--- a/modules/web-console/backend/test/data/clusters.json
+++ b/modules/web-console/backend/test/data/clusters.json
@@ -11,6 +11,7 @@
     },
     "igfss": ["000000000000000000000001"],
     "caches": ["000000000000000000000001", "000000000000000000000002"],
+    "models": ["000000000000000000000001", "000000000000000000000002"],
     "binaryConfiguration": {
       "compactFooter": true,
       "typeConfigurations": []
@@ -26,7 +27,7 @@
     }
   },
   {
-    "_id" : "000000000000000000000002",
+    "_id" : "000000000000000000000020",
     "space": "000000000000000000000001",
     "name": "cluster-caches",
     "connector": {
@@ -36,7 +37,8 @@
       "tcpNoDelay": true
     },
     "igfss": [],
-    "caches": ["000000000000000000000001", "000000000000000000000002", 
"000000000000000000000003", "000000000000000000000004", 
"000000000000000000000005"],
+    "caches": ["000000000000000000000021", "000000000000000000000022", 
"000000000000000000000023", "000000000000000000000024", 
"000000000000000000000025"],
+    "models": ["000000000000000000000023", "000000000000000000000024", 
"000000000000000000000025"],
     "binaryConfiguration": {
       "compactFooter": true,
       "typeConfigurations": []

http://git-wip-us.apache.org/repos/asf/ignite/blob/4c295f8f/modules/web-console/backend/test/data/domains.json
----------------------------------------------------------------------
diff --git a/modules/web-console/backend/test/data/domains.json 
b/modules/web-console/backend/test/data/domains.json
index e2662db..1585e98 100644
--- a/modules/web-console/backend/test/data/domains.json
+++ b/modules/web-console/backend/test/data/domains.json
@@ -41,7 +41,8 @@
         "javaFieldType": "int"
       }
     ],
-    "caches": []
+    "caches": [],
+    "clusters": ["000000000000000000000001"]
   },
   {
     "_id" : "000000000000000000000002",
@@ -85,10 +86,11 @@
         "javaFieldType": "int"
       }
     ],
-    "caches": []
+    "caches": [],
+    "clusters": ["000000000000000000000001"]
   },
   {
-    "_id" : "000000000000000000000003",
+    "_id" : "000000000000000000000023",
     "space": "000000000000000000000001",
     "keyType": "Integer",
     "valueType": "model.Employee",
@@ -224,10 +226,11 @@
         "javaFieldType": "int"
       }
     ],
-    "caches": []
+    "caches": [],
+    "clusters": ["000000000000000000000002"]
   },
   {
-    "_id" : "000000000000000000000004",
+    "_id" : "000000000000000000000024",
     "space": "000000000000000000000001",
     "keyType": "Integer",
     "valueType": "model.Country",
@@ -268,10 +271,11 @@
         "javaFieldType": "int"
       }
     ],
-    "caches": []
+    "caches": [],
+    "clusters": ["000000000000000000000002"]
   },
   {
-    "_id" : "000000000000000000000005",
+    "_id" : "000000000000000000000025",
     "space": "000000000000000000000001",
     "keyType": "Integer",
     "valueType": "model.Car",
@@ -312,6 +316,7 @@
         "javaFieldType": "int"
       }
     ],
-    "caches": []
+    "caches": [],
+    "clusters": ["000000000000000000000002"]
   }
 ]

http://git-wip-us.apache.org/repos/asf/ignite/blob/4c295f8f/modules/web-console/backend/test/index.js
----------------------------------------------------------------------
diff --git a/modules/web-console/backend/test/index.js 
b/modules/web-console/backend/test/index.js
index 4519219..258a876 100644
--- a/modules/web-console/backend/test/index.js
+++ b/modules/web-console/backend/test/index.js
@@ -17,14 +17,10 @@
 
 const Mocha = require('mocha');
 const glob = require('glob');
-const path = require('path');
 
 const mocha = new Mocha({ui: 'tdd', reporter: process.env.MOCHA_REPORTER || 
'spec'});
 const testPath = ['./test/unit/**/*.js', './test/routes/**/*.js'];
 
-if (process.env.IGNITE_MODULES)
-    testPath.push(path.join(process.env.IGNITE_MODULES, 'backend', 'test', 
'unit', '**', '*.js'));
-
 testPath
     .map((mask) => glob.sync(mask))
     .reduce((acc, items) => acc.concat(items), [])

http://git-wip-us.apache.org/repos/asf/ignite/blob/4c295f8f/modules/web-console/backend/test/injector.js
----------------------------------------------------------------------
diff --git a/modules/web-console/backend/test/injector.js 
b/modules/web-console/backend/test/injector.js
index bdeca91..a7c7d59 100644
--- a/modules/web-console/backend/test/injector.js
+++ b/modules/web-console/backend/test/injector.js
@@ -15,34 +15,19 @@
  * limitations under the License.
  */
 
-const fs = require('fs');
 const path = require('path');
 const fireUp = require('fire-up');
 
-const igniteModules = process.env.IGNITE_MODULES || './ignite_modules';
-
-let injector;
-
-try {
-    const igniteModulesInjector = path.resolve(path.join(igniteModules, 
'backend', 'test', 'injector.js'));
-
-    fs.accessSync(igniteModulesInjector, fs.F_OK);
-
-    injector = require(igniteModulesInjector);
-} catch (ignore) {
-    injector = fireUp.newInjector({
-        basePath: path.join(__dirname, '../'),
-        modules: [
-            './app/**/*.js',
-            './config/**/*.js',
-            './errors/**/*.js',
-            './middlewares/**/*.js',
-            './routes/**/*.js',
-            './services/**/*.js',
-            './test/app/*.js'
-        ],
-        use: ['mongoose:mock']
-    });
-}
-
-module.exports = injector;
+module.exports = fireUp.newInjector({
+    basePath: path.join(__dirname, '../'),
+    modules: [
+        './app/**/*.js',
+        './config/**/*.js',
+        './errors/**/*.js',
+        './middlewares/**/*.js',
+        './routes/**/*.js',
+        './services/**/*.js',
+        './test/app/*.js'
+    ],
+    use: ['mongoose:mock']
+});

http://git-wip-us.apache.org/repos/asf/ignite/blob/4c295f8f/modules/web-console/backend/test/routes/clusters.js
----------------------------------------------------------------------
diff --git a/modules/web-console/backend/test/routes/clusters.js 
b/modules/web-console/backend/test/routes/clusters.js
index b9f6565..c682ec5 100644
--- a/modules/web-console/backend/test/routes/clusters.js
+++ b/modules/web-console/backend/test/routes/clusters.js
@@ -17,7 +17,6 @@
 
 const assert = require('chai').assert;
 const injector = require('../injector');
-const mongoose = require('mongoose');
 
 let agentFactory;
 let db;
@@ -36,16 +35,16 @@ suite('routes.clusters', () => {
     });
 
     test('Save cluster model', (done) => {
-        const newCluster = Object.assign({}, db.mocks.clusters[0], {name: 
'newClusterName'});
+        const cluster = Object.assign({}, db.mocks.clusters[0], {name: 
'newClusterName'});
 
         agentFactory.authAgent(db.mocks.accounts[0])
             .then((agent) => {
-                agent.post('/configuration/clusters/save')
-                    .send(newCluster)
+                agent.put('/api/v1/configuration/clusters')
+                    .send({cluster})
                     .expect(200)
                     .expect((res) => {
                         assert.isNotNull(res.body);
-                        
assert.isTrue(mongoose.Types.ObjectId.isValid(res.body));
+                        assert.equal(res.body.rowsAffected, 1);
                     })
                     .end(done);
             })
@@ -55,7 +54,7 @@ suite('routes.clusters', () => {
     test('Remove cluster model', (done) => {
         agentFactory.authAgent(db.mocks.accounts[0])
             .then((agent) => {
-                agent.post('/configuration/clusters/remove')
+                agent.post('/api/v1/configuration/clusters/remove')
                     .send({_id: db.mocks.clusters[0]._id})
                     .expect(200)
                     .expect((res) => {
@@ -70,7 +69,7 @@ suite('routes.clusters', () => {
     test('Remove all clusters', (done) => {
         agentFactory.authAgent(db.mocks.accounts[0])
             .then((agent) => {
-                agent.post('/configuration/clusters/remove/all')
+                agent.post('/api/v1/configuration/clusters/remove/all')
                     .expect(200)
                     .expect((res) => {
                         assert.isNotNull(res.body);

http://git-wip-us.apache.org/repos/asf/ignite/blob/4c295f8f/modules/web-console/backend/test/routes/public.js
----------------------------------------------------------------------
diff --git a/modules/web-console/backend/test/routes/public.js 
b/modules/web-console/backend/test/routes/public.js
index 3c573c5..fe7793c 100644
--- a/modules/web-console/backend/test/routes/public.js
+++ b/modules/web-console/backend/test/routes/public.js
@@ -41,7 +41,7 @@ suite('routes.public', () => {
 
         agentFactory.guestAgent()
             .then((agent) => {
-                agent.post('/signin')
+                agent.post('/api/v1/signin')
                     .send({email: user.email, password: user.password})
                     .expect(200)
                     .expect((res) => {
@@ -58,7 +58,7 @@ suite('routes.public', () => {
 
         agentFactory.guestAgent()
             .then((agent) => {
-                agent.post('/signin')
+                agent.post('/api/v1/signin')
                     .send({email: user.email, password: 'notvalidpassword'})
                     .expect(401)
                     .end(done);

http://git-wip-us.apache.org/repos/asf/ignite/blob/4c295f8f/modules/web-console/backend/test/unit/AuthService.test.js
----------------------------------------------------------------------
diff --git a/modules/web-console/backend/test/unit/AuthService.test.js 
b/modules/web-console/backend/test/unit/AuthService.test.js
index 5ce473d..e33b6bd 100644
--- a/modules/web-console/backend/test/unit/AuthService.test.js
+++ b/modules/web-console/backend/test/unit/AuthService.test.js
@@ -37,17 +37,6 @@ suite('AuthServiceTestsSuite', () => {
 
     setup(() => db.init());
 
-    test('Check token generator', () => {
-        const tokenLength = 16;
-        const token1 = authService.generateResetToken(tokenLength);
-        const token2 = authService.generateResetToken(tokenLength);
-
-        assert.equal(token1.length, tokenLength);
-        assert.equal(token2.length, tokenLength);
-        assert.notEqual(token1, token2);
-    });
-
-
     test('Reset password token for non existing user', (done) => {
         authService.resetPasswordToken('non-exisi...@email.ee')
             .catch((err) => {

http://git-wip-us.apache.org/repos/asf/ignite/blob/4c295f8f/modules/web-console/backend/test/unit/CacheService.test.js
----------------------------------------------------------------------
diff --git a/modules/web-console/backend/test/unit/CacheService.test.js 
b/modules/web-console/backend/test/unit/CacheService.test.js
index 52936a0..419b9f7 100644
--- a/modules/web-console/backend/test/unit/CacheService.test.js
+++ b/modules/web-console/backend/test/unit/CacheService.test.js
@@ -127,7 +127,7 @@ suite('CacheServiceTestsSuite', () => {
     test('Get all caches by space', (done) => {
         cachesService.listBySpaces(testSpaces[0]._id)
             .then((caches) =>
-                assert.equal(caches.length, 5)
+                assert.equal(caches.length, 7)
             )
             .then(done)
             .catch(done);
@@ -136,7 +136,7 @@ suite('CacheServiceTestsSuite', () => {
     test('Remove all caches in space', (done) => {
         cachesService.removeAll(testAccounts[0]._id, false)
             .then(({rowsAffected}) =>
-                assert.equal(rowsAffected, 5)
+                assert.equal(rowsAffected, 7)
             )
             .then(done)
             .catch(done);

http://git-wip-us.apache.org/repos/asf/ignite/blob/4c295f8f/modules/web-console/backend/test/unit/ClusterService.test.js
----------------------------------------------------------------------
diff --git a/modules/web-console/backend/test/unit/ClusterService.test.js 
b/modules/web-console/backend/test/unit/ClusterService.test.js
index 66c7cf1..93edfc1 100644
--- a/modules/web-console/backend/test/unit/ClusterService.test.js
+++ b/modules/web-console/backend/test/unit/ClusterService.test.js
@@ -153,17 +153,17 @@ suite('ClusterServiceTestsSuite', () => {
             .then((clusters) => {
                 assert.equal(clusters.length, 2);
 
-                assert.equal(clusters[0].name, 'cluster-caches');
+                assert.equal(clusters[0].name, 'cluster-igfs');
                 assert.isNotNull(clusters[0].discovery);
-                assert.equal(clusters[0].cachesCount, 5);
-                assert.equal(clusters[0].modelsCount, 5);
-                assert.equal(clusters[0].igfsCount, 0);
+                assert.equal(clusters[0].cachesCount, 2);
+                assert.equal(clusters[0].modelsCount, 2);
+                assert.equal(clusters[0].igfsCount, 1);
 
-                assert.equal(clusters[1].name, 'cluster-igfs');
+                assert.equal(clusters[1].name, 'cluster-caches');
                 assert.isNotNull(clusters[1].discovery);
-                assert.equal(clusters[1].cachesCount, 2);
-                assert.equal(clusters[1].modelsCount, 5);
-                assert.equal(clusters[1].igfsCount, 1);
+                assert.equal(clusters[1].cachesCount, 5);
+                assert.equal(clusters[1].modelsCount, 3);
+                assert.equal(clusters[1].igfsCount, 0);
             })
             .then(done)
             .catch(done);
@@ -179,7 +179,7 @@ suite('ClusterServiceTestsSuite', () => {
             .then((output) => {
                 assert.isNotNull(output);
 
-                assert.equal(output.n, 1);
+                assert.equal(output.rowsAffected, 1);
             })
             .then(() => clusterService.get(testAccounts[0]._id, false, 
cluster._id))
             .then((savedCluster) => {
@@ -277,9 +277,7 @@ suite('ClusterServiceTestsSuite', () => {
             })
             .then(() => cacheService.get(testAccounts[0]._id, false, 
_.head(testClusters).caches[1]))
             .then((c2) => {
-                assert.isNotNull(c2);
-                assert.equal(c2.cacheMode, 'PARTITIONED');
-                assert.isTrue(c2.readThrough);
+                assert.isNull(c2);
             })
             .then(done)
             .catch(done);

http://git-wip-us.apache.org/repos/asf/ignite/blob/4c295f8f/modules/web-console/backend/test/unit/Utils.test.js
----------------------------------------------------------------------
diff --git a/modules/web-console/backend/test/unit/Utils.test.js 
b/modules/web-console/backend/test/unit/Utils.test.js
new file mode 100644
index 0000000..10aa0d0
--- /dev/null
+++ b/modules/web-console/backend/test/unit/Utils.test.js
@@ -0,0 +1,48 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License.  You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+const assert = require('chai').assert;
+const injector = require('../injector');
+
+let utils;
+let errors;
+let db;
+
+suite('UtilsTestsSuite', () => {
+    suiteSetup(() => {
+        return Promise.all([injector('services/utils'),
+            injector('errors'),
+            injector('dbHelper')])
+            .then(([_utils, _errors, _db]) => {
+                utils = _utils;
+                errors = _errors;
+                db = _db;
+            });
+    });
+
+    setup(() => db.init());
+
+    test('Check token generator', () => {
+        const tokenLength = 16;
+        const token1 = utils.randomString(tokenLength);
+        const token2 = utils.randomString(tokenLength);
+
+        assert.equal(token1.length, tokenLength);
+        assert.equal(token2.length, tokenLength);
+        assert.notEqual(token1, token2);
+    });
+});

http://git-wip-us.apache.org/repos/asf/ignite/blob/4c295f8f/modules/web-console/docker/compose/backend/.dockerignore
----------------------------------------------------------------------
diff --git a/modules/web-console/docker/compose/backend/.dockerignore 
b/modules/web-console/docker/compose/backend/.dockerignore
deleted file mode 100644
index 05df665..0000000
--- a/modules/web-console/docker/compose/backend/.dockerignore
+++ /dev/null
@@ -1,3 +0,0 @@
-build/config/*.json
-build/node_modules
-build/test

http://git-wip-us.apache.org/repos/asf/ignite/blob/4c295f8f/modules/web-console/docker/compose/backend/Dockerfile
----------------------------------------------------------------------
diff --git a/modules/web-console/docker/compose/backend/Dockerfile 
b/modules/web-console/docker/compose/backend/Dockerfile
index 6ae4c93..de2652c 100644
--- a/modules/web-console/docker/compose/backend/Dockerfile
+++ b/modules/web-console/docker/compose/backend/Dockerfile
@@ -15,15 +15,20 @@
 # limitations under the License.
 #
 
-FROM node:8
+FROM node:8-slim
 
-RUN mkdir -p /opt/web-console-backend
+ENV NPM_CONFIG_LOGLEVEL error
 
-WORKDIR /opt/web-console-backend
+WORKDIR /opt/web-console
 
-COPY build .
+# Install node modules for frontend and backend modules.
+COPY backend/package*.json backend/
+RUN (cd backend && npm install --no-optional --production)
 
-RUN npm install --only=production --no-optional
+# Copy source.
+COPY backend backend
+
+COPY web-agent/target/ignite-web-agent-*.zip backend/agent_dists
 
 EXPOSE 3000
 

http://git-wip-us.apache.org/repos/asf/ignite/blob/4c295f8f/modules/web-console/docker/compose/backend/build.sh
----------------------------------------------------------------------
diff --git a/modules/web-console/docker/compose/backend/build.sh 
b/modules/web-console/docker/compose/backend/build.sh
deleted file mode 100755
index a10b706..0000000
--- a/modules/web-console/docker/compose/backend/build.sh
+++ /dev/null
@@ -1,57 +0,0 @@
-#!/bin/bash
-#
-# Licensed to the Apache Software Foundation (ASF) under one or more
-# contributor license agreements.  See the NOTICE file distributed with
-# this work for additional information regarding copyright ownership.
-# The ASF licenses this file to You under the Apache License, Version 2.0
-# (the "License"); you may not use this file except in compliance with
-# the License.  You may obtain a copy of the License at
-#
-#      http://www.apache.org/licenses/LICENSE-2.0
-#
-# Unless required by applicable law or agreed to in writing, software
-# distributed under the License is distributed on an "AS IS" BASIS,
-# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-# See the License for the specific language governing permissions and
-# limitations under the License.
-#
-
-if [ -z "$IGNITE_HOME" ]; then
-    echo "Ignite source folder is not found or IGNITE_HOME environment 
variable is not valid."
-
-    exit 1
-fi
-
-WORK_DIR=`cd "$(dirname "$0")"; pwd`
-
-BUILD_DIR="$WORK_DIR/build"
-
-IGNITE_WEB_CONSOLE_BACKEND_DIR="$IGNITE_HOME/modules/web-console/backend"
-DOCKER_IMAGE_NAME="apacheignite/web-console-backend"
-
-echo "Receiving version..."
-VERSION=`cd $IGNITE_HOME && mvn 
org.apache.maven.plugins:maven-help-plugin:evaluate 
-Dexpression=project.version| grep -Ev '(^\[|Download\w+:)'`
-RELEASE_VERSION=${VERSION%-SNAPSHOT}
-
-echo "Building $DOCKER_IMAGE_NAME:$RELEASE_VERSION"
-echo "Step 1. Prepare build temp paths."
-cd $WORK_DIR
-rm -Rf $BUILD_DIR
-docker rmi -f $DOCKER_IMAGE_NAME:$RELEASE_VERSION
-
-echo "Step 2. Build ignite web agent."
-cd $IGNITE_HOME
-mvn versions:set -DnewVersion=$RELEASE_VERSION -DgenerateBackupPoms=false 
-Pweb-console -DartifactId='*'
-mvn clean package -pl :ignite-web-agent -am -P web-console -DskipTests=true
-mvn versions:set -DnewVersion=$VERSION -DgenerateBackupPoms=false 
-Pweb-console -DartifactId='*'
-
-echo "Step 3. Copy sources."
-cd $WORK_DIR
-cp -r $IGNITE_WEB_CONSOLE_BACKEND_DIR/. $BUILD_DIR
-cp $IGNITE_HOME/modules/web-console/web-agent/target/ignite-web-agent*.zip 
$BUILD_DIR/agent_dists/.
-
-echo "Step 4. Build docker image."
-docker build -f=./Dockerfile -t $DOCKER_IMAGE_NAME:$RELEASE_VERSION -t 
$DOCKER_IMAGE_NAME:latest .
-
-echo "Step 5. Cleanup."
-rm -Rf $BUILD_DIR

http://git-wip-us.apache.org/repos/asf/ignite/blob/4c295f8f/modules/web-console/docker/compose/docker-compose.yml
----------------------------------------------------------------------
diff --git a/modules/web-console/docker/compose/docker-compose.yml 
b/modules/web-console/docker/compose/docker-compose.yml
index 89ffe98..109bfca 100644
--- a/modules/web-console/docker/compose/docker-compose.yml
+++ b/modules/web-console/docker/compose/docker-compose.yml
@@ -15,40 +15,42 @@
 # limitations under the License.
 #
 
-mongodb:
-  image: mongo:latest
-  volumes:
-    # External volume for persisting data. (HOST_PATH:CONTAINER_PATH).
-    - ./data/mongo:/data/db
+version: 1
 
-backend:
-  image: apacheignite/web-console-backend
-  links:
-    # Link mongodb container as with mongodb hostname.
-    - mongodb:mongodb
-  # Restart on crash.
-  restart: always  
-  environment:
-    # Port for serving frontend API
-    - server_port=3000
-    # Cookie session secret
-    - server_sessionSecret=CHANGE ME
-    # URL for mongodb connection
-    - mongodb_url=mongodb://mongodb/console
-    # Mail connection settings. Leave empty if no needed. See also settings, 
https://github.com/nodemailer/nodemailer
-    - mail_service=
-    - mail_sign=
-    - mail_greeting=
-    - mail_from=
-    - mail_auth_user=
-    - mail_auth_pass=
+services:
+  mongodb:
+    image: mongo:3.4
+    container_name: 'mongodb'
+    volumes:
+      # External volume for persisting data. (HOST_PATH:CONTAINER_PATH).
+      - ./data/mongo:/data/db
 
-frontend:
-  image: apacheignite/web-console-frontend
-  links:
-    # Link backend container to proxy backend requests throught nginx 
container.
-    - backend:backend
+  backend:
+    image: apacheignite/web-console-backend
+    depends_on:
+      - mongodb
+    # Restart on crash.
+    restart: always
+    environment:
+      # Port for serving frontend API
+      - server_port=3000
+      # Cookie session secret
+      - server_sessionSecret=CHANGE ME
+      # URL for mongodb connection
+      - mongodb_url=mongodb://mongodb/console
+      # Mail connection settings. Leave empty if no needed. See also settings, 
https://github.com/nodemailer/nodemailer
+      - mail_service=
+      - mail_sign=
+      - mail_greeting=
+      - mail_from=
+      - mail_auth_user=
+      - mail_auth_pass=
 
-  ports:
-    # Proxy HTTP nginx port (HOST_PORT:DOCKER_PORT)
-    - 80:80
+  frontend:
+    image: apacheignite/web-console-frontend
+    depends_on:
+      - mongodb
+      - testenv
+    ports:
+      # Proxy HTTP nginx port (HOST_PORT:DOCKER_PORT)
+      - 80:80

http://git-wip-us.apache.org/repos/asf/ignite/blob/4c295f8f/modules/web-console/docker/compose/frontend/.dockerignore
----------------------------------------------------------------------
diff --git a/modules/web-console/docker/compose/frontend/.dockerignore 
b/modules/web-console/docker/compose/frontend/.dockerignore
deleted file mode 100644
index caf0e8e..0000000
--- a/modules/web-console/docker/compose/frontend/.dockerignore
+++ /dev/null
@@ -1,3 +0,0 @@
-src/build
-src/ignite_modules_temp
-src/node_modules

http://git-wip-us.apache.org/repos/asf/ignite/blob/4c295f8f/modules/web-console/docker/compose/frontend/Dockerfile
----------------------------------------------------------------------
diff --git a/modules/web-console/docker/compose/frontend/Dockerfile 
b/modules/web-console/docker/compose/frontend/Dockerfile
index 1b578d1..07cbc46 100644
--- a/modules/web-console/docker/compose/frontend/Dockerfile
+++ b/modules/web-console/docker/compose/frontend/Dockerfile
@@ -15,16 +15,29 @@
 # limitations under the License.
 #
 
-FROM nginx
+FROM node:8-slim as frontend-build
 
-RUN mkdir -p /data/www
+ENV NPM_CONFIG_LOGLEVEL error
+
+WORKDIR /opt/web-console
+
+# Install node modules for frontend.
+COPY frontend/package*.json frontend/
+RUN (cd frontend && npm install --no-optional)
+
+# Copy source.
+COPY frontend frontend
+
+RUN (cd frontend && npm run build)
+
+FROM nginx:1-alpine
 
 WORKDIR /data/www
 
-COPY ./build .
+COPY --from=frontend-build /opt/web-console/frontend/build .
 
-COPY nginx/nginx.conf /etc/nginx/nginx.conf
-COPY nginx/web-console.conf /etc/nginx/web-console.conf
+COPY docker/compose/frontend/nginx/nginx.conf /etc/nginx/nginx.conf
+COPY docker/compose/frontend/nginx/web-console.conf /etc/nginx/web-console.conf
 
 VOLUME /etc/nginx
 VOLUME /data/www

http://git-wip-us.apache.org/repos/asf/ignite/blob/4c295f8f/modules/web-console/docker/compose/frontend/DockerfileBuild
----------------------------------------------------------------------
diff --git a/modules/web-console/docker/compose/frontend/DockerfileBuild 
b/modules/web-console/docker/compose/frontend/DockerfileBuild
deleted file mode 100644
index 94f5244..0000000
--- a/modules/web-console/docker/compose/frontend/DockerfileBuild
+++ /dev/null
@@ -1,30 +0,0 @@
-#
-# Licensed to the Apache Software Foundation (ASF) under one or more
-# contributor license agreements.  See the NOTICE file distributed with
-# this work for additional information regarding copyright ownership.
-# The ASF licenses this file to You under the Apache License, Version 2.0
-# (the "License"); you may not use this file except in compliance with
-# the License.  You may obtain a copy of the License at
-#
-#      http://www.apache.org/licenses/LICENSE-2.0
-#
-# Unless required by applicable law or agreed to in writing, software
-# distributed under the License is distributed on an "AS IS" BASIS,
-# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-# See the License for the specific language governing permissions and
-# limitations under the License.
-#
-
-FROM node:8
-
-RUN mkdir -p /opt/web-console-frontend
-
-WORKDIR /opt/web-console-frontend
-
-COPY src .
-
-RUN npm install --no-optional --prod
-
-VOLUME /opt/web-console-frontend/build
-
-CMD ["npm", "run", "build"]

http://git-wip-us.apache.org/repos/asf/ignite/blob/4c295f8f/modules/web-console/docker/compose/frontend/build.sh
----------------------------------------------------------------------
diff --git a/modules/web-console/docker/compose/frontend/build.sh 
b/modules/web-console/docker/compose/frontend/build.sh
deleted file mode 100755
index c807a86..0000000
--- a/modules/web-console/docker/compose/frontend/build.sh
+++ /dev/null
@@ -1,59 +0,0 @@
-#!/bin/bash
-#
-# Licensed to the Apache Software Foundation (ASF) under one or more
-# contributor license agreements.  See the NOTICE file distributed with
-# this work for additional information regarding copyright ownership.
-# The ASF licenses this file to You under the Apache License, Version 2.0
-# (the "License"); you may not use this file except in compliance with
-# the License.  You may obtain a copy of the License at
-#
-#      http://www.apache.org/licenses/LICENSE-2.0
-#
-# Unless required by applicable law or agreed to in writing, software
-# distributed under the License is distributed on an "AS IS" BASIS,
-# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-# See the License for the specific language governing permissions and
-# limitations under the License.
-#
-
-if [ -z "$IGNITE_HOME" ]; then
-    echo "Ignite source folder is not found or IGNITE_HOME environment 
variable is not valid."
-
-    exit 1
-fi
-
-WORK_DIR=`cd "$(dirname "$0")"; pwd`
-
-SOURCE_DIR=$WORK_DIR/src
-BUILD_DIR=$WORK_DIR/build
-
-DOCKER_BUILD_CONTAINER=web-console-frontend-builder
-DOCKER_BUILD_IMAGE_NAME=apacheignite/$DOCKER_BUILD_CONTAINER
-DOCKER_IMAGE_NAME=apacheignite/web-console-frontend
-
-echo "Receiving version..."
-VERSION=`cd $IGNITE_HOME && mvn 
org.apache.maven.plugins:maven-help-plugin:evaluate 
-Dexpression=project.version| grep -Ev '(^\[|Download\w+:)'`
-RELEASE_VERSION=${VERSION%-SNAPSHOT}
-
-echo "Building $DOCKER_IMAGE_NAME:$RELEASE_VERSION"
-echo "Step 1. Build frontend SPA"
-cd $WORK_DIR
-
-rm -Rf $SOURCE_DIR
-rm -Rf $BUILD_DIR
-mkdir -p $SOURCE_DIR
-mkdir -p $BUILD_DIR
-
-cp -r $IGNITE_HOME/modules/web-console/frontend/. $SOURCE_DIR
-
-docker build -f=./DockerfileBuild -t $DOCKER_BUILD_IMAGE_NAME:latest .
-docker run -it -v $BUILD_DIR:/opt/web-console-frontend/build --name 
$DOCKER_BUILD_CONTAINER $DOCKER_BUILD_IMAGE_NAME
-
-echo "Step 2. Build NGINX container with SPA and proxy configuration"
-docker build -f=./Dockerfile -t $DOCKER_IMAGE_NAME:$RELEASE_VERSION -t 
$DOCKER_IMAGE_NAME:latest .
-
-echo "Step 3. Cleanup"
-docker rm -f $DOCKER_BUILD_CONTAINER
-docker rmi -f $DOCKER_BUILD_IMAGE_NAME
-rm -r $SOURCE_DIR
-rm -r $BUILD_DIR

http://git-wip-us.apache.org/repos/asf/ignite/blob/4c295f8f/modules/web-console/docker/compose/frontend/nginx/web-console.conf
----------------------------------------------------------------------
diff --git a/modules/web-console/docker/compose/frontend/nginx/web-console.conf 
b/modules/web-console/docker/compose/frontend/nginx/web-console.conf
index 3f5157d..4fbf204 100644
--- a/modules/web-console/docker/compose/frontend/nginx/web-console.conf
+++ b/modules/web-console/docker/compose/frontend/nginx/web-console.conf
@@ -24,17 +24,12 @@ server {
   server_name _;
 
   set $ignite_console_dir /data/www;
-  set $maintenance $ignite_console_dir/maintenance.file;
 
   root $ignite_console_dir;
 
   error_page 500 502 503 504 /50x.html;
 
   location / {
-    if (-f $maintenance) {
-      return 503;
-    }
-
     try_files $uri /index.html = 404;
   }
 

http://git-wip-us.apache.org/repos/asf/ignite/blob/4c295f8f/modules/web-console/docker/standalone/.dockerignore
----------------------------------------------------------------------
diff --git a/modules/web-console/docker/standalone/.dockerignore 
b/modules/web-console/docker/standalone/.dockerignore
deleted file mode 100644
index 0951480..0000000
--- a/modules/web-console/docker/standalone/.dockerignore
+++ /dev/null
@@ -1,2 +0,0 @@
-build/frontend/test
-build/backend/test

http://git-wip-us.apache.org/repos/asf/ignite/blob/4c295f8f/modules/web-console/docker/standalone/Dockerfile
----------------------------------------------------------------------
diff --git a/modules/web-console/docker/standalone/Dockerfile 
b/modules/web-console/docker/standalone/Dockerfile
index 2fd5f56..9b00734 100644
--- a/modules/web-console/docker/standalone/Dockerfile
+++ b/modules/web-console/docker/standalone/Dockerfile
@@ -15,57 +15,62 @@
 # limitations under the License.
 #
 
-FROM ubuntu:14.04
+FROM node:8-slim as frontend-build
 
-ENV NPM_CONFIG_LOGLEVEL info
-ENV NODE_VERSION 8.11.1
+ENV NPM_CONFIG_LOGLEVEL error
 
-RUN apt-key adv --keyserver hkp://keyserver.ubuntu.com:80 --recv EA312927 && \
-    echo "deb http://repo.mongodb.org/apt/ubuntu trusty/mongodb-org/3.2 
multiverse" | sudo tee /etc/apt/sources.list.d/mongodb-org-3.2.list
+WORKDIR /opt/web-console
+
+# Install node modules for frontend.
+COPY frontend/package*.json frontend/
+RUN (cd frontend && npm install --no-optional)
+
+# Copy source.
+COPY frontend frontend
+
+RUN (cd frontend && npm run build)
+
+FROM node:8-slim
+
+ENV NPM_CONFIG_LOGLEVEL error
 
 # Update package list & install.
-RUN apt-get update && \
-    apt-get install -y nginx-light mongodb-org-server curl xz-utils git
+RUN apt-key adv --keyserver hkp://keyserver.ubuntu.com:80 --recv 
0C49F3730359A14518585931BC711F9BA15703C6 \
+    && echo "deb http://repo.mongodb.org/apt/debian jessie/mongodb-org/3.4 
main" | tee /etc/apt/sources.list.d/mongodb-org-3.4.list
 
-# Install Node JS.
-RUN curl -SLO 
"https://nodejs.org/dist/v$NODE_VERSION/node-v$NODE_VERSION-linux-x64.tar.xz"; 
&& \
-    curl -SLO "https://nodejs.org/dist/v$NODE_VERSION/SHASUMS256.txt"; && \
-    grep " node-v$NODE_VERSION-linux-x64.tar.xz\$" SHASUMS256.txt | sha256sum 
-c - && \
-    tar -xJf "node-v$NODE_VERSION-linux-x64.tar.xz" -C /usr/local 
--strip-components=1 && \
-    rm -rf "node-v$NODE_VERSION-linux-x64.tar.xz" SHASUMS256.txt
+# Update package list & install.
+RUN apt-get update \
+    && apt-get install -y nginx-light mongodb-org-server dos2unix \
+    && apt-get clean \
+    && rm -rf /var/lib/apt/lists/*
 
 # Install global node packages.
 RUN npm install -g pm2
 
-# Install frontend & backend apps.
-RUN mkdir -p /opt/web-console
-
-# Copy source.
 WORKDIR /opt/web-console
-COPY build .
 
-# Install node modules for frontend and backend modules.
-RUN cd /opt/web-console/frontend && \
-    npm install --no-optional --prod && \
-    npm run build && \
-    cd /opt/web-console/backend && \
-    npm install --no-optional --prod
+COPY docker/standalone/docker-entrypoint.sh docker-entrypoint.sh
+
+RUN chmod +x docker-entrypoint.sh \
+    && dos2unix docker-entrypoint.sh
 
 # Copy nginx config.
-COPY nginx/* /etc/nginx/
+COPY docker/standalone/nginx/* /etc/nginx/
 
-# Copy entrypoint.
-COPY entrypoint.sh .
+# Install node modules for frontend and backend modules.
+COPY backend/package*.json backend/
+RUN (cd backend && npm install --no-optional --production)
 
-# Clean up.
-RUN apt-get clean && \
-    rm -rf /var/lib/apt/lists/* /tmp/* /var/tmp/*
+# Copy source.
+COPY backend backend
+
+COPY web-agent/target/ignite-web-agent-*.zip backend/agent_dists
+
+COPY --from=frontend-build /opt/web-console/frontend/build static
 
 VOLUME ["/etc/nginx"]
-VOLUME ["/var/lib/mongodb"]
+VOLUME ["/data/db"]
 VOLUME ["/opt/web-console/serve/agent_dists"]
 
 EXPOSE 80
-
-ENTRYPOINT ["/opt/web-console/entrypoint.sh"]
-
+ENTRYPOINT ["/opt/web-console/docker-entrypoint.sh"]

http://git-wip-us.apache.org/repos/asf/ignite/blob/4c295f8f/modules/web-console/docker/standalone/README.txt
----------------------------------------------------------------------
diff --git a/modules/web-console/docker/standalone/README.txt 
b/modules/web-console/docker/standalone/README.txt
deleted file mode 100644
index 68cfa8e..0000000
--- a/modules/web-console/docker/standalone/README.txt
+++ /dev/null
@@ -1,24 +0,0 @@
-Web Console Docker module
-=========================
-Web Console Docker module provides Dockerfile and accompanying files for 
building docker image.
-
-
-Build image
-===========
-1) Build Apache Ignite binary archive as described in DEVNOTES.txt.
-
-2) Goto Web Console's Docker module directory
-
-        cd modules/web-console/docker/standalone
-
-3) Copy build-related necessary files
-
-        mkdir -pv build
-        cp -rf ../../frontend ../../backend build
-        cp -rfv ../../web-agent/target/ignite-web-agent-*.zip 
build/backend/agent_dists/
-
-4) Build docker image
-
-        docker build . -t apacheignite/web-console-standalone[:<version>]
-
-   Prepared image will be available issuing `docker images` command

http://git-wip-us.apache.org/repos/asf/ignite/blob/4c295f8f/modules/web-console/docker/standalone/docker-entrypoint.sh
----------------------------------------------------------------------
diff --git a/modules/web-console/docker/standalone/docker-entrypoint.sh 
b/modules/web-console/docker/standalone/docker-entrypoint.sh
new file mode 100644
index 0000000..6757de6
--- /dev/null
+++ b/modules/web-console/docker/standalone/docker-entrypoint.sh
@@ -0,0 +1,23 @@
+#!/bin/sh
+#
+# Licensed to the Apache Software Foundation (ASF) under one or more
+# contributor license agreements.  See the NOTICE file distributed with
+# this work for additional information regarding copyright ownership.
+# The ASF licenses this file to You under the Apache License, Version 2.0
+# (the "License"); you may not use this file except in compliance with
+# the License.  You may obtain a copy of the License at
+#
+#      http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+#
+
+/usr/bin/mongod --fork --config=/etc/mongod.conf
+
+service nginx start
+
+cd backend && pm2 start ./index.js --no-daemon

http://git-wip-us.apache.org/repos/asf/ignite/blob/4c295f8f/modules/web-console/docker/standalone/entrypoint.sh
----------------------------------------------------------------------
diff --git a/modules/web-console/docker/standalone/entrypoint.sh 
b/modules/web-console/docker/standalone/entrypoint.sh
deleted file mode 100755
index 3882f06..0000000
--- a/modules/web-console/docker/standalone/entrypoint.sh
+++ /dev/null
@@ -1,23 +0,0 @@
-#!/bin/bash
-#
-# Licensed to the Apache Software Foundation (ASF) under one or more
-# contributor license agreements.  See the NOTICE file distributed with
-# this work for additional information regarding copyright ownership.
-# The ASF licenses this file to You under the Apache License, Version 2.0
-# (the "License"); you may not use this file except in compliance with
-# the License.  You may obtain a copy of the License at
-#
-#      http://www.apache.org/licenses/LICENSE-2.0
-#
-# Unless required by applicable law or agreed to in writing, software
-# distributed under the License is distributed on an "AS IS" BASIS,
-# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-# See the License for the specific language governing permissions and
-# limitations under the License.
-#
-
-/usr/bin/mongod --fork --config=/etc/mongod.conf
-
-service nginx start
-
-cd backend && pm2 start ./index.js --no-daemon

http://git-wip-us.apache.org/repos/asf/ignite/blob/4c295f8f/modules/web-console/docker/standalone/nginx/web-console.conf
----------------------------------------------------------------------
diff --git a/modules/web-console/docker/standalone/nginx/web-console.conf 
b/modules/web-console/docker/standalone/nginx/web-console.conf
index 6e36eed..caf171e 100644
--- a/modules/web-console/docker/standalone/nginx/web-console.conf
+++ b/modules/web-console/docker/standalone/nginx/web-console.conf
@@ -23,7 +23,7 @@ server {
   listen 80;
   server_name _;
 
-  set $ignite_console_dir /opt/web-console/frontend/build;
+  set $ignite_console_dir /opt/web-console/static;
 
   root $ignite_console_dir;
 

http://git-wip-us.apache.org/repos/asf/ignite/blob/4c295f8f/modules/web-console/e2e/docker-compose.yml
----------------------------------------------------------------------
diff --git a/modules/web-console/e2e/docker-compose.yml 
b/modules/web-console/e2e/docker-compose.yml
index 83054cc..ae99809 100644
--- a/modules/web-console/e2e/docker-compose.yml
+++ b/modules/web-console/e2e/docker-compose.yml
@@ -35,7 +35,7 @@ services:
     environment:
       - DB_URL=mongodb://mongodb:27017/console-e2e
       - APP_URL=http://testenv:9001/
-      - TEAMCITY=true
+      - REPORTER=teamcity
       - QUARANTINE_MODE=true
     depends_on:
       - mongodb

http://git-wip-us.apache.org/repos/asf/ignite/blob/4c295f8f/modules/web-console/e2e/testcafe/Dockerfile
----------------------------------------------------------------------
diff --git a/modules/web-console/e2e/testcafe/Dockerfile 
b/modules/web-console/e2e/testcafe/Dockerfile
index d890d10..d207eec 100644
--- a/modules/web-console/e2e/testcafe/Dockerfile
+++ b/modules/web-console/e2e/testcafe/Dockerfile
@@ -19,16 +19,14 @@ FROM testcafe/testcafe:latest
 
 USER 0
 
-RUN mkdir -p /opt/testcafe/tests
-
 WORKDIR /opt/testcafe/tests
 
-COPY . /opt/testcafe/tests
+COPY . .
 
-ENV NPM_CONFIG_LOGLEVEL warn
+ENV NPM_CONFIG_LOGLEVEL error
 
-RUN npm install --production && \
+RUN npm install --no-optional --production && \
  npm cache verify --force && \
  rm -rf /tmp/*
 
-ENTRYPOINT ["node", "./testcafe.js"]
\ No newline at end of file
+ENTRYPOINT ["node", "./index.js"]
\ No newline at end of file

http://git-wip-us.apache.org/repos/asf/ignite/blob/4c295f8f/modules/web-console/e2e/testcafe/components/FormField.js
----------------------------------------------------------------------
diff --git a/modules/web-console/e2e/testcafe/components/FormField.js 
b/modules/web-console/e2e/testcafe/components/FormField.js
index 5bd70f5..71d951c 100644
--- a/modules/web-console/e2e/testcafe/components/FormField.js
+++ b/modules/web-console/e2e/testcafe/components/FormField.js
@@ -24,6 +24,9 @@ export class FormField {
     static CONTROL_SELECTOR = '[ng-model]';
     static ERRORS_SELECTOR = '.ignite-form-field__errors';
 
+    /** @type {ReturnType<Selector>} */
+    _selector;
+
     constructor({id = '', label = '', model = ''} = {}) {
         if (!id && !label && !model) throw new Error('ID, label or model are 
required');
         if (id)

http://git-wip-us.apache.org/repos/asf/ignite/blob/4c295f8f/modules/web-console/e2e/testcafe/components/Table.js
----------------------------------------------------------------------
diff --git a/modules/web-console/e2e/testcafe/components/Table.js 
b/modules/web-console/e2e/testcafe/components/Table.js
index e690599..415f98d 100644
--- a/modules/web-console/e2e/testcafe/components/Table.js
+++ b/modules/web-console/e2e/testcafe/components/Table.js
@@ -15,31 +15,34 @@
  * limitations under the License.
  */
 
-import {Selector, t} from 'testcafe'
+import {Selector, t} from 'testcafe';
 
 const findCell = Selector((table, rowIndex, columnLabel) => {
     table = table();
 
     const columnIndex = [].constructor.from(
         
table.querySelectorAll('.ui-grid-header-cell:not(.ui-grid-header-span)'),
-        e => e.textContent
-    ).findIndex(t => t.includes(columnLabel));
+        (e) => e.textContent
+    ).findIndex((t) => t.includes(columnLabel));
 
-    const row = table.querySelector(`.ui-grid-render-container:not(.left) 
.ui-grid-viewport .ui-grid-row:nth-of-type(${rowIndex+1})`);
+    const row = table.querySelector(`.ui-grid-render-container:not(.left) 
.ui-grid-viewport .ui-grid-row:nth-of-type(${rowIndex + 1})`);
     const cell = 
row.querySelector(`.ui-grid-cell:nth-of-type(${columnIndex})`);
+
     return cell;
 });
 
 export class Table {
+    /** @param {ReturnType<Selector>} selector */
     constructor(selector) {
         this._selector = selector;
         this.title = this._selector.find('.panel-title');
         this.actionsButton = 
this._selector.find('.btn-ignite').withText('Actions');
-        this.allItemsCheckbox = this._selector.find('[role="checkbox button"]')
+        this.allItemsCheckbox = this._selector.find('[role="checkbox 
button"]');
     }
 
+    /** @param {string} label */
     async performAction(label) {
-        await t.hover(this.actionsButton).click(Selector('.dropdown-menu 
a').withText(label))
+        await t.hover(this.actionsButton).click(Selector('.dropdown-menu 
a').withText(label));
     }
 
     /**
@@ -47,10 +50,14 @@ export class Table {
      * @param {number} index Index of row, starting with 1
      */
     async toggleRowSelection(index) {
-        await t.click(this._selector.find(`.ui-grid-pinned-container 
.ui-grid-row:nth-of-type(${index}) .ui-grid-selection-row-header-buttons`))
+        await t.click(this._selector.find(`.ui-grid-pinned-container 
.ui-grid-row:nth-of-type(${index}) .ui-grid-selection-row-header-buttons`));
     }
 
+    /**
+     * @param {number} rowIndex
+     * @param {string} columnLabel
+     */
     findCell(rowIndex, columnLabel) {
-        return Selector(findCell(this._selector, rowIndex, columnLabel))
+        return Selector(findCell(this._selector, rowIndex, columnLabel));
     }
 }

http://git-wip-us.apache.org/repos/asf/ignite/blob/4c295f8f/modules/web-console/e2e/testcafe/environment/envtools.js
----------------------------------------------------------------------
diff --git a/modules/web-console/e2e/testcafe/environment/envtools.js 
b/modules/web-console/e2e/testcafe/environment/envtools.js
new file mode 100644
index 0000000..c86a34a
--- /dev/null
+++ b/modules/web-console/e2e/testcafe/environment/envtools.js
@@ -0,0 +1,196 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License.  You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+const MongoClient = require('mongodb').MongoClient;
+const objectid = require('objectid');
+const { spawn } = require('child_process');
+const url = require('url');
+
+const argv = require('minimist')(process.argv.slice(2));
+const start = argv._.includes('start');
+const stop = argv._.includes('stop');
+
+const mongoUrl = process.env.DB_URL || 'mongodb://localhost/console-e2e';
+
+const insertTestUser = ({userId = '000000000000000000000001', token = 
'ppw4tPI3JUOGHva8CODO'} = {}) => {
+    return new Promise((res, rej) => {
+        MongoClient
+            .connect(mongoUrl, function(err, db) {
+                if (err) {
+                    rej();
+                    throw err;
+                }
+
+                // Add test user.
+                const user = {
+                    _id: objectid(userId),
+                    salt: 
'ca8b49c2eacd498a0973de30c0873c166ed99fa0605981726aedcc85bee17832',
+                    hash: 
'c052c87e454cd0875332719e1ce085ccd92bedb73c8f939ba45d387f724da97128280643ad4f841d929d48de802f48f4a27b909d2dc806d957d38a1a4049468ce817490038f00ac1416aaf9f8f5a5c476730b46ea22d678421cd269869d4ba9d194f73906e5d5a4fec5229459e20ebda997fb95298067126f6c15346d886d44b67def03bf3ffe484b2e4fa449985de33a0c12e4e1da4c7d71fe7af5d138433f703d8c7eeebbb3d57f1a89659010a1f1d3cd4fbc524abab07860daabb08f08a28b8bfc64ecde2ea3c103030d0d54fc24d9c02f92ee6b3aa1bcd5c70113ab9a8045faea7dd2dc59ec4f9f69fcf634232721e9fb44012f0e8c8fdf7c6bf642db6867ef8e7877123e1bc78af7604fee2e34ad0191f8b97613ea458e0fca024226b7055e08a4bdb256fabf0a203a1e5b6a6c298fb0c60308569cefba779ce1e41fb971e5d1745959caf524ab0bedafce67157922f9c505cea033f6ed28204791470d9d08d31ce7e8003df8a3a05282d4d60bfe6e2f7de06f4b18377dac0fe764ed683c9b2553e75f8280c748aa166fef6f89190b1c6d369ab86422032171e6f9686de42ac65708e63bf018a043601d85bc5c820c7ad1d51ded32e59cdaa629a3f7ae325bbc931f9f21d90c9204effdbd53721a60c8b180dd8c236133e287a47ccc9e5072eb65937
 71e435e4d5196d50d6ddb32c226651c6503387895c5ad025f69fd3',
+                    password: 'a',
+                    email: 'a@a',
+                    firstName: 'John',
+                    lastName: 'Doe',
+                    company: 'TestCompany',
+                    country: 'Canada',
+                    industry: 'Banking',
+                    admin: true,
+                    token,
+                    attempts: 0,
+                    lastLogin: '2018-01-28T10:41:07.463Z',
+                    resetPasswordToken: '892rnLbEnVp1FP75Jgpi'
+                };
+                db.collection('accounts').insert(user);
+
+                // Add test spaces.
+
+                const spaces = [
+                    {
+                        _id: objectid('000000000000000000000001'),
+                        name: 'Personal space',
+                        owner: objectid(userId),
+                        demo: false
+                    },
+                    {
+                        _id: objectid('000000000000000000000002'),
+                        name: 'Demo space',
+                        owner: objectid(userId),
+                        demo: true
+                    }
+                ];
+                db.collection('spaces').insertMany(spaces);
+
+                db.close();
+                res();
+
+            });
+    });
+};
+
+const dropTestDB = () => {
+    return new Promise((resolve, reject) => {
+        MongoClient.connect(mongoUrl, async(err, db) => {
+            if (err)
+                return reject(err);
+
+            db.dropDatabase((err) => {
+                if (err)
+                    return reject(err);
+
+                resolve();
+            });
+        });
+    });
+};
+
+
+/**
+ * Spawns a new process using the given command.
+ * @param command {String} The command to run.
+ * @param onResolveString {String} Await string in output.
+ * @param cwd {String} Current working directory of the child process.
+ * @param env {Object} Environment key-value pairs.
+ * @return {Promise<ChildProcess>}
+ */
+const exec = (command, onResolveString, cwd, env) => {
+    return new Promise((resolve) => {
+        env = Object.assign({}, process.env, env, { FORCE_COLOR: true });
+
+        const [cmd, ...args] = command.split(' ');
+
+        const detached = process.platform !== 'win32';
+
+        const child = spawn(cmd, args, {cwd, env, detached});
+
+        if (detached) {
+            // do something when app is closing
+            process.on('exit', () => process.kill(-child.pid));
+
+            // catches ctrl+c event
+            process.on('SIGINT', () => process.kill(-child.pid));
+
+            // catches "kill pid" (for example: nodemon restart)
+            process.on('SIGUSR1', () => process.kill(-child.pid));
+            process.on('SIGUSR2', () => process.kill(-child.pid));
+
+            // catches uncaught exceptions
+            process.on('uncaughtException', () => process.kill(-child.pid));
+        }
+
+        // Pipe error messages to stdout.
+        child.stderr.on('data', (data) => {
+            process.stdout.write(data.toString());
+        });
+
+        child.stdout.on('data', (data) => {
+            process.stdout.write(data.toString());
+
+            if (data.includes(onResolveString))
+                resolve(child);
+        });
+    });
+};
+
+const startEnv = (webConsoleRootDirectoryPath = '../../') => {
+    return new Promise(async(resolve) => {
+        const command = `${process.platform === 'win32' ? 'npm.cmd' : 'npm'} 
start`;
+
+        let port = 9001;
+
+        if (process.env.APP_URL)
+            port = parseInt(url.parse(process.env.APP_URL).port, 10) || 80;
+
+        const backendInstanceLaunch = exec(command, 'Start listening', 
`${webConsoleRootDirectoryPath}backend`, {server_port: 3001, mongodb_url: 
mongoUrl}); // Todo: refactor cwd for backend when it's linked
+        const frontendInstanceLaunch = exec(command, 'Compiled successfully', 
`${webConsoleRootDirectoryPath}frontend`, {BACKEND_PORT: 3001, PORT: port});
+
+        console.log('Building backend in progress...');
+        await backendInstanceLaunch;
+        console.log('Building backend done!');
+
+        console.log('Building frontend in progress...');
+        await frontendInstanceLaunch;
+        console.log('Building frontend done!');
+
+        resolve();
+    });
+};
+
+if (start) {
+    startEnv();
+
+    process.on('SIGINT', async() => {
+        await dropTestDB();
+
+        process.exit(0);
+    });
+}
+
+if (stop) {
+    dropTestDB();
+
+    console.log('Cleaning done...');
+}
+
+
+/**
+ * @param {string} targetUrl
+ * @returns {string}
+ */
+const resolveUrl = (targetUrl) => {
+    return url.resolve(process.env.APP_URL || 'http://localhost:9001', 
targetUrl);
+};
+
+module.exports = { startEnv, insertTestUser, dropTestDB, resolveUrl };

http://git-wip-us.apache.org/repos/asf/ignite/blob/4c295f8f/modules/web-console/e2e/testcafe/environment/launch-env.js
----------------------------------------------------------------------
diff --git a/modules/web-console/e2e/testcafe/environment/launch-env.js 
b/modules/web-console/e2e/testcafe/environment/launch-env.js
new file mode 100644
index 0000000..73b4bae
--- /dev/null
+++ b/modules/web-console/e2e/testcafe/environment/launch-env.js
@@ -0,0 +1,26 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License.  You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+const { startEnv, dropTestDB } = require('./envtools');
+
+startEnv();
+
+process.on('SIGINT', async() => {
+    await dropTestDB();
+
+    process.exit(0);
+});

http://git-wip-us.apache.org/repos/asf/ignite/blob/4c295f8f/modules/web-console/e2e/testcafe/envtools.js
----------------------------------------------------------------------
diff --git a/modules/web-console/e2e/testcafe/envtools.js 
b/modules/web-console/e2e/testcafe/envtools.js
deleted file mode 100644
index e6b6d6c..0000000
--- a/modules/web-console/e2e/testcafe/envtools.js
+++ /dev/null
@@ -1,192 +0,0 @@
-/*
- * Licensed to the Apache Software Foundation (ASF) under one or more
- * contributor license agreements.  See the NOTICE file distributed with
- * this work for additional information regarding copyright ownership.
- * The ASF licenses this file to You under the Apache License, Version 2.0
- * (the "License"); you may not use this file except in compliance with
- * the License.  You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-const MongoClient = require('mongodb').MongoClient;
-const objectid = require('objectid');
-const { spawn } = require('child_process');
-const url = require('url');
-
-const argv = require('minimist')(process.argv.slice(2));
-const start = argv._.includes('start');
-const stop = argv._.includes('stop');
-
-const mongoUrl = process.env.DB_URL || 'mongodb://localhost/console-e2e';
-
-const insertTestUser = ({userId = '000000000000000000000001', token = 
'ppw4tPI3JUOGHva8CODO'} = {}) => {
-    return new Promise((res, rej) => {
-        MongoClient
-            .connect(mongoUrl, function(err, db) {
-                if (err) {
-                    rej();
-                    throw err;
-                }
-
-                // Add test user.
-                const user = {
-                    _id: objectid(userId),
-                    salt: 
'ca8b49c2eacd498a0973de30c0873c166ed99fa0605981726aedcc85bee17832',
-                    hash: 
'c052c87e454cd0875332719e1ce085ccd92bedb73c8f939ba45d387f724da97128280643ad4f841d929d48de802f48f4a27b909d2dc806d957d38a1a4049468ce817490038f00ac1416aaf9f8f5a5c476730b46ea22d678421cd269869d4ba9d194f73906e5d5a4fec5229459e20ebda997fb95298067126f6c15346d886d44b67def03bf3ffe484b2e4fa449985de33a0c12e4e1da4c7d71fe7af5d138433f703d8c7eeebbb3d57f1a89659010a1f1d3cd4fbc524abab07860daabb08f08a28b8bfc64ecde2ea3c103030d0d54fc24d9c02f92ee6b3aa1bcd5c70113ab9a8045faea7dd2dc59ec4f9f69fcf634232721e9fb44012f0e8c8fdf7c6bf642db6867ef8e7877123e1bc78af7604fee2e34ad0191f8b97613ea458e0fca024226b7055e08a4bdb256fabf0a203a1e5b6a6c298fb0c60308569cefba779ce1e41fb971e5d1745959caf524ab0bedafce67157922f9c505cea033f6ed28204791470d9d08d31ce7e8003df8a3a05282d4d60bfe6e2f7de06f4b18377dac0fe764ed683c9b2553e75f8280c748aa166fef6f89190b1c6d369ab86422032171e6f9686de42ac65708e63bf018a043601d85bc5c820c7ad1d51ded32e59cdaa629a3f7ae325bbc931f9f21d90c9204effdbd53721a60c8b180dd8c236133e287a47ccc9e5072eb65937
 71e435e4d5196d50d6ddb32c226651c6503387895c5ad025f69fd3',
-                    password: 'a',
-                    email: 'a@a',
-                    firstName: 'John',
-                    lastName: 'Doe',
-                    company: 'TestCompany',
-                    country: 'Canada',
-                    industry: 'Banking',
-                    admin: true,
-                    token,
-                    attempts: 0,
-                    lastLogin: '2018-01-28T10:41:07.463Z',
-                    resetPasswordToken: '892rnLbEnVp1FP75Jgpi'
-                };
-                db.collection('accounts').insert(user);
-
-                // Add test spaces.
-
-                const spaces = [
-                    {
-                        _id: objectid('000000000000000000000001'),
-                        name: 'Personal space',
-                        owner: objectid(userId),
-                        demo: false
-                    },
-                    {
-                        _id: objectid('000000000000000000000002'),
-                        name: 'Demo space',
-                        owner: objectid(userId),
-                        demo: true
-                    }
-                ];
-                db.collection('spaces').insertMany(spaces);
-
-                db.close();
-                res();
-
-            });
-    });
-};
-
-const dropTestDB = () => {
-    return new Promise((resolve, reject) => {
-        MongoClient.connect(mongoUrl, async(err, db) => {
-            if (err)
-                return reject(err);
-
-            db.dropDatabase((err) => {
-                if (err)
-                    return reject(err);
-
-                resolve();
-            });
-        });
-    });
-};
-
-
-/**
- * Spawns a new process using the given command.
- * @param command {String} The command to run.
- * @param onResolveString {String} Await string in output.
- * @param cwd {String} Current working directory of the child process.
- * @param env {Object} Environment key-value pairs.
- * @return {Promise<ChildProcess>}
- */
-const exec = (command, onResolveString, cwd, env) => {
-    return new Promise((resolve) => {
-        env = Object.assign({}, process.env, env, { FORCE_COLOR: true });
-
-        const [cmd, ...args] = command.split(' ');
-
-        const detached = process.platform !== 'win32';
-
-        const child = spawn(cmd, args, {cwd, env, detached});
-
-        if (detached) {
-            // do something when app is closing
-            process.on('exit', () => process.kill(-child.pid));
-
-            // catches ctrl+c event
-            process.on('SIGINT', () => process.kill(-child.pid));
-
-            // catches "kill pid" (for example: nodemon restart)
-            process.on('SIGUSR1', () => process.kill(-child.pid));
-            process.on('SIGUSR2', () => process.kill(-child.pid));
-
-            // catches uncaught exceptions
-            process.on('uncaughtException', () => process.kill(-child.pid));
-        }
-
-        // Pipe error messages to stdout.
-        child.stderr.on('data', (data) => {
-            process.stdout.write(data.toString());
-        });
-
-        child.stdout.on('data', (data) => {
-            process.stdout.write(data.toString());
-
-            if (data.includes(onResolveString))
-                resolve(child);
-        });
-    });
-};
-
-const startEnv = () => {
-    return new Promise(async(resolve) => {
-        const command = `${process.platform === 'win32' ? 'npm.cmd' : 'npm'} 
start`;
-
-        let port = 9001;
-
-        if (process.env.APP_URL)
-            port = parseInt(url.parse(process.env.APP_URL).port, 10) || 80;
-
-        const backendInstanceLaunch = exec(command, 'Start listening', 
'../../backend', {server_port: 3001, mongodb_url: mongoUrl});
-        const frontendInstanceLaunch = exec(command, 'Compiled successfully', 
'../../frontend', {BACKEND_PORT: 3001, PORT: port});
-
-        console.log('Building backend in progress...');
-        await backendInstanceLaunch;
-        console.log('Building backend done!');
-
-        console.log('Building frontend in progress...');
-        await frontendInstanceLaunch;
-        console.log('Building frontend done!');
-
-        resolve();
-    });
-};
-
-if (start) {
-    startEnv();
-
-    process.on('SIGINT', async() => {
-        await dropTestDB();
-
-        process.exit(0);
-    });
-}
-
-if (stop) {
-    dropTestDB();
-
-    console.log('Cleaning done...');
-}
-
-
-const resolveUrl = (targetUrl) => {
-    return url.resolve(process.env.APP_URL || 'http://localhost:9001', 
targetUrl);
-};
-
-module.exports = { startEnv, insertTestUser, dropTestDB, resolveUrl };

http://git-wip-us.apache.org/repos/asf/ignite/blob/4c295f8f/modules/web-console/e2e/testcafe/fixtures/admin-panel.js
----------------------------------------------------------------------
diff --git a/modules/web-console/e2e/testcafe/fixtures/admin-panel.js 
b/modules/web-console/e2e/testcafe/fixtures/admin-panel.js
index 9eea360..0851d3f 100644
--- a/modules/web-console/e2e/testcafe/fixtures/admin-panel.js
+++ b/modules/web-console/e2e/testcafe/fixtures/admin-panel.js
@@ -17,7 +17,7 @@
 
 import { Selector } from 'testcafe';
 import { AngularJSSelector } from 'testcafe-angular-selectors';
-import { dropTestDB, insertTestUser, resolveUrl } from '../envtools';
+import { dropTestDB, insertTestUser, resolveUrl } from 
'../environment/envtools';
 import { createRegularUser } from '../roles';
 
 const regularUser = createRegularUser();

http://git-wip-us.apache.org/repos/asf/ignite/blob/4c295f8f/modules/web-console/e2e/testcafe/fixtures/auth/forgot-password.js
----------------------------------------------------------------------
diff --git a/modules/web-console/e2e/testcafe/fixtures/auth/forgot-password.js 
b/modules/web-console/e2e/testcafe/fixtures/auth/forgot-password.js
index 33963fa..7a9f796 100644
--- a/modules/web-console/e2e/testcafe/fixtures/auth/forgot-password.js
+++ b/modules/web-console/e2e/testcafe/fixtures/auth/forgot-password.js
@@ -15,7 +15,7 @@
  * limitations under the License.
  */
 
-import { dropTestDB, resolveUrl, insertTestUser } from '../../envtools';
+import { dropTestDB, resolveUrl, insertTestUser } from 
'../../environment/envtools';
 import {PageSignIn} from '../../page-models/pageSignin';
 import {errorNotification} from '../../components/notifications';
 import {pageForgotPassword as page} from 
'../../page-models/pageForgotPassword';

http://git-wip-us.apache.org/repos/asf/ignite/blob/4c295f8f/modules/web-console/e2e/testcafe/fixtures/auth/logout.js
----------------------------------------------------------------------
diff --git a/modules/web-console/e2e/testcafe/fixtures/auth/logout.js 
b/modules/web-console/e2e/testcafe/fixtures/auth/logout.js
index d2e7e66..de495ef 100644
--- a/modules/web-console/e2e/testcafe/fixtures/auth/logout.js
+++ b/modules/web-console/e2e/testcafe/fixtures/auth/logout.js
@@ -15,7 +15,7 @@
  * limitations under the License.
  */
 
-import {dropTestDB, resolveUrl, insertTestUser} from 'envtools';
+import {dropTestDB, resolveUrl, insertTestUser} from 
'../../environment/envtools';
 import {createRegularUser} from '../../roles';
 import {userMenu} from '../../components/userMenu';
 import {pageSignin} from '../../page-models/pageSignin';

http://git-wip-us.apache.org/repos/asf/ignite/blob/4c295f8f/modules/web-console/e2e/testcafe/fixtures/auth/signup-validation-local.js
----------------------------------------------------------------------
diff --git 
a/modules/web-console/e2e/testcafe/fixtures/auth/signup-validation-local.js 
b/modules/web-console/e2e/testcafe/fixtures/auth/signup-validation-local.js
index d2e125c..d26ce33 100644
--- a/modules/web-console/e2e/testcafe/fixtures/auth/signup-validation-local.js
+++ b/modules/web-console/e2e/testcafe/fixtures/auth/signup-validation-local.js
@@ -15,7 +15,7 @@
  * limitations under the License.
  */
 
-import {resolveUrl} from '../../envtools';
+import {resolveUrl} from '../../environment/envtools';
 import {pageSignup as page} from '../../page-models/pageSignup';
 
 fixture('Signup validation local').page(resolveUrl('/signup'));

http://git-wip-us.apache.org/repos/asf/ignite/blob/4c295f8f/modules/web-console/e2e/testcafe/fixtures/auth/signup.js
----------------------------------------------------------------------
diff --git a/modules/web-console/e2e/testcafe/fixtures/auth/signup.js 
b/modules/web-console/e2e/testcafe/fixtures/auth/signup.js
index cd08282..44b199f 100644
--- a/modules/web-console/e2e/testcafe/fixtures/auth/signup.js
+++ b/modules/web-console/e2e/testcafe/fixtures/auth/signup.js
@@ -15,7 +15,7 @@
  * limitations under the License.
  */
 
-import {dropTestDB, resolveUrl, insertTestUser} from '../../envtools';
+import {dropTestDB, resolveUrl, insertTestUser} from 
'../../environment/envtools';
 import {pageSignup as page} from '../../page-models/pageSignup';
 import {errorNotification} from '../../components/notifications';
 import {userMenu} from '../../components/userMenu';

http://git-wip-us.apache.org/repos/asf/ignite/blob/4c295f8f/modules/web-console/e2e/testcafe/fixtures/configuration/basic.js
----------------------------------------------------------------------
diff --git a/modules/web-console/e2e/testcafe/fixtures/configuration/basic.js 
b/modules/web-console/e2e/testcafe/fixtures/configuration/basic.js
index 0522fe2..ed88a9c 100644
--- a/modules/web-console/e2e/testcafe/fixtures/configuration/basic.js
+++ b/modules/web-console/e2e/testcafe/fixtures/configuration/basic.js
@@ -15,8 +15,7 @@
  * limitations under the License.
  */
 
-import {Selector, Role} from 'testcafe';
-import {dropTestDB, insertTestUser, resolveUrl} from '../../envtools';
+import {dropTestDB, insertTestUser, resolveUrl} from 
'../../environment/envtools';
 import {createRegularUser} from '../../roles';
 import {PageConfigurationBasic} from 
'../../page-models/PageConfigurationBasic';
 import {successNotification} from '../../components/notifications';
@@ -24,7 +23,7 @@ import {successNotification} from 
'../../components/notifications';
 const regularUser = createRegularUser();
 
 fixture('Basic configuration')
-    .before(async(t) => {
+    .before(async() => {
         await dropTestDB();
         await insertTestUser();
     })

http://git-wip-us.apache.org/repos/asf/ignite/blob/4c295f8f/modules/web-console/e2e/testcafe/fixtures/configuration/overview.js
----------------------------------------------------------------------
diff --git 
a/modules/web-console/e2e/testcafe/fixtures/configuration/overview.js 
b/modules/web-console/e2e/testcafe/fixtures/configuration/overview.js
index f0495bd..8d7093a 100644
--- a/modules/web-console/e2e/testcafe/fixtures/configuration/overview.js
+++ b/modules/web-console/e2e/testcafe/fixtures/configuration/overview.js
@@ -17,7 +17,7 @@
 
 import {Selector} from 'testcafe';
 import {getLocationPathname} from '../../helpers';
-import {dropTestDB, insertTestUser, resolveUrl} from '../../envtools';
+import {dropTestDB, insertTestUser, resolveUrl} from 
'../../environment/envtools';
 import {createRegularUser} from '../../roles';
 import {PageConfigurationOverview} from 
'../../page-models/PageConfigurationOverview';
 import {PageConfigurationBasic} from 
'../../page-models/PageConfigurationBasic';

http://git-wip-us.apache.org/repos/asf/ignite/blob/4c295f8f/modules/web-console/e2e/testcafe/fixtures/menu-smoke.js
----------------------------------------------------------------------
diff --git a/modules/web-console/e2e/testcafe/fixtures/menu-smoke.js 
b/modules/web-console/e2e/testcafe/fixtures/menu-smoke.js
index fdd0edb..9b3853a 100644
--- a/modules/web-console/e2e/testcafe/fixtures/menu-smoke.js
+++ b/modules/web-console/e2e/testcafe/fixtures/menu-smoke.js
@@ -16,7 +16,7 @@
  */
 
 import { Selector } from 'testcafe';
-import { dropTestDB, insertTestUser, resolveUrl } from '../envtools';
+import { dropTestDB, insertTestUser, resolveUrl } from 
'../environment/envtools';
 import { createRegularUser } from '../roles';
 import { queriesNavButton, configureNavButton } from 
'../components/topNavigation';
 
@@ -35,7 +35,7 @@ fixture('Checking Ingite main menu')
         await dropTestDB();
     });
 
-test('Ingite main menu smoke test', async(t) => {
+test('Ignite main menu smoke test', async(t) => {
     await t
         .click(configureNavButton)
         .expect(Selector('title').innerText)

http://git-wip-us.apache.org/repos/asf/ignite/blob/4c295f8f/modules/web-console/e2e/testcafe/fixtures/queries/notebooks-list.js
----------------------------------------------------------------------
diff --git 
a/modules/web-console/e2e/testcafe/fixtures/queries/notebooks-list.js 
b/modules/web-console/e2e/testcafe/fixtures/queries/notebooks-list.js
index 0d6581a..6037b28 100644
--- a/modules/web-console/e2e/testcafe/fixtures/queries/notebooks-list.js
+++ b/modules/web-console/e2e/testcafe/fixtures/queries/notebooks-list.js
@@ -15,7 +15,7 @@
  * limitations under the License.
  */
 import { Selector } from 'testcafe';
-import { dropTestDB, insertTestUser, resolveUrl } from '../../envtools';
+import { dropTestDB, insertTestUser, resolveUrl } from 
'../../environment/envtools';
 import { createRegularUser } from '../../roles';
 import { PageQueriesNotebooksList } from '../../page-models/PageQueries';
 

http://git-wip-us.apache.org/repos/asf/ignite/blob/4c295f8f/modules/web-console/e2e/testcafe/fixtures/user-profile/credentials.js
----------------------------------------------------------------------
diff --git 
a/modules/web-console/e2e/testcafe/fixtures/user-profile/credentials.js 
b/modules/web-console/e2e/testcafe/fixtures/user-profile/credentials.js
index 42c76cf..b76a736 100644
--- a/modules/web-console/e2e/testcafe/fixtures/user-profile/credentials.js
+++ b/modules/web-console/e2e/testcafe/fixtures/user-profile/credentials.js
@@ -15,7 +15,7 @@
  * limitations under the License.
  */
 
-import { dropTestDB, insertTestUser, resolveUrl } from '../../envtools';
+import { dropTestDB, insertTestUser, resolveUrl } from 
'../../environment/envtools';
 import { createRegularUser } from '../../roles';
 import {pageProfile} from '../../page-models/pageProfile';
 import {confirmation} from '../../components/confirmation';

http://git-wip-us.apache.org/repos/asf/ignite/blob/4c295f8f/modules/web-console/e2e/testcafe/fixtures/user-profile/profile.js
----------------------------------------------------------------------
diff --git a/modules/web-console/e2e/testcafe/fixtures/user-profile/profile.js 
b/modules/web-console/e2e/testcafe/fixtures/user-profile/profile.js
index 1e9f0c3..d6030d9 100644
--- a/modules/web-console/e2e/testcafe/fixtures/user-profile/profile.js
+++ b/modules/web-console/e2e/testcafe/fixtures/user-profile/profile.js
@@ -16,7 +16,7 @@
  */
 
 import { Selector } from 'testcafe';
-import { dropTestDB, insertTestUser, resolveUrl } from '../../envtools';
+import { dropTestDB, insertTestUser, resolveUrl } from 
'../../environment/envtools';
 import { createRegularUser } from '../../roles';
 import {pageProfile} from '../../page-models/pageProfile';
 

http://git-wip-us.apache.org/repos/asf/ignite/blob/4c295f8f/modules/web-console/e2e/testcafe/index.js
----------------------------------------------------------------------
diff --git a/modules/web-console/e2e/testcafe/index.js 
b/modules/web-console/e2e/testcafe/index.js
new file mode 100644
index 0000000..837f2df
--- /dev/null
+++ b/modules/web-console/e2e/testcafe/index.js
@@ -0,0 +1,38 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License.  You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+const glob = require('glob');
+const argv = require('minimist')(process.argv.slice(2));
+const { startTestcafe } = require('./testcafe-runner');
+
+const enableEnvironment = argv.env;
+
+// See all supported browsers at 
http://devexpress.github.io/testcafe/documentation/using-testcafe/common-concepts/browsers/browser-support.html#locally-installed-browsers
+const BROWSERS = ['chromium:headless --no-sandbox']; // For example: 
['chrome', 'firefox'];
+
+const FIXTURES_PATHS = glob.sync('./fixtures/**/*.js');
+
+const testcafeRunnerConfig = {
+    browsers: BROWSERS,
+    enableEnvironment: enableEnvironment || false,
+    reporter: process.env.REPORTER || 'spec',
+    fixturesPathsArray: FIXTURES_PATHS
+};
+
+startTestcafe(testcafeRunnerConfig).then(() => {
+    process.exit(0);
+});

Reply via email to