diff --git a/.travis.yml b/.travis.yml index bfebd00947..36379390b8 100644 --- a/.travis.yml +++ b/.travis.yml @@ -4,11 +4,17 @@ dist: trusty python: - "2.7" +addons: + apt: + sources: + - google-chrome + packages: + - google-chrome-stable + services: - mysql before_install: - - export CHROME_BIN=chromium-browser - export DISPLAY=:99.0 - sh -e /etc/init.d/xvfb start @@ -23,18 +29,19 @@ install: - cd ~/ && bench init frappe-bench --frappe-path $TRAVIS_BUILD_DIR - cp -r $TRAVIS_BUILD_DIR/test_sites/test_site ~/frappe-bench/sites/ -script: - - set -e - - bench --verbose run-tests - before_script: - mysql -u root -ptravis -e 'create database test_frappe' - echo "USE mysql;\nCREATE USER 'test_frappe'@'localhost' IDENTIFIED BY 'test_frappe';\nFLUSH PRIVILEGES;\n" | mysql -u root -ptravis - echo "USE mysql;\nGRANT ALL PRIVILEGES ON \`test_frappe\`.* TO 'test_frappe'@'localhost';\n" | mysql -u root -ptravis - cd ~/frappe-bench - - npm install babel-core less chokidar babel-preset-es2015 babel-preset-es2016 babel-preset-es2017 babel-preset-babili - bench use test_site - bench reinstall --yes - bench start & - sleep 10 + +script: + - set -e + - bench --verbose run-tests + - bench reinstall --yes + - bench run-ui-tests --ci diff --git a/frappe/commands/utils.py b/frappe/commands/utils.py index 9d7d13a1a1..cfe6d83cbe 100644 --- a/frappe/commands/utils.py +++ b/frappe/commands/utils.py @@ -326,6 +326,33 @@ def run_tests(context, app=None, module=None, doctype=None, test=(), driver=None sys.exit(ret) +@click.command('run-ui-tests') +@click.option('--app', help="App to run tests on, leave blank for all apps") +@click.option('--ci', is_flag=True, default=False, help="Run in CI environment") +@pass_context +def run_ui_tests(context, app=None, ci=False): + "Run UI tests" + import subprocess + + site = get_site(context) + frappe.init(site=site) + + if app is None: + app = ",".join(frappe.get_installed_apps()) + + cmd = [ + './node_modules/.bin/nightwatch', + '--config', './apps/frappe/frappe/nightwatch.js', + '--app', app, + '--site', site + ] + + if ci: + cmd.extend(['--env', 'ci_server']) + + bench_path = frappe.utils.get_bench_path() + subprocess.call(cmd, cwd=bench_path) + @click.command('serve') @click.option('--port', default=8000) @click.option('--profile', is_flag=True, default=False) @@ -459,6 +486,7 @@ commands = [ request, reset_perms, run_tests, + run_ui_tests, serve, set_config, watch, diff --git a/frappe/nightwatch.global.js b/frappe/nightwatch.global.js new file mode 100644 index 0000000000..f7530e422f --- /dev/null +++ b/frappe/nightwatch.global.js @@ -0,0 +1,12 @@ +var chromedriver = require('chromedriver'); +module.exports = { + before: function (done) { + chromedriver.start(); + done(); + }, + + after: function (done) { + chromedriver.stop(); + done(); + } +}; \ No newline at end of file diff --git a/frappe/nightwatch.js b/frappe/nightwatch.js new file mode 100644 index 0000000000..a54c764b88 --- /dev/null +++ b/frappe/nightwatch.js @@ -0,0 +1,96 @@ +const fs = require('fs'); + +const ci_mode = get_cli_arg('env') === 'ci_server'; +const site_name = get_cli_arg('site'); +let app_name = get_cli_arg('app'); + +if(!app_name) { + console.log('Please specify app to run tests'); + return; +} + +if(!ci_mode && !site_name) { + console.log('Please specify site to run tests'); + return; +} + +// site url +let site_url; +if(site_name) { + site_url = 'http://' + site_name + ':' + get_port(); +} + +// multiple apps +if(app_name.includes(',')) { + app_name = app_name.split(','); +} else { + app_name = [app_name]; +} + +let test_folders = []; +let page_objects = []; +for(const app of app_name) { + const test_folder = `apps/${app}/${app}/tests/ui`; + const page_object = test_folder + '/page_objects'; + + if(!fs.existsSync(test_folder)) { + console.log(`No test folder found for "${app}"`); + continue; + } + test_folders.push(test_folder); + + if(fs.existsSync(page_object)) { + page_objects.push(); + } +} + +const config = { + "src_folders": test_folders, + "globals_path" : 'apps/frappe/frappe/nightwatch.global.js', + "page_objects_path": page_objects, + "selenium": { + "start_process": false + }, + "test_settings": { + "default": { + "launch_url": site_url, + "selenium_port": 9515, + "selenium_host": "127.0.0.1", + "default_path_prefix": "", + "silent": true, + // "screenshots": { + // "enabled": true, + // "path": SCREENSHOT_PATH + // }, + "globals": { + "waitForConditionTimeout": 15000 + }, + "desiredCapabilities": { + "browserName": "chrome", + "chromeOptions": { + "args": ["--no-sandbox", "--start-maximized"] + }, + "javascriptEnabled": true, + "acceptSslCerts": true + } + }, + "ci_server": { + "launch_url": 'http://localhost:8000' + } + } +} +module.exports = config; + +function get_cli_arg(key) { + var args = process.argv; + var i = args.indexOf('--' + key); + if(i === -1) { + return null; + } + return args[i + 1]; +} + +function get_port() { + var bench_config = JSON.parse(fs.readFileSync('sites/common_site_config.json')); + return bench_config.webserver_port; +} \ No newline at end of file diff --git a/frappe/tests/ui/login.js b/frappe/tests/ui/login.js new file mode 100644 index 0000000000..4d9c8ef21b --- /dev/null +++ b/frappe/tests/ui/login.js @@ -0,0 +1,19 @@ +module.exports = { + beforeEach: browser => { + browser + .url(browser.launch_url + '/login') + .waitForElementVisible('body', 5000) + }, + 'Login': browser => { + browser + .assert.title('Login') + .assert.visible('#login_email', 'Check if login box is visible') + .setValue("#login_email", "Administrator") + .setValue("#login_password", "admin") + .click(".btn-login") + .waitForElementVisible("#body_div", 15000); + }, + after: browser => { + browser.end(); + }, +}; \ No newline at end of file diff --git a/package.json b/package.json index c115c6bf9b..b26b4f2a53 100644 --- a/package.json +++ b/package.json @@ -20,9 +20,11 @@ "babel-preset-es2016": "^6.24.1", "babel-preset-es2017": "^6.24.1", "chokidar": "^1.7.0", + "chromedriver": "^2.30.1", "cookie": "^0.3.1", "express": "^4.15.3", "less": "^2.7.2", + "nightwatch": "^0.9.16", "redis": "^2.7.1", "socket.io": "^2.0.1", "superagent": "^3.5.2"