Skip to content

Commit

Permalink
Merge branch 'develop'
Browse files Browse the repository at this point in the history
  • Loading branch information
apendua committed Feb 16, 2015
2 parents df59dd2 + 70f2073 commit 39ef095
Show file tree
Hide file tree
Showing 31 changed files with 937 additions and 226 deletions.
2 changes: 1 addition & 1 deletion .versions
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
anti:[email protected].1
anti:[email protected].2
[email protected]
[email protected]
[email protected]
Expand Down
2 changes: 1 addition & 1 deletion README.md
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@ var server = meteor();
var client = browser(server); // before 0.4.0 you would use server.location here
```

# gagarin [![Circle CI](https://circleci.com/gh/anticoders/gagarin/tree/develop.svg?style=svg)](https://circleci.com/gh/anticoders/gagarin/tree/devel)
# gagarin [![Circle CI](https://circleci.com/gh/anticoders/gagarin/tree/develop.svg?style=svg)](https://circleci.com/gh/anticoders/gagarin/tree/develop)

Gagarin is a tool you can use in your tests to run Meteor apps in a sandboxed environment. It's useful when you need more refined control over the meteor processes and test fancy things, e.g. the behavior of your app on server restarts or when you have multiple app instances writing to the same database. This is currently not achievable with the official Meteor testing framework.

Expand Down
4 changes: 2 additions & 2 deletions bin/gagarin
Original file line number Diff line number Diff line change
Expand Up @@ -35,13 +35,14 @@ program
.option('-r, --remote-server <url>', 'run tests on a remote server')
.option('-m, --mute-build', 'do not show build logs', false)
.option('-f, --flavor <name>', 'default flavor of api (promise, fiber)', 'promise')
.option('-T, --startup-timeout <ms>' ,'server startup timeout [5000]', intParse, 5000)
.option('-U, --build-timeout <ms>' ,'meteor building timeout [120000]', intParse, 120000);

program.name = 'gagarin';

program.parse(process.argv);

var gagarin = new Gagarin(program);

var pathToTests = program.args[0] || path.join(program.pathToApp, 'tests', 'gagarin');

if (!fs.existsSync(pathToTests)) {
Expand Down Expand Up @@ -79,4 +80,3 @@ gagarin.run(function (failedCount) {
function intParse(v) {
return parseInt(v);
};

39 changes: 34 additions & 5 deletions lib/browser/helpers.js
Original file line number Diff line number Diff line change
@@ -1,11 +1,32 @@
var expect = require('chai').expect;
var either = require('../tools').either;
var Promise = require('es6-promise').Promise;

var DEFAULT_TIMEOUT = 5000;

// these two guys are required for screenshots
var fs = require('fs');
var path = require('path');

module.exports = {

addScript: function (url, verify, args) {
var self = this;
return self.promise(function (resolve, reject, url) {
var script = window.document.createElement('script');
script.src = url;
script.addEventListener('load', resolve);
window.document.head.appendChild(script);
}, [ url ]).then(function () {
if (verify) {
return self.noWait().execute(verify, args).then(function (success) {
if (!success) {
throw new Error('Script ' + url + ' has loaded but it seems that it does not contain the expected content.');
}
});
}
});
},

waitForDOM: function (selector, timeout) {
return this.wait(timeout || DEFAULT_TIMEOUT, 'until element ' + selector + ' is present', function (selector) {
return !!document.querySelector(selector);
Expand All @@ -21,7 +42,11 @@ module.exports = {
waitUntilNotVisible: function (selector, timeout) {
return this.wait(timeout || DEFAULT_TIMEOUT, 'until element ' + selector + ' is hidden', function (selector) {
var element = document.querySelector(selector);
return !element || window.getComputedStyle(element).display === 'none';
if(!!element){
return element.offsetWidth <= 0 && element.offsetHeight <= 0;
}else{
return false;
}
}, [ selector ]);
},

Expand Down Expand Up @@ -167,15 +192,15 @@ module.exports = {
disconnect: function () {
return this.execute(function () {
Meteor.disconnect();
}).wait(1000, 'unitl Meteor disconnects', function () {
}).wait(1000, 'until Meteor disconnects', function () {
return !Meteor.status().connected;
});
},

reconnect: function () {
return this.execute(function () {
Meteor.reconnect();
}).wait(1000, 'unitl Meteor reconnects', function () {
}).wait(1000, 'until Meteor reconnects', function () {
return Meteor.status().connected;
});
},
Expand Down Expand Up @@ -205,7 +230,11 @@ module.exports = {
checkIfVisible: function (selector) {
return this.execute(function (selector) {
var element = document.querySelector(selector);
return !!element && window.getComputedStyle(element).display !== 'none';
if(!!element){
return element.offsetWidth > 0 && element.offsetHeight > 0;
}else{
return false;
}
}, [ selector ]);
},

Expand Down
5 changes: 3 additions & 2 deletions lib/browser/index.js
Original file line number Diff line number Diff line change
Expand Up @@ -40,7 +40,8 @@ module.exports = function createBrowser (options) {
'setCookie',
'deleteAllCookies',
'deleteCookie',
'getLocation',
// seems like it's not working well
// 'getLocation',
];

// TODO: early detect colisions
Expand Down Expand Up @@ -71,7 +72,7 @@ module.exports = function createBrowser (options) {

function getClientLogs (action) {
return function (operand, done) {
return action(operand, function (err) {
return action.call(this, operand, function (err) {
var args = Array.prototype.slice.call(arguments, 0);
if (err) {
done(err);
Expand Down
33 changes: 26 additions & 7 deletions lib/browser/methods.js
Original file line number Diff line number Diff line change
@@ -1,4 +1,6 @@
var cleanError = require('../tools').cleanError;
var either = require('../tools').either;
var fs = require('fs');

module.exports = {};

Expand All @@ -7,7 +9,7 @@ module.exports.execute = function (code, args) {

var self = this;

if (arguments.length < 2) {
if (args === undefined) {
args = [];
}

Expand All @@ -20,12 +22,25 @@ module.exports.execute = function (code, args) {
}

return self.__custom__(function (operand, done) {
var closure = operand.closure ? operand.closure() : {};

code = wrapSourceCode(codeToString(code), args, closure);
if (this.lastError) {
if (this.retryCount <= 1 && /chai not found/.test(this.lastError.message)) {
operand.browser.execute(fs.readFileSync('./node_modules/chai/chai.js', "utf8"), either(done).or(doAction));
} else {
done(this.lastError);
}
} else {
doAction();
}

function doAction() {
var closure = operand.closure ? operand.closure() : {};

operand.browser.execute("return (" + wrapSourceCode(codeToString(code), args, closure) + ").apply(null, arguments)",
values(closure), feedbackProcessor(operand.closure.bind(operand), done));
}

operand.browser.execute("return (" + code + ").apply(null, arguments)",
values(closure), feedbackProcessor(operand.closure.bind(operand), done));
return true; // retry on first attempt
});
};

Expand All @@ -39,7 +54,7 @@ module.exports.promise = function (code, args) {

var self = this;

if (arguments.length < 2) {
if (args === undefined) {
args = [];
}

Expand Down Expand Up @@ -113,7 +128,7 @@ module.exports.promise = function (code, args) {
module.exports.wait = function (timeout, message, code, args) {
"use strict";

if (arguments.length < 4) {
if (args === undefined) {
args = [];
}

Expand Down Expand Up @@ -252,7 +267,11 @@ function wrapSourceCode(code, args, closure) {
//addSyncChunks(chunks, closure, accessor);

chunks.push(
" 'use strict';",
// " var expect;",
" try {",
// " if (!window.chai) { throw new Error('chai not found'); }",
// " expect = window.chai.expect;",
" return (function ($) {",
" return {",
" closure: {"
Expand Down
52 changes: 10 additions & 42 deletions lib/meteor/build.js
Original file line number Diff line number Diff line change
Expand Up @@ -12,11 +12,10 @@ var myBuildPromises = {};

module.exports = function BuildAsPromise (options) {
"use strict";

options = options || {};

var pathToApp = options.pathToApp || path.resolve('.');
var timeout = options.timeout || 60000;
var timeout = options.timeout || 120000;
var verbose = options.verbose !== undefined ? !!options.verbose : false;

var pathToSmartJson = path.join(pathToApp, 'smart.json');
Expand All @@ -33,25 +32,19 @@ module.exports = function BuildAsPromise (options) {

if (myBuildPromises[pathToApp]) return myBuildPromises[pathToApp];

if (fs.existsSync(pathToSmartJson)) {
myBuildPromises[pathToApp] = tools.smartPackagesAsPromise(pathToApp).then(function () {
return MongoServerAsPromise({ pathToApp: pathToApp }).then(function (mongoUrl) {
return BuildPromise({
pathToApp : pathToApp,
mongoUrl : mongoUrl,
verbose : verbose,
});
});
});
} else {
myBuildPromises[pathToApp] = MongoServerAsPromise({ pathToApp: pathToApp }).then(function (mongoUrl) {
var smartPackagesOrNothing = fs.existsSync(pathToSmartJson) ?
tools.smartPackagesAsPromise(pathToApp) : Promise.resolve();

myBuildPromises[pathToApp] = smartPackagesOrNothing.then(function () {
return MongoServerAsPromise({ pathToApp: pathToApp }).then(function (mongoUrl) {
return BuildPromise({
pathToApp : pathToApp,
mongoUrl : mongoUrl,
verbose : verbose,
timeout : timeout
});
});
}
});

return myBuildPromises[pathToApp];
};
Expand Down Expand Up @@ -106,12 +99,6 @@ function BuildPromise(options) {
reject(new Error('File ' + pathToMain + ' does not exist.'));
return;
}
try {
checkIfVersionsMatches(pathToApp);
} catch (err) {
reject(err);
return;
}
resolve(pathToMain);
});
meteor.kill('SIGINT');
Expand Down Expand Up @@ -181,7 +168,7 @@ function BuildPromise(options) {

setTimeout(function () {
meteor.once('exit', function () {
reject(new Error('Timeout while wating for meteor to start.'));
reject(new Error('Timeout while waiting for meteor to start.'));
});
meteor.kill('SIGINT')
}, timeout);
Expand All @@ -202,28 +189,9 @@ function BuildPromise(options) {
*/
function isLocked(pathToApp) {
var pathToMongoLock = path.join(pathToApp, '.meteor', 'local', 'db', 'mongod.lock');
return fs.existsSync(pathToMongoLock) && fs.readFileSync(pathToMongoLock).toString('utf8');
return fs.existsSync(pathToMongoLock) && fs.readFileSync(pathToMongoLock).toString('utf8');
}

/**
* Verify if Gagarin is instaled and if the version is compatible.
*/
function checkIfVersionsMatches(pathToApp) {

var pathToVersions = path.join(pathToApp, '.meteor', 'versions');
var versions = fs.readFileSync(pathToVersions, 'utf-8');
var versionMatch = versions.match(/anti:gagarin@(.*)/);

if (!versionMatch) { // looks like gagarin is not even instaled
throw new Error('Please add anti:gagarin to your app before running tests.');
} else if (versionMatch[1] !== version) { // versions of gagarin are not compatible
throw new Error(
'Versions of node package (' + version +
') and meteor package (' + versionMatch[1] +
') are not compatible; please update.'
);
}

}


39 changes: 31 additions & 8 deletions lib/meteor/index.js
Original file line number Diff line number Diff line change
Expand Up @@ -9,16 +9,16 @@ var Closure = require('../tools/closure');
var generic = require('../tools/generic');
var tools = require('../tools');
var url = require('url');
var path = require('path');
var fs = require('fs');
var version = require('../../package.json').version;

module.exports = function createMeteor (options) {
"use strict";

options = options || {};

if (typeof options === 'string') {
options = { pathToApp: options };
}

var pathToApp = options.pathToApp || path.resolve('.');
var skipBuild = !!options.skipBuild;
var verbose = !!options.verbose;
Expand Down Expand Up @@ -91,7 +91,7 @@ module.exports = function createMeteor (options) {
// TODO: do not start if we haven't done it yet

return this.__custom__(function (operand, done) {

operand.ddpClient.close();

if (!operand.process) { // e.g. if using remote server
Expand Down Expand Up @@ -169,6 +169,11 @@ module.exports = function createMeteor (options) {
}

function getMeteor () {
try {
checkIfVersionsMatch(options.pathToApp)
} catch (err) {
return Promise.reject(err);
}

if (remoteServer) {
return Promise.resolve(null);
Expand All @@ -179,7 +184,8 @@ module.exports = function createMeteor (options) {
getPathToMain(), getMongoUrl()

]).then(function (results) {



return getMeteorProcess({
pathToNode : tools.getNodePath(pathToApp),
pathToMain : results[0],
Expand All @@ -198,16 +204,16 @@ module.exports = function createMeteor (options) {
getDDPSetup(), getMeteor(), getConfig()

]).then(function (results) {

return getDDPClient(results[0]).then(function (ddpClient) {
return { ddpClient: ddpClient, process: results[1], closure: closure };
});

});
}

function getDDPSetup () {

if (remoteServer) {
return Promise.resolve({
host: remoteServer.hostname,
Expand All @@ -227,3 +233,20 @@ module.exports = function createMeteor (options) {
return meteor;

}

function checkIfVersionsMatch(pathToApp) {

var pathToVersions = path.join(pathToApp, '.meteor', 'versions');
var versions = fs.readFileSync(pathToVersions, 'utf-8');
var versionMatch = versions.match(/anti:gagarin@(.*)/);
if (!versionMatch) { // looks like gagarin is not even instaled
throw new Error('Please add anti:gagarin to your app before running tests.');
} else if (versionMatch[1] !== version) { // versions of gagarin are not compatible
throw new Error(
'Versions of node package (' + version +
') and meteor package (' + versionMatch[1] +
') are not compatible; please update.'
);
}

}
Loading

0 comments on commit 39ef095

Please sign in to comment.