Exemplo n.º 1
0
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)
Exemplo n.º 2
0
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)
Exemplo n.º 3
0
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")
Exemplo n.º 4
0
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")
Exemplo n.º 5
0
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')
Exemplo n.º 6
0
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("×")
Exemplo n.º 7
0
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("×")
Exemplo n.º 8
0
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)
Exemplo n.º 9
0
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)