diff --git a/CloudronManifest.json b/CloudronManifest.json index 2588b5e..163704a 100644 --- a/CloudronManifest.json +++ b/CloudronManifest.json @@ -4,7 +4,7 @@ "author": "FreshRSS Developers", "description": "file://DESCRIPTION.md", "changelog": "file://CHANGELOG", - "tagline": "RSS reader", + "tagline": "RSS feed reader", "version": "0.1.0", "healthCheckPath": "/", "httpPort": 8000, @@ -17,9 +17,14 @@ "contactEmail": "support@cloudron.io", "icon": "logo.png", "tags": [ - "rss" + "rss", + "atom", + "greader", + "reader", + "news feeds" ], "mediaLinks": [ + "https://git.cloudron.io/dswd/freshrss-app/raw/master/screenshots/1.png" ], "postInstallMessage": "file://POSTINSTALL.md" } diff --git a/Dockerfile b/Dockerfile index 0d16371..412594c 100644 --- a/Dockerfile +++ b/Dockerfile @@ -29,6 +29,9 @@ RUN rm /etc/apache2/sites-enabled/* \ && a2enmod headers expires \ && a2ensite freshrss +RUN rm -rf /var/lib/php \ + && ln -s /run/php /var/lib/php + ADD start.sh /app/code/start.sh ADD setup_db.php /app/code/setup_db.php diff --git a/README.md b/README.md index bb1fb1e..b0df86a 100644 --- a/README.md +++ b/README.md @@ -31,6 +31,7 @@ The e2e tests are located in the `test/` folder and require [nodejs](http://node cd freshrss-app/test npm install -USERNAME= PASSWORD= mocha --bail test.js +export PATH=$PATH:node_modules/.bin +mocha --bail test.js ``` diff --git a/start.sh b/start.sh index e3cbb1c..3c7973b 100755 --- a/start.sh +++ b/start.sh @@ -2,6 +2,8 @@ set -eu +mkdir -p /run/php/sessions + if ! [ -f /app/data/.installed ]; then echo "Fresh installation, setting up..." rsync -a /app/code/data-orig/ /app/data/ @@ -49,12 +51,12 @@ cat > /app/data/config.php </dev/stdout 2>/dev/stderr + sudo -u www-data php /app/code/app/actualize_script.php >/dev/stdout 2>/dev/stderr done & echo "Starting apache" diff --git a/test/.jshintrc b/test/.jshintrc new file mode 100644 index 0000000..174ffa3 --- /dev/null +++ b/test/.jshintrc @@ -0,0 +1,7 @@ +{ + "node": true, + "browser": true, + "unused": true, + "globalstrict": true, + "predef": [ "angular", "$", "describe", "it", "before", "after" ] +} diff --git a/test/package.json b/test/package.json new file mode 100644 index 0000000..733c0ca --- /dev/null +++ b/test/package.json @@ -0,0 +1,22 @@ +{ + "name": "test", + "version": "1.0.0", + "description": "", + "main": "index.js", + "scripts": { + "test": "echo \"Error: no test specified\" && exit 1" + }, + "author": "", + "license": "ISC", + "dependencies": { + "ejs": "^2.4.2", + "expect.js": "^0.3.1", + "mkdirp": "^0.5.1", + "mocha": "^2.5.3", + "rimraf": "^2.5.3", + "selenium-server-standalone-jar": "^2.53.1", + "selenium-webdriver": "^2.53.3", + "superagent": "^1.4.0", + "chromedriver": "^2.27.0" + } +} diff --git a/test/test.js b/test/test.js new file mode 100644 index 0000000..b242042 --- /dev/null +++ b/test/test.js @@ -0,0 +1,169 @@ +#!/usr/bin/env node + +'use strict'; + +var execSync = require('child_process').execSync, + expect = require('expect.js'), + path = require('path'), + webdriver = require('selenium-webdriver'); + +var by = webdriver.By, + until = webdriver.until; + +var username = 'admin', + password = 'password'; + + +process.env.NODE_TLS_REJECT_UNAUTHORIZED = '0'; + + +describe('Application life cycle test', function () { + this.timeout(0); + + var chrome = require('selenium-webdriver/chrome'); + var server, browser = new chrome.Driver(); + + before(function (done) { + 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(); + }); + + var LOCATION = 'freshrss-test'; + var TEST_TIMEOUT = 10000; + var app; + + function exists(selector, callback) { + return browser.wait(until.elementLocated(selector), TEST_TIMEOUT).then(function () { + callback(); + }); + } + + function visible(selector, callback) { + exists(selector, function () { + browser.wait(until.elementIsVisible(browser.findElement(selector)), TEST_TIMEOUT).then(function () { + callback(); + }); + }); + } + + function login(callback) { + browser.manage().deleteAllCookies(); + browser.get('https://' + app.fqdn); + + visible(by.id('loginButton'), function () { + browser.findElement(by.id('username')).sendKeys(username); + browser.findElement(by.id('passwordPlain')).sendKeys(password); + browser.findElement(by.id('loginButton')).click(); + browser.wait(until.elementLocated(by.id('dropdown-configure')), TEST_TIMEOUT).then(function () { callback(); }); + }); + } + + function logout(callback) { + var logout_btn = by.xpath('//ul[@class="dropdown-menu"]/li/a[@class="signout"]'); + + browser.get('https://' + app.fqdn); + + visible(by.id('stream'), function () { + browser.findElement(by.className('dropdown-toggle')).click(); + visible(logout_btn, function () { + browser.findElement(logout_btn).click(); + + browser.wait(until.elementLocated(by.id('loginButton')), TEST_TIMEOUT).then(function () { callback(); }); + }); + }); + } + + function addSubscription(callback) { + var url = "https://cloudron.io/blog/rss.xml"; + + browser.get('https://' + app.fqdn); + + visible(by.id('stream'), function () { + browser.findElement(by.xpath('//a[@href=".?c=subscription"]')).click(); + visible(by.id('add_rss'), function () { + browser.findElement(by.xpath('//input[@name="url_rss"]')).sendKeys(url); + browser.findElement(by.xpath('//form[@id="add_rss"]/div/button[@type="submit"]')).click(); + visible(by.xpath('//div[@id="notification" and @class="notification good"]'), function() { callback(); }); + }); + }); + } + + function addUser(callback) { + var test_username = 'test'; + var manage_users_btn = by.xpath('//a[@href=".?c=user&a=manage"]'); + + browser.get('https://' + app.fqdn); + + visible(by.id('stream'), function () { + browser.findElement(by.className('dropdown-toggle')).click(); + visible(manage_users_btn, function () { + browser.findElement(manage_users_btn).click(); + visible(by.id('new_user_name'), function () { + browser.findElement(by.id('new_user_name')).sendKeys(test_username); + browser.findElement(by.id('new_user_passwordPlain')).sendKeys(password); + browser.findElement(by.xpath('//form[@action=".?c=user&a=create"]/div/div/button[@type="submit"]')).click(); + visible(by.xpath('//div[@id="notification" and @class="notification good"]'), function() { callback(); }); + }); + }); + }); + } + + + xit('build app', function () { + execSync('cloudron build', { cwd: path.resolve(__dirname, '..'), stdio: 'inherit' }); + }); + + 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 login', login); + it('can subscribe', addSubscription); + it('can add users', addUser); + it('can logout', logout); + + 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); + it('can logout', logout); + + it('move to different location', function () { + browser.manage().deleteAllCookies(); + execSync('cloudron configure --location ' + LOCATION + '2', { 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'); + }); + + it('can login', login); + it('can logout', logout); + + it('uninstall app', function () { + execSync('cloudron uninstall --app ' + app.id, { cwd: path.resolve(__dirname, '..'), stdio: 'inherit' }); + }); + +});