commit/galaxy-central: carlfeberhard: browser tests: refactoring, add api module
1 new commit in galaxy-central: https://bitbucket.org/galaxy/galaxy-central/commits/f19741fdb9a6/ changeset: f19741fdb9a6 user: carlfeberhard date: 2013-03-18 20:14:22 summary: browser tests: refactoring, add api module affected #: 14 files diff -r 51d3a88f45ee2e3aa89395d2df13b5452d463274 -r f19741fdb9a6b6f15f3e9b983d4a8228b205ffda lib/galaxy/webapps/galaxy/api/history_contents.py --- a/lib/galaxy/webapps/galaxy/api/history_contents.py +++ b/lib/galaxy/webapps/galaxy/api/history_contents.py @@ -175,15 +175,20 @@ if from_ld_id: try: ld = self.get_library_dataset( trans, from_ld_id, check_ownership=False, check_accessible=False ) - assert type( ld ) is trans.app.model.LibraryDataset, "Library content id ( %s ) is not a dataset" % from_ld_id + assert type( ld ) is trans.app.model.LibraryDataset, ( + "Library content id ( %s ) is not a dataset" % from_ld_id ) + except AssertionError, e: trans.response.status = 400 return str( e ) + except Exception, e: return str( e ) + hda = ld.library_dataset_dataset_association.to_history_dataset_association( history, add_to_history=True ) trans.sa_session.flush() return hda.get_api_value() + else: # TODO: implement other "upload" methods here. trans.response.status = 403 diff -r 51d3a88f45ee2e3aa89395d2df13b5452d463274 -r f19741fdb9a6b6f15f3e9b983d4a8228b205ffda test/casperjs/anon-history-tests.js --- a/test/casperjs/anon-history-tests.js +++ b/test/casperjs/anon-history-tests.js @@ -68,15 +68,10 @@ }); // ------------------------------------------------------------------- check the empty history for well formedness -// grab the history frame bounds for mouse later tests -spaceghost.then( function(){ - historyFrameInfo = this.getElementInfo( 'iframe[name="galaxy_history"]' ); - //this.debug( 'historyFrameInfo:' + this.jsonStr( historyFrameInfo ) ); -}); - spaceghost.thenOpen( spaceghost.baseUrl, function testPanelStructure(){ this.test.comment( 'history panel for anonymous user, new history' ); - this.withFrame( spaceghost.data.selectors.frames.history, function(){ + + this.withHistoryPanel( function(){ this.test.comment( "frame should have proper url and title: 'History'" ); this.test.assertMatch( this.getCurrentUrl(), /\/history/, 'Found history frame url' ); this.test.assertTitle( this.getTitle(), 'History', 'Found history frame title' ); @@ -103,15 +98,12 @@ 'Message contains "' + emptyMsgStr + '"' ); this.test.comment( 'name should have a tooltip with info on anon-user name editing' ); - // mouse over to find tooltip - this.historypanel.hoverOver( nameSelector, function testingHover(){ - this.test.assertExists( tooltipSelector, "Found tooltip after name hover" ); - this.test.assertSelectorHasText( tooltipSelector, anonNameTooltip ); - }, historyFrameInfo ); + this.historypanel.hoverOver( nameSelector ); + this.test.assertExists( tooltipSelector, "Found tooltip after name hover" ); + this.test.assertSelectorHasText( tooltipSelector, anonNameTooltip ); this.test.comment( 'name should NOT be editable when clicked by anon-user' ); - this.assertDoesntHaveClass( nameSelector, editableTextClass, - "Name field is not classed as editable text" ); + this.assertDoesntHaveClass( nameSelector, editableTextClass, "Name field is not classed as editable text" ); this.click( nameSelector ); this.test.assertDoesntExist( editableTextInput, "Clicking on name does not create an input" ); }); @@ -120,12 +112,13 @@ // ------------------------------------------------------------------- anon user can upload file spaceghost.then( function testAnonUpload(){ this.test.comment( 'anon-user should be able to upload files' ); + spaceghost.tools.uploadFile( filepathToUpload, function uploadCallback( _uploadInfo ){ - this.debug( 'uploaded HDA info: ' + this.jsonStr( _uploadInfo ) ); + this.debug( 'uploaded HDA info: ' + this.jsonStr( this.quickInfo( _uploadInfo.hdaElement ) ) ); var hasHda = _uploadInfo.hdaElement, hasClass = _uploadInfo.hdaElement.attributes[ 'class' ], hasOkClass = _uploadInfo.hdaElement.attributes[ 'class' ].indexOf( 'historyItem-ok' ) !== -1; - this.test.assert( ( hasHda && hasClass && hasOkClass ), "Uploaded file: " + _uploadInfo.name ); + this.test.assert( ( hasHda && hasClass && hasOkClass ), "Uploaded file: " + _uploadInfo.hdaElement.text ); testUploadInfo = _uploadInfo; }); }); @@ -134,19 +127,18 @@ this.test.assertNotVisible( emptyMsgSelector, 'Empty history message is not visible' ); }); - // ------------------------------------------------------------------- anon user can run tool on file // ------------------------------------------------------------------- anon user registers/logs in -> same history spaceghost.user.loginOrRegisterUser( email, password ); spaceghost.thenOpen( spaceghost.baseUrl, function(){ + this.test.comment( 'anon-user should login and be associated with previous history' ); - this.test.comment( 'anon-user should login and be associated with previous history' ); var loggedInAs = spaceghost.user.loggedInAs(); this.test.assert( loggedInAs === email, 'loggedInAs() matches email: "' + loggedInAs + '"' ); - this.withFrame( spaceghost.data.selectors.frames.history, function(){ - var hdaInfo = this.historypanel.hdaElementInfoByTitle( testUploadInfo.name, testUploadInfo.hid ); + this.historypanel.waitForHdas( function(){ + var hdaInfo = this.historypanel.hdaElementInfoByTitle( testUploadInfo.hdaElement.text ); this.test.assert( hdaInfo !== null, "After logging in - found a matching hda by name and hid" ); if( hdaInfo ){ this.test.assert( testUploadInfo.hdaElement.attributes.id === hdaInfo.attributes.id, @@ -155,17 +147,18 @@ }); }); +// ------------------------------------------------------------------- logs out -> new history spaceghost.user.logout(); spaceghost.thenOpen( spaceghost.baseUrl, function(){ this.test.comment( 'logging out should create a new, anonymous history' ); - this.withFrame( spaceghost.data.selectors.frames.history, function(){ + + this.historypanel.waitForHdas( function(){ this.test.assertSelectorHasText( nameSelector, unnamedName, 'History name is ' + unnamedName ); this.test.assertSelectorHasText( emptyMsgSelector, emptyMsgStr, 'Message contains "' + emptyMsgStr + '"' ); }); }); - // =================================================================== spaceghost.run( function(){ this.test.done(); diff -r 51d3a88f45ee2e3aa89395d2df13b5452d463274 -r f19741fdb9a6b6f15f3e9b983d4a8228b205ffda test/casperjs/casperjs_runner.py --- a/test/casperjs/casperjs_runner.py +++ b/test/casperjs/casperjs_runner.py @@ -73,7 +73,7 @@ debug = False # bit of a hack - this is the beginning of the last string when capserjs --verbose=true --logLevel=debug # use this to get subprocess to stop waiting for output - casper_done_str = '# Tests complete' + casper_done_str = '# Stopping' # convert js test results to unittest.TestResults results_adapter = None #CasperJsonToUnittestResultsConverter() @@ -209,7 +209,8 @@ js_test_results = json.loads( results ) failures = js_test_results[ 'testResults' ][ 'failures' ] assert len( failures ) == 0, ( - "Some assertions failed in the headless browser tests (see the log for details)" ) + "%d assertions failed in the headless browser tests" %( len( failures ) ) + + " (see the log for details)" ) # ---------------------------------------------------------------- TestCase overrides def setUp( self ): @@ -299,10 +300,12 @@ # ==================================================================== TESTCASE EXAMPLE # these could be broken out into other py files - shouldn't be necc. ATM class Test_01_User( CasperJSTestCase ): - """TestCase that uses javascript and a headless browser to test dynamic pages. + """Tests for the Galaxy user centered functionality: + registration, login, etc. """ def test_10_registration( self ): - """User registration tests: register new user, logout, attempt bad registrations. + """User registration tests: + register new user, logout, attempt bad registrations. """ # all keywords will be compiled into a single JSON obj and passed to the server #self.run_js_script( 'registration-tests.js', @@ -331,7 +334,7 @@ class Test_03_HistoryPanel( CasperJSTestCase ): - """(Minimal) casperjs tests for tools. + """Tests for History fetching, rendering, and modeling. """ def test_00_history_panel( self ): """Test history panel basics (controls, structure, refresh, history options menu, etc.). @@ -339,13 +342,18 @@ self.run_js_script( 'history-panel-tests.js' ) def test_10_anonymous_histories( self ): + """Test history options button. + """ + self.run_js_script( 'history-options-tests.js' ) + + def test_20_anonymous_histories( self ): """Test history panel basics with an anonymous user. """ self.run_js_script( 'anon-history-tests.js' ) class Test_04_HDAs( CasperJSTestCase ): - """(Minimal) casperjs tests for tools. + """Tests for HistoryDatasetAssociation fetching, rendering, and modeling. """ def test_00_HDA_states( self ): """Test structure rendering of HDAs in all the possible HDA states diff -r 51d3a88f45ee2e3aa89395d2df13b5452d463274 -r f19741fdb9a6b6f15f3e9b983d4a8228b205ffda test/casperjs/hda-state-tests.js --- a/test/casperjs/hda-state-tests.js +++ b/test/casperjs/hda-state-tests.js @@ -55,17 +55,10 @@ // start a new user spaceghost.user.loginOrRegisterUser( email, password ); -// grab the history frame bounds for later mouse tests -spaceghost.then( function(){ - historyFrameInfo = this.getElementInfo( 'iframe[name="galaxy_history"]' ); - //this.debug( 'historyFrameInfo:' + this.jsonStr( historyFrameInfo ) ); -}); - // upload a file spaceghost.then( function upload(){ spaceghost.tools.uploadFile( filepathToUpload, function uploadCallback( _uploadInfo ){ testUploadInfo = _uploadInfo; - this.info( 'testUploadInfo:' + this.jsonStr( testUploadInfo ) ); }); }); @@ -73,13 +66,12 @@ // =================================================================== TEST HELPERS //NOTE: to be called with fn.call( spaceghost, ... ) -function testTitle( hdaSelector, hid, name ){ - var titleSelector = hdaSelector + ' ' + this.historypanel.data.selectors.hda.title, - titleShouldBe = hid + ': ' + name; +function testTitle( hdaSelector, name ){ + var titleSelector = hdaSelector + ' ' + this.historypanel.data.selectors.hda.title; this.test.assertVisible( titleSelector, 'HDA title is visible' ); - this.test.assertSelectorHasText( titleSelector, titleShouldBe, - 'HDA has proper hid and title' ); + this.test.assertSelectorHasText( titleSelector, name, + 'HDA contains name (' + name + '): ' + this.fetchText( titleSelector ) ); } function testTitleButtonStructure( hdaSelector, shouldHaveTheseButtons ){ @@ -87,28 +79,9 @@ shouldHaveTheseButtons = shouldHaveTheseButtons || [ 'display', 'edit', 'delete' ]; var hdaDbId = this.getElementAttribute( hdaSelector, 'id' ).split( '-' )[1], - buttonsArea = hdaSelector + ' ' + this.historypanel.data.selectors.hda.titleButtons, - buttons = { - // this seems backwards -> TODO: move buttonsArea concat into loop below, move this data to historypanel.data - display : { - nodeName : this.historypanel.data.text.hda.ok.nodeNames.displayButton, - selector : buttonsArea + ' ' + this.historypanel.data.selectors.hda.displayButton, - tooltip : this.historypanel.data.text.hda.ok.tooltips.displayButton, - hrefTpl : this.historypanel.data.text.hda.ok.hrefs.displayButton - }, - edit : { - nodeName : this.historypanel.data.text.hda.ok.nodeNames.editAttrButton, - selector : buttonsArea + ' ' + this.historypanel.data.selectors.hda.editAttrButton, - tooltip : this.historypanel.data.text.hda.ok.tooltips.editAttrButton, - hrefTpl : this.historypanel.data.text.hda.ok.hrefs.editAttrButton - }, - 'delete' : { - nodeName : this.historypanel.data.text.hda.ok.nodeNames.deleteButton, - selector : buttonsArea + ' ' + this.historypanel.data.selectors.hda.deleteButton, - tooltip : this.historypanel.data.text.hda.ok.tooltips.deleteButton, - hrefTpl : this.historypanel.data.text.hda.ok.hrefs.deleteButton - } - }; + buttonsArea = hdaSelector + ' ' + this.historypanel.data.selectors.hda.titleButtonArea, + buttons = this.historypanel.data.hdaTitleButtons; + this.test.assertVisible( buttonsArea, 'Button area is visible' ); for( var i=0; i<shouldHaveTheseButtons.length; i++ ){ @@ -123,7 +96,7 @@ this.test.assertVisible( button.selector, buttonName + ' button is visible' ); var buttonElement = this.getElementInfo( button.selector ); - this.debug( 'buttonElement:' + this.jsonStr( buttonElement ) ); + this.debug( 'buttonElement:' + this.jsonStr( this.quickInfo( buttonElement ) ) ); // should be an anchor this.test.assert( buttonElement.nodeName === button.nodeName, @@ -135,12 +108,13 @@ this.assertTextContains( href, hrefShouldBe, buttonName + ' has proper href (' + hrefShouldBe + '): ' + href ); - this.historypanel.hoverOver( button.selector, function testingHover(){ - var tooltipText = button.tooltip; - this.test.assertVisible( tooltipSelector, buttonName + ' button tooltip is visible when hovering' ); - this.test.assertSelectorHasText( tooltipSelector, tooltipText, - buttonName + ' button has tooltip text: "' + tooltipText + '"' ); - }, historyFrameInfo ); + this.historypanel.hoverOver( button.selector ); + var tooltipText = button.tooltip; + this.test.assertVisible( tooltipSelector, buttonName + ' button tooltip is visible when hovering' ); + this.test.assertSelectorHasText( tooltipSelector, tooltipText, + buttonName + ' button has tooltip text: "' + tooltipText + '"' ); + // clear the tooltip + this.page.sendEvent( 'mouseover', 0, 0 ); } } @@ -185,6 +159,7 @@ this.test.comment( 'Primary action buttons div should exist and be visible' ); this.test.assertExists( buttonsSelector, 'Primary action buttons div exists' ); this.test.assertVisible( buttonsSelector, 'Primary action buttons div is visible' ); + //TODO: ... } function testSecondaryActionButtons( hdaSelector ){ @@ -193,6 +168,7 @@ this.test.comment( 'Secondary action buttons div should exist and be visible' ); this.test.assertExists( buttonsSelector, 'Secondary action buttons div exists' ); this.test.assertVisible( buttonsSelector, 'Secondary action buttons div is visible' ); + //TODO: ... } function testPeek( hdaSelector, expectedPeekArray ){ @@ -239,112 +215,97 @@ // =================================================================== TESTS // ------------------------------------------------------------------- ok state -spaceghost.then( function checkOkState(){ +spaceghost.withHistoryPanel( function(){ this.test.comment( 'HDAs in the "ok" state should be well formed' ); - this.withFrame( spaceghost.data.selectors.frames.history, function(){ - var uploadSelector = '#' + testUploadInfo.hdaElement.attributes.id; - this.test.assertVisible( uploadSelector, 'HDA is visible' ); + var uploadSelector = '#' + testUploadInfo.hdaElement.attributes.id; + this.test.assertVisible( uploadSelector, 'HDA is visible' ); - this.test.comment( 'should have the proper state class' ); - this.assertHasClass( uploadSelector, this.historypanel.data.selectors.hda.wrapper.stateClasses.ok, - 'HDA has ok state class' ); + this.test.comment( 'should have the proper state class' ); + this.assertHasClass( uploadSelector, this.historypanel.data.selectors.hda.wrapper.stateClasses.ok, + 'HDA has ok state class' ); - // since we're using css there's no great way to test state icon (.state-icon is empty) + // since we're using css there's no great way to test state icon (.state-icon is empty) - this.test.comment( 'should have proper title and hid' ); - testTitle.call( spaceghost, uploadSelector, testUploadInfo.hid, testUploadInfo.name ); + this.test.comment( 'should have proper title and hid' ); + testTitle.call( spaceghost, uploadSelector, testUploadInfo.filename ); - this.test.comment( 'should have all of the three, main buttons' ); - testTitleButtonStructure.call( spaceghost, uploadSelector ); + this.test.comment( 'should have all of the three, main buttons' ); + testTitleButtonStructure.call( spaceghost, uploadSelector ); - this.test.comment( 'body is not visible before clicking the hda title' ); - var body = uploadSelector + ' ' + this.historypanel.data.selectors.hda.body; - this.test.assertNotVisible( body, 'body is not visible' ); + this.test.comment( 'body is not visible before clicking the hda title' ); + var body = uploadSelector + ' ' + this.historypanel.data.selectors.hda.body; + this.test.assertNotVisible( body, 'body is not visible' ); - this.test.comment( 'clicking the hda title should expand its body' ); - var hdaTitle = uploadSelector + ' ' + this.historypanel.data.selectors.hda.title; - this.click( hdaTitle ); - this.wait( 500, function(){ + this.test.comment( 'clicking the hda title should expand its body' ); + this.historypanel.thenExpandHda( uploadSelector, function(){ + // ugh. + this.jumpToHistory( function(){ testExpandedBody.call( spaceghost, uploadSelector, summaryShouldBeArray, infoShouldBe, false ); }); }); }); +// restore to collapsed +spaceghost.then( function(){ + this.test.comment( "Collapsing hda in 'ok' state should hide body again" ); + var uploadSelector = '#' + testUploadInfo.hdaElement.attributes.id; -// restore to collapsed -spaceghost.then( function collapseOkState(){ - this.test.comment( "Collapsing hda in 'ok' state should hide body again" ); - this.withFrame( spaceghost.data.selectors.frames.history, function(){ - var uploadSelector = '#' + testUploadInfo.hdaElement.attributes.id, - hdaTitle = uploadSelector + ' ' + this.historypanel.data.selectors.hda.title; - body = uploadSelector + ' ' + this.historypanel.data.selectors.hda.body; - - this.click( hdaTitle ); - this.wait( 500, function(){ - this.test.assertNotVisible( body, 'body is not visible' ); - }); + spaceghost.historypanel.thenCollapseHda( uploadSelector, function collapseOkState(){ + this.test.assertNotVisible( uploadSelector + ' ' + this.historypanel.data.selectors.hda.body, + 'body is not visible' ); }); }); +// ------------------------------------------------------------------- new state +spaceghost.withHistoryPanel( function(){ + // set state directly through model, wait for re-render + //TODO: not ideal to test this + this.evaluate( function(){ + return Galaxy.currHistoryPanel.model.hdas.at( 0 ).set( 'state', 'new' ); + }); + this.wait( 1000, function(){ + this.test.comment( 'HDAs in the "new" state should be well formed' ); -// ------------------------------------------------------------------- new state -spaceghost.then( function checkNewState(){ - this.test.comment( 'HDAs in the "new" state should be well formed' ); + var uploadSelector = '#' + testUploadInfo.hdaElement.attributes.id; + this.test.assertVisible( uploadSelector, 'HDA is visible' ); - this.withFrame( spaceghost.data.selectors.frames.history, function(){ - // set state directly through model - //TODO: not ideal - this.evaluate( function(){ - return Galaxy.currHistoryPanel.model.hdas.at( 0 ).set( 'state', 'new' ); - }); - // wait for re-render - this.wait( 500, function(){ - var uploadSelector = '#' + testUploadInfo.hdaElement.attributes.id; - this.test.assertVisible( uploadSelector, 'HDA is visible' ); + // should have proper title and hid + testTitle.call( spaceghost, uploadSelector, testUploadInfo.filename ); - // should have proper title and hid - testTitle.call( spaceghost, uploadSelector, testUploadInfo.hid, testUploadInfo.name ); + this.test.comment( 'new HDA should have the new state class' ); + this.assertHasClass( uploadSelector, this.historypanel.data.selectors.hda.wrapper.stateClasses['new'], + 'HDA has new state class' ); - this.test.comment( 'new HDA should have the new state class' ); - this.assertHasClass( uploadSelector, this.historypanel.data.selectors.hda.wrapper.stateClasses['new'], - 'HDA has new state class' ); + this.test.comment( 'new HDA should NOT have any of the three, main buttons' ); + var buttonSelector = uploadSelector + ' ' + this.historypanel.data.selectors.hda.titleButtons + ' a'; + this.test.assertDoesntExist( buttonSelector, 'No display, edit, or delete buttons' ); - this.test.comment( 'new HDA should NOT have any of the three, main buttons' ); - var buttonSelector = uploadSelector + ' ' + this.historypanel.data.selectors.hda.titleButtons + ' a'; - this.test.assertDoesntExist( buttonSelector, 'No display, edit, or delete buttons' ); + this.test.comment( 'clicking the title of the new HDA will expand the body' ); - this.test.comment( 'clicking the title of the new HDA will expand the body' ); - var hdaTitle = uploadSelector + ' ' + this.historypanel.data.selectors.hda.title; - this.click( hdaTitle ); - this.wait( 500, function(){ - var bodySelector = uploadSelector + ' ' + this.historypanel.data.selectors.hda.body; - this.test.assertVisible( bodySelector, 'HDA body is visible (after expanding)' ); + this.historypanel.thenExpandHda( uploadSelector, function(){ + var bodySelector = uploadSelector + ' ' + this.historypanel.data.selectors.hda.body; + this.test.assertVisible( bodySelector, 'HDA body is visible (after expanding)' ); - var expectedBodyText = 'This is a new dataset'; - this.test.comment( 'the body should have the text: ' + expectedBodyText ); - this.test.assertSelectorHasText( bodySelector, expectedBodyText, - 'HDA body has text: ' + expectedBodyText ); - - // restore to collapsed - this.click( hdaTitle ); - }); + var expectedBodyText = 'This is a new dataset'; + this.test.comment( 'the body should have the text: ' + expectedBodyText ); + this.test.assertSelectorHasText( bodySelector, expectedBodyText, + 'HDA body has text: ' + expectedBodyText ); }); }); }); // restore state, collapse -spaceghost.then( function revertStateAndCollapse(){ - this.withFrame( spaceghost.data.selectors.frames.history, function(){ +spaceghost.withHistoryPanel( function revertStateAndCollapse(){ + var uploadSelector = '#' + testUploadInfo.hdaElement.attributes.id; + + this.historypanel.thenCollapseHda( uploadSelector, function(){ this.evaluate( function(){ return Galaxy.currHistoryPanel.model.hdas.at( 0 ).set( 'state', 'ok' ); }); - this.wait( 500, function(){ - var hdaTitle = '#' + testUploadInfo.hdaElement.attributes.id - + ' ' + this.historypanel.data.selectors.hda.title; - this.click( hdaTitle ); - }); }); + this.wait( 1000 ); }); - +/* +*/ // =================================================================== spaceghost.run( function(){ diff -r 51d3a88f45ee2e3aa89395d2df13b5452d463274 -r f19741fdb9a6b6f15f3e9b983d4a8228b205ffda test/casperjs/history-options-tests.js --- /dev/null +++ b/test/casperjs/history-options-tests.js @@ -0,0 +1,145 @@ +// 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 + }); + + spaceghost.start(); + +} catch( error ){ + console.debug( error ); + phantom.exit( 1 ); +} + +// =================================================================== +/* TODO: + possibly break this file up +*/ +// =================================================================== globals and helpers +var email = spaceghost.user.getRandomEmail(), + password = '123456'; +if( spaceghost.fixtureData.testUser ){ + email = spaceghost.fixtureData.testUser.email; + password = spaceghost.fixtureData.testUser.password; + spaceghost.info( 'Will use fixtureData.testUser: ' + email ); +} + +// selectors and labels +var includeDeletedOptionsLabel = spaceghost.historyoptions.data.labels.options.includeDeleted; + +// local +var filepathToUpload = '../../test-data/1.txt', + testUploadInfo = {}; + + +// =================================================================== TESTS +// ------------------------------------------------------------------- set up +// start a new user +spaceghost.user.loginOrRegisterUser( email, password ); + +spaceghost.tools.uploadFile( filepathToUpload, function uploadCallback( _uploadInfo ){ + testUploadInfo = _uploadInfo; +}); + +// ------------------------------------------------------------------- history options menu structure +//NOTE: options menu should be functionally tested elsewhere +spaceghost.historypanel.waitForHdas().then( function checkHistoryOptions(){ + this.test.comment( 'History options icon should be in place and menu should have the proper structure' ); + + // check the button and icon + this.test.assertExists( this.historyoptions.data.selectors.button, "Found history options button" ); + this.test.assertVisible( this.historyoptions.data.selectors.button, "History options button is visible" ); + this.test.assertVisible( this.historyoptions.data.selectors.buttonIcon, "History options icon is visible" ); + + // open the menu + this.click( this.historyoptions.data.selectors.button ); + this.test.assertVisible( this.historyoptions.data.selectors.menu, + "Menu is visible when options button is clicked" ); + + // check the options + var historyOptions = this.historyoptions.data.labels.options; + for( var optionKey in historyOptions ){ + if( historyOptions.hasOwnProperty( optionKey ) ){ + var optionLabel = historyOptions[ optionKey ]; + this.test.assertVisible( this.historyoptions.data.selectors.optionXpathByLabelFn( optionLabel ), + 'Option label is visible: ' + optionLabel ); + } + } + + // clear the menu + this.click( 'body' ); + this.test.assertNotVisible( this.historyoptions.data.selectors.menu, + "Clicking away from the menu closes it" ); +}); + +// ------------------------------------------------------------------- options allow showing/hiding deleted hdas +spaceghost.then( function(){ + this.test.comment( 'Deleting HDA' ); + var uploadSelector = '#' + testUploadInfo.hdaElement.attributes.id; + + this.historypanel.deleteHda( uploadSelector, function(){ + this.test.assertNotExists( uploadSelector, "Deleted HDA is NOT in the DOM" ); + }); +}); + +spaceghost.then( function(){ + this.test.comment( 'History options->' + includeDeletedOptionsLabel + ' shows deleted datasets' ); + var uploadSelector = '#' + testUploadInfo.hdaElement.attributes.id; + + this.historyoptions.includeDeleted( function(){ + this.test.assertExists( uploadSelector, + "Deleted HDA is in the DOM (using history options -> " + includeDeletedOptionsLabel + ")" ); + this.test.assertVisible( uploadSelector, + "Deleted HDA is visible again (using history options -> " + includeDeletedOptionsLabel + ")" ); + }); +}); + +spaceghost.then( function(){ + this.test.comment( 'History options->' + includeDeletedOptionsLabel + ' (again) re-hides deleted datasets' ); + + this.historyoptions.excludeDeleted( function(){ + this.test.assertDoesntExist( '#' + testUploadInfo.hdaElement.attributes.id, + "Deleted HDA is not in the DOM (using history options -> " + includeDeletedOptionsLabel + ")" ); + }); + // undelete the uploaded file + this.historypanel.undeleteHda( '#' + testUploadInfo.hdaElement.attributes.id ); +}); + +// ------------------------------------------------------------------- hidden hdas aren't shown +// ------------------------------------------------------------------- history options allows showing hidden hdas +// can't test this yet w/o a way to make hdas hidden thru the ui or api + + +// ------------------------------------------------------------------- history options collapses all expanded hdas +spaceghost.then( function(){ + this.historypanel.thenExpandHda( '#' + testUploadInfo.hdaElement.attributes.id ); +}); +spaceghost.then( function(){ + this.test.comment( 'History option collapses all expanded hdas' ); + + this.historyoptions.collapseExpanded( function(){ + var uploadedSelector = '#' + testUploadInfo.hdaElement.attributes.id; + this.withHistoryPanel( function(){ + this.test.assertNotVisible( uploadedSelector + ' ' + this.historypanel.data.selectors.hda.body, + "Body for uploaded file is not visible" ); + }); + }); +}); + +// =================================================================== +spaceghost.run( function(){ + this.test.done(); +}); diff -r 51d3a88f45ee2e3aa89395d2df13b5452d463274 -r f19741fdb9a6b6f15f3e9b983d4a8228b205ffda test/casperjs/history-panel-tests.js --- a/test/casperjs/history-panel-tests.js +++ b/test/casperjs/history-panel-tests.js @@ -72,177 +72,164 @@ // ------------------------------------------------------------------- set up // start a new user spaceghost.user.loginOrRegisterUser( email, password ); -//??: why is a reload needed here? If we don't, loggedInAs === '' ... -spaceghost.thenOpen( spaceghost.baseUrl, function(){ - var loggedInAs = spaceghost.user.loggedInAs(); - this.test.assert( loggedInAs === email, 'loggedInAs() matches email: "' + loggedInAs + '"' ); + +// ------------------------------------------------------------------- check structure of empty history +spaceghost.thenOpen( spaceghost.baseUrl ).historypanel.waitForHdas( function(){ + this.test.comment( 'history panel with a new, empty history should be well formed' ); + this.test.comment( "frame should have proper url and title: 'History'" ); + this.test.assertMatch( this.getCurrentUrl(), /\/history/, 'Found history frame url' ); + this.test.assertTitle( this.getTitle(), 'History', 'Found history frame title' ); + + this.test.comment( "history name should exist, be visible, and have text " + unnamedName ); + this.test.assertExists( nameSelector, nameSelector + ' exists' ); + this.test.assertVisible( nameSelector, 'History name is visible' ); + this.test.assertSelectorHasText( nameSelector, unnamedName, 'History name is ' + unnamedName ); + + this.test.comment( "history subtitle should display size and size should be: " + initialSizeStr ); + this.test.assertExists( subtitleSelector, 'Found ' + subtitleSelector ); + this.test.assertVisible( subtitleSelector, 'History subtitle is visible' ); + this.test.assertSelectorHasText( subtitleSelector, initialSizeStr, + 'History subtitle has "' + initialSizeStr + '"' ); + + this.test.comment( "tags and annotation icons should be available" ); + this.test.assertExists( tagIconSelector, 'Tag icon button found' ); + this.test.assertExists( annoIconSelector, 'Annotation icon button found' ); + + this.test.comment( "A message about the current history being empty should be displayed" ); + this.test.assertExists( emptyMsgSelector, emptyMsgSelector + ' exists' ); + this.test.assertVisible( emptyMsgSelector, 'Empty history message is visible' ); + this.test.assertSelectorHasText( emptyMsgSelector, emptyMsgStr, + 'Message contains "' + emptyMsgStr + '"' ); }); -// grab the history frame bounds for later mouse tests -spaceghost.then( function(){ - historyFrameInfo = this.getElementInfo( 'iframe[name="galaxy_history"]' ); - //this.debug( 'historyFrameInfo:' + this.jsonStr( historyFrameInfo ) ); -}); +// ------------------------------------------------------------------- name editing +spaceghost.withHistoryPanel( function(){ + this.test.comment( 'history panel, editing the history name' ); -// ------------------------------------------------------------------- check structure of empty history -spaceghost.thenOpen( spaceghost.baseUrl, function testPanelStructure(){ - this.test.comment( 'history panel, new history' ); - this.withFrame( spaceghost.data.selectors.frames.history, function(){ - this.test.comment( "frame should have proper url and title: 'History'" ); - this.test.assertMatch( this.getCurrentUrl(), /\/history/, 'Found history frame url' ); - this.test.assertTitle( this.getTitle(), 'History', 'Found history frame title' ); + this.test.comment( 'name should have a tooltip with proper info on name editing' ); + this.historypanel.hoverOver( nameSelector ); + this.test.assertExists( tooltipSelector, "Found tooltip after name hover" ); + this.test.assertSelectorHasText( tooltipSelector, nameTooltip ); + // clear the tooltip + this.page.sendEvent( 'mousemove', -1, -1 ); - this.test.comment( "history name should exist, be visible, and have text " + unnamedName ); - this.test.assertExists( nameSelector, nameSelector + ' exists' ); - this.test.assertVisible( nameSelector, 'History name is visible' ); - this.test.assertSelectorHasText( nameSelector, unnamedName, 'History name is ' + unnamedName ); + this.test.comment( 'name should be create an input when clicked' ); + this.assertHasClass( nameSelector, editableTextClass, "Name field classed for editable text" ); + this.click( nameSelector ); + this.test.assertExists( editableTextInput, "Clicking on name creates an input" ); - this.test.comment( "history subtitle should display size and size should be: " + initialSizeStr ); - this.test.assertExists( subtitleSelector, 'Found ' + subtitleSelector ); - this.test.assertVisible( subtitleSelector, 'History subtitle is visible' ); - this.test.assertSelectorHasText( subtitleSelector, initialSizeStr, - 'History subtitle has "' + initialSizeStr + '"' ); - - this.test.comment( "tags and annotation icons should be available" ); - this.test.assertExists( tagIconSelector, 'Tag icon button found' ); - this.test.assertExists( annoIconSelector, 'Annotation icon button found' ); - - this.test.comment( "A message about the current history being empty should be displayed" ); - this.test.assertExists( emptyMsgSelector, emptyMsgSelector + ' exists' ); - this.test.assertVisible( emptyMsgSelector, 'Empty history message is visible' ); - this.test.assertSelectorHasText( emptyMsgSelector, emptyMsgStr, - 'Message contains "' + emptyMsgStr + '"' ); + this.test.comment( 'name should be editable by entering keys and pressing enter' ); + //NOTE: casperjs.sendKeys adds a click before and a selector.blur after sending - won't work here + this.page.sendEvent( 'keypress', newHistoryName ); + this.page.sendEvent( 'keypress', this.page.event.key.Enter ); + // wait for send and re-render name + this.wait( 1000, function(){ + this.test.assertSelectorHasText( nameSelector, newHistoryName, 'History name is ' + newHistoryName ); + this.test.assertDoesntExist( editableTextInput, "Input disappears after pressing enter" ); }); }); -// ------------------------------------------------------------------- name editing -spaceghost.then( function(){ - this.test.comment( 'history panel, editing the history name' ); - this.withFrame( spaceghost.data.selectors.frames.history, function(){ - this.test.comment( 'name should have a tooltip with proper info on name editing' ); - var nameInfo = this.getElementInfo( nameSelector ); - this.page.sendEvent( 'mousemove', historyFrameInfo.x + nameInfo.x + 1, historyFrameInfo.y + nameInfo.y + 1 ); - this.test.assertExists( tooltipSelector, "Found tooltip after name hover" ); - this.test.assertSelectorHasText( tooltipSelector, nameTooltip ); +spaceghost.withHistoryPanel( function(){ + this.test.comment( 'name should revert if user clicks away while editing' ); - this.test.comment( 'name should be create an input when clicked' ); - this.assertHasClass( nameSelector, editableTextClass, "Name field classed for editable text" ); - this.click( nameSelector ); - this.test.assertExists( editableTextInput, "Clicking on name creates an input" ); + this.click( nameSelector ); + this.page.sendEvent( 'keypress', "Woodchipper metagenomics, Fargo, ND" ); - this.test.comment( 'name should be editable by entering keys and pressing enter' ); - //NOTE: casperjs.sendKeys adds a click before and a selector.blur after sending - won't work here - this.page.sendEvent( 'keypress', newHistoryName ); - this.page.sendEvent( 'keypress', this.page.event.key.Enter ); - this.wait( 1000, function(){ - this.test.assertSelectorHasText( nameSelector, newHistoryName, 'History name is ' + newHistoryName ); - this.test.assertDoesntExist( editableTextInput, "Input disappears after pressing enter" ); - }); + this.page.sendEvent( 'mousedown', -1, -1 ); + this.wait( 1000, function(){ + this.test.assertSelectorHasText( nameSelector, newHistoryName, 'History name is STILL ' + newHistoryName ); + this.test.assertDoesntExist( editableTextInput, "Input disappears after clicking away" ); }); }); -spaceghost.then( function(){ - this.withFrame( spaceghost.data.selectors.frames.history, function(){ - this.test.comment( 'name should revert if user clicks away while editing' ); - this.click( nameSelector ); - this.page.sendEvent( 'keypress', "Woodchipper metagenomics, Fargo, ND" ); - // click above the name input element - var inputInfo = this.getElementInfo( editableTextInput ); - this.page.sendEvent( 'mousedown', historyFrameInfo.x + inputInfo.x + 1, historyFrameInfo.y + inputInfo.y - 5 ); +spaceghost.withHistoryPanel( function(){ + this.test.comment( 'name should revert if user hits ESC while editing' ); - this.wait( 1000, function(){ - this.test.assertSelectorHasText( nameSelector, newHistoryName, 'History name is STILL ' + newHistoryName ); - this.test.assertDoesntExist( editableTextInput, "Input disappears after clicking away" ); - }); - }); -}); -spaceghost.then( function(){ - this.withFrame( spaceghost.data.selectors.frames.history, function(){ - this.test.comment( 'name should revert if user hits ESC while editing' ); - this.click( nameSelector ); - this.page.sendEvent( 'keypress', "Arsenic Bacteria" ); + this.click( nameSelector ); + this.page.sendEvent( 'keypress', "Arsenic Bacteria" ); - this.page.sendEvent( 'keypress', this.page.event.key.Escape ); - this.wait( 1000, function(){ - this.test.assertSelectorHasText( nameSelector, newHistoryName, 'History name is STILL ' + newHistoryName ); - this.test.assertDoesntExist( editableTextInput, "Input disappears after hitting ESC" ); - }); + this.page.sendEvent( 'keypress', this.page.event.key.Escape ); + this.wait( 1000, function(){ + this.test.assertSelectorHasText( nameSelector, newHistoryName, 'History name is STILL ' + newHistoryName ); + this.test.assertDoesntExist( editableTextInput, "Input disappears after hitting ESC" ); }); }); // ------------------------------------------------------------------- check structure of NON empty history // upload file: 1.txt -spaceghost.then( function upload(){ +spaceghost.tools.uploadFile( filepathToUpload, function uploadCallback( _uploadInfo ){ this.test.comment( 'uploaded file should appear in history' ); - spaceghost.tools.uploadFile( filepathToUpload, function uploadCallback( _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 ); - testUploadInfo = _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 ); + testUploadInfo = _uploadInfo; }); -spaceghost.then( function checkPanelStructure(){ +spaceghost.withHistoryPanel( function checkPanelStructure(){ this.test.comment( 'checking structure of non-empty panel' ); - this.withFrame( spaceghost.data.selectors.frames.history, function(){ - this.test.comment( "history name should exist, be visible, and have text " + unnamedName ); - this.test.assertExists( nameSelector, nameSelector + ' exists' ); - this.test.assertVisible( nameSelector, 'History name is visible' ); - this.test.assertSelectorHasText( nameSelector, newHistoryName, 'History name is ' + newHistoryName ); + this.test.comment( "history name should exist, be visible, and have text " + unnamedName ); + this.test.assertExists( nameSelector, nameSelector + ' exists' ); + this.test.assertVisible( nameSelector, 'History name is visible' ); + this.test.assertSelectorHasText( nameSelector, newHistoryName, 'History name is ' + newHistoryName ); - this.test.comment( "history subtitle should display size and size should be " + onetxtFilesize + " bytes" ); - var onetxtFilesize = require( 'fs' ).size( this.options.scriptDir + filepathToUpload ), - expectedSubtitle = onetxtFilesize + ' bytes'; - this.test.assertExists( subtitleSelector, 'Found ' + subtitleSelector ); - this.test.assertVisible( subtitleSelector, 'History subtitle is visible' ); - this.test.assertSelectorHasText( subtitleSelector, expectedSubtitle, - 'History subtitle has "' + expectedSubtitle + '"' ); + this.test.comment( "history subtitle should display size and size should be " + onetxtFilesize + " bytes" ); + var onetxtFilesize = require( 'fs' ).size( this.options.scriptDir + filepathToUpload ), + expectedSubtitle = onetxtFilesize + ' bytes'; + this.test.assertExists( subtitleSelector, 'Found ' + subtitleSelector ); + this.test.assertVisible( subtitleSelector, 'History subtitle is visible' ); + this.test.assertSelectorHasText( subtitleSelector, expectedSubtitle, + 'History subtitle has "' + expectedSubtitle + '": ' + this.fetchText( subtitleSelector ).trim() ); - this.test.comment( "tags and annotation icons should be available" ); - this.test.assertExists( tagIconSelector, 'Tag icon button found' ); - this.test.assertExists( annoIconSelector, 'Annotation icon button found' ); + this.test.comment( "tags and annotation icons should be available" ); + this.test.assertExists( tagIconSelector, 'Tag icon button found' ); + this.test.assertExists( annoIconSelector, 'Annotation icon button found' ); - this.test.comment( "A message about the current history being empty should NOT be displayed" ); - this.test.assertExists( emptyMsgSelector, emptyMsgSelector + ' exists' ); - this.test.assertNotVisible( emptyMsgSelector, 'Empty history message is NOT visible' ); - }); + this.test.comment( "A message about the current history being empty should NOT be displayed" ); + this.test.assertExists( emptyMsgSelector, emptyMsgSelector + ' exists' ); + this.test.assertNotVisible( emptyMsgSelector, 'Empty history message is NOT visible' ); }); // ------------------------------------------------------------------- tags // keeping this light here - better for it's own test file //TODO: check tooltips -spaceghost.then( function openTags(){ +spaceghost.withHistoryPanel( function openTags(){ this.test.comment( 'tag area should open when the history panel tag icon is clicked' ); - this.withFrame( spaceghost.data.selectors.frames.history, function(){ - this.mouseEvent( 'click', tagIconSelector ); - this.wait( 1000, function(){ - this.test.assertVisible( tagAreaSelector, 'Tag area is now displayed' ); - }); + + this.click( tagIconSelector ); + this.wait( 1000, function(){ + this.test.assertVisible( tagAreaSelector, 'Tag area is now displayed' ); + }); +}); +spaceghost.withHistoryPanel( function closeAnnotation(){ + this.test.comment( 'annotation area should close when the history panel tag icon is clicked again' ); + + this.click( tagIconSelector ); + this.wait( 1000, function(){ + this.test.assertNotVisible( tagAreaSelector, 'Tag area is now hidden' ); }); }); // ------------------------------------------------------------------- annotation // keeping this light here - better for it's own test file //TODO: check tooltips -spaceghost.then( function openAnnotation(){ +spaceghost.withHistoryPanel( function openAnnotation(){ this.test.comment( 'annotation area should open when the history panel annotation icon is clicked' ); - this.withFrame( spaceghost.data.selectors.frames.history, function(){ - this.mouseEvent( 'click', annoIconSelector ); - this.wait( 1000, function(){ - this.test.assertVisible( annoAreaSelector, 'Annotation area is now displayed' ); - }); + + this.click( annoIconSelector ); + this.wait( 1000, function(){ + this.test.assertVisible( annoAreaSelector, 'Annotation area is now displayed' ); }); }); -spaceghost.then( function closeAnnotation(){ +spaceghost.withHistoryPanel( function closeAnnotation(){ this.test.comment( 'annotation area should close when the history panel tag icon is clicked again' ); - this.withFrame( spaceghost.data.selectors.frames.history, function bler(){ - this.mouseEvent( 'click', annoIconSelector ); - this.wait( 1000, function(){ - this.test.assertNotVisible( annoAreaSelector, 'Tag area is now hidden' ); - }); + + this.click( annoIconSelector ); + this.wait( 1000, function(){ + this.test.assertNotVisible( annoAreaSelector, 'Annotation area is now hidden' ); }); }); @@ -261,96 +248,16 @@ }); }); -// ------------------------------------------------------------------- history options menu structure -//NOTE: options menu should be functionally tested elsewhere -spaceghost.then( function historyOptions(){ - this.test.comment( 'History options icon should be in place and menu should have the proper structure' ); - - // check the button and icon - this.test.assertExists( this.historyoptions.data.selectors.button, "Found history options button" ); - this.test.assertVisible( this.historyoptions.data.selectors.button, "History options button is visible" ); - this.test.assertVisible( this.historyoptions.data.selectors.buttonIcon, "History options icon is visible" ); - - // open the menu - this.click( this.historyoptions.data.selectors.button ); - this.test.assertVisible( this.historyoptions.data.selectors.menu, - "Menu is visible when options button is clicked" ); - - // check the options - for( var optionKey in this.historyoptions.data.labels.options ){ - if( this.historyoptions.data.labels.options.hasOwnProperty( optionKey ) ){ - var optionLabel = this.historyoptions.data.labels.options[ optionKey ], - optionXpath = this.historyoptions.data.selectors.optionXpathByLabelFn( optionLabel ); - this.test.assertVisible( optionXpath, 'Option label is visible: ' + optionLabel ); - } - } -}); - -// ------------------------------------------------------------------- deleted hdas aren't in the dom -spaceghost.then( function(){ - this.test.comment( 'deleted hdas shouldn\'t be in the history panel DOM' ); - - this.historypanel.deleteHda( '#' + testUploadInfo.hdaElement.attributes.id, function(){ - this.test.assertDoesntExist( '#' + testUploadInfo.hdaElement.attributes.id, - "Deleted HDA is not in the DOM" ); - }); -}); - -// ------------------------------------------------------------------- options allow showing/hiding deleted hdas -spaceghost.then( function(){ - this.test.comment( 'History options->' + includeDeletedOptionsLabel + ' shows deleted datasets' ); - - this.historyoptions.includeDeleted(); - this.withFrame( spaceghost.data.selectors.frames.history, function(){ - this.waitForSelector( nameSelector, function(){ - this.test.assertExists( '#' + testUploadInfo.hdaElement.attributes.id, - "Deleted HDA is in the DOM (using history options -> " + includeDeletedOptionsLabel + ")" ); - this.test.assertVisible( '#' + testUploadInfo.hdaElement.attributes.id, - "Deleted HDA is visible again (using history options -> " + includeDeletedOptionsLabel + ")" ); - }); - }); -}); - -spaceghost.then( function(){ - this.test.comment( 'History options->' + includeDeletedOptionsLabel + ' (again) re-hides deleted datasets' ); - - this.historyoptions.includeDeleted(); - this.withFrame( spaceghost.data.selectors.frames.history, function(){ - this.waitForSelector( nameSelector, function(){ - this.test.assertDoesntExist( '#' + testUploadInfo.hdaElement.attributes.id, - "Deleted HDA is not in the DOM (using history options -> " + includeDeletedOptionsLabel + ")" ); - }); - }); -}); - -// undelete the uploaded file -spaceghost.then( function(){ - this.historyoptions.includeDeleted(); - this.withFrame( spaceghost.data.selectors.frames.history, function(){ - this.waitForSelector( nameSelector, function(){ - //TODO: to conv. fn - this.click( '#' + testUploadInfo.hdaElement.attributes.id - + ' ' + this.historypanel.data.selectors.history.undeleteLink ); - }); - }); -}); - -// ------------------------------------------------------------------- hidden hdas aren't shown -// ------------------------------------------------------------------- history options allows showing hidden hdas -// can't test this yet w/o a way to make hdas hidden thru the ui or api - // ------------------------------------------------------------------- hdas can be expanded by clicking on the hda name // broken in webkit w/ jq 1.7 -spaceghost.then( function(){ +spaceghost.historypanel.waitForHdas( function(){ this.test.comment( 'HDAs can be expanded by clicking on the name' ); var uploadedSelector = '#' + testUploadInfo.hdaElement.attributes.id; - this.withFrame( spaceghost.data.selectors.frames.history, function(){ - this.click( uploadedSelector + ' .historyItemTitle' ); - this.wait( 1000, function(){ - this.test.assertVisible( uploadedSelector + ' ' + this.historypanel.data.selectors.hda.body, - "Body for uploaded file is visible" ); - }); + this.click( uploadedSelector + ' ' + this.historypanel.data.selectors.hda.title ); + this.wait( 1000, function(){ + this.test.assertVisible( uploadedSelector + ' ' + this.historypanel.data.selectors.hda.body, + "Body for uploaded file is visible" ); }); }); @@ -360,26 +267,22 @@ var uploadedSelector = '#' + testUploadInfo.hdaElement.attributes.id; this.click( refreshButtonSelector ); - this.withFrame( spaceghost.data.selectors.frames.history, function(){ - this.waitForSelector( nameSelector, function(){ - this.test.assertVisible( uploadedSelector + ' ' + this.historypanel.data.selectors.hda.body, - "Body for uploaded file is visible" ); - }); + this.historypanel.waitForHdas( function(){ + this.test.assertVisible( uploadedSelector + ' ' + this.historypanel.data.selectors.hda.body, + "Body for uploaded file is visible" ); }); // this will break: webkit + jq 1.7 }); // ------------------------------------------------------------------- expanded hdas collapse by clicking name again -spaceghost.then( function(){ +spaceghost.withHistoryPanel( function(){ this.test.comment( 'Expanded hdas collapse by clicking name again' ); var uploadedSelector = '#' + testUploadInfo.hdaElement.attributes.id; - this.withFrame( spaceghost.data.selectors.frames.history, function(){ - this.click( uploadedSelector + ' ' + this.historypanel.data.selectors.hda.title ); - this.wait( 500, function(){ - this.test.assertNotVisible( uploadedSelector + ' ' + this.historypanel.data.selectors.hda.body, - "Body for uploaded file is not visible" ); - }); + this.click( uploadedSelector + ' ' + this.historypanel.data.selectors.hda.title ); + this.wait( 500, function(){ + this.test.assertNotVisible( uploadedSelector + ' ' + this.historypanel.data.selectors.hda.body, + "Body for uploaded file is not visible" ); }); }); @@ -389,32 +292,9 @@ var uploadedSelector = '#' + testUploadInfo.hdaElement.attributes.id; this.click( refreshButtonSelector ); - this.withFrame( spaceghost.data.selectors.frames.history, function(){ - this.waitForSelector( nameSelector, function(){ - this.test.assertNotVisible( uploadedSelector + ' ' + this.historypanel.data.selectors.hda.body, - "Body for uploaded file is not visible" ); - }); - }); -}); - -// ------------------------------------------------------------------- history options collapses all expanded hdas -spaceghost.then( function(){ - // expand again - this.withFrame( spaceghost.data.selectors.frames.history, function(){ - this.click( '#' + testUploadInfo.hdaElement.attributes.id + ' ' + this.historypanel.data.selectors.hda.title ); - this.wait( 500, function(){}); - }); -}); -spaceghost.then( function(){ - this.test.comment( 'History option collapses all expanded hdas' ); - var uploadedSelector = '#' + testUploadInfo.hdaElement.attributes.id; - - this.historyoptions.collapseExpanded(); - this.wait( 500, function(){ - this.withFrame( spaceghost.data.selectors.frames.history, function(){ - this.test.assertNotVisible( uploadedSelector + ' ' + this.historypanel.data.selectors.hda.body, - "Body for uploaded file is not visible" ); - }); + this.historypanel.waitForHdas( function(){ + this.test.assertNotVisible( uploadedSelector + ' ' + this.historypanel.data.selectors.hda.body, + "Body for uploaded file is not visible" ); }); }); diff -r 51d3a88f45ee2e3aa89395d2df13b5452d463274 -r f19741fdb9a6b6f15f3e9b983d4a8228b205ffda test/casperjs/login-tests.js --- a/test/casperjs/login-tests.js +++ b/test/casperjs/login-tests.js @@ -39,6 +39,8 @@ password = spaceghost.fixtureData.testUser.password; } +var userEmailSelector = '//a[contains(text(),"Logged in as")]/span["id=#user-email"]'; + // =================================================================== TESTS // register a user (again...) spaceghost.thenOpen( spaceghost.baseUrl, function(){ @@ -52,8 +54,7 @@ spaceghost.user.logout(); }); spaceghost.then( function(){ - this.test.assertSelectorDoesntHaveText( - xpath( '//a[contains(text(),"Logged in as")]/span["id=#user-email"]' ), /\w/ ); + this.test.assertSelectorDoesntHaveText( xpath( userEmailSelector ), /\w/ ); this.test.assert( spaceghost.user.loggedInAs() === '', 'loggedInAs() is empty string' ); }); @@ -63,8 +64,7 @@ spaceghost.user._submitLogin( email, password ); //No such user }); spaceghost.thenOpen( spaceghost.baseUrl, function(){ - this.test.assertSelectorHasText( - xpath( '//a[contains(text(),"Logged in as")]/span["id=#user-email"]' ), email ); + this.test.assertSelectorHasText( xpath( userEmailSelector ), email ); this.test.assert( spaceghost.user.loggedInAs() === email, 'loggedInAs() matches email' ); }); diff -r 51d3a88f45ee2e3aa89395d2df13b5452d463274 -r f19741fdb9a6b6f15f3e9b983d4a8228b205ffda test/casperjs/modules/api.js --- /dev/null +++ b/test/casperjs/modules/api.js @@ -0,0 +1,231 @@ +// =================================================================== module object, exports +/** Creates a new api module object. + * @param {SpaceGhost} spaceghost a spaceghost instance + * @exported + */ +exports.create = function createAPI( spaceghost, apikey ){ + return new API( spaceghost ); +}; + +/** User object constructor. + * @param {SpaceGhost} spaceghost a spaceghost instance + * @param {String} apikey apikey for use when not using session authentication + */ +var API = function API( spaceghost, apikey ){ + this.spaceghost = spaceghost; + this.apikey = apikey; + + this.encodedIdExpectedLength = 16; + this.jQueryLocation = '../../static/scripts/libs/jquery/jquery.js'; + + this.histories = new HistoriesAPI( this ); + this.hdas = new HDAAPI( this ); +}; +exports.API = API; + +API.prototype.toString = function toString(){ + return ( this.spaceghost + '.API:' + + (( this.apikey )?( this.apikey ):( '(session)' )) ); +}; + +// ------------------------------------------------------------------- APIError +APIError.prototype = new Error(); +APIError.prototype.constructor = Error; +/** @class Thrown when Galaxy the API returns an error from a request */ +function APIError( msg ){ + Error.apply( this, arguments ); + this.name = "APIError"; + this.message = msg; +} +exports.APIError = APIError; + +/* ------------------------------------------------------------------- TODO: + can we component-ize this to become the basis for js-based api binding/resource + +*/ +// =================================================================== INTERNAL +var utils = require( 'utils' ); + +API.prototype._ajax = function _ajax( url, options ){ + options = options || {}; + options.async = false; + + this.ensureJQuery( '../../static/scripts/libs/jquery/jquery.js' ); + var resp = this.spaceghost.evaluate( function( url, options ){ + return jQuery.ajax( url, options ); + }, url, options ); + //this.spaceghost.debug( 'resp: ' + this.spaceghost.jsonStr( resp ) ); + + if( resp.status !== 200 ){ + // grrr... this doesn't lose the \n\r\t + throw new APIError( resp.responseText.replace( /[\s\n\r\t]+/gm, ' ' ).replace( /"/, '' ) ); + } + return JSON.parse( resp.responseText ); +}; + +// =================================================================== MISC +API.prototype.isEncodedId = function isEncodedId( id ){ + if( typeof id !== 'string' ){ return false; } + if( id.match( /[g-zG-Z]/ ) ){ return false; } + return ( id.length === this.encodedIdExpectedLength ); +}; + +// ------------------------------------------------------------------- is type or throw err +API.prototype.ensureId = function ensureId( id ){ + if( !this.isEncodedId( id ) ){ + throw new APIError( 'ID is not a valid encoded id: ' + id ); + } + return id; +}; + +API.prototype.ensureObject = function ensureObject( obj ){ + if( !utils.isObject( obj ) ){ + throw new APIError( 'Not a valid object: ' + obj ); + } + return obj; +}; + +// ------------------------------------------------------------------- jquery +// using jq for the ajax in this module - that's why these are here +//TODO:?? could go in spaceghost +API.prototype.hasJQuery = function hasJQuery(){ + return this.spaceghost.evaluate( function pageHasJQuery(){ + var has = false; + try { + has = typeof ( jQuery + '' ) === 'string'; + } catch( err ){} + return has; + }); +}; + +API.prototype.ensureJQuery = function ensureJQuery(){ + if( !this.hasJQuery() ){ + var absLoc = this.spaceghost.options.scriptDir + this.jQueryLocation, + injected = this.spaceghost.page.injectJs( absLoc ); + if( !injected ){ + throw new APIError( 'Could not inject jQuery' ); + } + } +}; + + +// =================================================================== HISTORIES +var HistoriesAPI = function HistoriesAPI( api ){ + this.api = api; +}; +HistoriesAPI.prototype.toString = function toString(){ + return this.api + '.HistoriesAPI'; +}; + +// ------------------------------------------------------------------- +HistoriesAPI.prototype.urlTpls = { + index : 'api/histories', + show : 'api/histories/%s', + create : 'api/histories', + delete_ : 'api/histories/%s', + undelete: 'api/histories/deleted/%s/undelete' +}; + +HistoriesAPI.prototype.index = function index( deleted ){ + this.api.spaceghost.info( 'history.index: ' + (( deleted )?( 'w deleted' ):( '(wo deleted)' )) ); + + deleted = deleted || false; + return this.api._ajax( this.urlTpls.index, { + data : { deleted: deleted } + }); +}; + +HistoriesAPI.prototype.show = function show( id, deleted ){ + this.api.spaceghost.info( 'history.show: ' + [ id, (( deleted )?( 'w deleted' ):( '' )) ] ); + + id = ( id === 'most_recently_used' )?( id ):( this.api.ensureId( id ) ); + deleted = deleted || false; + return this.api._ajax( utils.format( this.urlTpls.show, id ), { + data : { deleted: deleted } + }); +}; + +HistoriesAPI.prototype.create = function create( payload ){ + this.api.spaceghost.info( 'history.create: ' + this.api.spaceghost.jsonStr( payload ) ); + + // py.payload <-> ajax.data + payload = this.api.ensureObject( payload ); + return this.api._ajax( utils.format( this.urlTpls.create ), { + type : 'POST', + data : payload + }); +}; + +HistoriesAPI.prototype.delete_ = function delete_( id, purge ){ + this.api.spaceghost.info( 'history.delete: ' + [ id, (( purge )?( '(purge!)' ):( '' )) ] ); + + // py.payload <-> ajax.data + var payload = ( purge )?({ purge: true }):({}); + return this.api._ajax( utils.format( this.urlTpls.delete_, this.api.ensureId( id ) ), { + type : 'DELETE', + data : payload + }); +}; + +HistoriesAPI.prototype.undelete = function undelete( id ){ + //throw ( 'unimplemented' ); + this.api.spaceghost.info( 'history.undelete: ' + id ); + + return this.api._ajax( utils.format( this.urlTpls.undelete, this.api.ensureId( id ) ), { + type : 'POST' + }); +}; + + +// =================================================================== HDAS +var HDAAPI = function HDAAPI( api ){ + this.api = api; +}; +HDAAPI.prototype.toString = function toString(){ + return this.api + '.HDAAPI'; +}; + +// ------------------------------------------------------------------- +HDAAPI.prototype.urlTpls = { + index : 'api/histories/%s/contents', + show : 'api/histories/%s/contents/%s', + create : 'api/histories/%s/contents'//, + // not implemented + //delete_ : 'api/histories/%s', + //undelete: 'api/histories/deleted/%s/undelete' +}; + +HDAAPI.prototype.index = function index( historyId, ids ){ + this.api.spaceghost.info( 'history.index: ' + [ historyId, ids ] ); + var data = {}; + if( ids ){ + ids = ( utils.isArray( ids ) )?( ids.join( ',' ) ):( ids ); + data.ids = ids; + } + + return this.api._ajax( utils.format( this.urlTpls.index, this.api.ensureId( historyId ) ), { + data : data + }); +}; + +HDAAPI.prototype.show = function show( historyId, id, deleted ){ + this.api.spaceghost.info( 'history.show: ' + [ id, (( deleted )?( 'w deleted' ):( '' )) ] ); + + id = ( id === 'most_recently_used' )?( id ):( this.api.ensureId( id ) ); + deleted = deleted || false; + return this.api._ajax( utils.format( this.urlTpls.show, id ), { + data : { deleted: deleted } + }); +}; + +HDAAPI.prototype.create = function create( historyId, payload ){ + this.api.spaceghost.info( 'history.create: ' + this.api.spaceghost.jsonStr( payload ) ); + + // py.payload <-> ajax.data + payload = this.api.ensureObject( payload ); + return this.api._ajax( utils.format( this.urlTpls.create ), { + type : 'POST', + data : payload + }); +}; + diff -r 51d3a88f45ee2e3aa89395d2df13b5452d463274 -r f19741fdb9a6b6f15f3e9b983d4a8228b205ffda test/casperjs/modules/historyoptions.js --- a/test/casperjs/modules/historyoptions.js +++ b/test/casperjs/modules/historyoptions.js @@ -21,23 +21,65 @@ // ------------------------------------------------------------------- /* TODO: + some of the fns below can be applied to any popup */ +// =================================================================== internal +var xpath = require( 'casper' ).selectXPath; + // =================================================================== API (external) /** Just open the menu + * @param {Function} fn function to call when the menu opens + * @returns {Any} the return value of fn */ -HistoryOptions.prototype.openMenu = function openMenu(){ - this.spaceghost.click( this.data.selectors.button ); +HistoryOptions.prototype.openMenu = function openMenu( fn ){ + return this.spaceghost.jumpToTop( function(){ + this.click( this.historyoptions.data.selectors.button ); + return fn.call( this ); + }); }; /** Click an option by Label + * @param {String} optionLabel the label of the option to click (can be partial?) + * @returns {SpaceGhost} for chaining */ HistoryOptions.prototype.clickOption = function clickOption( optionLabel ){ - this.openMenu(); - // casperjs clickLabel - var optionXpath = this.data.selectors.optionXpathByLabelFn( optionLabel ); - this.spaceghost.click( optionXpath ); + this.openMenu( function(){ + this.click( this.historyoptions.data.selectors.optionXpathByLabelFn( optionLabel ) ); + // shouldnt need to clear - clicking an option will do that + }); + return this.spaceghost; +}; + +/** Is the history option with the given label showing as toggled? + * @param {String} optionLabel the label of the option to check (can be partial?) + * @returns {Boolean} true if the option is on, false if off OR not a toggle + */ +HistoryOptions.prototype.isOn = function isOn( optionLabel ){ + return this.openMenu( function(){ + var toggleIconInfo = this.elementInfoOrNull( + this.historyoptions.data.selectors.optionIsOnXpathByLabelFn( optionLabel ) ); + // have to clear manually + this.click( 'body' ); + return !!toggleIconInfo; + }); +}; + +/** Toggle the option - optionally forcing to on or off. + * @param {String} optionLabel the label of the option to check (can be partial?) + * @param {Boolean} force if true ensure option is on, if false ensure it's off, + * if undefined simply toggle + * @returns {Boolean} true if the option is now on, false if now off or not a toggle + */ +HistoryOptions.prototype.toggle = function toggle( optionLabel, force ){ + var isOn = this.isOn( optionLabel ); + if( ( force === false && isOn ) + || ( force === true && !isOn ) + || ( force === undefined ) ){ + return this.clickOption( optionLabel ); + } + return force; }; // ------------------------------------------------------------------- @@ -101,22 +143,68 @@ //}; -// ------------------------------------------------------------------- +// ------------------------------------------------------------------- check the togglable options // these are easy, one click options (they don't open a new page) +/** Is 'Include Deleted Datasets' on (accrd. to the menu)? + */ +HistoryOptions.prototype.deletedAreIncluded = function deletedAreIncluded(){ + return this.isOn( this.data.labels.options.includeDeleted ); +}; +/** Is 'Include Deleted Datasets' on (accrd. to the menu)? + */ +HistoryOptions.prototype.hiddenAreIncluded = function hiddenAreIncluded(){ + return this.isOn( this.data.labels.options.includeHidden ); +}; + +// ------------------------------------------------------------------- options that control the hpanel /** corresponds to history options menu: 'Collapse Expanded Datasets' */ -HistoryOptions.prototype.collapseExpanded = function collapseExpanded(){ - this.clickOption( this.data.labels.options.collapseExpanded ); +HistoryOptions.prototype.collapseExpanded = function collapseExpanded( then ){ + return this.spaceghost.then( function(){ + this.historyoptions.clickOption( this.historyoptions.data.labels.options.collapseExpanded ); + this.wait( 500, then ); + }); }; -/** corresponds to history options menu: 'Include Deleted Datasets' + +/** set 'Include Deleted Datasets' to on + * @param {Function} then casper step to run when option is set */ -HistoryOptions.prototype.includeDeleted = function includeDeleted(){ - this.clickOption( this.data.labels.options.includeDeleted ); +HistoryOptions.prototype.includeDeleted = function includeDeleted( then ){ + return this.spaceghost.then( function(){ + this.historyoptions.toggle( this.historyoptions.data.labels.options.includeDeleted, true ); + this.historypanel.waitForHdas( then ); + }); }; -/** corresponds to history options menu: 'Include Hidden Datasets' + +/** set 'Include Deleted Datasets' to off + * @param {Function} then casper step to run when option is set */ -HistoryOptions.prototype.includeHidden = function includeHidden(){ - this.clickOption( this.data.labels.options.includeHidden ); +HistoryOptions.prototype.excludeDeleted = function excludeDeleted( then ){ + return this.spaceghost.then( function(){ + this.historyoptions.toggle( this.historyoptions.data.labels.options.includeDeleted, false ); + //TODO:?? this puts in the history frame. Is that what we want? + this.historypanel.waitForHdas( then ); + }); +}; + +/** set 'Include Hidden Datasets' to on + * @param {Function} then casper step to run when option is set + */ +HistoryOptions.prototype.includeHidden = function includeHidden( then ){ + return this.spaceghost.then( function(){ + this.historyoptions.toggle( this.historyoptions.data.labels.options.includeHidden, true ); + this.historypanel.waitForHdas( then ); + }); +}; + +/** set 'Include Hidden Datasets' to off + * @param {Function} then casper step to run when option is set + */ +HistoryOptions.prototype.excludeHidden = function excludeHidden( then ){ + return this.spaceghost.then( function(){ + this.historyoptions.toggle( this.historyoptions.data.labels.options.includeHidden, false ); + this.historypanel.waitForHdas( then ); + }); }; @@ -129,6 +217,10 @@ menu : '#history-options-button-menu', optionXpathByLabelFn : function optionXpathByLabelFn( label ){ return xpath( '//ul[@id="history-options-button-menu"]/li/a[text()[contains(.,"' + label + '")]]' ); + }, + optionIsOnXpathByLabelFn : function optionIsOnXpathByLabelFn( label ){ + return xpath( '//ul[@id="history-options-button-menu"]/li/a[text()[contains(.,"' + label + '")]]' + + '/span[@class="fa-icon-ok"]' ); } }, labels : { This diff is so big that we needed to truncate the remainder. Repository URL: https://bitbucket.org/galaxy/galaxy-central/ -- This is a commit notification from bitbucket.org. You are receiving this because you have the service enabled, addressing the recipient of this email.
participants (1)
-
commits-noreply@bitbucket.org