def login(browser: Browser, email: str, password: str) -> None: """Log in through `/account/login` as the given user.""" browser.visit("/account/login") browser.fill_in("login", email) browser.fill_in("password", password) browser.click_button("Sign In") browser.wait_for_element("a", text="MY WORKFLOWS", wait=True)
def login(browser: Browser, email: str, password: str) -> None: """Log in through `/account/login` as the given user.""" browser.visit('/account/login') browser.fill_in('login', email) browser.fill_in('password', password) browser.click_button('Sign In') browser.wait_for_element('a', text='MY WORKFLOWS', wait=True)
def login(browser: Browser, email: str, password: str) -> None: """Log in through `/account/login` as the given user.""" # Selectors designed to work in any locale_id browser.visit("/account/login") browser.fill_in("login", email) browser.fill_in("password", password) browser.click_whatever('.account_form.login button[type="submit"]') browser.wait_for_element(".create-workflow")
def login(browser: Browser, email: str, password: str) -> None: """Log in through `/account/login` as the given user. The login page must be in `locale_id`, while the workflows page must be in `after_login_locale_id` """ browser.visit("/account/login") browser.fill_in("login", email) browser.fill_in("password", password) browser.click_whatever('.account_form.login button[type="submit"]') browser.wait_for_element(".create-workflow")
def import_workbench_module(browser: Browser, slug: str) -> None: """Import a module by clicking through the browser. Assumes there's a context menu with an "Import Module" modal. """ browser.click_button('menu', wait=True) # wait for page to load browser.click_button('Import Module') browser.fill_in('url', f'http://git-server/{slug}.git', wait=True) browser.click_button('Import') browser.wait_for_element('.import-github-success', wait=True) browser.click_button('OK')
def import_workbench_module(browser: Browser, slug: str) -> None: """ Import a module by clicking through the browser. Assumes there's a context menu with an "Import Module" modal. """ with browser.scope(".navbar", wait=True): # wait for page to load browser.click_button("menu") browser.click_button("Import Module") with browser.scope(".modal-dialog"): browser.fill_in("url", f"http://git-server/{slug}.git", wait=True) browser.click_button("Import") browser.wait_for_element(".import-github-success", text="Imported", wait=True) browser.click_button("×")
def import_workbench_module(browser: Browser, module_id: str) -> None: """ Import a module by clicking through the browser. Assumes there's a context menu with an "Import Module" modal. Side-effect: this will launch a singleton HTTP-server thread at http://module-zipfile-server:PORT, where PORT is an unused TCP port. """ server = _get_singleton_http_server() port = server.server_port path = ZIPFILE_PATHS[module_id] with browser.scope(".navbar", wait=True): # wait for page to load browser.click_button("menu") browser.click_button("Import Module") with browser.scope(".modal-dialog"): browser.fill_in("url", f"http://module-zipfile-server:{port}{path}", wait=True) browser.click_button("Import") browser.wait_for_element(".import-github-success", text="Imported", wait=True) browser.click_button("×")
class WorkbenchBase(unittest.TestCase): serve_static = True live_server_url = "http://frontend:8080" db_connect_str = "user=cjworkbench host=workbench-db password=cjworkbench" data_path = "/app" account_admin = accounts.AccountAdmin(live_server_url, db_connect_str, data_path) def setUp(self): super().setUp() self.account_admin.clear_data_from_previous_tests() self.browser = Browser(base_url=self.live_server_url) def tearDown(self): self.browser.quit() def create_browser(self): return Browser(base_url=self.live_server_url) # TODO move to a helper .py file def import_module(self, slug: str) -> None: import_workbench_module(self.browser, slug) # TODO move to a helper .py file def add_step(self, name: str, position=None) -> None: """Add module with name 'name' to the workflow. Keyword arguments: position -- if set, add after the 'position'th existing module. """ b = self.browser if position is None: with b.scope(".in-between-steps:last-child"): b.click_button("ADD STEP") else: assert position > 0 # for 0, use add_data_step(). i = position * 2 with b.scope(f".in-between-steps:nth-child({i})"): b.click_button("ADD STEP") # Search. That way, we won't need to worry about overflow:auto b.fill_in("moduleQ", name) b.click_whatever("button.module-search-result", text=name) b.assert_element(f'.step[data-module-name="{name}"]:not(.status-busy)', wait=True) # TODO move to a helper .py file def add_data_step(self, name: str) -> None: """Add module with name 'name' to the workflow. Assumes the 'Add Data' modal is open. """ b = self.browser b.fill_in("moduleQ", name) b.click_link(name) # Wait for module to appear and render b.assert_element(f'.step[data-module-name="{name}"]:not(.status-busy)', wait=True) # TODO move to a helper .py file def delete_step(self, position: int) -> None: """Delete module at index `position` from the workflow. The first module has `position == 0`. """ b = self.browser with b.scope(f".step:nth-child({position * 2 + 1})"): b.click_button("Delete") # TODO move to a helper .py file def add_csv_data_module(self, csv=None): """Add Paste Data module to the workflow with given data csv -- Text of csv. If not set, use default data. """ if csv is None: csv = "\n".join([ "Month,Amount,Name", "Jan,10,Alicia Aliciason", "Feb,666,Fred Frederson", ]) self.import_module("pastecsv") self.add_data_step("Paste data") self.browser.fill_in("csv", csv) self.submit_step() # TODO move to a helper .py file def select_column(self, module_name: str, name: str, text: str, **kwargs) -> None: """Select 'text' in the ColumnSelect box with name 'name'. Waits for '.loading' to disappear before filling in the text. Note: unlike browser.select(), this does _not_ handle id or label locators. Keyword arguments: wait -- True or number of seconds to wait until element appears """ with self.browser.scope( f'.step[data-module-name="{module_name}"] .param[data-name="{name}"]', **kwargs, ): self.browser.assert_element(".react-select:not(.loading)", wait=True) self.browser.click_whatever(".react-select__dropdown-indicator") self.browser.click_whatever(".react-select__option", text=text) # TODO move to a helper .py file def select_tab_param(self, module_name: str, name: str, text: str, **kwargs) -> None: """Select 'text' in the TabParam box with name 'name'. Note: unlike browser.select(), this does _not_ handle id or label locators. Keyword arguments: wait -- True or number of seconds to wait until element appears """ with self.browser.scope( f'.step[data-module-name="{module_name}"] .param[data-name="{name}"]', **kwargs, ): self.browser.click_whatever(".react-select__dropdown-indicator") self.browser.click_whatever(".react-select__option", text=text) def submit_step(self, **kwargs): """Click the submit button of the active Step. Keyword arguments: wait -- True or number of seconds to wait until element is ready """ self.browser.click_whatever( "form.module-card-params button[name=submit]:not(:disabled)", **kwargs)
class WorkbenchBase(unittest.TestCase): serve_static = True live_server_url = 'http://frontend:8080' db_connect_str = 'user=cjworkbench host=workbench-db password=cjworkbench' data_path = '/app' account_admin = accounts.AccountAdmin(live_server_url, db_connect_str, data_path) def setUp(self): super().setUp() self.account_admin.clear_data_from_previous_tests() # self.current_site = Site.objects.get_current() # self.SocialApp1 = self.current_site.socialapp_set.create( # provider="facebook", # name="Facebook", # client_id="1234567890", # secret="0987654321", # ) # self.SocialApp2 = self.current_site.socialapp_set.create( # provider="google", # name="Google", # client_id="1234567890", # secret="0987654321", # ) self.browser = Browser(base_url=self.live_server_url) def tearDown(self): self.browser.quit() def create_browser(self): return Browser(base_url=self.live_server_url) # TODO move to a helper .py file def import_module(self, slug: str) -> None: import_workbench_module(self.browser, slug) # TODO move to a helper .py file def add_wf_module(self, name: str, position=None) -> None: """Adds module with name 'name' to the workflow. Keyword arguments: position -- if set, add after the 'position'th existing module. """ b = self.browser if position is None: with b.scope('.in-between-modules:last-child'): b.click_button('ADD STEP') else: i = position * 2 + 1 with b.scope(f'.in-between-modules:nth-child({i})'): b.click_button('ADD STEP') # Search. That way, we won't need to worry about overflow:auto b.fill_in('moduleQ', name) b.click_whatever('button.module-search-result', text=name) b.assert_element( f'.wf-module[data-module-name="{name}"]:not(.status-busy)', wait=True) # TODO move to a helper .py file def delete_wf_module(self, position: int) -> None: """Deletes module at index `position` from the workflow. The first module has `position == 0`. """ b = self.browser with b.scope(f'.wf-module:nth-child({position * 2 + 2})'): b.click_button('more', visible='all') # Dropdown menu is at root of document (in a <Portal>) with b.scope('.dropdown-menu'): b.click_button('Delete') # TODO move to a helper .py file def add_csv_data_module(self, csv=None): """Adds Paste Data module to the workflow with given data csv -- Text of csv. If not set, use default data. """ if csv is None: csv = '\n'.join([ 'Month,Amount,Name', 'Jan,10,Alicia Aliciason', 'Feb,666,Fred Frederson', ]) self.browser.click_button('ADD STEP') self.browser.fill_in('moduleQ', 'Paste data') self.browser.click_whatever('.module-search-result', text='Paste data') # wait for wfmodule to appear self.browser.fill_in('csv', csv, wait=True) self.submit_wf_module() # TODO move to a helper .py file def select_column(self, module_name: str, name: str, text: str, **kwargs) -> None: """Selects 'text' in the ColumnSelect box with name 'name'. Waits for '.loading' to disappear before filling in the text. Note: unlike browser.select(), this does _not_ handle id or label locators. Keyword arguments: wait -- True or number of seconds to wait until element appears """ with self.browser.scope( (f'.wf-module[data-module-name="{module_name}"] ' f'.param[data-name="{name}"]'), **kwargs): self.browser.assert_element(f'.react-select:not(.loading)', wait=True) self.browser.click_whatever('.react-select__dropdown-indicator') self.browser.click_whatever('.react-select__option', text=text) # TODO move to a helper .py file def select_tab_param(self, module_name: str, name: str, text: str, **kwargs) -> None: """ Select 'text' in the TabParam box with name 'name'. Note: unlike browser.select(), this does _not_ handle id or label locators. Keyword arguments: wait -- True or number of seconds to wait until element appears """ with self.browser.scope( (f'.wf-module[data-module-name="{module_name}"] ' f'.param[data-name="{name}"]'), **kwargs): self.browser.click_whatever('.react-select__dropdown-indicator') self.browser.click_whatever('.react-select__option', text=text) def submit_wf_module(self, **kwargs): """ Click the submit button of the active WfModule. Keyword arguments: wait -- True or number of seconds to wait until element is ready """ self.browser.click_whatever( 'form.module-card-params button[name=submit]:not(:disabled)', **kwargs)