mirror of
https://github.com/elastic/kibana.git
synced 2025-04-23 17:28:26 -04:00
Merge branch '4.2' into implement/xsrfProtectionFor4.2
This commit is contained in:
commit
92d30802f9
25 changed files with 1425 additions and 95 deletions
1
.gitignore
vendored
1
.gitignore
vendored
|
@ -10,6 +10,7 @@ target
|
|||
.idea
|
||||
*.iml
|
||||
*.log
|
||||
/test/output
|
||||
/esvm
|
||||
.htpasswd
|
||||
installedPlugins
|
||||
|
|
|
@ -102,6 +102,41 @@ The standard `npm run test` task runs several sub tasks and can take several min
|
|||
</dd>
|
||||
</dl>
|
||||
|
||||
### Functional UI Testing
|
||||
|
||||
#### Handy references
|
||||
|
||||
- https://theintern.github.io/
|
||||
- https://theintern.github.io/leadfoot/Element.html
|
||||
|
||||
#### Running tests using npm task:
|
||||
|
||||
*The Selenium server that is started currently only runs the tests in Firefox*
|
||||
|
||||
To runt the functional UI tests, execute the following command:
|
||||
|
||||
`npm run test:ui`
|
||||
|
||||
The task above takes a little time to start the servers. You can also start the servers and leave them running, and then run the tests separately:
|
||||
|
||||
`npm run test:ui:server` will start the server required to run the selenium tests, leave this open
|
||||
|
||||
`npm run test:ui:runner` will run the frontend tests and close when complete
|
||||
|
||||
#### Running tests locally with your existing (and already running) ElasticSearch, Kibana, and Selenium Server:
|
||||
|
||||
Set your es and kibana ports in `test/intern.js` to 9220 and 5620, respecitively. You can configure your Selenium server to run the tests on Chrome,IE, or other browsers here.
|
||||
|
||||
Once you've got the services running, execute the following:
|
||||
|
||||
`npm run test:ui:runner`
|
||||
|
||||
#### General notes:
|
||||
|
||||
- Using Page Objects pattern (https://theintern.github.io/intern/#writing-functional-test)
|
||||
- At least the initial tests for the Settings, Discover, and Visualize tabs all depend on a very specific set of logstash-type data (generated with makelogs). Since that is a static set of data, all the Discover and Visualize tests use a specific Absolute time range. This gaurantees the same results each run.
|
||||
- These tests have been developed and tested with Chrome and Firefox browser. In theory, they should work on all browsers (that's the benefit of Intern using Leadfoot).
|
||||
- These tests should also work with an external testing service like https://saucelabs.com/ or https://www.browserstack.com/ but that has not been tested.
|
||||
|
||||
### Submit a pull request
|
||||
|
||||
|
|
|
@ -1,6 +1,9 @@
|
|||
var cloneDeep = require('lodash').cloneDeep;
|
||||
var fromRoot = require('path').resolve.bind(null, __dirname, '../../');
|
||||
process.env.BABEL_CACHE_PATH = fromRoot('optimize/.babelcache.json');
|
||||
|
||||
if (!process.env.BABEL_CACHE_PATH) {
|
||||
process.env.BABEL_CACHE_PATH = fromRoot('optimize/.babelcache.json');
|
||||
}
|
||||
|
||||
exports.webpack = {
|
||||
stage: 1,
|
||||
|
|
|
@ -1,6 +1,9 @@
|
|||
var cloneDeep = require('lodash').cloneDeep;
|
||||
var fromRoot = require('path').resolve.bind(null, __dirname, '../../');
|
||||
process.env.BABEL_CACHE_PATH = fromRoot('optimize/.babelcache.json');
|
||||
|
||||
if (!process.env.BABEL_CACHE_PATH) {
|
||||
process.env.BABEL_CACHE_PATH = fromRoot('optimize/.babelcache.json');
|
||||
}
|
||||
|
||||
exports.webpack = {
|
||||
stage: 1,
|
||||
|
|
|
@ -44,7 +44,7 @@ module.exports = function (grunt) {
|
|||
purge: true,
|
||||
config: {
|
||||
http: {
|
||||
port: uiConfig.elasticsearch.port
|
||||
port: uiConfig.servers.elasticsearch.port
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -33,8 +33,8 @@ module.exports = function (grunt) {
|
|||
},
|
||||
cmd: /^win/.test(platform) ? '.\\bin\\kibana.bat' : './bin/kibana',
|
||||
args: [
|
||||
'--server.port=' + uiConfig.kibana.port,
|
||||
'--elasticsearch.url=' + format(uiConfig.elasticsearch),
|
||||
'--server.port=' + uiConfig.servers.kibana.port,
|
||||
'--elasticsearch.url=' + format(uiConfig.servers.elasticsearch),
|
||||
'--logging.json=false'
|
||||
]
|
||||
},
|
||||
|
@ -89,7 +89,7 @@ module.exports = function (grunt) {
|
|||
'-jar',
|
||||
'selenium/selenium-server-standalone-2.47.1.jar',
|
||||
'-port',
|
||||
uiConfig.webdriver.port
|
||||
uiConfig.servers.webdriver.port
|
||||
]
|
||||
},
|
||||
|
||||
|
@ -105,7 +105,7 @@ module.exports = function (grunt) {
|
|||
'-jar',
|
||||
'selenium/selenium-server-standalone-2.47.1.jar',
|
||||
'-port',
|
||||
uiConfig.webdriver.port
|
||||
uiConfig.servers.webdriver.port
|
||||
]
|
||||
},
|
||||
|
||||
|
|
92
test/fixtures/__tests__/scenarioManager.js
vendored
92
test/fixtures/__tests__/scenarioManager.js
vendored
|
@ -21,11 +21,11 @@ describe('scenario manager', function () {
|
|||
|
||||
it('should be able to load scenarios', function () {
|
||||
return manager.load('makelogs')
|
||||
.then(function () {
|
||||
expect(create.getCall(0).args[0].index).to.be('logstash-2015.09.17');
|
||||
expect(create.getCall(1).args[0].index).to.be('logstash-2015.09.18');
|
||||
expect(bulk.called).to.be(true);
|
||||
});
|
||||
.then(function () {
|
||||
expect(create.getCall(0).args[0].index).to.be('logstash-2015.09.17');
|
||||
expect(create.getCall(1).args[0].index).to.be('logstash-2015.09.18');
|
||||
expect(bulk.called).to.be(true);
|
||||
});
|
||||
});
|
||||
|
||||
it('should be able to delete all indices', function () {
|
||||
|
@ -55,6 +55,52 @@ describe('scenario manager', function () {
|
|||
});
|
||||
});
|
||||
|
||||
it('should load if the index does not exist', function () {
|
||||
var load = sinon.stub(manager, 'load', Promise.resolve);
|
||||
var throwError = sinon.stub(manager.client, 'count', Promise.reject);
|
||||
var id = 'makelogs';
|
||||
return manager.loadIfEmpty(id).then(function () {
|
||||
expect(load.calledWith(id)).to.be(true);
|
||||
|
||||
load.restore();
|
||||
throwError.restore();
|
||||
});
|
||||
});
|
||||
|
||||
it('should load if the index is empty', function () {
|
||||
var load = sinon.stub(manager, 'load', Promise.resolve);
|
||||
var returnZero = sinon.stub(manager.client, 'count', function () {
|
||||
return Promise.resolve({
|
||||
'count': 0
|
||||
});
|
||||
});
|
||||
var id = 'makelogs';
|
||||
return manager.loadIfEmpty(id).then(function () {
|
||||
expect(load.calledWith(id)).to.be(true);
|
||||
|
||||
load.restore();
|
||||
returnZero.restore();
|
||||
});
|
||||
});
|
||||
|
||||
|
||||
it('should not load if the index is not empty', function () {
|
||||
var load = sinon.stub(manager, 'load', Promise.resolve);
|
||||
var returnOne = sinon.stub(manager.client, 'count', function () {
|
||||
return Promise.resolve({
|
||||
'count': 1
|
||||
});
|
||||
});
|
||||
var id = 'makelogs';
|
||||
return manager.loadIfEmpty(id).then(function () {
|
||||
expect(load.called).to.be(false);
|
||||
|
||||
load.restore();
|
||||
returnOne.restore();
|
||||
});
|
||||
});
|
||||
|
||||
|
||||
afterEach(function () {
|
||||
bulk.restore();
|
||||
create.restore();
|
||||
|
@ -62,12 +108,40 @@ describe('scenario manager', function () {
|
|||
});
|
||||
});
|
||||
|
||||
it('should throw an error if the scenario is not defined', function () {
|
||||
expect(manager.load).withArgs('makelogs').to.throwError();
|
||||
describe('load', function () {
|
||||
it('should reject if the scenario is not specified', function () {
|
||||
return manager.load()
|
||||
.then(function () {
|
||||
throw new Error('Promise should reject')
|
||||
})
|
||||
.catch(function () { return; });
|
||||
});
|
||||
|
||||
it('should reject if the scenario is not defined', function () {
|
||||
return manager.load('idonotexist')
|
||||
.then(function () {
|
||||
throw new Error('Promise should reject')
|
||||
})
|
||||
.catch(function () { return; });
|
||||
});
|
||||
});
|
||||
|
||||
it('should throw an error if an index is not defined when clearing', function () {
|
||||
expect(manager.unload).to.throwError();
|
||||
describe('unload', function () {
|
||||
it('should reject if the scenario is not specified', function () {
|
||||
return manager.unload()
|
||||
.then(function () {
|
||||
throw new Error('Promise should reject')
|
||||
})
|
||||
.catch(function () { return; });
|
||||
});
|
||||
|
||||
it('should reject if the scenario is not defined', function () {
|
||||
return manager.unload('idonotexist')
|
||||
.then(function () {
|
||||
throw new Error('Promise should reject')
|
||||
})
|
||||
.catch(function () { return; });
|
||||
});
|
||||
});
|
||||
|
||||
it('should throw an error if an es server is not specified', function () {
|
||||
|
|
40
test/fixtures/config.js
vendored
40
test/fixtures/config.js
vendored
|
@ -2,23 +2,27 @@ var path = require('path');
|
|||
var rootDir = path.join(__dirname, 'scenarios');
|
||||
|
||||
module.exports = {
|
||||
makelogs: {
|
||||
baseDir: path.join(rootDir, 'makelogs'),
|
||||
bulk: [{
|
||||
indexDefinition: 'makelogsIndexDefinition.js',
|
||||
indexName: 'logstash-2015.09.17',
|
||||
source: 'logstash-2015.09.17.js'
|
||||
}, {
|
||||
indexDefinition: 'makelogsIndexDefinition.js',
|
||||
indexName: 'logstash-2015.09.18',
|
||||
source: 'logstash-2015.09.18.js'
|
||||
}]
|
||||
},
|
||||
emptyKibana: {
|
||||
baseDir: path.join(rootDir, 'emptyKibana'),
|
||||
bulk: [{
|
||||
indexName: '.kibana',
|
||||
source: 'kibana.js'
|
||||
}]
|
||||
scenarios: {
|
||||
makelogs: {
|
||||
baseDir: path.join(rootDir, 'makelogs'),
|
||||
bulk: [{
|
||||
indexName: 'logstash-2015.09.17',
|
||||
indexDefinition: 'makelogsIndexDefinition.js',
|
||||
source: 'logstash-2015.09.17.js'
|
||||
}, {
|
||||
indexName: 'logstash-2015.09.18',
|
||||
indexDefinition: 'makelogsIndexDefinition.js',
|
||||
source: 'logstash-2015.09.18.js'
|
||||
}]
|
||||
},
|
||||
emptyKibana: {
|
||||
baseDir: path.join(rootDir, 'emptyKibana'),
|
||||
bulk: [{
|
||||
indexName: '.kibana',
|
||||
indexDefinition: 'kibanaDefinition.js',
|
||||
source: 'kibana.js',
|
||||
haltOnFailure: false
|
||||
}]
|
||||
}
|
||||
}
|
||||
};
|
||||
|
|
61
test/fixtures/scenarioManager.js
vendored
61
test/fixtures/scenarioManager.js
vendored
|
@ -1,6 +1,7 @@
|
|||
var path = require('path');
|
||||
var config = require('./config');
|
||||
var elasticsearch = require('elasticsearch');
|
||||
var Promise = require('bluebird');
|
||||
var config = require('./config').scenarios;
|
||||
|
||||
function ScenarioManager(server) {
|
||||
if (!server) throw new Error('No server defined');
|
||||
|
@ -16,28 +17,33 @@ function ScenarioManager(server) {
|
|||
* @return {Promise} A promise that is resolved when elasticsearch has a response
|
||||
*/
|
||||
ScenarioManager.prototype.load = function (id) {
|
||||
var scenario = config[id];
|
||||
if (!scenario) throw new Error('No scenario found for ' + id);
|
||||
|
||||
var self = this;
|
||||
var scenario = config[id];
|
||||
if (!scenario) return Promise.reject('No scenario found for ' + id);
|
||||
|
||||
return Promise.all(scenario.bulk.map(function mapBulk(bulk) {
|
||||
var loadIndexDefinition;
|
||||
|
||||
if (bulk.indexDefinition) {
|
||||
var body = require(path.join(scenario.baseDir, bulk.indexDefinition));
|
||||
loadIndexDefinition = self.client.indices.create({
|
||||
index: bulk.indexName,
|
||||
body: require(path.join(scenario.baseDir, bulk.indexDefinition))
|
||||
body: body
|
||||
});
|
||||
} else {
|
||||
loadIndexDefinition = Promise.resolve();
|
||||
}
|
||||
|
||||
return loadIndexDefinition.then(function bulkRequest() {
|
||||
self.client.bulk({
|
||||
body: require(path.join(scenario.baseDir, bulk.source)),
|
||||
return loadIndexDefinition
|
||||
.then(function bulkRequest() {
|
||||
var body = require(path.join(scenario.baseDir, bulk.source));
|
||||
return self.client.bulk({
|
||||
body: body
|
||||
});
|
||||
})
|
||||
.catch(function (err) {
|
||||
if (bulk.haltOnFailure === false) return;
|
||||
throw err;
|
||||
});
|
||||
|
||||
}));
|
||||
};
|
||||
|
||||
|
@ -48,7 +54,7 @@ ScenarioManager.prototype.load = function (id) {
|
|||
*/
|
||||
ScenarioManager.prototype.unload = function (id) {
|
||||
var scenario = config[id];
|
||||
if (!scenario) throw new Error('Expected index');
|
||||
if (!scenario) return Promise.reject('No scenario found for ' + id);
|
||||
|
||||
var indices = scenario.bulk.map(function mapBulk(bulk) {
|
||||
return bulk.indexName;
|
||||
|
@ -67,7 +73,8 @@ ScenarioManager.prototype.unload = function (id) {
|
|||
ScenarioManager.prototype.reload = function (id) {
|
||||
var self = this;
|
||||
|
||||
return this.unload(id).then(function load() {
|
||||
return self.unload(id)
|
||||
.then(function load() {
|
||||
return self.load(id);
|
||||
});
|
||||
};
|
||||
|
@ -82,4 +89,32 @@ ScenarioManager.prototype.deleteAll = function () {
|
|||
});
|
||||
};
|
||||
|
||||
module.exports = ScenarioManager;
|
||||
/**
|
||||
* Load a testing scenario if not already loaded
|
||||
* @param {string} id The scenario id to load
|
||||
* @return {Promise} A promise that is resolved when elasticsearch has a response
|
||||
*/
|
||||
ScenarioManager.prototype.loadIfEmpty = function (id) {
|
||||
var self = this;
|
||||
var scenario = config[id];
|
||||
if (!scenario) throw new Error('No scenario found for ' + id);
|
||||
|
||||
var self = this;
|
||||
return Promise.all(scenario.bulk.map(function mapBulk(bulk) {
|
||||
var loadIndexDefinition;
|
||||
|
||||
return self.client.count({
|
||||
index: bulk.indexName
|
||||
})
|
||||
.then(function handleCountResponse(response) {
|
||||
if (response.count === 0) {
|
||||
return self.load(id);
|
||||
}
|
||||
})
|
||||
}))
|
||||
.catch(function (reason) {
|
||||
return self.load(id);
|
||||
});
|
||||
};
|
||||
|
||||
module.exports = ScenarioManager;
|
16
test/fixtures/scenarios/emptyKibana/kibanaDefinition.js
vendored
Normal file
16
test/fixtures/scenarios/emptyKibana/kibanaDefinition.js
vendored
Normal file
|
@ -0,0 +1,16 @@
|
|||
module.exports = {
|
||||
settings: {
|
||||
number_of_shards: 1,
|
||||
number_of_replicas: 1
|
||||
},
|
||||
mappings: {
|
||||
config: {
|
||||
properties: {
|
||||
buildNum: {
|
||||
type: 'string',
|
||||
index: 'not_analyzed'
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
59
test/functional/apps/settings/_creation_form_changes.js
Normal file
59
test/functional/apps/settings/_creation_form_changes.js
Normal file
|
@ -0,0 +1,59 @@
|
|||
define(function (require) {
|
||||
var Common = require('../../../support/pages/Common');
|
||||
var SettingsPage = require('../../../support/pages/SettingsPage');
|
||||
var expect = require('intern/dojo/node!expect.js');
|
||||
|
||||
return function (bdd, scenarioManager) {
|
||||
bdd.describe('user input reactions', function () {
|
||||
var common;
|
||||
var settingsPage;
|
||||
|
||||
bdd.before(function () {
|
||||
common = new Common(this.remote);
|
||||
settingsPage = new SettingsPage(this.remote);
|
||||
});
|
||||
|
||||
bdd.beforeEach(function () {
|
||||
return scenarioManager.reload('emptyKibana')
|
||||
.then(function () {
|
||||
return settingsPage.navigateTo();
|
||||
});
|
||||
});
|
||||
|
||||
bdd.it('should hide time-based index pattern when time-based option is unchecked', function () {
|
||||
var self = this;
|
||||
return settingsPage.getTimeBasedEventsCheckbox()
|
||||
.then(function (selected) {
|
||||
// uncheck the 'time-based events' checkbox
|
||||
return selected.click();
|
||||
})
|
||||
// try to find the checkbox (this shouldn fail)
|
||||
.then(function () {
|
||||
return settingsPage.getTimeBasedIndexPatternCheckbox();
|
||||
})
|
||||
.then(function () {
|
||||
// we expect the promise above to fail
|
||||
var handler = common.handleError(self);
|
||||
var msg = 'Found time based index pattern checkbox';
|
||||
handler(msg);
|
||||
})
|
||||
.catch(function () {
|
||||
// we expect this failure since checkbox should be hidden
|
||||
return;
|
||||
});
|
||||
});
|
||||
|
||||
bdd.it('should enable creation after selecting time field', function () {
|
||||
// select a time field and check that Create button is enabled
|
||||
return settingsPage.selectTimeFieldOption('@timestamp')
|
||||
.then(function () {
|
||||
return settingsPage.getCreateButton().isEnabled()
|
||||
.then(function (enabled) {
|
||||
expect(enabled).to.be.ok();
|
||||
});
|
||||
})
|
||||
.catch(common.handleError(this));
|
||||
});
|
||||
});
|
||||
};
|
||||
});
|
104
test/functional/apps/settings/_index_pattern_create_delete.js
Normal file
104
test/functional/apps/settings/_index_pattern_create_delete.js
Normal file
|
@ -0,0 +1,104 @@
|
|||
define(function (require) {
|
||||
var Common = require('../../../support/pages/Common');
|
||||
var SettingsPage = require('../../../support/pages/SettingsPage');
|
||||
var expect = require('intern/dojo/node!expect.js');
|
||||
var Promise = require('bluebird');
|
||||
|
||||
return function (bdd, scenarioManager) {
|
||||
bdd.describe('creating and deleting default index', function describeIndexTests() {
|
||||
var common;
|
||||
var settingsPage;
|
||||
var remote;
|
||||
|
||||
bdd.before(function () {
|
||||
common = new Common(this.remote);
|
||||
settingsPage = new SettingsPage(this.remote);
|
||||
remote = this.remote;
|
||||
|
||||
return scenarioManager.reload('emptyKibana')
|
||||
.then(function () {
|
||||
return settingsPage.navigateTo();
|
||||
});
|
||||
});
|
||||
|
||||
bdd.describe('index pattern creation', function indexPatternCreation() {
|
||||
bdd.before(function () {
|
||||
return settingsPage.createIndexPattern();
|
||||
});
|
||||
|
||||
bdd.it('should have index pattern in page header', function pageHeader() {
|
||||
return settingsPage.getIndexPageHeading().getVisibleText()
|
||||
.then(function (patternName) {
|
||||
expect(patternName).to.be('logstash-*');
|
||||
})
|
||||
.catch(common.handleError(this));
|
||||
});
|
||||
|
||||
bdd.it('should have index pattern in url', function url() {
|
||||
return common.tryForTime(5000, function () {
|
||||
return remote.getCurrentUrl()
|
||||
.then(function (currentUrl) {
|
||||
expect(currentUrl).to.contain('logstash-*');
|
||||
});
|
||||
})
|
||||
.catch(common.handleError(this));
|
||||
});
|
||||
|
||||
bdd.it('should have expected table headers', function checkingHeader() {
|
||||
return settingsPage.getTableHeader()
|
||||
.then(function (headers) {
|
||||
var expectedHeaders = [
|
||||
'name',
|
||||
'type',
|
||||
'format',
|
||||
'analyzed',
|
||||
'indexed',
|
||||
'controls'
|
||||
];
|
||||
|
||||
// 6 name type format analyzed indexed controls
|
||||
expect(headers.length).to.be(expectedHeaders.length);
|
||||
|
||||
var comparedHeaders = headers.map(function compareHead(header, i) {
|
||||
return header.getVisibleText()
|
||||
.then(function (text) {
|
||||
expect(text).to.be(expectedHeaders[i]);
|
||||
});
|
||||
});
|
||||
|
||||
return Promise.all(comparedHeaders);
|
||||
})
|
||||
.catch(common.handleError(this));
|
||||
});
|
||||
});
|
||||
|
||||
bdd.describe('index pattern deletion', function indexDelete() {
|
||||
bdd.before(function () {
|
||||
var expectedAlertText = 'Are you sure you want to remove this index pattern?';
|
||||
return settingsPage.removeIndexPattern()
|
||||
.then(function (alertText) {
|
||||
expect(alertText).to.be(expectedAlertText);
|
||||
});
|
||||
});
|
||||
|
||||
bdd.it('should return to index pattern creation page', function returnToPage() {
|
||||
return common.tryForTime(5000, function () {
|
||||
return settingsPage.getCreateButton();
|
||||
})
|
||||
.catch(common.handleError(this));
|
||||
});
|
||||
|
||||
bdd.it('should remove index pattern from url', function indexNotInUrl() {
|
||||
// give the url time to settle
|
||||
return common.tryForTime(5000, function () {
|
||||
return remote.getCurrentUrl()
|
||||
.then(function (currentUrl) {
|
||||
expect(currentUrl).to.not.contain('logstash-*');
|
||||
})
|
||||
})
|
||||
.catch(common.handleError(this));
|
||||
});
|
||||
});
|
||||
});
|
||||
};
|
||||
});
|
111
test/functional/apps/settings/_index_pattern_popularity.js
Normal file
111
test/functional/apps/settings/_index_pattern_popularity.js
Normal file
|
@ -0,0 +1,111 @@
|
|||
define(function (require) {
|
||||
var Common = require('../../../support/pages/Common');
|
||||
var SettingsPage = require('../../../support/pages/SettingsPage');
|
||||
var expect = require('intern/dojo/node!expect.js');
|
||||
//var Promise = require('bluebird');
|
||||
|
||||
return function (bdd, scenarioManager) {
|
||||
bdd.describe('index result popularity', function describeIndexTests() {
|
||||
var common;
|
||||
var settingsPage;
|
||||
var remote;
|
||||
|
||||
bdd.before(function () {
|
||||
common = new Common(this.remote);
|
||||
settingsPage = new SettingsPage(this.remote);
|
||||
remote = this.remote;
|
||||
|
||||
return scenarioManager.reload('emptyKibana')
|
||||
.then(function () {
|
||||
return settingsPage.navigateTo();
|
||||
});
|
||||
});
|
||||
|
||||
bdd.beforeEach(function be() {
|
||||
return settingsPage.createIndexPattern();
|
||||
});
|
||||
|
||||
bdd.afterEach(function ae() {
|
||||
return settingsPage.removeIndexPattern();
|
||||
});
|
||||
|
||||
bdd.describe('change popularity', function indexPatternCreation() {
|
||||
var fieldName = 'geo.coordinates';
|
||||
|
||||
// set the page size to All again, https://github.com/elastic/kibana/issues/5030
|
||||
// TODO: remove this after issue #5030 is closed
|
||||
function fix5030() {
|
||||
return settingsPage.setPageSize('All')
|
||||
.then(function () {
|
||||
return common.sleep(1000);
|
||||
});
|
||||
}
|
||||
|
||||
bdd.beforeEach(function () {
|
||||
// increase Popularity of geo.coordinates
|
||||
return settingsPage.setPageSize('All')
|
||||
.then(function () {
|
||||
return common.sleep(1000);
|
||||
})
|
||||
.then(function openControlsByName() {
|
||||
return settingsPage.openControlsByName(fieldName);
|
||||
})
|
||||
.then(function increasePopularity() {
|
||||
return settingsPage.increasePopularity();
|
||||
});
|
||||
});
|
||||
|
||||
bdd.afterEach(function () {
|
||||
// Cancel saving the popularity change (we didn't make a change in this case, just checking the value)
|
||||
return settingsPage.controlChangeCancel();
|
||||
});
|
||||
|
||||
bdd.it('should update the popularity input', function () {
|
||||
return settingsPage.getPopularity()
|
||||
.then(function (popularity) {
|
||||
expect(popularity).to.be('1');
|
||||
})
|
||||
.catch(common.handleError(this));
|
||||
});
|
||||
|
||||
bdd.it('should be reset on cancel', function pageHeader() {
|
||||
// Cancel saving the popularity change
|
||||
return settingsPage.controlChangeCancel()
|
||||
.then(function () {
|
||||
return fix5030();
|
||||
})
|
||||
.then(function openControlsByName() {
|
||||
return settingsPage.openControlsByName(fieldName);
|
||||
})
|
||||
// check that its 0 (previous increase was cancelled)
|
||||
.then(function getPopularity() {
|
||||
return settingsPage.getPopularity()
|
||||
})
|
||||
.then(function (popularity) {
|
||||
expect(popularity).to.be('0');
|
||||
})
|
||||
.catch(common.handleError(this));
|
||||
});
|
||||
|
||||
bdd.it('can be saved', function pageHeader() {
|
||||
// Saving the popularity change
|
||||
return settingsPage.controlChangeSave()
|
||||
.then(function () {
|
||||
return fix5030();
|
||||
})
|
||||
.then(function openControlsByName() {
|
||||
return settingsPage.openControlsByName(fieldName);
|
||||
})
|
||||
// check that its 0 (previous increase was cancelled)
|
||||
.then(function getPopularity() {
|
||||
return settingsPage.getPopularity();
|
||||
})
|
||||
.then(function (popularity) {
|
||||
expect(popularity).to.be('1');
|
||||
})
|
||||
.catch(common.handleError(this));
|
||||
});
|
||||
}); // end 'change popularity'
|
||||
}); // end index result popularity
|
||||
};
|
||||
});
|
134
test/functional/apps/settings/_index_pattern_results_sort.js
Normal file
134
test/functional/apps/settings/_index_pattern_results_sort.js
Normal file
|
@ -0,0 +1,134 @@
|
|||
define(function (require) {
|
||||
var Common = require('../../../support/pages/Common');
|
||||
var SettingsPage = require('../../../support/pages/SettingsPage');
|
||||
var expect = require('intern/dojo/node!expect.js');
|
||||
var Promise = require('bluebird');
|
||||
|
||||
return function (bdd, scenarioManager) {
|
||||
bdd.describe('index result field sort', function describeIndexTests() {
|
||||
var common;
|
||||
var settingsPage;
|
||||
var remote;
|
||||
|
||||
bdd.before(function () {
|
||||
common = new Common(this.remote);
|
||||
settingsPage = new SettingsPage(this.remote);
|
||||
remote = this.remote
|
||||
|
||||
return scenarioManager.reload('emptyKibana')
|
||||
});
|
||||
|
||||
var columns = [{
|
||||
heading: 'name',
|
||||
first: '@message',
|
||||
last: 'xss.raw',
|
||||
selector: function () {
|
||||
return settingsPage.getTableRow(0, 0).getVisibleText()
|
||||
}
|
||||
}, {
|
||||
heading: 'type',
|
||||
first: '_source',
|
||||
last: 'string',
|
||||
selector: function () {
|
||||
return settingsPage.getTableRow(0, 1).getVisibleText()
|
||||
}
|
||||
}];
|
||||
|
||||
columns.forEach(function (col) {
|
||||
bdd.describe('sort by heading - ' + col.heading, function indexPatternCreation() {
|
||||
bdd.before(function () {
|
||||
return settingsPage.navigateTo()
|
||||
});
|
||||
|
||||
bdd.beforeEach(function () {
|
||||
return settingsPage.createIndexPattern();
|
||||
});
|
||||
|
||||
bdd.afterEach(function () {
|
||||
return settingsPage.removeIndexPattern();
|
||||
});
|
||||
|
||||
bdd.it('should sort ascending', function pageHeader() {
|
||||
return settingsPage.sortBy(col.heading)
|
||||
.then(function getText() {
|
||||
return col.selector();
|
||||
})
|
||||
.then(function (rowText) {
|
||||
expect(rowText).to.be(col.first);
|
||||
})
|
||||
.catch(common.handleError(this));
|
||||
});
|
||||
|
||||
bdd.it('should sort descending', function pageHeader() {
|
||||
return settingsPage.sortBy(col.heading)
|
||||
.then(function sortAgain() {
|
||||
return settingsPage.sortBy(col.heading);
|
||||
})
|
||||
.then(function getText() {
|
||||
return col.selector();
|
||||
})
|
||||
.then(function (rowText) {
|
||||
expect(rowText).to.be(col.last);
|
||||
})
|
||||
.catch(common.handleError(this));
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
bdd.describe('field list pagination', function () {
|
||||
var expectedDefaultPageSize = 25;
|
||||
var expectedFieldCount = 85;
|
||||
var expectedLastPageCount = 10;
|
||||
var pages = [1, 2, 3, 4];
|
||||
|
||||
bdd.before(function () {
|
||||
return settingsPage.navigateTo()
|
||||
.then(function () {
|
||||
return settingsPage.createIndexPattern();
|
||||
});
|
||||
});
|
||||
|
||||
bdd.after(function () {
|
||||
return settingsPage.removeIndexPattern();
|
||||
});
|
||||
|
||||
bdd.it('makelogs data should have expected number of fields', function () {
|
||||
return settingsPage.getFieldsTabCount()
|
||||
.then(function (tabCount) {
|
||||
expect(tabCount).to.be('' + expectedFieldCount);
|
||||
})
|
||||
.catch(common.handleError(this));
|
||||
});
|
||||
|
||||
bdd.it('should have correct default page size selected', function () {
|
||||
return settingsPage.getPageSize()
|
||||
.then(function (pageSize) {
|
||||
expect(pageSize).to.be('' + expectedDefaultPageSize);
|
||||
})
|
||||
.catch(common.handleError(this));
|
||||
});
|
||||
|
||||
bdd.it('should have the correct number of rows per page', function () {
|
||||
var pageCount = Math.ceil(expectedFieldCount / expectedDefaultPageSize);
|
||||
var chain = pages.reduce(function (chain, val) {
|
||||
return chain.then(function () {
|
||||
return settingsPage.goToPage(val)
|
||||
.then(function () {
|
||||
return common.sleep(1000);
|
||||
})
|
||||
.then(function () {
|
||||
return settingsPage.getPageFieldCount();
|
||||
})
|
||||
.then(function (pageCount) {
|
||||
var expectedSize = (val < 4) ? expectedDefaultPageSize : expectedLastPageCount;
|
||||
expect(pageCount.length).to.be(expectedSize);
|
||||
});
|
||||
});
|
||||
}, Promise.resolve());
|
||||
|
||||
return chain.catch(common.handleError(this));
|
||||
});
|
||||
}); // end describe pagination
|
||||
}); // end index result field sort
|
||||
};
|
||||
});
|
64
test/functional/apps/settings/_initial_state.js
Normal file
64
test/functional/apps/settings/_initial_state.js
Normal file
|
@ -0,0 +1,64 @@
|
|||
define(function (require) {
|
||||
var expect = require('intern/dojo/node!expect.js');
|
||||
var Common = require('../../../support/pages/Common');
|
||||
var SettingsPage = require('../../../support/pages/SettingsPage');
|
||||
|
||||
return function (bdd, scenarioManager) {
|
||||
bdd.describe('initial state', function () {
|
||||
var common;
|
||||
var settingsPage;
|
||||
|
||||
bdd.before(function () {
|
||||
common = new Common(this.remote);
|
||||
settingsPage = new SettingsPage(this.remote);
|
||||
|
||||
return scenarioManager.reload('emptyKibana')
|
||||
.then(function () {
|
||||
return settingsPage.navigateTo();
|
||||
});
|
||||
});
|
||||
|
||||
bdd.it('should load with time pattern checked', function () {
|
||||
return settingsPage.getTimeBasedEventsCheckbox().isSelected()
|
||||
.then(function (selected) {
|
||||
expect(selected).to.be.ok();
|
||||
})
|
||||
.catch(common.handleError(this));
|
||||
});
|
||||
|
||||
bdd.it('should load with name pattern unchecked', function () {
|
||||
return settingsPage.getTimeBasedIndexPatternCheckbox().isSelected()
|
||||
.then(function (selected) {
|
||||
expect(selected).to.not.be.ok();
|
||||
})
|
||||
.catch(common.handleError(this));
|
||||
});
|
||||
|
||||
bdd.it('should contain default index pattern', function () {
|
||||
var defaultPattern = 'logstash-*';
|
||||
|
||||
return settingsPage.getIndexPatternField().getProperty('value')
|
||||
.then(function (pattern) {
|
||||
expect(pattern).to.be(defaultPattern);
|
||||
})
|
||||
.catch(common.handleError(this));
|
||||
});
|
||||
|
||||
bdd.it('should not select the time field', function () {
|
||||
return settingsPage.getTimeFieldNameField().isSelected()
|
||||
.then(function (timeFieldIsSelected) {
|
||||
expect(timeFieldIsSelected).to.not.be.ok();
|
||||
})
|
||||
.catch(common.handleError(this));
|
||||
});
|
||||
|
||||
bdd.it('should not be enable creation', function () {
|
||||
return settingsPage.getCreateButton().isEnabled()
|
||||
.then(function (enabled) {
|
||||
expect(enabled).to.not.be.ok();
|
||||
})
|
||||
.catch(common.handleError(this));
|
||||
});
|
||||
});
|
||||
};
|
||||
});
|
38
test/functional/apps/settings/index.js
Normal file
38
test/functional/apps/settings/index.js
Normal file
|
@ -0,0 +1,38 @@
|
|||
define(function (require) {
|
||||
var bdd = require('intern!bdd');
|
||||
var config = require('intern').config;
|
||||
var url = require('intern/dojo/node!url');
|
||||
var ScenarioManager = require('intern/dojo/node!../../../fixtures/scenarioManager');
|
||||
|
||||
var initialStateTest = require('./_initial_state');
|
||||
var creationChangesTest = require('./_creation_form_changes');
|
||||
var indexPatternCreateDeleteTest = require('./_index_pattern_create_delete');
|
||||
var indexPatternResultsSortTest = require('./_index_pattern_results_sort');
|
||||
var indexPatternPopularityTest = require('./_index_pattern_popularity');
|
||||
|
||||
bdd.describe('settings app', function () {
|
||||
var scenarioManager = new ScenarioManager(url.format(config.servers.elasticsearch));
|
||||
|
||||
// on setup, we create an settingsPage instance
|
||||
// that we will use for all the tests
|
||||
bdd.before(function () {
|
||||
return scenarioManager.reload('emptyKibana')
|
||||
.then(function () {
|
||||
return scenarioManager.loadIfEmpty('makelogs')
|
||||
})
|
||||
});
|
||||
|
||||
bdd.after(function () {
|
||||
return scenarioManager.unload('makelogs')
|
||||
.then(function () {
|
||||
scenarioManager.unload('emptyKibana');
|
||||
});
|
||||
});
|
||||
|
||||
initialStateTest(bdd, scenarioManager);
|
||||
creationChangesTest(bdd, scenarioManager);
|
||||
indexPatternCreateDeleteTest(bdd, scenarioManager);
|
||||
indexPatternResultsSortTest(bdd, scenarioManager);
|
||||
indexPatternPopularityTest(bdd, scenarioManager);
|
||||
});
|
||||
});
|
|
@ -1,21 +0,0 @@
|
|||
define(function (require) {
|
||||
var registerSuite = require('intern!object');
|
||||
var expect = require('intern/dojo/node!expect.js');
|
||||
var config = require('intern').config;
|
||||
var getUrl = require('intern/dojo/node!../utils/getUrl');
|
||||
|
||||
registerSuite(function () {
|
||||
return {
|
||||
'status': function () {
|
||||
return this.remote
|
||||
.get(getUrl(config.kibana, 'status'))
|
||||
.setFindTimeout(60000)
|
||||
.findByCssSelector('.plugin_status_breakdown')
|
||||
.getVisibleText()
|
||||
.then(function (text) {
|
||||
expect(text.indexOf('plugin:kibana Ready')).to.be.above(-1);
|
||||
});
|
||||
}
|
||||
};
|
||||
});
|
||||
});
|
30
test/functional/status_page/index.js
Normal file
30
test/functional/status_page/index.js
Normal file
|
@ -0,0 +1,30 @@
|
|||
define(function (require) {
|
||||
var bdd = require('intern!bdd');
|
||||
var expect = require('intern/dojo/node!expect.js');
|
||||
var config = require('intern').config;
|
||||
var Common = require('../../support/pages/Common');
|
||||
|
||||
bdd.describe('status page', function () {
|
||||
var common;
|
||||
|
||||
bdd.before(function () {
|
||||
common = new Common(this.remote);
|
||||
// load the status page
|
||||
return common.navigateToApp('statusPage', false);
|
||||
});
|
||||
|
||||
bdd.it('should show the kibana plugin as ready', function () {
|
||||
var self = this;
|
||||
|
||||
return common.tryForTime(6000, function () {
|
||||
return self.remote
|
||||
.findByCssSelector('.plugin_status_breakdown')
|
||||
.getVisibleText()
|
||||
.then(function (text) {
|
||||
expect(text.indexOf('plugin:kibana Ready')).to.be.above(-1);
|
||||
})
|
||||
})
|
||||
.catch(common.handleError(self));
|
||||
});
|
||||
});
|
||||
});
|
|
@ -3,6 +3,7 @@ define(function (require) {
|
|||
var _ = require('intern/dojo/node!lodash');
|
||||
|
||||
return _.assign({
|
||||
debug: false,
|
||||
capabilities: {
|
||||
'selenium-version': '2.47.1',
|
||||
'idle-timeout': 30
|
||||
|
@ -10,8 +11,17 @@ define(function (require) {
|
|||
environments: [{
|
||||
browserName: 'firefox'
|
||||
}],
|
||||
tunnelOptions: serverConfig.webdriver,
|
||||
functionalSuites: ['test/functional/status.js'],
|
||||
excludeInstrumentation: /(fixtures|node_modules)\//
|
||||
tunnelOptions: serverConfig.servers.webdriver,
|
||||
functionalSuites: [
|
||||
'test/functional/status_page/index',
|
||||
'test/functional/apps/settings/index'
|
||||
],
|
||||
excludeInstrumentation: /(fixtures|node_modules)\//,
|
||||
loaderOptions: {
|
||||
paths: {
|
||||
'bluebird': './node_modules/bluebird/js/browser/bluebird.js',
|
||||
'moment': './node_modules/moment/moment.js'
|
||||
}
|
||||
}
|
||||
}, serverConfig);
|
||||
});
|
||||
|
|
|
@ -1,17 +1,42 @@
|
|||
var kibanaURL = '/app/kibana';
|
||||
|
||||
module.exports = {
|
||||
webdriver: {
|
||||
protocol: process.env.TEST_UI_WEBDRIVER_PROTOCOL || 'http',
|
||||
hostname: process.env.TEST_UI_WEBDRIVER_HOSTNAME || 'localhost',
|
||||
port: parseInt(process.env.TEST_UI_WEBDRIVER_PORT, 10) || 4444
|
||||
servers: {
|
||||
webdriver: {
|
||||
protocol: process.env.TEST_UI_WEBDRIVER_PROTOCOL || 'http',
|
||||
hostname: process.env.TEST_UI_WEBDRIVER_HOSTNAME || 'localhost',
|
||||
port: parseInt(process.env.TEST_UI_WEBDRIVER_PORT, 10) || 4444
|
||||
},
|
||||
kibana: {
|
||||
protocol: process.env.TEST_UI_KIBANA_PROTOCOL || 'http',
|
||||
hostname: process.env.TEST_UI_KIBANA_HOSTNAME || 'localhost',
|
||||
port: parseInt(process.env.TEST_UI_KIBANA_PORT, 10) || 5620
|
||||
},
|
||||
elasticsearch: {
|
||||
protocol: process.env.TEST_UI_ES_PROTOCOL || 'http',
|
||||
hostname: process.env.TEST_UI_ES_HOSTNAME || 'localhost',
|
||||
port: parseInt(process.env.TEST_UI_ES_PORT, 10) || 9220
|
||||
}
|
||||
},
|
||||
kibana: {
|
||||
protocol: process.env.TEST_UI_KIBANA_PROTOCOL || 'http',
|
||||
hostname: process.env.TEST_UI_KIBANA_HOSTNAME || 'localhost',
|
||||
port: parseInt(process.env.TEST_UI_KIBANA_PORT, 10) || 5620
|
||||
},
|
||||
elasticsearch: {
|
||||
protocol: process.env.TEST_UI_ES_PROTOCOL || 'http',
|
||||
hostname: process.env.TEST_UI_ES_HOSTNAME || 'localhost',
|
||||
port: parseInt(process.env.TEST_UI_ES_PORT, 10) || 9220
|
||||
apps: {
|
||||
statusPage: {
|
||||
pathname: 'status'
|
||||
},
|
||||
discover: {
|
||||
pathname: kibanaURL,
|
||||
hash: '/discover',
|
||||
},
|
||||
visualize: {
|
||||
pathname: kibanaURL,
|
||||
hash: '/visualize',
|
||||
},
|
||||
dashboard: {
|
||||
pathname: kibanaURL,
|
||||
hash: '/dashboard',
|
||||
},
|
||||
settings: {
|
||||
pathname: kibanaURL,
|
||||
hash: '/settings'
|
||||
}
|
||||
}
|
||||
};
|
||||
|
|
199
test/support/pages/Common.js
Normal file
199
test/support/pages/Common.js
Normal file
|
@ -0,0 +1,199 @@
|
|||
// in test/support/pages/Common.js
|
||||
define(function (require) {
|
||||
var config = require('intern').config;
|
||||
var Promise = require('bluebird');
|
||||
var moment = require('moment');
|
||||
var getUrl = require('intern/dojo/node!../../utils/getUrl');
|
||||
var fs = require('intern/dojo/node!fs');
|
||||
var path = require('intern/dojo/node!path');
|
||||
|
||||
function Common(remote) {
|
||||
this.remote = remote;
|
||||
}
|
||||
|
||||
Common.prototype = {
|
||||
constructor: Common,
|
||||
|
||||
navigateToApp: function (appName, testStatusPage) {
|
||||
var self = this;
|
||||
var urlTimeout = 10000;
|
||||
var appUrl = getUrl(config.servers.kibana, config.apps[appName]);
|
||||
|
||||
var doNavigation = function (url) {
|
||||
return self.tryForTime(urlTimeout, function () {
|
||||
// since we're using hash URLs, always reload first to force re-render
|
||||
return self.remote.get(url)
|
||||
.then(function () {
|
||||
return self.remote.refresh();
|
||||
})
|
||||
.then(function () {
|
||||
if (testStatusPage !== false) {
|
||||
return self.checkForKibanaApp()
|
||||
.then(function (kibanaLoaded) {
|
||||
if (!kibanaLoaded) throw new Error('Kibana is not loaded, retrying');
|
||||
});
|
||||
}
|
||||
})
|
||||
.then(function () {
|
||||
return self.remote.getCurrentUrl();
|
||||
})
|
||||
.then(function (currentUrl) {
|
||||
var navSuccessful = new RegExp(appUrl).test(currentUrl);
|
||||
if (!navSuccessful) throw new Error('App failed to load: ' + appName);
|
||||
})
|
||||
});
|
||||
};
|
||||
|
||||
return doNavigation(appUrl)
|
||||
.then(function () {
|
||||
return self.remote.getCurrentUrl();
|
||||
})
|
||||
.then(function (currentUrl) {
|
||||
var lastUrl = currentUrl;
|
||||
return self.tryForTime(urlTimeout, function () {
|
||||
// give the app time to update the URL
|
||||
return self.sleep(500)
|
||||
.then(function () {
|
||||
return self.remote.getCurrentUrl();
|
||||
})
|
||||
.then(function (currentUrl) {
|
||||
if (lastUrl !== currentUrl) {
|
||||
lastUrl = currentUrl;
|
||||
throw new Error('URL changed, waiting for it to settle');
|
||||
}
|
||||
});
|
||||
});
|
||||
});
|
||||
},
|
||||
|
||||
runScript: function (fn, timeout) {
|
||||
var self = this;
|
||||
timeout = timeout || 2000;
|
||||
|
||||
// wait for deps on window before running script
|
||||
return self.remote
|
||||
.setExecuteAsyncTimeout(timeout)
|
||||
.executeAsync(function (done) {
|
||||
var interval = setInterval(function () {
|
||||
var ready = (document.readyState === 'complete');
|
||||
var hasJQuery = !!window.$;
|
||||
|
||||
if (ready && hasJQuery) {
|
||||
console.log('doc ready, jquery loaded');
|
||||
clearInterval(interval);
|
||||
done();
|
||||
}
|
||||
}, 10);
|
||||
}).then(function () {
|
||||
return self.remote.execute(fn);
|
||||
});
|
||||
},
|
||||
|
||||
getApp: function () {
|
||||
var self = this;
|
||||
var loadTimeout = 5000;
|
||||
|
||||
return self.tryForTime(3000, function () {
|
||||
return self.remote.setFindTimeout(loadTimeout)
|
||||
.findByCssSelector('.content > .application');
|
||||
})
|
||||
.then(function () {
|
||||
return self.runScript(function () {
|
||||
var $ = window.$;
|
||||
var $scope = $('.content > .application').scope();
|
||||
return $scope ? $scope.chrome.getApp() : {};
|
||||
});
|
||||
});
|
||||
},
|
||||
|
||||
checkForKibanaApp: function () {
|
||||
var self = this;
|
||||
|
||||
return self.getApp()
|
||||
.then(function (app) {
|
||||
var appId = app.id;
|
||||
self.debug('current application: ' + appId);
|
||||
return appId === 'kibana';
|
||||
})
|
||||
.catch(function (err) {
|
||||
self.debug('kibana check failed');
|
||||
self.debug(err);
|
||||
// not on the kibana app...
|
||||
return false;
|
||||
});
|
||||
},
|
||||
|
||||
tryForTime: function (timeout, block) {
|
||||
var self = this;
|
||||
var start = Date.now();
|
||||
var retryDelay = 500;
|
||||
var lastTry = 0;
|
||||
|
||||
function attempt() {
|
||||
lastTry = Date.now();
|
||||
|
||||
if (lastTry - start > timeout) {
|
||||
throw new Error('timeout');
|
||||
}
|
||||
|
||||
return Promise
|
||||
.try(block)
|
||||
.then(function tryForTimeSuccess() {
|
||||
self.debug('tryForTime success in about ' + (lastTry - start) + ' ms');
|
||||
return (lastTry - start);
|
||||
})
|
||||
.catch(function tryForTimeCatch(err) {
|
||||
self.debug('tryForTime failure, retry in ' + retryDelay + 'ms - ' + err.message);
|
||||
return Promise.delay(retryDelay).then(attempt);
|
||||
});
|
||||
}
|
||||
|
||||
return Promise.try(attempt);
|
||||
},
|
||||
|
||||
log: function (logString) {
|
||||
console.log(moment().format('HH:mm:ss.SSS') + ': ' + logString);
|
||||
},
|
||||
|
||||
debug: function (logString) {
|
||||
if (config.debug) this.log(logString);
|
||||
},
|
||||
|
||||
sleep: function (sleepMilliseconds) {
|
||||
this.debug('sleeping for ' + sleepMilliseconds + 'ms');
|
||||
return Promise.resolve().delay(sleepMilliseconds);
|
||||
},
|
||||
|
||||
handleError: function (testObj) {
|
||||
var self = this;
|
||||
var testName = (testObj.parent) ? [testObj.parent.name, testObj.name].join('_') : testObj.name;
|
||||
|
||||
return function (reason) {
|
||||
var now = Date.now();
|
||||
var filename = ['failure', now, testName].join('_') + '.png';
|
||||
|
||||
return self.saveScreenshot(filename)
|
||||
.finally(function () {
|
||||
throw new Error(reason);
|
||||
});
|
||||
};
|
||||
},
|
||||
|
||||
saveScreenshot: function (filename) {
|
||||
var self = this;
|
||||
var outDir = path.resolve('test', 'output');
|
||||
|
||||
return self.remote.takeScreenshot()
|
||||
.then(function writeScreenshot(data) {
|
||||
var filepath = path.resolve(outDir, filename);
|
||||
self.debug('Test Failed, taking screenshot "' + filepath + '"');
|
||||
fs.writeFileSync(filepath, data);
|
||||
})
|
||||
.catch(function (err) {
|
||||
self.log('SCREENSHOT FAILED: ' + err);
|
||||
});
|
||||
}
|
||||
};
|
||||
|
||||
return Common;
|
||||
});
|
54
test/support/pages/HeaderPage.js
Normal file
54
test/support/pages/HeaderPage.js
Normal file
|
@ -0,0 +1,54 @@
|
|||
// in test/support/pages/HeaderPage.js
|
||||
define(function (require) {
|
||||
|
||||
var Common = require('./Common');
|
||||
|
||||
var common;
|
||||
|
||||
// the page object is created as a constructor
|
||||
// so we can provide the remote Command object
|
||||
// at runtime
|
||||
function HeaderPage(remote) {
|
||||
this.remote = remote;
|
||||
common = new Common(this.remote);
|
||||
}
|
||||
|
||||
var defaultTimeout = 5000;
|
||||
|
||||
HeaderPage.prototype = {
|
||||
constructor: HeaderPage,
|
||||
|
||||
clickSelector: function (selector) {
|
||||
var self = this.remote;
|
||||
return common.tryForTime(5000, function () {
|
||||
return self.setFindTimeout(defaultTimeout)
|
||||
.findByCssSelector(selector)
|
||||
.then(function (tab) {
|
||||
return tab.click();
|
||||
});
|
||||
});
|
||||
},
|
||||
|
||||
clickDiscover: function () {
|
||||
common.debug('click Discover tab');
|
||||
this.clickSelector('a[href*=\'discover\']');
|
||||
},
|
||||
|
||||
clickVisualize: function () {
|
||||
common.debug('click Visualize tab');
|
||||
this.clickSelector('a[href*=\'visualize\']');
|
||||
},
|
||||
|
||||
clickDashboard: function () {
|
||||
common.debug('click Dashboard tab');
|
||||
this.clickSelector('a[href*=\'dashboard\']');
|
||||
},
|
||||
|
||||
clickSettings: function () {
|
||||
common.debug('click Settings tab');
|
||||
this.clickSelector('a[href*=\'settings\']');
|
||||
}
|
||||
};
|
||||
|
||||
return HeaderPage;
|
||||
});
|
331
test/support/pages/SettingsPage.js
Normal file
331
test/support/pages/SettingsPage.js
Normal file
|
@ -0,0 +1,331 @@
|
|||
// in test/support/pages/SettingsPage.js
|
||||
define(function (require) {
|
||||
// the page object is created as a constructor
|
||||
// so we can provide the remote Command object
|
||||
// at runtime
|
||||
|
||||
var Promise = require('bluebird');
|
||||
var Common = require('./Common');
|
||||
|
||||
var defaultTimeout = 5000;
|
||||
var common;
|
||||
|
||||
function SettingsPage(remote) {
|
||||
this.remote = remote;
|
||||
common = new Common(this.remote);
|
||||
}
|
||||
|
||||
SettingsPage.prototype = {
|
||||
constructor: SettingsPage,
|
||||
|
||||
navigateTo: function () {
|
||||
return common.navigateToApp('settings');
|
||||
},
|
||||
|
||||
getTimeBasedEventsCheckbox: function getTimeBasedEventsCheckbox() {
|
||||
return this.remote.setFindTimeout(defaultTimeout)
|
||||
.findByCssSelector('input[ng-model="index.isTimeBased"]');
|
||||
},
|
||||
|
||||
getTimeBasedIndexPatternCheckbox: function getTimeBasedIndexPatternCheckbox() {
|
||||
// fail faster since we're sometimes checking that it doesn't exist
|
||||
return this.remote.setFindTimeout(defaultTimeout / 2)
|
||||
.findByCssSelector('input[ng-model="index.nameIsPattern"]');
|
||||
},
|
||||
|
||||
getIndexPatternField: function getIndexPatternField() {
|
||||
return this.remote.setFindTimeout(defaultTimeout)
|
||||
.findByCssSelector('[ng-model="index.name"]');
|
||||
},
|
||||
|
||||
getTimeFieldNameField: function getTimeFieldNameField() {
|
||||
return this.remote.setFindTimeout(defaultTimeout)
|
||||
.findByCssSelector('select[ng-model="index.timeField"]');
|
||||
},
|
||||
|
||||
selectTimeFieldOption: function selectTimeFieldOption(selection) {
|
||||
var self = this;
|
||||
return common.tryForTime(defaultTimeout * 2, function () {
|
||||
return self.getTimeFieldNameField().click();
|
||||
})
|
||||
.then(function () {
|
||||
return self.getTimeFieldNameField().click();
|
||||
})
|
||||
.then(function () {
|
||||
return self.getTimeFieldOption(selection);
|
||||
})
|
||||
// DEBUGGING
|
||||
.catch(function (err) {
|
||||
common.debug('selectTimeFieldOption: FAILED to create index pattern');
|
||||
return common.checkForKibanaApp()
|
||||
.then(function (onKibana) {
|
||||
common.debug('onKibana')
|
||||
common.debug(onKibana)
|
||||
})
|
||||
.then(function () {
|
||||
return self.remote.getCurrentUrl();
|
||||
})
|
||||
.then(function (url) {
|
||||
common.debug('FAILED on url ' + url);
|
||||
throw err
|
||||
})
|
||||
});
|
||||
},
|
||||
|
||||
getTimeFieldOption: function getTimeFieldOption(selection) {
|
||||
return this.remote.setFindTimeout(defaultTimeout * 2)
|
||||
.findByCssSelector('option[label="' + selection + '"]').click();
|
||||
},
|
||||
|
||||
getCreateButton: function getCreateButton() {
|
||||
return this.remote.setFindTimeout(defaultTimeout)
|
||||
.findByCssSelector('.btn');
|
||||
},
|
||||
|
||||
clickCreateButton: function clickCreateButton() {
|
||||
return this.remote.setFindTimeout(defaultTimeout)
|
||||
.findByCssSelector('.btn').click();
|
||||
},
|
||||
|
||||
clickDefaultIndexButton: function clickDefaultIndexButton() {
|
||||
return this.remote.setFindTimeout(defaultTimeout)
|
||||
.findByCssSelector('button.btn.btn-warning.ng-scope').click();
|
||||
},
|
||||
|
||||
clickDeletePattern: function clickDeletePattern() {
|
||||
return this.remote.setFindTimeout(defaultTimeout)
|
||||
.findByCssSelector('button.btn.btn-danger.ng-scope').click();
|
||||
},
|
||||
|
||||
getIndexPageHeading: function getIndexPageHeading() {
|
||||
return this.remote.setFindTimeout(defaultTimeout)
|
||||
.findByCssSelector('h1.title.ng-binding.ng-isolate-scope');
|
||||
},
|
||||
|
||||
getConfigureHeader: function getConfigureHeader() {
|
||||
return this.remote.setFindTimeout(defaultTimeout)
|
||||
.findByCssSelector('h1');
|
||||
},
|
||||
getTableHeader: function getTableHeader() {
|
||||
return this.remote.setFindTimeout(defaultTimeout)
|
||||
.findAllByCssSelector('table.table.table-condensed thead tr th');
|
||||
},
|
||||
|
||||
sortBy: function sortBy(columnName) {
|
||||
return this.remote.setFindTimeout(defaultTimeout)
|
||||
.findAllByCssSelector('table.table.table-condensed thead tr th span')
|
||||
.then(function (chartTypes) {
|
||||
|
||||
function getChartType(chart) {
|
||||
return chart.getVisibleText()
|
||||
.then(function (chartString) {
|
||||
if (chartString === columnName) {
|
||||
return chart.click();
|
||||
}
|
||||
});
|
||||
}
|
||||
var getChartTypesPromises = chartTypes.map(getChartType);
|
||||
return Promise.all(getChartTypesPromises);
|
||||
});
|
||||
},
|
||||
|
||||
getTableRow: function getTableRow(rowNumber, colNumber) {
|
||||
return this.remote.setFindTimeout(defaultTimeout)
|
||||
// passing in zero-based index, but adding 1 for css 1-based indexes
|
||||
.findByCssSelector('div.agg-table-paginated table.table.table-condensed tbody tr:nth-child(' +
|
||||
(rowNumber + 1) + ') td.ng-scope:nth-child(' +
|
||||
(colNumber + 1) + ') span.ng-binding'
|
||||
);
|
||||
},
|
||||
|
||||
getFieldsTabCount: function getFieldsTabCount() {
|
||||
var self = this;
|
||||
var selector = 'li.kbn-settings-tab.active a small';
|
||||
|
||||
var getText = function () {
|
||||
return self.remote.setFindTimeout(defaultTimeout)
|
||||
.findByCssSelector(selector).getVisibleText();
|
||||
}
|
||||
|
||||
return common.tryForTime(defaultTimeout * 4, function () {
|
||||
return getText();
|
||||
})
|
||||
.then(function () {
|
||||
return getText();
|
||||
})
|
||||
.then(function (theText) {
|
||||
// the value has () around it, remove them
|
||||
return theText.replace(/\((.*)\)/, '$1');
|
||||
});
|
||||
},
|
||||
|
||||
getPageSize: function getPageSize() {
|
||||
var selectedItemLabel = '';
|
||||
return this.remote.setFindTimeout(defaultTimeout)
|
||||
.findAllByCssSelector('select.ng-pristine.ng-valid.ng-untouched option')
|
||||
.then(function (chartTypes) {
|
||||
|
||||
function getChartType(chart) {
|
||||
var thisChart = chart;
|
||||
return chart.isSelected()
|
||||
.then(function (isSelected) {
|
||||
if (isSelected === true) {
|
||||
return thisChart.getProperty('label')
|
||||
.then(function (theLabel) {
|
||||
selectedItemLabel = theLabel;
|
||||
});
|
||||
}
|
||||
});
|
||||
}
|
||||
var getChartTypesPromises = chartTypes.map(getChartType);
|
||||
return Promise.all(getChartTypesPromises);
|
||||
})
|
||||
.then(function () {
|
||||
return selectedItemLabel;
|
||||
});
|
||||
},
|
||||
|
||||
getPageFieldCount: function getPageFieldCount() {
|
||||
return this.remote.setFindTimeout(defaultTimeout)
|
||||
.findAllByCssSelector('div.agg-table-paginated table.table.table-condensed tbody tr td.ng-scope:nth-child(1) span.ng-binding');
|
||||
},
|
||||
|
||||
goToPage: function goToPage(pageNum) {
|
||||
return this.remote.setFindTimeout(defaultTimeout)
|
||||
.findByCssSelector('ul.pagination-other-pages-list.pagination-sm.ng-scope li.ng-scope:nth-child(' +
|
||||
(pageNum + 1) + ') a.ng-binding'
|
||||
)
|
||||
.then(function (page) {
|
||||
return page.click();
|
||||
});
|
||||
},
|
||||
|
||||
openControlsRow: function openControlsRow(row) {
|
||||
return this.remote.setFindTimeout(defaultTimeout)
|
||||
.findByCssSelector('table.table.table-condensed tbody tr:nth-child(' +
|
||||
(row + 1) + ') td.ng-scope div.actions a.btn.btn-xs.btn-default i.fa.fa-pencil'
|
||||
)
|
||||
.then(function (page) {
|
||||
return page.click();
|
||||
});
|
||||
},
|
||||
|
||||
openControlsByName: function openControlsByName(name) {
|
||||
return this.remote.setFindTimeout(defaultTimeout * 2)
|
||||
.findByCssSelector('div.actions a.btn.btn-xs.btn-default[href$="/' + name + '"]')
|
||||
.then(function (button) {
|
||||
return button.click();
|
||||
});
|
||||
},
|
||||
|
||||
increasePopularity: function increasePopularity() {
|
||||
return this.remote.setFindTimeout(defaultTimeout)
|
||||
.findByCssSelector('button.btn.btn-default[aria-label="Plus"]')
|
||||
.then(function (button) {
|
||||
return button.click();
|
||||
});
|
||||
},
|
||||
|
||||
getPopularity: function getPopularity() {
|
||||
return this.remote.setFindTimeout(defaultTimeout)
|
||||
.findByCssSelector('input[ng-model="editor.field.count"]')
|
||||
.then(function (input) {
|
||||
return input.getProperty('value');
|
||||
});
|
||||
},
|
||||
|
||||
controlChangeCancel: function controlChangeCancel() {
|
||||
return this.remote.setFindTimeout(defaultTimeout)
|
||||
.findByCssSelector('button.btn.btn-primary[aria-label="Cancel"]')
|
||||
.then(function (button) {
|
||||
return button.click();
|
||||
});
|
||||
},
|
||||
|
||||
controlChangeSave: function controlChangeSave() {
|
||||
return this.remote.setFindTimeout(defaultTimeout)
|
||||
.findByCssSelector('button.btn.btn-success.ng-binding[aria-label="Update Field"]')
|
||||
.then(function (button) {
|
||||
return button.click();
|
||||
});
|
||||
},
|
||||
|
||||
setPageSize: function setPageSize(size) {
|
||||
return this.remote.setFindTimeout(defaultTimeout)
|
||||
.findByCssSelector('form.form-inline.pagination-size.ng-scope.ng-pristine.ng-valid div.form-group option[label="' + size + '"]')
|
||||
.then(function (button) {
|
||||
return button.click();
|
||||
});
|
||||
},
|
||||
|
||||
createIndexPattern: function createIndexPattern() {
|
||||
var self = this;
|
||||
|
||||
return common.tryForTime(defaultTimeout, function () {
|
||||
return self.selectTimeFieldOption('@timestamp')
|
||||
.then(function () {
|
||||
return self.getCreateButton().click();
|
||||
});
|
||||
})
|
||||
.then(function () {
|
||||
return common.tryForTime(defaultTimeout, function () {
|
||||
return self.remote.getCurrentUrl()
|
||||
.then(function (currentUrl) {
|
||||
if (!currentUrl.match(/indices\/.+\?/)) {
|
||||
throw new Error('Index pattern not created');
|
||||
}
|
||||
});
|
||||
});
|
||||
})
|
||||
// DEBUGGING
|
||||
.catch(function (err) {
|
||||
common.debug('createIndexPattern: FAILED to create index pattern');
|
||||
return common.checkForKibanaApp()
|
||||
.then(function (onKibana) {
|
||||
common.debug('onKibana')
|
||||
common.debug(onKibana)
|
||||
})
|
||||
.then(function () {
|
||||
return self.remote.getCurrentUrl();
|
||||
})
|
||||
.then(function (url) {
|
||||
common.debug('FAILED on url ' + url);
|
||||
throw err
|
||||
})
|
||||
});
|
||||
},
|
||||
|
||||
removeIndexPattern: function removeIndexPattern() {
|
||||
var self = this;
|
||||
var alertText;
|
||||
|
||||
return common.tryForTime(defaultTimeout, function () {
|
||||
return self.clickDeletePattern()
|
||||
.then(function () {
|
||||
return self.remote.getAlertText();
|
||||
})
|
||||
.then(function (text) {
|
||||
alertText = text;
|
||||
})
|
||||
.then(function () {
|
||||
return self.remote.acceptAlert();
|
||||
});
|
||||
})
|
||||
.then(function () {
|
||||
return common.tryForTime(defaultTimeout, function () {
|
||||
return self.remote.getCurrentUrl()
|
||||
.then(function (currentUrl) {
|
||||
if (currentUrl.match(/indices\/.+\?/)) {
|
||||
throw new Error('Index pattern not removed');
|
||||
}
|
||||
});
|
||||
});
|
||||
})
|
||||
.then(function () {
|
||||
return alertText;
|
||||
});
|
||||
}
|
||||
};
|
||||
|
||||
return SettingsPage;
|
||||
});
|
|
@ -2,17 +2,36 @@ var expect = require('expect.js');
|
|||
var getUrl = require('../getUrl');
|
||||
|
||||
describe('getUrl', function () {
|
||||
it('should be able to convert a config and a path to a url', function () {
|
||||
expect(getUrl({
|
||||
it('should convert to a url', function () {
|
||||
var url = getUrl({
|
||||
protocol: 'http',
|
||||
hostname: 'localhost',
|
||||
}, {
|
||||
pathname: 'foo'
|
||||
});
|
||||
|
||||
expect(url).to.be('http://localhost/foo');
|
||||
});
|
||||
|
||||
it('should convert to a secure url with port', function () {
|
||||
var url = getUrl({
|
||||
protocol: 'http',
|
||||
hostname: 'localhost',
|
||||
port: 9220
|
||||
}, 'foo')).to.be('http://localhost:9220/foo');
|
||||
}, {
|
||||
pathname: 'foo'
|
||||
});
|
||||
|
||||
expect(url).to.be('http://localhost:9220/foo');
|
||||
});
|
||||
|
||||
it('should convert to a secure hashed url', function () {
|
||||
expect(getUrl({
|
||||
protocol: 'https',
|
||||
hostname: 'localhost',
|
||||
}, 'foo')).to.be('https://localhost/foo');
|
||||
|
||||
}, {
|
||||
pathname: 'foo',
|
||||
hash: 'bar'
|
||||
})).to.be('https://localhost/foo#bar');
|
||||
});
|
||||
});
|
||||
|
|
|
@ -1,7 +1,6 @@
|
|||
var _ = require('lodash');
|
||||
var url = require('url');
|
||||
|
||||
|
||||
/**
|
||||
* Converts a config and a pathname to a url
|
||||
* @param {object} config A url config
|
||||
|
@ -11,11 +10,14 @@ var url = require('url');
|
|||
* hostname: 'localhost',
|
||||
* port: 9220
|
||||
* }
|
||||
* @param {string} pathname The requested path
|
||||
* @param {object} app The params to append
|
||||
* example:
|
||||
* {
|
||||
* pathname: 'app/kibana',
|
||||
* hash: '/discover'
|
||||
* }
|
||||
* @return {string}
|
||||
*/
|
||||
module.exports = function getPage(config, pathname) {
|
||||
return url.format(_.assign(config, {
|
||||
pathname: pathname
|
||||
}));
|
||||
module.exports = function getPage(config, app) {
|
||||
return url.format(_.assign(config, app));
|
||||
};
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue