diff --git a/.testing/cache_build_and_dependencies.js b/.testing/cache_build_and_dependencies.js new file mode 100755 index 00000000..a9c3f32f --- /dev/null +++ b/.testing/cache_build_and_dependencies.js @@ -0,0 +1,38 @@ +#!/usr/bin/env node + +const path = require('path'); +const spawn = require('child_process').spawn; +const baseDir = path.resolve(__dirname, '../'); +const srcDir = baseDir; + +const cacheMeteor = function() { + console.log('Caching build & dependencies (can take a while the first time)'); + const childProcess = spawn('meteor', ['--raw-logs'], { + cwd: srcDir, + env: process.env + }); + childProcess.stdout.setEncoding('utf8'); + childProcess.stderr.setEncoding('utf8'); + childProcess.stdout.on('data', function(line) { + process.stdout.write(line); + }); + childProcess.stderr.on('data', function(line) { + process.stderr.write(line); + }); + const exitAfterBuild = function exitAfterBuild(line) { + if (line.indexOf('App running at') !== -1) { + childProcess.kill(); + console.log('Done caching build & dependencies'); + } else if ( + line.indexOf('Your application is crashing') !== -1 || + line.indexOf('Errors prevented startup') !== -1) { + childProcess.kill(); + console.error('There were issues whilst trying to cache build & dependencies'); + throw new Error(line); + } + }; + childProcess.stdout.on('data', exitAfterBuild); + childProcess.stderr.on('data', exitAfterBuild); +}; + +cacheMeteor(); \ No newline at end of file diff --git a/.testing/cache_build_and_dependencies.sh b/.testing/cache_build_and_dependencies.sh new file mode 100755 index 00000000..01493b13 --- /dev/null +++ b/.testing/cache_build_and_dependencies.sh @@ -0,0 +1,3 @@ +export MONGO_URL="mongodb://localhost:27017/cache" +echo "Running meteor to cache it …" +node ./.testing/cache_build_and_dependencies.js \ No newline at end of file diff --git a/.testing/cache_meteor.sh b/.testing/cache_meteor.sh new file mode 100755 index 00000000..01f4e413 --- /dev/null +++ b/.testing/cache_meteor.sh @@ -0,0 +1,3 @@ +# Cache Meteor +if [ -d ~/.meteor ]; then sudo ln -s ~/.meteor/meteor /usr/local/bin/meteor; fi +if [ ! -e $HOME/.meteor/meteor ]; then curl https://install.meteor.com | sh; fi \ No newline at end of file diff --git a/.testing/cache_npm_dependencies.sh b/.testing/cache_npm_dependencies.sh new file mode 100755 index 00000000..8ab54567 --- /dev/null +++ b/.testing/cache_npm_dependencies.sh @@ -0,0 +1,4 @@ +# Cache npm deps +if [ ! -e /home/ubuntu/nvm/versions/node/v5.2.0/lib/node_modules/chimp/bin/chimp.js ]; then npm install -g chimp; fi +if [ ! -e /home/ubuntu/nvm/versions/node/v5.2.0/lib/node_modules/spacejam/bin/spacejam ]; then npm install -g spacejam; fi +npm install \ No newline at end of file diff --git a/.testing/chimp.js b/.testing/chimp.js new file mode 100644 index 00000000..e1d7979a --- /dev/null +++ b/.testing/chimp.js @@ -0,0 +1,59 @@ +#!/usr/bin/env node +"use strict"; + +var path = require('path'); +var extend = require('util')._extend; +var baseDir = path.resolve(__dirname, '../'); +var srcDir = path.resolve(baseDir); +var source = require(srcDir + '/node_modules/shell-source'); +var processes = require('./processes.js'); +var isCi = process.argv[2] === '--ci'; + +var startTestApp = function(onStarted, options) { + return processes.start({ + name: 'Test App', + command: 'meteor --port=3100', + waitForMessage: 'App running at: http://localhost:3100', + options: { + cwd: srcDir, + env: extend(process.env, options) + } + }, function() { + console.log("Test app is running …"); + onStarted(); + }); +}; + +var startChimpWatch = function() { + processes.start({ + name: 'Chimp Watch', + command: 'chimp --ddp=http://localhost:3100 --watch --path=tests --mocha --chai --browser=chrome', + options: { cwd: baseDir } + }); +}; + +var startChimpCi = function() { + var command = 'chimp --ddp=http://localhost:3100 --path=tests --browser=chrome --mocha --chai'; + processes.start({ + name: 'Chimp CI', + command: command, + options: { cwd: baseDir } + }); +}; + +if (isCi) { + // CI mode -> run once + if (process.env.CIRCLECI) { + startTestApp(startChimpCi); + } else { + // Use a different db for local ci testing to avoid nuking of the dev db + startTestApp(startChimpCi, { + MONGO_URL: 'mongodb://localhost:3001/chimp_db' + }); + } +} else { + // DEV mode -> watch + startTestApp(startChimpWatch, { + MONGO_URL: 'mongodb://localhost:3001/chimp_db' + }); +} \ No newline at end of file diff --git a/.testing/processes.js b/.testing/processes.js new file mode 100644 index 00000000..d7fb0362 --- /dev/null +++ b/.testing/processes.js @@ -0,0 +1,45 @@ +"use strict"; +var fs = require('fs'); +var exec = require('child_process').exec; +var processes = []; + +/** + * Helper function to start a process and listen for + * specific stdout console output and invoke a callback. + * This is used in this case to listen when the normal dev + * app started its mongoDb, so we can reuse that for the test app. + */ +module.exports = { + start: function(opts, callback) { + var proc = exec( + opts.command, + opts.options + ); + if (opts.waitForMessage) { + proc.stdout.on('data', function waitForMessage(data) { + if (data.toString().match(opts.waitForMessage)) { + if (callback) { + callback(); + } + } + }); + } + if (!opts.silent) { + proc.stdout.pipe(process.stdout); + proc.stderr.pipe(process.stderr); + } + if (opts.logFile) { + var logStream = fs.createWriteStream(opts.logFile, {flags: 'a'}); + proc.stdout.pipe(logStream); + proc.stderr.pipe(logStream); + } + proc.on('close', function(code) { + console.log(opts.name, 'exited with code ' + code); + for (var i = 0; i < processes.length; i += 1) { + processes[i].kill(); + } + process.exit(code); + }); + processes.push(proc); + } +}; \ No newline at end of file diff --git a/circle.yml b/circle.yml index f03cbc87..f1713061 100644 --- a/circle.yml +++ b/circle.yml @@ -1,13 +1,27 @@ machine: node: - version: 0.10.40 + version: 5.2.0 dependencies: + cache_directories: + - "~/.npm" + - "~/.meteor" + - "node_modules" + - "./.meteor/local/build" + - "./.meteor/local/bundler-cache" + - "./.meteor/local/isopacks" + - "./.meteor/local/plugin-cache" + - "/home/ubuntu/nvm/versions/node/v5.2.0/bin" + - "/home/ubuntu/nvm/versions/node/v5.2.0/lib/node_modules" override: - - curl https://install.meteor.com | /bin/sh - - meteor npm install + - ./.testing/cache_meteor.sh + - ./.testing/cache_npm_dependencies.sh + - ./.testing/cache_build_and_dependencies.sh + - chimp --path=features # Cache chimp deps by running it without any tests checkout: post: - git submodule update --init test: + pre: + - mkdir -p $CIRCLE_TEST_REPORTS/cucumber override: - - meteor npm test + - ./tests/acceptance_run \ No newline at end of file diff --git a/package.json b/package.json index acc161e5..ce2f3049 100644 --- a/package.json +++ b/package.json @@ -8,8 +8,7 @@ "test-app-watch": "meteor test --full-app --driver-package practicalmeteor:mocha", "test-watch-terminal": "TEST_WATCH=1 meteor test --driver-package dispatch:mocha-phantomjs", "test-app-watch-terminal": "TEST_WATCH=1 meteor test --full-app --driver-package dispatch:mocha-phantomjs", - "lint": "eslint .", - "chimp-watch": "chimp --ddp=http://localhost:3000 --watch --mocha --path=tests" + "lint": "eslint ." }, "dependencies": { "autoprefixer": "^6.3.7", @@ -23,7 +22,8 @@ "eslint-plugin-import": "^1.10.3", "eslint-plugin-jsx-a11y": "^1.5.3", "eslint-plugin-meteor": "^3.6.0", - "eslint-plugin-react": "^5.2.2" + "eslint-plugin-react": "^5.2.2", + "shell-source": "^1.1.0" }, "eslintConfig": { "parser": "babel-eslint", diff --git a/tests/acceptance_run b/tests/acceptance_run new file mode 100755 index 00000000..bd178a93 --- /dev/null +++ b/tests/acceptance_run @@ -0,0 +1,2 @@ +#!/bin/sh +node ./.testing/chimp.js --ci \ No newline at end of file diff --git a/tests/acceptance_watch b/tests/acceptance_watch new file mode 100755 index 00000000..ad679636 --- /dev/null +++ b/tests/acceptance_watch @@ -0,0 +1,2 @@ +#!/bin/sh +node ./.testing/chimp.js \ No newline at end of file diff --git a/tests/lists.js b/tests/lists.js index 25b55c09..91a54eb7 100644 --- a/tests/lists.js +++ b/tests/lists.js @@ -3,14 +3,14 @@ /* globals browser assert */ const countLists = () => { - browser.waitForExist('.list-todo'); + browser.waitForVisible('.list-todo', 5000); const elements = browser.elements('.list-todo'); return elements.value.length; }; describe('list ui', () => { beforeEach(() => { - browser.url('http://localhost:3000'); + browser.url('http://localhost:3100'); }); it('can create a list @watch', () => {