#!/usr/bin/env node /* jslint node:true */ /* global it:false */ /* global xit:false */ /* global describe:false */ /* global before:false */ /* global after:false */ 'use strict'; require('chromedriver'); var execSync = require('child_process').execSync, ejs = require('ejs'), expect = require('expect.js'), fs = require('fs'), mkdirp = require('mkdirp'), path = require('path'), rimraf = require('rimraf'), superagent = require('superagent'), util = require('util'), webdriver = require('selenium-webdriver'); var by = require('selenium-webdriver').By, until = require('selenium-webdriver').until, Key = require('selenium-webdriver').Key, Builder = require('selenium-webdriver').Builder; process.env.NODE_TLS_REJECT_UNAUTHORIZED = '0'; describe('Application life cycle test', function () { this.timeout(0); var server, browser = new Builder().forBrowser('chrome').build(); var LOCATION = 'test'; var app; var username = process.env.USERNAME; var password = process.env.PASSWORD; var adminUsername = 'admin'; var adminPassword = 'changeme'; var TIMEOUT = parseInt(process.env.TIMEOUT, 10) || 20000; var email, token; before(function (done) { if (!process.env.USERNAME) return done(new Error('USERNAME env var not set')); if (!process.env.PASSWORD) return done(new Error('PASSWORD env var not set')); var seleniumJar= require('selenium-server-standalone-jar'); var SeleniumServer = require('selenium-webdriver/remote').SeleniumServer; server = new SeleniumServer(seleniumJar.path, { port: 4444 }); server.start(); done(); }); after(function (done) { browser.quit(); server.stop(); done(); }); function login(username, password, done) { browser.manage().deleteAllCookies().then(function () { return browser.get('https://' + app.fqdn + '/wp-login.php'); }).then(function () { return browser.sleep(2000); // there seems to be some javascript that gives auto-focus to username }).then(function () { return browser.findElement(by.id('user_login')).sendKeys(username); }).then(function () { return browser.findElement(by.id('user_pass')).sendKeys(password); }).then(function () { return browser.findElement(by.tagName('form')).submit(); }).then(function () { return browser.wait(until.elementLocated(by.xpath('//h1[text()="Dashboard"]')), TIMEOUT); }).then(function () { done(); }); } function logout(done) { browser.manage().deleteAllCookies().then(function () { browser.executeScript('localStorage.clear();'); browser.executeScript('sessionStorage.clear();'); done(); }); } function checkHtaccess(done) { var out = execSync(util.format('cloudron exec --app %s -- cat /app/data/htaccess', app.id)); expect(out.toString('utf8').indexOf('RewriteEngine On')).to.not.be(-1); // wp generates this with permalinks in hard mode done(); } function checkPermalink(done) { browser.get('https://' + app.fqdn + '/hello-world').then(function () { return browser.findElement(by.xpath('//h1[text()="Hello Cloudron!"]')); }).then(function () { done(); }); } function checkPost(done) { browser.get('https://' + app.fqdn).then(function () { if (app.manifest.version === '1.7.0') { return browser.wait(until.elementLocated(by.xpath('//h3/a[text()="Hello Cloudron!"]')), TIMEOUT); } else { return browser.wait(until.elementLocated(by.xpath('//h2/a[text()="Hello Cloudron!"]')), TIMEOUT); } }).then(function () { done(); }); } function editPostWordpress4(done) { browser.get('https://' + app.fqdn + '/wp-admin/post.php?post=1&action=edit').then(function () { return browser.wait(until.elementLocated(by.xpath('//input[@id="title"]')), TIMEOUT); }).then(function () { return browser.findElement(by.xpath('//input[@id="title"]')).sendKeys(Key.chord(Key.CONTROL, 'a')); }).then(function () { return browser.findElement(by.xpath('//input[@id="title"]')).sendKeys('Hello Cloudron!'); }).then(function () { return browser.findElement(by.xpath('//input[@id="publish"]')).click(); }).then(function () { return browser.wait(until.elementLocated(by.xpath('//*[contains(text(), "Post updated.")]')), TIMEOUT); }).then(function () { done(); }); } function editPost(done) { browser.get('https://' + app.fqdn + '/wp-admin/post.php?post=1&action=edit').then(function () { return browser.wait(until.elementLocated(by.xpath('//button[@aria-label="Disable tips"]')), TIMEOUT); }).then(function () { return browser.findElement(by.xpath('//button[@aria-label="Disable tips"]')).click(); }).then(function () { return browser.findElement(by.xpath('//textarea[@id="post-title-0"]')).sendKeys(Key.chord(Key.CONTROL, 'a')); }).then(function () { return browser.findElement(by.xpath('//textarea[@id="post-title-0"]')).sendKeys('Hello Cloudron!'); }).then(function () { return browser.findElement(by.xpath('//button[text()="Update"]')).click(); }).then(function () { return browser.wait(until.elementLocated(by.xpath('//*[contains(text(), "Post updated.")]')), TIMEOUT); }).then(function () { return browser.sleep(3000); }).then(function () { done(); }); } function uploadMedia(done) { browser.get('https://' + app.fqdn + '/wp-admin/media-new.php?browser-uploader').then(function () { return browser.wait(until.elementLocated(by.id('async-upload')), TIMEOUT); }).then(function () { return browser.findElement(by.xpath('//input[@id="async-upload" and @type="file"]')).sendKeys(path.resolve(__dirname, '../logo.png')); }).then(function () { return browser.findElement(by.id('html-upload')).click(); }).then(function () { return browser.wait(function () { return browser.getCurrentUrl().then(function (url) { return url === 'https://' + app.fqdn + '/wp-admin/upload.php'; }); }, TIMEOUT); }).then(function () { done(); }); } function checkMedia(item, done) { browser.get(`https://${app.fqdn}/wp-admin/upload.php?item=${item}`).then(function () { // there's got to be a better way.. return browser.wait(until.elementLocated(by.xpath('//*[text()="Attachment Details"]')), TIMEOUT); }).then(function () { return browser.findElement(by.xpath('//img[@class="details-image"]')).getAttribute('src'); }).then(function (srcLink) { console.log('media is located at ', srcLink); mediaLink = srcLink; done(); }); } function checkMediaLink(done) { superagent.get(mediaLink).end(function (error, result) { expect(error).to.be(null); expect(result.statusCode).to.be(200); done(); }); } xit('build app', function () { execSync('cloudron build', { cwd: path.resolve(__dirname, '..'), stdio: 'inherit' }); }); it('can login', function (done) { var inspect = JSON.parse(execSync('cloudron inspect')); superagent.post('https://' + inspect.apiEndpoint + '/api/v1/developer/login').send({ username: username, password: password }).end(function (error, result) { if (error) return done(error); if (result.statusCode !== 200) return done(new Error('Login failed with status ' + result.statusCode)); token = result.body.accessToken; superagent.get('https://' + inspect.apiEndpoint + '/api/v1/profile') .query({ access_token: token }).end(function (error, result) { if (error) return done(error); if (result.statusCode !== 200) return done(new Error('Get profile failed with status ' + result.statusCode)); email = result.body.email; done(); }); }); }); it('install app', function () { execSync('cloudron install --new --wait --location ' + LOCATION, { cwd: path.resolve(__dirname, '..'), stdio: 'inherit' }); }); it('can get app information', function () { var inspect = JSON.parse(execSync('cloudron inspect')); app = inspect.apps.filter(function (a) { return a.location === LOCATION; })[0]; expect(app).to.be.an('object'); }); it('can get the main page', function (done) { superagent.get('https://' + app.fqdn).end(function (error, result) { expect(error).to.be(null); expect(result.status).to.eql(200); done(); }); }); it('can login', login.bind(null, username, password)); it('can edit', editPost); it('is an admin dashboard', function (done) { browser.wait(until.elementLocated(by.xpath('//div[@class="wp-menu-name" and contains(text(), "Plugins")]')), TIMEOUT).then(function () { done(); }); }); it('can upload media', uploadMedia); var mediaLink; it('can see media', checkMedia.bind(null, 6)); it('can see media link', checkMediaLink); it('has correct htaccess', checkHtaccess); it('can access permalink', checkPermalink); it('can restart app', function (done) { execSync('cloudron restart --wait --app ' + app.id); done(); }); it('can login', login.bind(null, username, password)); it('can see updated post', checkPost); it('can see media link', checkMediaLink); it('has correct htaccess', checkHtaccess); it('can access permalink', checkPermalink); it('backup app', function () { execSync('cloudron backup create --app ' + app.id, { cwd: path.resolve(__dirname, '..'), stdio: 'inherit' }); }); it('restore app', function () { execSync('cloudron restore --app ' + app.id, { cwd: path.resolve(__dirname, '..'), stdio: 'inherit' }); }); it('can login', login.bind(null, username, password)); it('can see updated post', checkPost); it('can see media link', checkMediaLink); it('has correct htaccess', checkHtaccess); it('can access permalink', checkPermalink); it('can login', login.bind(null, username, password)); it('runs cron jobs', function (done) { this.timeout(6 * 60 * 1000); // cron runs only every 5 minutes console.log('It can take upto 6 mins to detect that cron is working'); function checkLogs() { var logs = execSync('cloudron logs --lines 1000 --app ' + app.id).toString('utf8'); if (logs.indexOf('Executed the cron event \'wp_version_check\'') !== -1) return done(); setTimeout(checkLogs, 45000); } setTimeout(checkLogs, 45000); }); it('move to different location', function () { browser.manage().deleteAllCookies(); execSync('cloudron configure --wait --location ' + LOCATION + '2 --app ' + app.id, { cwd: path.resolve(__dirname, '..'), stdio: 'inherit' }); var inspect = JSON.parse(execSync('cloudron inspect')); app = inspect.apps.filter(function (a) { return a.location === LOCATION + '2'; })[0]; expect(app).to.be.an('object'); mediaLink = mediaLink.replace(LOCATION, LOCATION + '2'); }); it('can login', login.bind(null, username, password)); it('can see updated post', checkPost); it('can see media link', checkMediaLink); it('has correct htaccess', checkHtaccess); it('can access permalink', checkPermalink); it('can login', login.bind(null, username, password)); it('can logout', logout); it('uninstall app', function () { execSync('cloudron uninstall --app ' + app.id, { cwd: path.resolve(__dirname, '..'), stdio: 'inherit' }); }); // check if the _first_ login via email succeeds it('can login via email', function (done) { execSync('cloudron install --new --wait --location ' + LOCATION, { cwd: path.resolve(__dirname, '..'), stdio: 'inherit' }); var inspect = JSON.parse(execSync('cloudron inspect')); app = inspect.apps.filter(function (a) { return a.location === LOCATION; })[0]; expect(app).to.be.an('object'); login(email, password, function () { execSync('cloudron uninstall --app ' + app.id, { cwd: path.resolve(__dirname, '..'), stdio: 'inherit' }); logout(done); }); }); // No SSO it('install app (no sso)', function () { execSync('cloudron install --new --wait --no-sso --location ' + LOCATION, { cwd: path.resolve(__dirname, '..'), stdio: 'inherit' }); }); it('can get app information', function () { var inspect = JSON.parse(execSync('cloudron inspect')); app = inspect.apps.filter(function (a) { return a.location === LOCATION; })[0]; expect(app).to.be.an('object'); }); it('can login (no sso)', login.bind(null, adminUsername, adminPassword)); it('is an admin dashboard (no sso)', function (done) { browser.wait(until.elementLocated(by.xpath('//div[@class="wp-menu-name" and contains(text(), "Plugins")]')), TIMEOUT).then(function () { done(); }); }); it('can logout', logout); it('uninstall app (no sso)', function () { execSync('cloudron uninstall --app ' + app.id, { cwd: path.resolve(__dirname, '..'), stdio: 'inherit' }); }); // test update it('can install app', function () { execSync('cloudron install --new --wait --appstore-id org.wordpress.cloudronapp --location ' + LOCATION, { cwd: path.resolve(__dirname, '..'), stdio: 'inherit' }); var inspect = JSON.parse(execSync('cloudron inspect')); app = inspect.apps.filter(function (a) { return a.location === LOCATION; })[0]; expect(app).to.be.an('object'); }); it('can login', login.bind(null, username, password)); it('can edit', editPost); it('can upload media', uploadMedia); it('can update', function () { execSync('cloudron install --wait --app ' + LOCATION, { cwd: path.resolve(__dirname, '..'), stdio: 'inherit' }); }); it('can see updated post', checkPost); it('can login', login.bind(null, username, password)); it('is an admin dashboard', function (done) { browser.wait(until.elementLocated(by.xpath('//div[@class="wp-menu-name" and contains(text(), "Plugins")]')), TIMEOUT).then(function () { done(); }); }); it('can see media', checkMedia.bind(null, 6)); it('can see media link', checkMediaLink); it('can access permalink', checkPermalink); it('uninstall app', function () { execSync('cloudron uninstall --app ' + app.id, { cwd: path.resolve(__dirname, '..'), stdio: 'inherit' }); }); });