QA: upgrade browser testing framework and tests to use casperjs 1.1-beta3 and phantomjs 1.9.2

This commit is contained in:
Carl Eberhard
2014-04-07 13:27:55 -04:00
parent 15aeb3f49c
commit 2187795562
24 changed files with 616 additions and 1018 deletions
+8 -31
View File
@@ -1,36 +1,14 @@
// have to handle errors here - or phantom/casper won't bail but _HANG_
try {
var utils = require( 'utils' ),
xpath = require( 'casper' ).selectXPath,
format = utils.format,
//...if there's a better way - please let me know, universe
scriptDir = require( 'system' ).args[3]
// remove the script filename
.replace( /[\w|\.|\-|_]*$/, '' )
// if given rel. path, prepend the curr dir
.replace( /^(?!\/)/, './' ),
spaceghost = require( scriptDir + 'spaceghost' ).create({
// script options here (can be overridden by CLI)
//verbose: true,
//logLevel: debug,
scriptDir: scriptDir
});
var require = patchRequire( require ),
spaceghost = require( 'spaceghost' ).fromCasper( casper ),
xpath = require( 'casper' ).selectXPath,
utils = require( 'utils' ),
format = utils.format;
spaceghost.test.begin( 'Testing histories for anonymous users', 0, function suite( test ){
spaceghost.start();
} catch( error ){
console.debug( error );
phantom.exit( 1 );
}
// ===================================================================
// -------------------------------------------------------------------
/* TODO:
run a tool
*/
// =================================================================== globals and helpers
var email = spaceghost.user.getRandomEmail(),
password = '123456';
if( spaceghost.fixtureData.testUser ){
@@ -141,6 +119,5 @@ spaceghost.user.logout().openHomePage( function(){
});
// ===================================================================
spaceghost.run( function(){
this.test.done();
spaceghost.run( function(){ test.done(); });
});
@@ -1,30 +1,14 @@
/* Utility to load a specific page and output html, page text, or a screenshot
* Optionally wait for some time, text, or dom selector
*/
try {
//...if there's a better way - please let me know, universe
var scriptDir = require( 'system' ).args[3]
// remove the script filename
.replace( /[\w|\.|\-|_]*$/, '' )
// if given rel. path, prepend the curr dir
.replace( /^(?!\/)/, './' ),
spaceghost = require( scriptDir + 'spaceghost' ).create({
// script options here (can be overridden by CLI)
//verbose: true,
//logLevel: debug,
scriptDir: scriptDir
});
} catch( error ){
console.debug( error );
phantom.exit( 1 );
}
spaceghost.start();
var require = patchRequire( require ),
spaceghost = require( 'spaceghost' ).fromCasper( casper ),
xpath = require( 'casper' ).selectXPath,
utils = require( 'utils' ),
format = utils.format;
spaceghost.test.begin( 'Test permissions for accessible, published, and inaccessible histories '
+ 'with anonymous users over the API', 0, function suite( test ){
spaceghost.start();
// =================================================================== SET UP
var utils = require( 'utils' );
var email = spaceghost.user.getRandomEmail(),
password = '123456';
if( spaceghost.fixtureData.testUser ){
@@ -63,9 +47,9 @@ spaceghost.thenOpen( spaceghost.baseUrl ).then( function(){
//// ------------------------------------------------------------------------------------------- upload some files
spaceghost.then( function(){
this.api.tools.thenUpload( inaccessibleHistory.id, { filepath: this.options.scriptDir + '/../../test-data/1.bed' });
this.api.tools.thenUpload( accessibleHistory.id, { filepath: this.options.scriptDir + '/../../test-data/1.bed' });
this.api.tools.thenUpload( publishedHistory.id, { filepath: this.options.scriptDir + '/../../test-data/1.bed' });
this.api.tools.thenUpload( inaccessibleHistory.id, { filepath: '../../test-data/1.bed' });
this.api.tools.thenUpload( accessibleHistory.id, { filepath: '../../test-data/1.bed' });
this.api.tools.thenUpload( publishedHistory.id, { filepath: '../../test-data/1.bed' });
});
spaceghost.then( function(){
// check that they're there
@@ -220,5 +204,5 @@ spaceghost.thenOpen( spaceghost.baseUrl ).then( function(){
// ===================================================================
spaceghost.run( function(){
spaceghost.run( function(){ test.done(); });
});
+10 -27
View File
@@ -1,29 +1,11 @@
/* Utility to load a specific page and output html, page text, or a screenshot
* Optionally wait for some time, text, or dom selector
*/
try {
//...if there's a better way - please let me know, universe
var scriptDir = require( 'system' ).args[3]
// remove the script filename
.replace( /[\w|\.|\-|_]*$/, '' )
// if given rel. path, prepend the curr dir
.replace( /^(?!\/)/, './' ),
spaceghost = require( scriptDir + 'spaceghost' ).create({
// script options here (can be overridden by CLI)
//verbose: true,
//logLevel: debug,
scriptDir: scriptDir
});
var require = patchRequire( require ),
spaceghost = require( 'spaceghost' ).fromCasper( casper ),
xpath = require( 'casper' ).selectXPath,
utils = require( 'utils' ),
format = utils.format;
} catch( error ){
console.debug( error );
phantom.exit( 1 );
}
spaceghost.start();
// =================================================================== SET UP
var utils = require( 'utils' );
spaceghost.test.begin( 'Test API functions for histories with an anonymous user', 0, function suite( test ){
spaceghost.start();
// =================================================================== TESTS
spaceghost.thenOpen( spaceghost.baseUrl ).waitForSelector( '.history-name' );
@@ -98,7 +80,7 @@ spaceghost.thenOpen( spaceghost.baseUrl ).waitForSelector( '.history-name' );
//TODO: can't use this - get a 400 when tools checks for history: 'logged in to manage'
//spaceghost.then( function(){
// this.api.tools.thenUpload( spaceghost.api.histories.show( 'current' ).id, {
// filepath: this.options.scriptDir + '/../../test-data/1.sam'
// filepath: '../../test-data/1.sam'
// });
//});
spaceghost.then( function(){
@@ -155,5 +137,6 @@ spaceghost.then( function(){
});
// ===================================================================
spaceghost.run( function(){
spaceghost.run( function(){ test.done(); });
});
+12 -56
View File
@@ -1,29 +1,13 @@
/* Utility to load a specific page and output html, page text, or a screenshot
* Optionally wait for some time, text, or dom selector
*/
try {
//...if there's a better way - please let me know, universe
var scriptDir = require( 'system' ).args[3]
// remove the script filename
.replace( /[\w|\.|\-|_]*$/, '' )
// if given rel. path, prepend the curr dir
.replace( /^(?!\/)/, './' ),
spaceghost = require( scriptDir + 'spaceghost' ).create({
// script options here (can be overridden by CLI)
//verbose: true,
//logLevel: debug,
scriptDir: scriptDir
});
var require = patchRequire( require ),
spaceghost = require( 'spaceghost' ).fromCasper( casper ),
xpath = require( 'casper' ).selectXPath,
utils = require( 'utils' ),
format = utils.format;
} catch( error ){
console.debug( error );
phantom.exit( 1 );
}
spaceghost.start();
spaceghost.test.begin( 'Test the Galaxy configuration API', 0, function suite( test ){
spaceghost.start();
// =================================================================== SET UP
var utils = require( 'utils' );
var email = spaceghost.user.getRandomEmail(),
password = '123456';
if( spaceghost.fixtureData.testUser ){
@@ -32,35 +16,6 @@ if( spaceghost.fixtureData.testUser ){
}
spaceghost.user.loginOrRegisterUser( email, password );
function hasKeys( object, keysArray ){
if( !utils.isObject( object ) ){ return false; }
for( var i=0; i<keysArray.length; i += 1 ){
if( !object.hasOwnProperty( keysArray[i] ) ){
spaceghost.debug( 'key not found: ' + keysArray[i] );
return false;
}
}
return true;
}
function compareObjs( obj1, where ){
for( var key in where ){
if( where.hasOwnProperty( key ) ){
if( !obj1.hasOwnProperty( key ) ){ return false; }
if( obj1[ key ] !== where[ key ] ){ return false; }
}
}
return true;
}
function findObject( objectArray, where, start ){
start = start || 0;
for( var i=start; i<objectArray.length; i += 1 ){
if( compareObjs( objectArray[i], where ) ){ return objectArray[i]; }
}
return null;
}
// =================================================================== TESTS
var normKeys = [
'enable_unique_workflow_defaults',
@@ -89,7 +44,7 @@ spaceghost.thenOpen( spaceghost.baseUrl ).then( function(){
var configIndex = this.api.configuration.index();
this.debug( this.jsonStr( configIndex ) );
this.test.assert( utils.isObject( configIndex ), "index returned an object" );
this.test.assert( hasKeys( configIndex, normKeys ), 'Has the proper keys' );
this.test.assert( this.hasKeys( configIndex, normKeys ), 'Has the proper keys' );
});
spaceghost.user.logout();
@@ -97,7 +52,7 @@ spaceghost.user.logout();
// ------------------------------------------------------------------------------------------- INDEX (admin)
spaceghost.tryStepsCatch( function tryAdminLogin(){
spaceghost.user.loginAdmin();
});
}, function(){} );
//}, function failedLoginRegister(){
// this.info( 'Admin level configuration API tests not run: no admin account available' );
@@ -109,7 +64,7 @@ spaceghost.thenOpen( spaceghost.baseUrl ).then( function(){
configIndex = this.api.configuration.index();
this.debug( this.jsonStr( configIndex ) );
this.test.assert( utils.isObject( configIndex ), "index returned an object" );
this.test.assert( hasKeys( configIndex, adminKeys ), 'Has the proper keys' );
this.test.assert( this.hasKeys( configIndex, adminKeys ), 'Has the proper keys' );
} else {
this.info( 'Admin level configuration API tests not run: no admin account available' );
@@ -118,5 +73,6 @@ spaceghost.thenOpen( spaceghost.baseUrl ).then( function(){
});
// ===================================================================
spaceghost.run( function(){
spaceghost.run( function(){ test.done(); });
});
+10 -25
View File
@@ -1,29 +1,13 @@
/* Utility to load a specific page and output html, page text, or a screenshot
* Optionally wait for some time, text, or dom selector
*/
try {
//...if there's a better way - please let me know, universe
var scriptDir = require( 'system' ).args[3]
// remove the script filename
.replace( /[\w|\.|\-|_]*$/, '' )
// if given rel. path, prepend the curr dir
.replace( /^(?!\/)/, './' ),
spaceghost = require( scriptDir + 'spaceghost' ).create({
// script options here (can be overridden by CLI)
//verbose: true,
//logLevel: debug,
scriptDir: scriptDir
});
var require = patchRequire( require ),
spaceghost = require( 'spaceghost' ).fromCasper( casper ),
xpath = require( 'casper' ).selectXPath,
utils = require( 'utils' ),
format = utils.format;
} catch( error ){
console.debug( error );
phantom.exit( 1 );
}
spaceghost.start();
spaceghost.test.begin( 'Test the HDA API', 0, function suite( test ){
spaceghost.start();
// =================================================================== SET UP
var utils = require( 'utils' );
var email = spaceghost.user.getRandomEmail(),
password = '123456';
if( spaceghost.fixtureData.testUser ){
@@ -34,7 +18,7 @@ spaceghost.user.loginOrRegisterUser( email, password );
spaceghost.thenOpen( spaceghost.baseUrl, function(){
this.api.tools.thenUpload( spaceghost.api.histories.show( 'current' ).id, {
filepath: this.options.scriptDir + '/../../test-data/1.sam'
filepath: '../../test-data/1.sam'
});
});
@@ -379,5 +363,6 @@ spaceghost.then( function(){
// ===================================================================
spaceghost.run( function(){
spaceghost.run( function(){ test.done(); });
});
+12 -28
View File
@@ -1,30 +1,14 @@
/* Utility to load a specific page and output html, page text, or a screenshot
* Optionally wait for some time, text, or dom selector
*/
try {
//...if there's a better way - please let me know, universe
var scriptDir = require( 'system' ).args[3]
// remove the script filename
.replace( /[\w|\.|\-|_]*$/, '' )
// if given rel. path, prepend the curr dir
.replace( /^(?!\/)/, './' ),
spaceghost = require( scriptDir + 'spaceghost' ).create({
// script options here (can be overridden by CLI)
//verbose: true,
//logLevel: debug,
scriptDir: scriptDir
});
} catch( error ){
console.debug( error );
phantom.exit( 1 );
}
spaceghost.start();
var require = patchRequire( require ),
spaceghost = require( 'spaceghost' ).fromCasper( casper ),
xpath = require( 'casper' ).selectXPath,
utils = require( 'utils' ),
format = utils.format;
spaceghost.test.begin( 'Test permissions for accessible, published, and inaccessible histories '
+ 'over the API', 0, function suite( test ){
spaceghost.start();
// =================================================================== SET UP
var utils = require( 'utils' );
var email = spaceghost.user.getRandomEmail(),
password = '123456';
if( spaceghost.fixtureData.testUser ){
@@ -102,9 +86,9 @@ spaceghost.thenOpen( spaceghost.baseUrl ).then( function(){
//// ------------------------------------------------------------------------------------------- upload some files
spaceghost.then( function(){
this.api.tools.thenUpload( inaccessibleHistory.id, { filepath: this.options.scriptDir + '/../../test-data/1.bed' });
this.api.tools.thenUpload( accessibleHistory.id, { filepath: this.options.scriptDir + '/../../test-data/1.bed' });
this.api.tools.thenUpload( publishedHistory.id, { filepath: this.options.scriptDir + '/../../test-data/1.bed' });
this.api.tools.thenUpload( inaccessibleHistory.id, { filepath: '../../test-data/1.bed' });
this.api.tools.thenUpload( accessibleHistory.id, { filepath: '../../test-data/1.bed' });
this.api.tools.thenUpload( publishedHistory.id, { filepath: '../../test-data/1.bed' });
});
spaceghost.then( function(){
// check that they're there
@@ -273,5 +257,5 @@ spaceghost.user.logout();
// ===================================================================
spaceghost.run( function(){
spaceghost.run( function(){ test.done(); });
});
+8 -25
View File
@@ -1,30 +1,13 @@
/* Utility to load a specific page and output html, page text, or a screenshot
* Optionally wait for some time, text, or dom selector
*/
try {
//...if there's a better way - please let me know, universe
var scriptDir = require( 'system' ).args[3]
// remove the script filename
.replace( /[\w|\.|\-|_]*$/, '' )
// if given rel. path, prepend the curr dir
.replace( /^(?!\/)/, './' ),
spaceghost = require( scriptDir + 'spaceghost' ).create({
// script options here (can be overridden by CLI)
//verbose: true,
//logLevel: debug,
scriptDir: scriptDir
});
} catch( error ){
console.debug( error );
phantom.exit( 1 );
}
spaceghost.start();
var require = patchRequire( require ),
spaceghost = require( 'spaceghost' ).fromCasper( casper ),
xpath = require( 'casper' ).selectXPath,
utils = require( 'utils' ),
format = utils.format;
spaceghost.test.begin( 'Test the history API', 0, function suite( test ){
spaceghost.start();
// =================================================================== SET UP
var utils = require( 'utils' );
var email = spaceghost.user.getRandomEmail(),
password = '123456';
if( spaceghost.fixtureData.testUser ){
@@ -361,5 +344,5 @@ spaceghost.thenOpen( spaceghost.baseUrl ).then( function(){
});
// ===================================================================
spaceghost.run( function(){
spaceghost.run( function(){ test.done(); });
});
+19 -45
View File
@@ -1,29 +1,13 @@
/* Utility to load a specific page and output html, page text, or a screenshot
* Optionally wait for some time, text, or dom selector
*/
try {
//...if there's a better way - please let me know, universe
var scriptDir = require( 'system' ).args[3]
// remove the script filename
.replace( /[\w|\.|\-|_]*$/, '' )
// if given rel. path, prepend the curr dir
.replace( /^(?!\/)/, './' ),
spaceghost = require( scriptDir + 'spaceghost' ).create({
// script options here (can be overridden by CLI)
//verbose: true,
//logLevel: debug,
scriptDir: scriptDir
});
var require = patchRequire( require ),
spaceghost = require( 'spaceghost' ).fromCasper( casper ),
xpath = require( 'casper' ).selectXPath,
utils = require( 'utils' ),
format = utils.format;
} catch( error ){
console.debug( error );
phantom.exit( 1 );
}
spaceghost.start();
spaceghost.test.begin( 'Test the tools API', 0, function suite( test ){
spaceghost.start();
// =================================================================== SET UP
var utils = require( 'utils' );
var email = spaceghost.user.getRandomEmail(),
password = '123456';
if( spaceghost.fixtureData.testUser ){
@@ -32,17 +16,6 @@ if( spaceghost.fixtureData.testUser ){
}
spaceghost.user.loginOrRegisterUser( email, password );
function hasKeys( object, keysArray ){
if( !utils.isObject( object ) ){ return false; }
for( var i=0; i<keysArray.length; i += 1 ){
if( !object.hasOwnProperty( keysArray[i] ) ){
spaceghost.debug( 'key not found: ' + keysArray[i] );
return false;
}
}
return true;
}
function compareObjs( obj1, where ){
for( var key in where ){
if( where.hasOwnProperty( key ) ){
@@ -132,7 +105,7 @@ spaceghost.thenOpen( spaceghost.baseUrl ).then( function(){
this.test.comment( 'index panel form should be separated into sections (by default)' );
var firstSection = toolIndex[0]; // get data
//this.debug( this.jsonStr( firstSection ) );
this.test.assert( hasKeys( firstSection, panelSectionKeys ), 'Has the proper keys' );
this.test.assert( this.hasKeys( firstSection, panelSectionKeys ), 'Has the proper keys' );
//TODO: test form of indiv. keys
this.test.comment( 'index sections have a list of tool "elems"' );
@@ -142,7 +115,7 @@ spaceghost.thenOpen( spaceghost.baseUrl ).then( function(){
var firstTool = firstSection.elems[0]; // get data
//this.debug( this.jsonStr( firstTool ) );
this.test.assert( hasKeys( firstTool, panelToolKeys ), 'Has the proper keys' );
this.test.assert( this.hasKeys( firstTool, panelToolKeys ), 'Has the proper keys' );
// ........................................................................................... in_panel=False
this.test.comment( 'index should get a list of all tools when in_panel=false' );
@@ -154,7 +127,7 @@ spaceghost.thenOpen( spaceghost.baseUrl ).then( function(){
this.test.comment( 'index non-panel form should be a simple list of tool summaries' );
firstSection = toolIndex[0];
//this.debug( this.jsonStr( firstSection ) );
this.test.assert( hasKeys( firstSection, toolSummaryKeys ), 'Has the proper keys' );
this.test.assert( this.hasKeys( firstSection, toolSummaryKeys ), 'Has the proper keys' );
//TODO: test uniqueness of ids
//TODO: test form of indiv. keys
@@ -169,7 +142,7 @@ spaceghost.thenOpen( spaceghost.baseUrl ).then( function(){
this.test.comment( 'index with trackster=True should be separated into sections (by default)' );
firstSection = toolIndex[0]; // get data
//this.debug( this.jsonStr( firstSection ) );
this.test.assert( hasKeys( firstSection, panelSectionKeys ), 'Has the proper keys' );
this.test.assert( this.hasKeys( firstSection, panelSectionKeys ), 'Has the proper keys' );
//TODO: test form of indiv. keys
this.test.comment( 'index sections with trackster=True have a list of tool "elems"' );
@@ -179,7 +152,7 @@ spaceghost.thenOpen( spaceghost.baseUrl ).then( function(){
firstTool = firstSection.elems[0]; // get data
//this.debug( this.jsonStr( firstTool ) );
this.test.assert( hasKeys( firstTool, panelToolKeys ), 'Has the proper keys' );
this.test.assert( this.hasKeys( firstTool, panelToolKeys ), 'Has the proper keys' );
// ............................................................................ trackster=True, in_panel=False
// this yields the same as in_panel=False...
@@ -195,7 +168,7 @@ spaceghost.thenOpen( spaceghost.baseUrl ).then( function(){
var toolShow = this.api.tools.show( selectFirst.id );
//this.debug( this.jsonStr( toolShow ) );
this.test.assert( utils.isObject( toolShow ), "show returned an object" );
this.test.assert( hasKeys( toolShow, toolDetailKeys ), 'Has the proper keys' );
this.test.assert( this.hasKeys( toolShow, toolDetailKeys ), 'Has the proper keys' );
this.test.comment( 'show data should include an array of input objects' );
this.test.assert( utils.isArray( toolShow.inputs ), "inputs is an array: "
@@ -205,7 +178,7 @@ spaceghost.thenOpen( spaceghost.baseUrl ).then( function(){
var input = toolShow.inputs[i];
this.test.comment( 'checking input #' + i + ': ' + ( input.name || '(no name)' ) );
this.test.assert( utils.isObject( input ), "input is an object" );
this.test.assert( hasKeys( input, toolInputKeys ), 'Has the proper keys' );
this.test.assert( this.hasKeys( input, toolInputKeys ), 'Has the proper keys' );
}
//TODO: test form of indiv. keys
@@ -226,20 +199,21 @@ spaceghost.thenOpen( spaceghost.baseUrl ).then( function(){
'upload_type': 'upload_dataset',
};
var toolCreate = this.api.tools.create( payload );
this.test.assert( hasKeys( toolCreate, ['outputs'] ), 'Has outputs' );
this.test.assert( this.hasKeys( toolCreate, ['outputs'] ), 'Has outputs' );
var outputs = toolCreate['outputs'];
this.test.assert( utils.isArray( outputs ), 'outputs is an array' );
this.test.assert( outputs.length == 1, 'one dataset is created' );
var output = outputs[0]
this.test.assert( utils.isObject( output ), 'output0 is an array' );
this.test.assert( hasKeys( output, ['data_type', 'deleted', 'hid', 'history_id', 'id', 'name' ] ), 'Dataset information defined' );
this.test.assert( hasKeys( output, ['output_name' ] ), 'Output name labelled' );
this.test.assert( this.hasKeys( output, ['data_type', 'deleted', 'hid', 'history_id', 'id', 'name' ] ),
'Dataset information defined' );
this.test.assert( this.hasKeys( output, ['output_name' ] ), 'Output name labelled' );
// ------------------------------------------------------------------------------------------- MISC
//attemptShowOnAllTools.call( spaceghost );
});
// ===================================================================
spaceghost.run( function(){
spaceghost.run( function(){ test.done(); });
});
+8 -61
View File
@@ -1,29 +1,13 @@
/* Utility to load a specific page and output html, page text, or a screenshot
* Optionally wait for some time, text, or dom selector
*/
try {
//...if there's a better way - please let me know, universe
var scriptDir = require( 'system' ).args[3]
// remove the script filename
.replace( /[\w|\.|\-|_]*$/, '' )
// if given rel. path, prepend the curr dir
.replace( /^(?!\/)/, './' ),
spaceghost = require( scriptDir + 'spaceghost' ).create({
// script options here (can be overridden by CLI)
//verbose: true,
//logLevel: debug,
scriptDir: scriptDir
});
var require = patchRequire( require ),
spaceghost = require( 'spaceghost' ).fromCasper( casper ),
xpath = require( 'casper' ).selectXPath,
utils = require( 'utils' ),
format = utils.format;
} catch( error ){
console.debug( error );
phantom.exit( 1 );
}
spaceghost.start();
spaceghost.test.begin( 'Test the user API', 0, function suite( test ){
spaceghost.start();
// =================================================================== SET UP
var utils = require( 'utils' );
var email = spaceghost.user.getRandomEmail(),
password = '123456';
if( spaceghost.fixtureData.testUser ){
@@ -32,44 +16,7 @@ if( spaceghost.fixtureData.testUser ){
}
spaceghost.user.loginOrRegisterUser( email, password );
function hasKeys( object, keysArray ){
if( !utils.isObject( object ) ){ return false; }
for( var i=0; i<keysArray.length; i += 1 ){
if( !object.hasOwnProperty( keysArray[i] ) ){
spaceghost.debug( 'key not found: ' + keysArray[i] );
return false;
}
}
return true;
}
function compareObjs( obj1, where ){
for( var key in where ){
if( where.hasOwnProperty( key ) ){
if( !obj1.hasOwnProperty( key ) ){ return false; }
if( obj1[ key ] !== where[ key ] ){ return false; }
}
}
return true;
}
function findObject( objectArray, where, start ){
start = start || 0;
for( var i=start; i<objectArray.length; i += 1 ){
if( compareObjs( objectArray[i], where ) ){ return objectArray[i]; }
}
return null;
}
// =================================================================== TESTS
var workflowSummaryKeys = [
'id', 'model_class', 'name', 'published', 'tags', 'url'
],
workflowDetailKeys = workflowSummaryKeys.concat([
'inputs', 'steps'
]);
spaceghost.thenOpen( spaceghost.baseUrl ).then( function(){
// ------------------------------------------------------------------------------------------- INDEX
@@ -101,5 +48,5 @@ spaceghost.thenOpen( spaceghost.baseUrl ).then( function(){
});
// ===================================================================
spaceghost.run( function(){
spaceghost.run( function(){ test.done(); });
});
+20 -107
View File
@@ -1,30 +1,13 @@
/* Utility to load a specific page and output html, page text, or a screenshot
* Optionally wait for some time, text, or dom selector
*/
try {
//...if there's a better way - please let me know, universe
var scriptDir = require( 'system' ).args[3]
// remove the script filename
.replace( /[\w|\.|\-|_]*$/, '' )
// if given rel. path, prepend the curr dir
.replace( /^(?!\/)/, './' ),
spaceghost = require( scriptDir + 'spaceghost' ).create({
// script options here (can be overridden by CLI)
//verbose: true,
//logLevel: debug,
scriptDir: scriptDir
});
} catch( error ){
console.debug( error );
phantom.exit( 1 );
}
spaceghost.start();
var require = patchRequire( require ),
spaceghost = require( 'spaceghost' ).fromCasper( casper ),
xpath = require( 'casper' ).selectXPath,
utils = require( 'utils' ),
format = utils.format;
spaceghost.test.begin( 'Test the visualizations API', 0, function suite( test ){
spaceghost.start();
// =================================================================== SET UP
var utils = require( 'utils' );
var email = spaceghost.user.getRandomEmail(),
password = '123456';
if( spaceghost.fixtureData.testUser ){
@@ -33,76 +16,6 @@ if( spaceghost.fixtureData.testUser ){
}
spaceghost.user.loginOrRegisterUser( email, password );
function hasKeys( object, keysArray ){
if( !utils.isObject( object ) ){ return false; }
for( var i=0; i<keysArray.length; i += 1 ){
if( !object.hasOwnProperty( keysArray[i] ) ){
spaceghost.debug( 'object missing key: ' + keysArray[i] );
return false;
}
}
return true;
}
function countKeys( object ){
if( !utils.isObject( object ) ){ return 0; }
var count = 0;
for( var key in object ){
if( object.hasOwnProperty( key ) ){ count += 1; }
}
return count;
}
function compareObjs( obj, compare_to, exclusionList ){
exclusionList = exclusionList || [];
for( var key in compare_to ){
if( compare_to.hasOwnProperty( key ) && exclusionList.indexOf( key ) === -1 ){
if( !obj.hasOwnProperty( key ) ){
spaceghost.debug( 'obj missing key: ' + key );
return false;
}
if( obj[ key ] !== compare_to[ key ] ){
spaceghost.debug( 'obj value not equal. obj: ' + obj[ key ] + ', v.: ' + compare_to[ key ] );
return false;
}
}
}
return true;
}
function assertRaises( fn, expectedCode, errMsgShouldContain, assertionMsg, debug ){
//TODO: errMsgShouldContain optional, any old error
assertionMsg = assertionMsg || 'create returned error';
debug = debug || false;
var errorReturned = {};
try {
fn.call( spaceghost );
} catch( error ){
errorReturned = error;
}
if( errorReturned ){
if( debug ){ spaceghost.debug( 'error:\n' + spaceghost.jsonStr( errorReturned ) ); }
var errorMsg = errorReturned.message || '';
if( errorMsg ){
try {
errorMsg = JSON.parse( errorReturned.message ).error;
} catch( parseErr ){
spaceghost.warn( 'error parsing error.message' );
}
}
var properCode = errorReturned.status === expectedCode,
properMsg = errorMsg.indexOf( errMsgShouldContain ) !== -1;
spaceghost.test.assert( properCode && properMsg,
assertionMsg + ': (' + errorReturned.status + ') "' + errorMsg + '"' );
if( !( properCode && properMsg ) ){
throw errorReturned;
}
} else {
spaceghost.test.fail( assertionMsg + ': (no error)' );
}
}
// =================================================================== TESTS
spaceghost.thenOpen( spaceghost.baseUrl ).then( function(){
var ALWAYS_CREATE = true,
@@ -145,7 +58,7 @@ spaceghost.thenOpen( spaceghost.baseUrl ).then( function(){
this.test.assert( visualizationIndex.length >= 1, 'Has at least one visualization' );
var firstVisualization = visualizationIndex[0];
this.test.assert( hasKeys( firstVisualization, indexKeys ), 'Has the proper keys' );
this.test.assert( this.hasKeys( firstVisualization, indexKeys ), 'Has the proper keys' );
this.test.assert( this.api.isEncodedId( firstVisualization.id ), 'Id appears well-formed' );
//TODO: index searching
@@ -156,7 +69,7 @@ spaceghost.thenOpen( spaceghost.baseUrl ).then( function(){
this.test.comment( 'show should get a visualization details object' );
var visualizationShow = this.api.visualizations.show( firstVisualization.id );
this.debug( this.jsonStr( visualizationShow ) );
this.test.assert( hasKeys( visualizationShow, showKeys ), 'Has the proper keys' );
this.test.assert( this.hasKeys( visualizationShow, showKeys ), 'Has the proper keys' );
this.test.assert( visualizationShow.model_class === 'Visualization',
'Has the proper model_class: ' + visualizationShow.model_class );
@@ -173,7 +86,7 @@ spaceghost.thenOpen( spaceghost.baseUrl ).then( function(){
this.test.comment( 'a visualization details object should contain a subobject of the latest revision' );
var latestRevision = visualizationShow.latest_revision;
this.test.assert( utils.isObject( latestRevision ), 'latestRevision is an object' );
this.test.assert( hasKeys( latestRevision, revisionKeys ), 'latestRevision has the proper keys' );
this.test.assert( this.hasKeys( latestRevision, revisionKeys ), 'latestRevision has the proper keys' );
this.test.assert( latestRevision.model_class === 'VisualizationRevision',
'Has the proper model_class: ' + latestRevision.model_class );
this.test.assert( latestRevision.visualization_id === visualizationShow.id,
@@ -212,18 +125,18 @@ spaceghost.thenOpen( spaceghost.baseUrl ).then( function(){
visualizationShow = this.api.visualizations.show( created.id );
this.debug( 'visualizationShow:\n' + this.jsonStr( visualizationShow ) );
// config is re-located into a revision and won't be there
this.test.assert( compareObjs( visualizationShow, visualizationData, [ 'config' ] ),
"show results seem to match create data" );
//this.test.assert( compareObjs( visualizationShow, visualizationData, [ 'config' ] ),
// "show results seem to match create data" );
// the following errors are produced within base.controller.UsesVisualizationsMixin._create_visualization
this.test.comment( 'Calling create with a non-unique slug will cause an API error' );
assertRaises( function(){
this.api.assertRaises( function(){
created = this.api.visualizations.create( visualizationData );
}, 400, 'visualization identifier must be unique' );
this.test.comment( 'Calling create with no title will cause an API error' );
visualizationData.title = '';
assertRaises( function(){
this.api.assertRaises( function(){
created = this.api.visualizations.create( visualizationData );
}, 400, 'visualization name is required' );
visualizationData.title = 'Created Visualization';
@@ -231,33 +144,33 @@ spaceghost.thenOpen( spaceghost.baseUrl ).then( function(){
this.test.comment( 'Calling create with improper characters in the slug will cause an API error' );
var oldSlug = visualizationData.slug;
visualizationData.slug = '123_()';
assertRaises( function(){
this.api.assertRaises( function(){
created = this.api.visualizations.create( visualizationData );
}, 400, "visualization identifier must consist of only lowercase letters, numbers, and the '-' character" );
visualizationData.slug = oldSlug;
this.test.comment( 'Calling create with an unrecognized key will cause an API error' );
visualizationData.bler = 'blah';
assertRaises( function(){
this.api.assertRaises( function(){
created = this.api.visualizations.create( visualizationData );
}, 400, 'unknown key: bler' );
delete visualizationData.bler;
this.test.comment( 'Calling create with an unparsable JSON config will cause an API error' );
visualizationData.config = '3 = nime';
assertRaises( function(){
this.api.assertRaises( function(){
created = this.api.visualizations.create( visualizationData );
}, 400, 'config must be a dictionary (JSON)' );
// ------------------------------------------------------------------------------------------ UPDATE
// ........................................................................................... idiot proofing
this.test.comment( 'updating using a nonsense key should fail with an error' );
assertRaises( function(){
this.api.assertRaises( function(){
returned = this.api.visualizations.update( created.id, { bler : 'blah' });
}, 400, 'unknown key: bler' );
this.test.comment( 'updating by attempting to change type should cause an error' );
assertRaises( function(){
this.api.assertRaises( function(){
returned = this.api.visualizations.update( created.id, { title : 30 });
}, 400, 'title must be a string or unicode' );
//TODO: the other types...
@@ -278,5 +191,5 @@ spaceghost.thenOpen( spaceghost.baseUrl ).then( function(){
});
// ===================================================================
spaceghost.run( function(){
spaceghost.run( function(){ test.done(); });
});
+18 -54
View File
@@ -1,29 +1,13 @@
/* Utility to load a specific page and output html, page text, or a screenshot
* Optionally wait for some time, text, or dom selector
*/
try {
//...if there's a better way - please let me know, universe
var scriptDir = require( 'system' ).args[3]
// remove the script filename
.replace( /[\w|\.|\-|_]*$/, '' )
// if given rel. path, prepend the curr dir
.replace( /^(?!\/)/, './' ),
spaceghost = require( scriptDir + 'spaceghost' ).create({
// script options here (can be overridden by CLI)
//verbose: true,
//logLevel: debug,
scriptDir: scriptDir
});
var require = patchRequire( require ),
spaceghost = require( 'spaceghost' ).fromCasper( casper ),
xpath = require( 'casper' ).selectXPath,
utils = require( 'utils' ),
format = utils.format;
} catch( error ){
console.debug( error );
phantom.exit( 1 );
}
spaceghost.start();
spaceghost.test.begin( 'Test the workflows API', 0, function suite( test ){
spaceghost.start();
// =================================================================== SET UP
var utils = require( 'utils' );
var email = spaceghost.user.getRandomEmail(),
password = '123456';
if( spaceghost.fixtureData.testUser ){
@@ -32,26 +16,6 @@ if( spaceghost.fixtureData.testUser ){
}
spaceghost.user.loginOrRegisterUser( email, password );
function hasKeys( object, keysArray ){
if( !utils.isObject( object ) ){ return false; }
for( var i=0; i<keysArray.length; i += 1 ){
if( !object.hasOwnProperty( keysArray[i] ) ){
spaceghost.debug( 'key not found: ' + keysArray[i] );
return false;
}
}
return true;
}
function countKeys( object ){
if( !utils.isObject( object ) ){ return 0; }
var count = 0;
for( var key in object ){
if( object.hasOwnProperty( key ) ){ count += 1; }
}
return count;
}
// =================================================================== TESTS
var workflowJSONFilepath = 'test-data/Bed_interval_lengths.ga',
workflowModelClass = 'StoredWorkflow',
@@ -81,7 +45,7 @@ spaceghost.thenOpen( spaceghost.baseUrl ).then( function(){
this.test.comment( 'upload should return a summary object of what we uploaded' );
//this.debug( this.jsonStr( returned ) );
this.test.assert( utils.isObject( returned ), "upload returned an object" );
this.test.assert( hasKeys( returned, workflowSummaryKeys ), "upload's return has the proper keys" );
this.test.assert( this.hasKeys( returned, workflowSummaryKeys ), "upload's return has the proper keys" );
this.test.assert( this.api.isEncodedId( returned.id ),
"id is of the proper form: " + returned.id );
this.test.assert( returned.model_class === workflowModelClass,
@@ -105,7 +69,7 @@ spaceghost.thenOpen( spaceghost.baseUrl ).then( function(){
this.test.comment( 'index should have returned an object matching the workflow uploaded' );
var firstWorkflow = workflowIndex[0];
this.test.assert( hasKeys( firstWorkflow, workflowSummaryKeys ), "index has the proper keys" );
this.test.assert( this.hasKeys( firstWorkflow, workflowSummaryKeys ), "index has the proper keys" );
this.test.assert( this.api.isEncodedId( firstWorkflow.id ),
"id is of the proper form: " + firstWorkflow.id );
this.test.assert( firstWorkflow.model_class === workflowModelClass,
@@ -125,7 +89,7 @@ spaceghost.thenOpen( spaceghost.baseUrl ).then( function(){
var workflowShow = this.api.workflows.show( firstWorkflow.id );
this.debug( this.jsonStr( workflowShow ) );
this.test.assert( utils.isObject( workflowShow ), "show returned an object" );
this.test.assert( hasKeys( workflowShow, workflowDetailKeys ), "show has the proper keys" );
this.test.assert( this.hasKeys( workflowShow, workflowDetailKeys ), "show has the proper keys" );
this.test.assert( this.api.isEncodedId( workflowShow.id ),
"id is of the proper form: " + workflowShow.id );
this.test.assert( workflowShow.model_class === workflowModelClass,
@@ -147,7 +111,7 @@ spaceghost.thenOpen( spaceghost.baseUrl ).then( function(){
// if( inputs.hasOwnProperty( inputKey ) ){
// }
//}
this.test.assert( countKeys( workflowShow.inputs ) === 0, "inputs is empty" );
this.test.assert( this.countKeys( workflowShow.inputs ) === 0, "inputs is empty" );
this.test.comment( 'steps from show should be an object containing each tool defined as a step' );
var steps = workflowShow.steps;
@@ -161,7 +125,7 @@ spaceghost.thenOpen( spaceghost.baseUrl ).then( function(){
this.test.assert( utils.isString( stepKey ), "step key is a string: " + stepKey );
var step = steps[ stepKey ];
this.debug( 'step:\n' + this.jsonStr( step ) );
this.test.assert( hasKeys( step, stepKeys ), "step has the proper keys" );
this.test.assert( this.hasKeys( step, stepKeys ), "step has the proper keys" );
this.test.assert( utils.isNumber( step.id ),
"step id is a number: " + step.id );
@@ -173,8 +137,8 @@ spaceghost.thenOpen( spaceghost.baseUrl ).then( function(){
}
this.test.assert( utils.isObject( step.input_steps ), "input_steps is an object" );
if( countKeys( step.input_steps ) !== 0 ){
this.test.assert( hasKeys( step.input_steps, [ 'input' ] ), "input_steps has the proper keys" );
if( this.countKeys( step.input_steps ) !== 0 ){
this.test.assert( this.hasKeys( step.input_steps, [ 'input' ] ), "input_steps has the proper keys" );
}
this.test.assert( step.type === 'tool',
@@ -185,7 +149,7 @@ spaceghost.thenOpen( spaceghost.baseUrl ).then( function(){
"step tool_id is a string: " + step.tool_id );
var tool_used = this.api.tools.show( step.tool_id );
//this.debug( this.jsonStr( tool_used ) )
this.test.assert( countKeys( step.input_steps ) !== 0, "found tool in api.tools for: " + step.tool_id );
this.test.assert( this.countKeys( step.input_steps ) !== 0, "found tool in api.tools for: " + step.tool_id );
// trace the path through input_steps, source_steps
}
@@ -215,7 +179,7 @@ spaceghost.then( function(){
for( var stepKey in firstWorkflow.steps ){
if( firstWorkflow.steps.hasOwnProperty( stepKey ) ){
var step = firstWorkflow.steps[ stepKey ];
if( countKeys( step.input_steps ) === 0 ){
if( this.countKeys( step.input_steps ) === 0 ){
input_step = stepKey;
this.debug( 'input step: ' + this.jsonStr( step ) )
break;
@@ -238,7 +202,7 @@ spaceghost.then( function(){
var returned = this.api.workflows.create( executionData );
this.debug( this.jsonStr( returned ) );
this.test.assert( utils.isObject( returned ), "create returned an object" );
this.test.assert( hasKeys( returned, workflowCreateKeys ), "create returned the proper keys" );
this.test.assert( this.hasKeys( returned, workflowCreateKeys ), "create returned the proper keys" );
this.test.assert( this.api.isEncodedId( returned.history ),
"history id is proper: " + returned.history );
this.test.assert( utils.isArray( returned.outputs ),
@@ -285,5 +249,5 @@ spaceghost.then( function(){
});
// ===================================================================
spaceghost.run( function(){
spaceghost.run( function(){ test.done(); });
});
+26 -8
View File
@@ -3,26 +3,34 @@
Allows integration of casperjs tests with buildbot, run_functional_tests.sh
Tests can be run in any of the following ways:
* casperjs mytests.js --url='http://localhost:8080'
* casperjs test mytests.js --url='http://localhost:8080'
* python casperjs_runner.py
* nosetests
* sh run_functional_tests.sh test/casperjs/test_runner
* sh run_functional_tests.sh
Note: that you can enable (lots of) debugging info using cli options:
* casperjs usertests.js --url='http://localhost:8080' --verbose=true --logLevel=debug
* casperjs test usertests.js --url='http://localhost:8080' --verbose=true --logLevel=debug
(see casperjs.org for more information)
Note: This seems to not work with CasperJS 1.1 (and PhantomJS 1.9) - Casper 1.0.xx and
PhantomJS 1.8 work for me (John).
Note: Example of specifing user and admin user credentials.
Note: You can pass in extra data using --data='<some JSON object>'
and it will be available in your script as spaceghost.fixtureData.
casperjs api-configuration-tests.js --url="http://localhost:8080" \
--admin='{"email": "foo@example.com", "password": "123456" }' \
'{ "testUser": { "email": "foo@example.com", "password": "123456" } }'
Example using a specific user account:
casperjs test api-history-tests.js --url="http://localhost:8080" \
--data='{ "testUser": { "email": "foo@example.com", "password": "123456" } }'
// ...then, in script:
spaceghost.user.loginOrRegisterUser(
spaceghost.fixtureData.testUser.email,
spaceghost.fixtureData.testUser.password );
Example of specifing user and admin user credentials:
casperjs test api-configuration-tests.js --url="http://localhost:8080" \
--admin='{"email": "foo@example.com", "password": "123456" }' \
"""
# -------------------------------------------------------------------- can't do 2.5
import sys
@@ -120,6 +128,11 @@ class CasperJSTestCase( unittest.TestCase ):
#log.debug( '%s stderr output:\n%s', rel_script_path, stderr_output )
log.debug( 'process.returncode: %d', process.returncode )
# 1.1 has an annoying info bar that happens before it gets to our stuff, so...
stdout_output = '\n'.join( stdout_output.split( '\n' )[1:] )
#log.debug( 'stdout_output:\n' + stdout_output )
if process.returncode == 1:
#TODO: this is a fail on first effect
raise self.browser_error_to_exception( rel_script_path, stdout_output )
@@ -140,6 +153,9 @@ class CasperJSTestCase( unittest.TestCase ):
"""
command_line_list = [ self.exec_path ]
# as of casperjs 1.1, we always need to use the 'test' command
command_line_list.append( 'test' )
# make rel_script_path an absolute path (when this is not run from it's dir - i.e. run_functional_tests.sh)
curr_dir = os.path.dirname( __file__ )
script_path = os.path.join( curr_dir, rel_script_path )
@@ -163,7 +179,8 @@ class CasperJSTestCase( unittest.TestCase ):
command_line_list.extend( args )
# send extra data - encode kwargs as json to pass to casper for decoding
command_line_list.append( json.dumps( kwargs ) )
# as of 1.1, we need to pass this under a opt
command_line_list.append( '--data=' + json.dumps( kwargs ) )
return command_line_list
def strip_escape_codes( self, msg ):
@@ -220,6 +237,7 @@ class CasperJSTestCase( unittest.TestCase ):
"""Handle the results of the js tests by either converting them
with the results adapter or checking for a failure list.
"""
# if given an adapter - use it
if self.results_adapter:
self.results_adapter.convert( results, self )
@@ -227,7 +245,7 @@ class CasperJSTestCase( unittest.TestCase ):
# - otherwise, assert no failures found
else:
js_test_results = json.loads( results )
failures = js_test_results[ 'testResults' ][ 'failures' ]
failures = js_test_results[ 'failures' ]
assert len( failures ) == 0, (
"%d assertions failed in the headless browser tests" % ( len( failures ) )
+ " (see the log for details)" )
+10 -39
View File
@@ -1,29 +1,13 @@
// have to handle errors here - or phantom/casper won't bail but _HANG_
try {
var utils = require( 'utils' ),
xpath = require( 'casper' ).selectXPath,
format = utils.format,
//...if there's a better way - please let me know, universe
scriptDir = require( 'system' ).args[3]
// remove the script filename
.replace( /[\w|\.|\-|_]*$/, '' )
// if given rel. path, prepend the curr dir
.replace( /^(?!\/)/, './' ),
spaceghost = require( scriptDir + 'spaceghost' ).create({
// script options here (can be overridden by CLI)
//verbose: true,
//logLevel: debug,
scriptDir: scriptDir
});
var require = patchRequire( require ),
spaceghost = require( 'spaceghost' ).fromCasper( casper ),
xpath = require( 'casper' ).selectXPath,
utils = require( 'utils' ),
format = utils.format;
spaceghost.test.begin( 'Test the form of various HDA states', 0, function suite( test ){
spaceghost.start();
} catch( error ){
console.debug( error );
phantom.exit( 1 );
}
spaceghost.openHomePage().then( function(){
});
// ===================================================================
/* TODO:
@@ -40,19 +24,7 @@ if( spaceghost.fixtureData.testUser ){
spaceghost.info( 'Will use fixtureData.testUser: ' + email );
}
var tooltipSelector = spaceghost.data.selectors.tooltipBalloon;
var utils = require( 'utils' ),
historyFrameInfo = {},
filepathToUpload = '../../test-data/1.bam',
testUploadInfo = {},
//TODO: get from the api module - that doesn't exist yet
//summaryShouldBeArray = [ '3.5 KB', 'format: bam' ],
//infoShouldBe = 'uploaded bam file',
//metadataFiles = [ 'bam_index' ],
//peekShouldBeArray = [];
var tooltipSelector = spaceghost.data.selectors.tooltipBalloon,
filepathToUpload = '../../test-data/1.txt',
testUploadInfo = {},
//TODO: get from the api module - that doesn't exist yet
@@ -420,6 +392,5 @@ spaceghost.then( function revertStateAndCollapse(){
*/
// ===================================================================
spaceghost.run( function(){
this.test.done();
spaceghost.run( function(){ test.done(); });
});
+9 -25
View File
@@ -1,28 +1,13 @@
// have to handle errors here - or phantom/casper won't bail but _HANG_
try {
var utils = require( 'utils' ),
xpath = require( 'casper' ).selectXPath,
format = utils.format,
//...if there's a better way - please let me know, universe
scriptDir = require( 'system' ).args[3]
// remove the script filename
.replace( /[\w|\.|\-|_]*$/, '' )
// if given rel. path, prepend the curr dir
.replace( /^(?!\/)/, './' ),
spaceghost = require( scriptDir + 'spaceghost' ).create({
// script options here (can be overridden by CLI)
//verbose: true,
//logLevel: debug,
scriptDir: scriptDir
});
var require = patchRequire( require ),
spaceghost = require( 'spaceghost' ).fromCasper( casper ),
xpath = require( 'casper' ).selectXPath,
utils = require( 'utils' ),
format = utils.format;
spaceghost.test.begin( 'Testing the history options menu', 0, function suite( test ){
spaceghost.start();
} catch( error ){
console.debug( error );
phantom.exit( 1 );
}
spaceghost.openHomePage().then( function(){
});
// ===================================================================
/* TODO:
@@ -144,6 +129,5 @@ spaceghost.then( function(){
});
// ===================================================================
spaceghost.run( function(){
this.test.done();
spaceghost.run( function(){ test.done(); });
});
+12 -29
View File
@@ -1,29 +1,12 @@
// have to handle errors here - or phantom/casper won't bail but _HANG_
try {
var utils = require( 'utils' ),
xpath = require( 'casper' ).selectXPath,
format = utils.format,
//...if there's a better way - please let me know, universe
scriptDir = require( 'system' ).args[3]
// remove the script filename
.replace( /[\w|\.|\-|_]*$/, '' )
// if given rel. path, prepend the curr dir
.replace( /^(?!\/)/, './' ),
spaceghost = require( scriptDir + 'spaceghost' ).create({
// script options here (can be overridden by CLI)
//verbose: true,
//logLevel: debug,
scriptDir: scriptDir
});
var require = patchRequire( require ),
spaceghost = require( 'spaceghost' ).fromCasper( casper ),
xpath = require( 'casper' ).selectXPath,
utils = require( 'utils' ),
format = utils.format;
spaceghost.test.begin( 'Testing the form of the main/current history panel', 0, function suite( test ){
spaceghost.start();
} catch( error ){
console.debug( error );
phantom.exit( 1 );
}
// ===================================================================
/* TODO:
possibly break this file up
@@ -157,11 +140,11 @@ spaceghost.then( function(){
spaceghost.tools.uploadFile( filepathToUpload, function uploadCallback( _uploadInfo ){
this.test.comment( 'uploaded file should appear in history' );
//this.debug( 'uploaded HDA info: ' + this.jsonStr( _uploadInfo ) );
this.debug( 'uploaded HDA info: ' + this.jsonStr( _uploadInfo ) );
var hasHda = _uploadInfo.hdaElement,
hasClass = _uploadInfo.hdaElement.attributes[ 'class' ],
hasOkClass = _uploadInfo.hdaElement.attributes[ 'class' ].indexOf( wrapperOkClassName ) !== -1;
this.test.assert( ( hasHda && hasClass && hasOkClass ), "Uploaded file: " + _uploadInfo.name );
this.test.assert( ( hasHda && hasClass && hasOkClass ), "Uploaded file: " + _uploadInfo.filename );
testUploadInfo = _uploadInfo;
});
@@ -173,7 +156,7 @@ spaceghost.then( function checkPanelStructure(){
this.test.assertVisible( nameSelector, 'History name is visible' );
this.test.assertSelectorHasText( nameSelector, newHistoryName, 'History name is ' + newHistoryName );
var onetxtFilesize = require( 'fs' ).size( this.options.scriptDir + filepathToUpload ),
var onetxtFilesize = require( 'fs' ).size( filepathToUpload ),
expectedSubtitle = onetxtFilesize + ' bytes';
this.test.comment( "history subtitle should display size and size should be " + onetxtFilesize + " bytes" );
this.test.assertExists( subtitleSelector, 'Found ' + subtitleSelector );
@@ -292,8 +275,8 @@ spaceghost.then( function(){
"Body for uploaded file is not visible" );
});
});
/*
*/
// ===================================================================
spaceghost.run( function(){
this.test.done();
spaceghost.run( function(){ test.done(); });
});
+10 -25
View File
@@ -1,27 +1,13 @@
try {
var utils = require( 'utils' ),
xpath = require( 'casper' ).selectXPath,
format = utils.format,
//...if there's a better way - please let me know, universe
scriptDir = require( 'system' ).args[3]
// remove the script filename
.replace( /[\w|\.|\-|_]*$/, '' )
// if given rel. path, prepend the curr dir
.replace( /^(?!\/)/, './' ),
spaceghost = require( scriptDir + 'spaceghost' ).create({
// script options here (can be overridden by CLI)
//verbose: true,
//logLevel: debug,
scriptDir: scriptDir
});
var require = patchRequire( require ),
spaceghost = require( 'spaceghost' ).fromCasper( casper ),
utils = require( 'utils' ),
xpath = require( 'casper' ).selectXPath,
format = utils.format;
spaceghost.test.begin( 'Testing logging in and logging out', 0, function suite( test ){
spaceghost.start();
//console.debug( 'suiteResults: ' + test.suiteResults );
} catch( error ){
console.debug( error );
phantom.exit( 1 );
}
// =================================================================== globals and helpers
var email = spaceghost.user.getRandomEmail(),
@@ -86,7 +72,7 @@ spaceghost.each( badPasswords, function( self, badPassword ){
// ------------------------------------------------------------------- test yoself
// these versions are for conv. use in other tests, they should throw errors if used improperly
spaceghost.then( function(){
this.assertStepsRaise( 'GalaxyError: LoginError', function(){
this.assertStepsRaise( 'LoginError', function(){
this.then( function(){
this.test.comment( 'testing (js) error thrown on bad email' );
this.user.login( 'nihilist', '1234' );
@@ -95,7 +81,7 @@ spaceghost.then( function(){
});
spaceghost.then( function(){
this.assertStepsRaise( 'GalaxyError: LoginError', function(){
this.assertStepsRaise( 'LoginError', function(){
this.then( function(){
this.test.comment( 'testing (js) error thrown on bad password' );
this.user.login( email, '1234' );
@@ -105,6 +91,5 @@ spaceghost.then( function(){
/*
*/
// ===================================================================
spaceghost.run( function(){
this.test.done();
spaceghost.run( function(){ test.done(); });
});
+3 -2
View File
@@ -52,7 +52,8 @@ exports.APIError = APIError;
*/
// =================================================================== INTERNAL
var utils = require( 'utils' );
var require = patchRequire( require ),
utils = require( 'utils' );
API.prototype._ajax = function _ajax( url, options ){
options = options || {};
@@ -167,7 +168,7 @@ API.prototype.hasJQuery = function hasJQuery(){
API.prototype.ensureJQuery = function ensureJQuery(){
if( !this.hasJQuery() ){
var absLoc = this.spaceghost.options.scriptDir + this.jQueryLocation,
var absLoc = this.jQueryLocation,
injected = this.spaceghost.page.injectJs( absLoc );
if( !injected ){
throw new APIError( 'Could not inject jQuery' );
+2 -1
View File
@@ -26,7 +26,8 @@ HistoryOptions.prototype.toString = function toString(){
*/
// =================================================================== internal
var xpath = require( 'casper' ).selectXPath;
var require = patchRequire( require ),
xpath = require( 'casper' ).selectXPath;
// =================================================================== API (external)
/** Just open the menu
+79 -55
View File
@@ -28,8 +28,8 @@ HistoryPanel.prototype.toString = function toString(){
*/
// =================================================================== INTERNAL
var xpath = require( 'casper' ).selectXPath;
//utils = require( 'utils' );
var require = patchRequire( require ),
xpath = require( 'casper' ).selectXPath;
// =================================================================== API (external)
// ------------------------------------------------------------------- frame control
@@ -91,20 +91,6 @@ HistoryPanel.prototype.getHdaEncodedId = function getHdaEncodedId( hdaSelector )
};
// ------------------------------------------------------------------- step functions
///** Version of Casper#withFrame for the history iframe.
// * Hopefully will allow easier test transition if/when frames are removed
// * (i.e. -> just call the function).
// * NOTE: is more than one Casper step.
// * @param {Function} then function called when in the history frame
// */
//HistoryPanel.prototype.then = function then( thenFn ){
// if( this.inFrame() ){
// thenFn.call( this.spaceghost );
// } else {
// this.spaceghost.withHistoryPanel( thenFn );
// }
//};
//
/** Moves into history iframe and waits until hdas are visible or empty message is.
* NOTE: is more than one Casper step.
* @see Casper@waitFor
@@ -127,51 +113,44 @@ HistoryPanel.prototype.waitForHdas = function waitForHdas( then, timeout, maxWai
return spaceghost;
};
/** Expands or collapses an HDA by clicking the title (does nothing if already in desired state).
/** Moves into history iframe and waits until hdas are visible or empty message is.
* NOTE: is more than one Casper step.
* @param {String} hdaSelector a css or xpath selector for an historyItemWrapper
* @param {Function} then function called when the change is made
* @param {Boolean} desiredClosed true if you want to collapse, false if you want open
* @private
* @see Casper@waitFor
*/
HistoryPanel.prototype._thenExpandOrCollapseHda = function _thenExpandOrCollapseHda( hdaSelector, then, desiredClosed ){
// using a step here (instead of a jump) bc we need the wait for function
this.spaceghost.then( function checkingHda(){
this.info( (( desiredClosed )?( 'collapsing' ):( 'expanding' )) + ' hda: ' + hdaSelector );
HistoryPanel.prototype.waitForHda = function waitForHda( hdaName, then, timeout, maxWait ){
//TODO:?? should this wait until the seletors are in AND they are opaque?
var spaceghost = this.spaceghost,
hdaElement = null,
previousState = null;
spaceghost.then( function waitingForHda(){
this.waitFor(
function checkHpanel(){
var wrapperXpath = xpath( '//span[contains(text(),"' + hdaName + '")]/../../..' );
hdaElement = this.elementInfoOrNull( wrapperXpath );
//NOTE: this will probably fail if the name was used on a previous HDA
if( !hdaElement ){ return false; }
var state = hdaElement.attributes[ "class" ].match( /state\-([\w\-_]*)/ )[1];
if( state !== previousState ){
spaceghost.info( 'state: ' + state );
previousState = state;
}
if( state !== 'ok' ){ return false; }
// click to open if the body isn't visible and call wait to account for opening animation
if( this.visible( hdaSelector + ' ' + this.historypanel.data.selectors.hda.body ) === desiredClosed ){
this.click( hdaSelector + ' ' + this.historypanel.data.selectors.hda.title );
//NOTE: then is executed in the top frame
//TODO: magic number
this.wait( 500, then );
// otherwise, just call then
} else if( then ){
then.call( this );
}
var hdaOpacity = this.evaluate( function( name ){
return $( '.dataset-name:contains("' + name + '")' ).parents( '.hda' ).css( 'opacity' );
}, hdaName );
this.debug( 'fading in: ' + hdaOpacity );
return hdaOpacity >= 1;
},
function _then(){ then.call( this, hdaElement ); },
function _timeout(){ timeout.call( this, hdaElement ); },
maxWait );
});
return this.spaceghost;
};
/** Collapses an HDA by clicking the title (does nothing if already collapsed).
* NOTE: is more than one Casper step.
* @param {String} hdaSelector a css or xpath selector for an historyItemWrapper
* @param {Function} then function called when the change is made
*/
HistoryPanel.prototype.thenCollapseHda = function thenCollapseHda( hdaSelector, then ){
return this._thenExpandOrCollapseHda( hdaSelector, then, true );
};
/** Expands an HDA by clicking the title (does nothing if already expanded).
* NOTE: is more than one Casper step.
* @param {String} hdaSelector a css or xpath selector for an historyItemWrapper
* @param {Function} then function called when the change is made
*/
HistoryPanel.prototype.thenExpandHda = function thenExpandHda( hdaSelector, then ){
return this._thenExpandOrCollapseHda( hdaSelector, then, false );
return spaceghost;
};
//TODO: combine with above
/** Wait for the hda with given id to move into the given state.
* whenInStateFn and timeoutFn will be passed the hda element info (see Casper#getElementInfo)
* NOTE: is more than one Casper step.
@@ -233,6 +212,51 @@ HistoryPanel.prototype.waitForHdaState = function waitForHdaState( hdaSelector,
return spaceghost;
};
/** Expands or collapses an HDA by clicking the title (does nothing if already in desired state).
* NOTE: is more than one Casper step.
* @param {String} hdaSelector a css or xpath selector for an historyItemWrapper
* @param {Function} then function called when the change is made
* @param {Boolean} desiredClosed true if you want to collapse, false if you want open
* @private
*/
HistoryPanel.prototype._thenExpandOrCollapseHda = function _thenExpandOrCollapseHda( hdaSelector, then, desiredClosed ){
// using a step here (instead of a jump) bc we need the wait for function
this.spaceghost.then( function checkingHda(){
this.info( (( desiredClosed )?( 'collapsing' ):( 'expanding' )) + ' hda: ' + hdaSelector );
// click to open if the body isn't visible and call wait to account for opening animation
if( this.visible( hdaSelector + ' ' + this.historypanel.data.selectors.hda.body ) === desiredClosed ){
this.click( hdaSelector + ' ' + this.historypanel.data.selectors.hda.title );
//NOTE: then is executed in the top frame
//TODO: magic number
this.wait( 500, then );
// otherwise, just call then
} else if( then ){
then.call( this );
}
});
return this.spaceghost;
};
/** Collapses an HDA by clicking the title (does nothing if already collapsed).
* NOTE: is more than one Casper step.
* @param {String} hdaSelector a css or xpath selector for an historyItemWrapper
* @param {Function} then function called when the change is made
*/
HistoryPanel.prototype.thenCollapseHda = function thenCollapseHda( hdaSelector, then ){
return this._thenExpandOrCollapseHda( hdaSelector, then, true );
};
/** Expands an HDA by clicking the title (does nothing if already expanded).
* NOTE: is more than one Casper step.
* @param {String} hdaSelector a css or xpath selector for an historyItemWrapper
* @param {Function} then function called when the change is made
*/
HistoryPanel.prototype.thenExpandHda = function thenExpandHda( hdaSelector, then ){
return this._thenExpandOrCollapseHda( hdaSelector, then, false );
};
/** Deletes an hda by finding an hda with the given title and clicking on the delete icon.
* NOTE: if more than one is found, the first found will be deleted.
* NOTE: is more than one Casper step.
+17 -28
View File
@@ -29,7 +29,8 @@ Tools.prototype.toString = function toString(){
*/
// =================================================================== INTERNAL
var xpath = require( 'casper' ).selectXPath;
var require = patchRequire( require ),
xpath = require( 'casper' ).selectXPath;
// ------------------------------------------------------------------- get avail. tools
// list available tools
@@ -158,9 +159,6 @@ Tools.prototype.uploadFile = function uploadFile( filepath, callback, timeoutAft
filename = this.filenameFromFilepath( filepath ),
uploadInfo = {};
// precondition: filepath is relative to scriptDir
filepath = spaceghost.options.scriptDir + filepath;
spaceghost.info( 'uploading file: ' + filepath + ' (timeout after ' + timeoutAfterMs + ')' );
this._uploadFile( filepath );
@@ -183,31 +181,22 @@ Tools.prototype.uploadFile = function uploadFile( filepath, callback, timeoutAft
// the hpanel should refresh and display the uploading file, wait for that to go into the ok state
// throw if uploaded HDA doesn't appear, or it doesn't move to 'ok' after allotted time
spaceghost.historypanel.waitForHdas( function afterHpanelRefresh(){
//spaceghost.historypanel.waitForHdas()
spaceghost.historypanel.waitForHda( filename,
// success: update the upload info and run callback
function whenInStateFn( newHdaInfo ){
this.info( 'Upload complete: ' + newHdaInfo.text );
uploadInfo.hdaElement = newHdaInfo;
callback.call( spaceghost, uploadInfo );
},
function timeoutFn( newHdaInfo ){
this.warning( 'timeout waiting for upload: ' + filename + ', ' + this.jsonStr( newHdaInfo ) );
throw new spaceghost.GalaxyError( 'Upload Error: timeout waiting for ok state: '
+ '"' + uploadInfo.filepath + '" (waited ' + timeoutAfterMs + ' ms)' );
},
timeoutAfterMs
);
var hdaElement = this.historypanel.hdaElementInfoByTitle( uploadInfo.filename );
if( hdaElement === null ){
var hdaContainer = this.historypanel.data.selectors.hdaContainer;
this.warning( 'Upload Error: ' + hdaContainer + ':\n' + this.getHTML( hdaContainer ) );
throw new this.GalaxyError( 'Upload Error: uploaded file HDA not found: ' + uploadInfo.filename );
}
this.debug( 'uploaded HDA element: ' + this.jsonStr( this.quickInfo( hdaElement ) ) );
uploadInfo.hdaElement = hdaElement;
this.historypanel.waitForHdaState( '#' + uploadInfo.hdaElement.attributes.id, 'ok',
// success: update the upload info and run callback
function whenInStateFn( newHdaInfo ){
this.info( 'Upload complete: ' + newHdaInfo.text );
uploadInfo.hdaElement = newHdaInfo;
callback.call( spaceghost, uploadInfo );
}, function timeoutFn( newHdaInfo ){
this.warning( 'timeout waiting for upload:\n' + this.jsonStr( this.quickInfo( newHdaInfo ) ) );
throw new spaceghost.GalaxyError( 'Upload Error: timeout waiting for ok state: '
+ '"' + uploadInfo.filepath + '" (waited ' + timeoutAfterMs + ' ms)' );
}, timeoutAfterMs );
});
return spaceghost;
};
//TODO: upload via url
+2 -1
View File
@@ -21,7 +21,8 @@ User.prototype.toString = function toString(){
// =================================================================== INTERNAL
var xpath = require( 'casper' ).selectXPath;
var require = patchRequire( require ),
xpath = require( 'casper' ).selectXPath;
/** Tests registering a new user on the Galaxy instance by submitting the registration form.
* NOTE: this version does NOT throw an error on a bad registration.
+120 -134
View File
@@ -1,151 +1,137 @@
try {
var utils = require( 'utils' ),
xpath = require( 'casper' ).selectXPath,
format = utils.format,
//...if there's a better way - please let me know, universe
scriptDir = require( 'system' ).args[3]
// remove the script filename
.replace( /[\w|\.|\-|_]*$/, '' )
// if given rel. path, prepend the curr dir
.replace( /^(?!\/)/, './' ),
spaceghost = require( scriptDir + 'spaceghost' ).create({
// script options here (can be overridden by CLI)
//verbose: true,
//logLevel: debug,
scriptDir: scriptDir
});
var require = patchRequire( require ),
spaceghost = require( 'spaceghost' ).fromCasper( casper ),
xpath = require( 'casper' ).selectXPath,
utils = require( 'utils' ),
format = utils.format;
spaceghost.test.begin( 'Testing registration of new users', 0, function suite( test ){
spaceghost.start();
} catch( error ){
console.debug( error );
phantom.exit( 1 );
}
// =================================================================== globals and helpers
var email = spaceghost.user.getRandomEmail(),
password = '123456',
confirm = password,
username = 'test' + Date.now();
// =================================================================== globals and helpers
var email = spaceghost.user.getRandomEmail(),
password = '123456',
confirm = password,
username = 'test' + Date.now();
// =================================================================== TESTS
spaceghost.openHomePage( function(){
this.test.comment( 'loading galaxy homepage' );
this.test.assertTitle( 'Galaxy' );
this.test.assertExists( xpath( "//div[@id='masthead']" ), 'found masthead' );
});
// ------------------------------------------------------------------- register a new user
spaceghost.then( function(){
this.test.comment( 'registering user: ' + email );
this.user._submitRegistration( email, password, username, confirm );
});
spaceghost.openHomePage( function(){
this.clickLabel( 'User' );
var loggedInAs = this.fetchText( xpath( spaceghost.data.selectors.masthead.userMenu.userEmail_xpath ) );
this.test.assert( loggedInAs.indexOf( email ) !== -1, 'found proper email in user menu: ' + loggedInAs );
});
// ------------------------------------------------------------------- log out that user
spaceghost.user.logout().openHomePage( function(){
var emailSelector = xpath( this.data.selectors.masthead.userMenu.userEmail_xpath );
this.test.assert( !this.elementInfoOrNull( emailSelector ), 'user email not found' );
});
// ------------------------------------------------------------------- bad user registrations
spaceghost.then( function(){
this.test.comment( 'attempting to re-register user: ' + email );
this.user._submitRegistration( email, password, username, confirm );
});
spaceghost.then(function(){
this.assertErrorMessage( 'User with that email already exists' );
});
// emails must be in the form -@-.- (which is an email on main, btw)
var badEmails = [ 'bob', 'bob@', 'bob@idontwanttocleanup', 'bob.cantmakeme' ];
spaceghost.each( badEmails, function( self, badEmail ){
self.then( function(){
this.test.comment( 'attempting bad email: ' + badEmail );
this.user._submitRegistration( badEmail, password, username, confirm );
// =================================================================== TESTS
spaceghost.openHomePage( function(){
this.test.comment( 'loading galaxy homepage' );
this.test.assertTitle( 'Galaxy' );
this.test.assertExists( xpath( "//div[@id='masthead']" ), 'found masthead' );
});
self.then(function(){
this.assertErrorMessage( 'Please enter your valid email address' );
});
});
// passwords must be at least 6 chars long
var badPasswords = [ '1234' ];
spaceghost.each( badPasswords, function( self, badPassword ){
self.then( function(){
this.test.comment( 'attempting bad password: ' + badPassword );
this.user._submitRegistration( spaceghost.user.getRandomEmail(), badPassword, username, badPassword );
// ------------------------------------------------------------------- register a new user
spaceghost.then( function(){
this.test.comment( 'registering user: ' + email );
this.user._submitRegistration( email, password, username, confirm );
});
self.then(function(){
this.assertErrorMessage( 'Please use a password of at least 6 characters' );
spaceghost.openHomePage( function(){
this.clickLabel( 'User' );
var loggedInAs = this.fetchText( xpath( spaceghost.data.selectors.masthead.userMenu.userEmail_xpath ) );
this.test.assert( loggedInAs.indexOf( email ) !== -1, 'found proper email in user menu: ' + loggedInAs );
});
});
// and confirm must match
var badConfirms = [ '1234', '12345678', '123456 7', '' ];
spaceghost.each( badConfirms, function( self, badConfirm ){
self.then( function(){
this.test.comment( 'attempting bad password confirmation: ' + badConfirm );
this.user._submitRegistration( spaceghost.user.getRandomEmail(), password, username, badConfirm );
// ------------------------------------------------------------------- log out that user
spaceghost.user.logout().openHomePage( function(){
var emailSelector = xpath( this.data.selectors.masthead.userMenu.userEmail_xpath );
this.test.assert( !this.elementInfoOrNull( emailSelector ), 'user email not found' );
});
self.then(function(){
this.assertErrorMessage( 'Passwords don\'t match' );
// ------------------------------------------------------------------- bad user registrations
spaceghost.then( function(){
this.test.comment( 'attempting to re-register user: ' + email );
this.user._submitRegistration( email, password, username, confirm );
});
});
// usernames must be >=4 chars...
//NOTE: that short username errors only show AFTER checking for existing/valid emails
// so: we need to generate new emails for each one
spaceghost.then( function(){
var newEmail = spaceghost.user.getRandomEmail(),
badUsername = 'bob';
this.test.comment( 'attempting short username: ' + badUsername );
this.user._submitRegistration( newEmail, password, badUsername, confirm );
});
spaceghost.then(function(){
this.assertErrorMessage( 'Public name must be at least 4 characters in length' );
});
// ...and be lower-case letters, numbers and '-'...
var badUsernames = [ 'BOBERT', 'Robert Paulson', 'bobert!', 'bob_dobbs' ];
spaceghost.each( badUsernames, function( self, badUsername ){
self.then( function(){
var newEmail = spaceghost.user.getRandomEmail();
this.test.comment( 'attempting bad username: ' + badUsername );
this.user._submitRegistration( newEmail, password, badUsername, confirm );
spaceghost.then(function(){
this.assertErrorMessage( 'User with that email already exists' );
});
self.then(function(){
this.assertErrorMessage( 'Public name must contain only lowercase letters, numbers and "-"' );
});
});
// ...and the name can't be used already
spaceghost.then( function(){
var newEmail = spaceghost.user.getRandomEmail();
this.test.comment( 'attempting previously used username with new user: ' + newEmail );
this.user._submitRegistration( newEmail, password, username, confirm );
});
spaceghost.then(function(){
this.assertErrorMessage( 'Public name is taken; please choose another' );
});
// ------------------------------------------------------------------- test the convenience fns
// these versions are for conv. use in other tests, they should throw errors if used improperly
spaceghost.then( function(){
this.assertStepsRaise( 'GalaxyError: RegistrationError', function(){
this.then( function(){
this.test.comment( 'testing (js) error thrown on bad email' );
this.user.registerUser( '@internet', '123456', 'ignobel' );
// emails must be in the form -@-.- (which is an email on main, btw)
var badEmails = [ 'bob', 'bob@', 'bob@idontwanttocleanup', 'bob.cantmakeme' ];
spaceghost.each( badEmails, function( self, badEmail ){
self.then( function(){
this.test.comment( 'attempting bad email: ' + badEmail );
this.user._submitRegistration( badEmail, password, username, confirm );
});
self.then(function(){
this.assertErrorMessage( 'Please enter your valid email address' );
});
});
// passwords must be at least 6 chars long
var badPasswords = [ '1234' ];
spaceghost.each( badPasswords, function( self, badPassword ){
self.then( function(){
this.test.comment( 'attempting bad password: ' + badPassword );
this.user._submitRegistration( spaceghost.user.getRandomEmail(), badPassword, username, badPassword );
});
self.then(function(){
this.assertErrorMessage( 'Please use a password of at least 6 characters' );
});
});
// and confirm must match
var badConfirms = [ '1234', '12345678', '123456 7', '' ];
spaceghost.each( badConfirms, function( self, badConfirm ){
self.then( function(){
this.test.comment( 'attempting bad password confirmation: ' + badConfirm );
this.user._submitRegistration( spaceghost.user.getRandomEmail(), password, username, badConfirm );
});
self.then(function(){
this.assertErrorMessage( 'Passwords don\'t match' );
});
});
// usernames must be >=4 chars...
//NOTE: that short username errors only show AFTER checking for existing/valid emails
// so: we need to generate new emails for each one
spaceghost.then( function(){
var newEmail = spaceghost.user.getRandomEmail(),
badUsername = 'bob';
this.test.comment( 'attempting short username: ' + badUsername );
this.user._submitRegistration( newEmail, password, badUsername, confirm );
});
spaceghost.then(function(){
this.assertErrorMessage( 'Public name must be at least 4 characters in length' );
});
// ...and be lower-case letters, numbers and '-'...
var badUsernames = [ 'BOBERT', 'Robert Paulson', 'bobert!', 'bob_dobbs' ];
spaceghost.each( badUsernames, function( self, badUsername ){
self.then( function(){
var newEmail = spaceghost.user.getRandomEmail();
this.test.comment( 'attempting bad username: ' + badUsername );
this.user._submitRegistration( newEmail, password, badUsername, confirm );
});
self.then(function(){
this.assertErrorMessage( 'Public name must contain only lowercase letters, numbers and "-"' );
});
});
// ...and the name can't be used already
spaceghost.then( function(){
var newEmail = spaceghost.user.getRandomEmail();
this.test.comment( 'attempting previously used username with new user: ' + newEmail );
this.user._submitRegistration( newEmail, password, username, confirm );
});
spaceghost.then(function(){
this.assertErrorMessage( 'Public name is taken; please choose another' );
});
// ------------------------------------------------------------------- test the convenience fns
// these versions are for conv. use in other tests, they should throw errors if used improperly
spaceghost.then( function(){
this.assertStepsRaise( 'RegistrationError', function(){
this.then( function(){
this.test.comment( 'testing (js) error thrown on bad email' );
this.user.registerUser( '@internet', '123456', 'ignobel' );
});
});
});
// ===================================================================
spaceghost.run( function(){
test.done();
});
});
// ===================================================================
spaceghost.run( function(){
this.test.done();
});
+171 -135
View File
@@ -32,24 +32,34 @@
*/
// ------------------------------------------------------------------- modules
var Casper = require( 'casper' ).Casper,
var require = patchRequire( require ),
Casper = require( 'casper' ).Casper,
fs = require( 'fs' ),
utils = require( 'utils' );
// ------------------------------------------------------------------- inheritance
/** @class An extension of the Casper object with methods and overrides specifically
* for interacting with a Galaxy web page.
* @augments Casper
*/
function SpaceGhost(){
SpaceGhost.super_.apply( this, arguments );
this._init.apply( this, arguments );
// an empty object just to store functions in a prototype for patching onto a casper isntance
}
utils.inherits( SpaceGhost, Casper );
/** String representation
* @returns {String}
*/
exports.fromCasper = function fromCasper( casper, options ){
"use strict";
// patch the sg prototype over the casper instance proto
for( var k in SpaceGhost.prototype ){
if( SpaceGhost.prototype.hasOwnProperty( k ) ){
// monkey patch directly onto the casper instance - we need the prototype
casper[ k ] = SpaceGhost.prototype[ k ];
}
}
casper._init( options );
return casper;
};
// =================================================================== METHODS / OVERRIDES
/** String representation */
SpaceGhost.prototype.toString = function(){
var currentUrl = '';
try {
@@ -58,61 +68,27 @@ SpaceGhost.prototype.toString = function(){
return 'SpaceGhost(' + currentUrl + ')';
};
// ------------------------------------------------------------------- included libs
//??: can we require underscore, etc. from the ../../static/scripts/lib?
// yep!
//var _ = require( '../../static/scripts/libs/underscore' );
//var stooges = [{name : 'moe', age : 40}, {name : 'larry', age : 50}, {name : 'curly', age : 60}];
//console.debug( JSON.stringify( _.pluck(stooges, 'name') ) );
//exports._ = _;
// ------------------------------------------------------------------- error types
//TODO: change to inheriting from Error
PageError.prototype = new CasperError();
PageError.prototype.constructor = CasperError;
/** @class Represents a javascript error on the page casper is browsing
* (as opposed to an error in the test script).
*/
function PageError(){
CasperError.apply( this, arguments );
this.name = "PageError";
}
SpaceGhost.prototype.PageError = PageError;
GalaxyError.prototype = new CasperError();
GalaxyError.prototype.constructor = CasperError;
/** @class Thrown when Galaxy has (gracefully?) indicated pilot error. */
function GalaxyError(){
CasperError.apply( this, arguments );
this.name = "GalaxyError";
}
SpaceGhost.prototype.GalaxyError = GalaxyError;
AlertError.prototype = new CasperError();
AlertError.prototype.constructor = CasperError;
/** @class Thrown when Galaxy has displayed a javascript alert. */
function AlertError(){
CasperError.apply( this, arguments );
this.name = "AlertError";
}
SpaceGhost.prototype.AlertError = AlertError;
// =================================================================== METHODS / OVERRIDES
// ------------------------------------------------------------------- set up
/** More initialization: cli, event handlers, etc.
* @param {Object} options option hash
* @private
*/
SpaceGhost.prototype._init = function _init( options ){
//console.debug( 'init, options:', JSON.stringify( options, null, 2 ) );
////console.debug( 'init, options:', JSON.stringify( options, null, 2 ) );
//
//NOTE: cli will override in-script options
this._setOptionsFromCli();
// save errors for later output (needs to go before process CLI)
/** cache of errors that have occurred
* @memberOf SpaceGhost */
this.on( 'step.error', function stepErrorHandler( error ){
//console.debug( 'step.error: ' + error.name + ', ' + error.message );
this.errors.push({ msg: error.message, backtrace: error.stackArray });
//if( error.name !== 'AssertionError' ){
// throw error;
//}
});
// save errors for later output
// set this now so ALL errors are processed well (including errors during set up)
/** cache of errors that have occurred */
this.errors = [];
this.on( 'error', function pushErrorToStack( msg, backtrace ){
//this.debug( 'adding error to stack: ' + msg + ', trace:' + this.jsonStr( backtrace ) );
@@ -121,14 +97,19 @@ SpaceGhost.prototype._init = function _init( options ){
this._processCLIArguments();
this._setUpEventHandlers();
/** cache of test failures */
this.failures = [];
/** cache of test passes */
this.passes = [];
// inject these scripts by default
this.debug( 'this.options.scriptDir:' + this.options.scriptDir );
this.options.clientScripts = [
//this.options.scriptDir + '../../static/scripts/libs/jquery/jquery.js'
//'../../static/scripts/libs/jquery/jquery.js'
//...
].concat( this.options.clientScripts );
this.debug( 'clientScripts: ' + this.jsonStr( this.options.clientScripts ) );
this.changeToScriptDir();
this._loadModules();
};
@@ -141,13 +122,29 @@ SpaceGhost.prototype._setOptionsFromCli = function setOptionsFromCli(){
// get and remove any casper options passed on the command line
for( var optionName in this.options ){
if( this.cli.has( optionName ) ){
//console.debug( optionName + ':' + this.options[ optionName ] + ',' + this.cli.get( optionName ) );
//console.debug( optionName + ': '
// + '(was) ' + this.options[ optionName ]
// + ', (now) ' + this.cli.get( optionName ) );
this.options[ optionName ] = this.cli.get( optionName );
this.cli.drop( optionName );
}
}
};
/** Change the working directory to that of the current script */
SpaceGhost.prototype.changeToScriptDir = function changeToScriptDir(){
var fs = require( 'fs' ),
args = require( 'system' ).args,
scriptPathArray = args[4].split( '/' );
//console.debug( this.jsonStr( scriptPathArray ) );
if( scriptPathArray.length > 1 ){
scriptPathArray.pop();
//console.debug( this.jsonStr( scriptPathArray.join( '/' ) ) );
fs.changeWorkingDirectory( scriptPathArray.join( '/' ) );
}
};
// ------------------------------------------------------------------- cli args and options
/** Set up any SG specific options passed in on the cli.
* @private
@@ -190,9 +187,10 @@ SpaceGhost.prototype._processCLIArguments = function _processCLIArguments(){
this.options.returnJsonOnly = true;
this._redirectOutputToStderr();
this.test.removeAllListeners( 'tests.complete' );
// output json on fail-first error
this.on( 'error', function outputJSONOnError( msg, backtrace ){
//console.debug( 'return-json caught error' );
if( spaceghost.options.exitOnError ){
this._sendStopSignal();
this.outputStateAsJson();
@@ -240,9 +238,8 @@ SpaceGhost.prototype._processCLIArguments = function _processCLIArguments(){
// --fail-screen: print the casper browser screen output on an test failure
*/
// get any fixture data passed in as JSON in args
// (NOTE: currently the 2nd arg (with the url being 1st?)
this.fixtureData = ( this.cli.has( 0 ) )?( JSON.parse( this.cli.get( 0 ) ) ):( {} );
// get any fixture data passed in as JSON (e.g. --data='{ "one": 1 }')
this.fixtureData = ( this.cli.has( 'data' ) )?( JSON.parse( this.cli.get( 'data' ) ) ):( {} );
this.debug( 'fixtureData:' + this.jsonStr( this.fixtureData ) );
/** only output log messages with the given namespace */
@@ -284,18 +281,19 @@ SpaceGhost.prototype._redirectOutputToStderr = function _redirectOutputToStderr(
spaceghost.stderr( msg );
};
//this.removeListener( 'error', this.listeners( 'error' )[0] );
// clear the casper listener that outputs formatted error messages
this.removeListener( 'error', this.listeners( 'error' )[1] );
this.removeListener( 'error', this.listeners( 'error' )[0] );
//this.removeListener( 'error', this.listeners( 'error' )[1] );
};
/** Outputs logs, test results and errors in a single JSON formatted object to the console.
*/
SpaceGhost.prototype.outputStateAsJson = function outputStateAsJson(){
var returnedJSON = {
logs: this.result,
testResults: this.test.testResults,
errors: this.errors
logs : this.result,
passes : this.passes,
failures : this.failures,
errors : this.errors
};
// use phantomjs console since echo can't be used (suppressed - see init)
console.debug( JSON.stringify( returnedJSON, null, 2 ) );
@@ -303,6 +301,34 @@ SpaceGhost.prototype.outputStateAsJson = function outputStateAsJson(){
// ------------------------------------------------------------------- event handling
/** Sets up event handlers.
* @private
*/
SpaceGhost.prototype._setUpEventHandlers = function _setUpEventHandlers(){
//console.debug( '_setUpEventHandlers' );
var spaceghost = this;
// ........................ page errors
this.on( 'page.error', this._pageErrorHandler );
//this.on( 'load.failed', this._loadFailedHandler );
// ........................ page info/debugging
this.on( 'remote.alert', this._alertHandler );
//this.on( 'remote.message', function( msg ){ this.debug( 'remote: ' + msg ); });
//this.on( 'navigation.requested', function( url ){ this.debug( 'navigation: ' + url ); });
// ........................ timeouts
this._setUpTimeoutHandlers();
// ........................ test results
this.test.on( "fail", function( failure ){
spaceghost.failures.push( failure );
});
this.test.on( "success", function( pass ){
spaceghost.passes.push( pass );
});
};
//note: using non-anon fns to allow removal if needed
/** 'load failed' Event handler for failed page loads that only records to the log
@@ -415,25 +441,6 @@ SpaceGhost.prototype._setUpTimeoutHandlers = function _setUpTimeoutHandlers(){
};
};
/** Sets up event handlers.
* @private
*/
SpaceGhost.prototype._setUpEventHandlers = function _setUpEventHandlers(){
//console.debug( '_setUpEventHandlers' );
// ........................ page errors
this.on( 'page.error', this._pageErrorHandler );
//this.on( 'load.failed', this._loadFailedHandler );
// ........................ page info/debugging
this.on( 'remote.alert', this._alertHandler );
//this.on( 'remote.message', function( msg ){ this.debug( 'remote: ' + msg ); });
//this.on( 'navigation.requested', function( url ){ this.debug( 'navigation: ' + url ); });
// ........................ timeouts
this._setUpTimeoutHandlers();
};
// ------------------------------------------------------------------- sub modules
/** Load sub modules (similar to casperjs.test)
* @requires User modules/user.js
@@ -443,11 +450,11 @@ SpaceGhost.prototype._setUpEventHandlers = function _setUpEventHandlers(){
* @private
*/
SpaceGhost.prototype._loadModules = function _loadModules(){
this.user = require( this.options.scriptDir + 'modules/user' ).create( this );
this.tools = require( this.options.scriptDir + 'modules/tools' ).create( this );
this.historypanel = require( this.options.scriptDir + 'modules/historypanel' ).create( this );
this.historyoptions = require( this.options.scriptDir + 'modules/historyoptions' ).create( this );
this.api = require( this.options.scriptDir + 'modules/api' ).create( this );
this.user = require( './modules/user' ).create( this );
this.tools = require( './modules/tools' ).create( this );
this.historypanel = require( './modules/historypanel' ).create( this );
this.historyoptions = require( './modules/historyoptions' ).create( this );
this.api = require( './modules/api' ).create( this );
};
// =================================================================== PAGE CONTROL
@@ -484,27 +491,32 @@ SpaceGhost.prototype._sendStopSignal = function _sendStopSignal(){
* Exits with 2 if a test has failed.
* Exits with 1 if some error has occurred.
* Exits with 0 if all tests passed.
* @see Casper#run run, boy, run (doesn't he fly?)
*/
SpaceGhost.prototype.run = function run( onComplete, time ){
var oldFn = spaceghost.test.done;
spaceghost.test.done = function(){
oldFn.call( spaceghost.test );
}
var new_onComplete = function(){
onComplete.call( this );
var returnCode = ( this.test.testResults.failed )?( 2 ):( 0 );
onComplete.call( this );
//var returnCode = ( this.test.getFailures() )?( 2 ):( 0 );
var returnCode = ( this.failures.length )?( 2 ):( 0 );
// if --return-json is used: output json and exit
//NOTE: used by the test runner to gather JSON test info from stdout
if( this.options.returnJsonOnly ){
// echo a string to indicate that tests are complete (used in casperjs_runner.py to stop process)
this._sendStopSignal();
this.outputStateAsJson();
this.exit( returnCode );
// if --return-json is used: output json and exit
//NOTE: used by the test runner to gather JSON test info from stdout
if( this.options.returnJsonOnly ){
// echo a string to indicate that tests are complete (used in casperjs_runner.py to stop process)
this._sendStopSignal();
this.outputStateAsJson();
this.exit( returnCode );
// otherwise, render the nice casper output and exit
} else {
this.test.renderResults( true, returnCode );
}
};
// otherwise, render the nice casper output and exit
//} else {
// this.test.renderResults( true, returnCode );
}
};
Casper.prototype.run.call( this, new_onComplete, time );
//Casper.prototype.run.call( this, onComplete, time );
};
// ------------------------------------------------------------------- home page
@@ -550,18 +562,18 @@ SpaceGhost.prototype.tryStepsCatch = function tryStepsCatch( stepsFn, catchFn ){
// create three steps: 1) set up new error handler, 2) try the fn, 3) check for errors and rem. handler
var originalExitOnError,
originalErrorHandlers = [],
errorMsg = '', errorTrace = [],
recordError = function( msg, trace ){
errorMsg = msg; errorTrace = trace;
errorCaught,
recordError = function( error ){
errorCaught = error;
};
// dont bail on the error (but preserve option), uninstall other handlers,
// and install hndlr to simply record msg, trace
this.then( function(){
this.then( function replaceHandlers(){
originalExitOnError = this.options.exitOnError;
this.options.exitOnError = false;
originalErrorHandlers = this.popAllListeners( 'error' );
this.on( 'error', recordError );
originalErrorHandlers = this.popAllListeners( 'step.error' );
this.on( 'step.error', recordError );
});
// try the step...
@@ -569,15 +581,15 @@ SpaceGhost.prototype.tryStepsCatch = function tryStepsCatch( stepsFn, catchFn ){
//TODO: this doesn't work well with wait for (see upload-tests.js)
// possibly combine above and below?
this.then( function(){
// ...and if an error was recorded call the catch with the info
if( errorMsg ){
catchFn.call( this, errorMsg, errorTrace );
}
this.then( function catchWrapper(){
// remove that listener either way, restore original handlers, and restore the bail option
this.removeListener( 'error', recordError );
this.addListeners( 'error', originalErrorHandlers );
this.removeListener( 'step.error', recordError );
this.addListeners( 'step.error', originalErrorHandlers );
this.options.exitOnError = originalExitOnError;
// ...and if an error was recorded call the catch with the info
if( errorCaught ){
catchFn.call( this, errorCaught );
}
});
};
@@ -823,8 +835,12 @@ SpaceGhost.prototype.assertStepsRaise = function assertStepsRaise( msgContains,
// casper provides an assertRaises but this doesn't work well with steps
//TODO: * @param {Boolean} removeOtherListeners option to remove other listeners while this fires
var spaceghost = this;
function testTheError( msg, backtrace ){
spaceghost.test.assert( msg.indexOf( msgContains ) !== -1, 'Raised correct error: ' + msg );
function testTheError( errorCaught ){
if( errorCaught.message.indexOf( msgContains ) !== -1 ){
spaceghost.test.pass( 'Raised correct error: ' + errorCaught.message );
} else {
throw errorCaught;
}
}
this.tryStepsCatch( stepsFn, testTheError );
};
@@ -1085,29 +1101,27 @@ SpaceGhost.prototype.lastError = function(){
// ------------------------------------------------------------------- file system
/** Load and parse a JSON file into an object.
* @param {String} filepath filepath relative to the current scriptDir
* @param {String} filepath filepath relative to the current script
* @returns {Object} the object parsed
*/
SpaceGhost.prototype.loadJSONFile = function loadJSONFile( filepath ){
//precondition: filepath is relative to script dir
filepath = this.options.scriptDir + filepath;
return JSON.parse( fs.read( filepath ) );
};
/** Write an object to a JSON file.
* @param {String} filepath filepath relative to the current scriptDir
* @param {String} filepath filepath relative to the current script
* @param {Object} object the object to write
* @param {String} mode 'w' for a new file, 'a' for append
*/
SpaceGhost.prototype.writeJSONFile = function writeJSONFile( filepath, object, mode ){
mode = mode || 'w';
//precondition: filepath is relative to script dir
filepath = this.options.scriptDir + filepath;
return fs.write( filepath, this.jsonStr( object ), mode );
};
/** Save the HTML from the current page to file.
* @param {String} filepath filepath relative to the current scriptDir
* @param {String} filepath filepath relative to the current script
* @param {String} selector A DOM CSS3/XPath selector (optional)
* @param {Boolean} outer Whether to fetch outer HTML contents (default: false)
*/
@@ -1116,13 +1130,12 @@ SpaceGhost.prototype.writeHTMLFile = function writeHTMLFile( filepath, selector,
};
/** Read and search a file for the given regex.
* @param {String} filepath filepath relative to the current scriptDir
* @param {String} filepath filepath relative to the current script
* @param {Regex} searchFor regex to search for
* @returns {Object} search results
*/
SpaceGhost.prototype.searchFile = function searchFile( filepath, regex ){
//precondition: filepath is relative to script dir
filepath = this.options.scriptDir + filepath;
var read = fs.read( filepath );
return read.match( regex );
};
@@ -1235,14 +1248,37 @@ SpaceGhost.prototype.data = {
};
// =================================================================== EXPORTS
exports.SpaceGhost = SpaceGhost;
// =================================================================== error types
/** @class Represents a javascript error on the page casper is browsing
* (as opposed to an error in the test script).
*/
function PageError(){
CasperError.apply( this, arguments );
this.name = "PageError";
}
//TODO: change to inheriting from Error
PageError.prototype = new CasperError();
PageError.prototype.constructor = CasperError;
SpaceGhost.prototype.PageError = PageError;
/** @class Thrown when Galaxy has (gracefully?) indicated pilot error. */
function GalaxyError(){
CasperError.apply( this, arguments );
this.name = "GalaxyError";
}
GalaxyError.prototype = new CasperError();
GalaxyError.prototype.constructor = CasperError;
SpaceGhost.prototype.GalaxyError = GalaxyError;
/** @class Thrown when Galaxy has displayed a javascript alert. */
function AlertError(){
CasperError.apply( this, arguments );
this.name = "AlertError";
}
AlertError.prototype = new CasperError();
AlertError.prototype.constructor = CasperError;
SpaceGhost.prototype.AlertError = AlertError;
exports.PageError = PageError;
exports.GalaxyError = GalaxyError;
exports.AlertError = AlertError;
/** creation function
*/
exports.create = function create(options) {
"use strict";
return new SpaceGhost(options);
};
+18 -49
View File
@@ -1,30 +1,12 @@
// have to handle errors here - or phantom/casper won't bail but _HANG_
try {
var utils = require( 'utils' ),
xpath = require( 'casper' ).selectXPath,
format = utils.format,
//...if there's a better way - please let me know, universe
scriptDir = require( 'system' ).args[3]
// remove the script filename
.replace( /[\w|\.|\-|_]*$/, '' )
// if given rel. path, prepend the curr dir
.replace( /^(?!\/)/, './' ),
spaceghost = require( scriptDir + 'spaceghost' ).create({
// script options here (can be overridden by CLI)
//verbose: true,
//logLevel: debug,
scriptDir: scriptDir
});
var require = patchRequire( require ),
spaceghost = require( 'spaceghost' ).fromCasper( casper ),
xpath = require( 'casper' ).selectXPath,
utils = require( 'utils' ),
format = utils.format;
spaceghost.test.begin( 'Test uploading data to a history', 0, function suite( test ){
spaceghost.start();
} catch( error ){
console.debug( error );
phantom.exit( 1 );
}
// ===================================================================
/* TODO:
@@ -54,7 +36,7 @@ spaceghost.then( function(){
this.test.comment( 'Test uploading a file' );
var filename = '1.txt',
filepath = this.options.scriptDir + '/../../test-data/' + filename;
filepath = '../../test-data/' + filename;
this.tools._uploadFile( filepath );
// when an upload begins successfully main should reload with a infomessagelarge
@@ -70,28 +52,16 @@ spaceghost.then( function(){
});
// ... and move to the history panel and wait for upload to finish
spaceghost.historypanel.waitForHdas( function(){
this.test.comment( 'Waiting for upload to move to ok state in history' );
var hdaInfo = this.historypanel.hdaElementInfoByTitle( testUploadInfo.name );
if( !hdaInfo ){
this.test.fail( 'Could not locate new hda: ' + testUploadInfo.name );
} else {
spaceghost.debugElement( spaceghost.jsonStr( hdaInfo ) );
this.historypanel.waitForHdaState( '#' + hdaInfo.attributes.id, 'ok',
function whenInStateFn( newHdaInfo ){
//this.debug( 'newHdaInfo:\n' + this.jsonStr( newHdaInfo ) );
this.test.pass( 'Upload completed successfully for: ' + testUploadInfo.name );
},
function timeoutFn( newHdaInfo ){
this.debug( 'newHdaInfo:\n' + this.jsonStr( newHdaInfo ) );
this.test.fail( 'Test timed out for upload: ' + testUploadInfo.name );
},
// wait a maximum of 30 secs
30 * 1000 );
}
});
spaceghost.historypanel.waitForHda( '1.txt',
function uploadComplete( hdaElement ){
this.test.pass( 'Upload completed successfully for: ' + this.jsonStr( hdaElement.attributes.id ) );
},
function timeout( hdaElement ){
this.debug( 'hdaElement:\n' + this.jsonStr( hdaElement ) );
this.test.fail( 'Test timed out for upload: ' + testUploadInfo.name );
},
30 * 1000
);
// ------------------------------------------------------------------- short form
spaceghost.then( function(){
@@ -118,6 +88,5 @@ spaceghost.then( function(){
*/
// ===================================================================
spaceghost.run( function(){
this.test.done();
spaceghost.run( function(){ test.done(); });
});