Exemple #1
0
 def test_control_lookup(self):
     self.browser.get(
         self.url("/controls/catalogs/NIST_SP-800-53_rev4/control/au-2"))
     wait_for_sleep_after(
         lambda: self.assertInNodeText("AU-2", "#control-heading"))
     wait_for_sleep_after(
         lambda: self.assertInNodeText("Audit Events", "#control-heading"))
Exemple #2
0
    def create_fill_statement_form(self, name, statement, part, status,
                                   statusvalue, remarks, num):
        """
        In the component statements tab create and then fill a new component statement with the given information.
        """

        self.click_components_tab()

        # Click to add new component statement
        self.click_element("#new_component_statement")

        # Open the new component form open
        try:
            new_comp_btn = self.browser.find_element_by_link_text(
                "New Component Statement")
        except:
            new_comp_btn = self.browser.find_element_by_id(
                f"producer_element-{num}-title")
        new_comp_btn.click()
        # Fill out form
        wait_for_sleep_after(lambda: self.browser.find_element_by_id(
            "producer_element_name").send_keys(name))

        self.browser.find_elements_by_name("body")[-1].send_keys(statement)
        self.browser.find_elements_by_name("pid")[-1].send_keys(part)
        select = self.dropdown_option(status)
        select.select_by_value(statusvalue)
        self.browser.find_elements_by_name("remarks")[-1].send_keys(remarks)
        # Save form
        self.browser.find_elements_by_name("save")[-1].click()
        self.browser.refresh()
 def start_invitation(username):
     # Fill out the invitation modal.
     # self.select_option_by_visible_text('#invite-user-select', username) # This is for selecting user from dropdown list
     wait_for_sleep_after(
         lambda: self.fill_field("input#invite-user-email", username))
     wait_for_sleep_after(lambda: self.click_element(
         "#invitation_modal button.btn-submit"))
    def test_display_impact_level(self):
        """ Tests for project page mini compliance dashboard """

        # Log in, create a new project.
        self._login()
        self._new_project()
        # On project page?
        wait_for_sleep_after(lambda: self.assertInNodeText(
            "I want to answer some questions", "#project-title"))

        # Display imact level testing
        # New project should not be categorized
        self.assertInNodeText("Mission Impact: Not Categorized",
                              "#systems-security-sensitivity-level")

        # Update impact level
        # Get project.system.root_element to attach statement holding fisma impact level
        project = self.current_project
        fil = "Low"
        # Test change and test system security_sensitivity_level set/get methods
        project.system.set_security_sensitivity_level(fil)
        # Check value changed worked
        self.assertEqual(project.system.get_security_sensitivity_level, fil)
        # Refresh project page
        self.click_element('#menu-btn-project-home')
        # See if project page has changed
        wait_for_sleep_after(lambda: self.assertInNodeText(
            "low", "#systems-security-sensitivity-level"))
        impact_level_smts = project.system.root_element.statements_consumed.filter(
            statement_type=StatementTypeEnum.SECURITY_SENSITIVITY_LEVEL.name)
        self.assertEqual(impact_level_smts.count(), 1)
Exemple #5
0
    def test_deployments_page_exists(self):

        # login as the first user and create a new project
        self._login()
        self._new_project()

        # systemid = System.objects.all().first()
        project = Project.objects.all().last()
        system = project.system

        self.navigateToPage(f"/systems/{system.id}/deployments")
        wait_for_sleep_after(lambda: self.assertInNodeText(
            "New Deployment", ".systems-element-button"))

        # # Add deault deployments to system
        deployment = Deployment(name="Training",
                                description="Training environment",
                                system=system)
        deployment.save()

        # Does new deployment appear on deployments list?
        self.navigateToPage(f"/systems/{system.id}/deployments")
        var_sleep(3)  # wait for page to open
        wait_for_sleep_after(lambda: self.assertInNodeText(
            "New Deployment", ".systems-element-button"))
    def _accept_invitation(self, username):
        # Assumes an invitation email was sent.

        # Extract the URL in the email and visit it.
        invitation_body = self.pop_email().body
        invitation_url_pattern = re.escape(self.url("/invitation/")) + r"\S+"
        self.assertRegex(invitation_body, invitation_url_pattern)
        m = re.search(invitation_url_pattern, invitation_body)
        self.browser.get(m.group(0))
        # Since we're not logged in, we hit the invitation splash page.
        wait_for_sleep_after(lambda: self.click_element('#button-sign-in'))
        wait_for_sleep_after(
            lambda: self.assertRegex(self.browser.title, "Sign In"))
Exemple #7
0
    def _new_project(self):
        self.browser.get(self.url("/projects"))
        self.click_element("#new-project")

        # Select Portfolio
        self.select_option_by_visible_text('#id_portfolio', self.user.username)
        self.click_element("#select_portfolio_submit")

        # Start a project
        wait_for_sleep_after(lambda: self.click_element(".app[data-app='project/simple_project'] .view-app"))
        # var_sleep(10.5)
        self.click_element("#start-project")
        # wait_for_sleep_after(lambda: self.click_element("#start-project"))
        wait_for_sleep_after(lambda: self.assertRegex(self.browser.title, "I want to answer some questions on Q."))
Exemple #8
0
    def _new_project(self):
        self.browser.get(self.url("/store"))

        # wait_for_sleep_after(lambda: self.click_element("#new-project-link-from-projects"))

        var_sleep(1)
        # Click Add Button
        wait_for_sleep_after(lambda: self.click_element(
            ".app-form[data-app='project/simple_project'] .start-app"))
        wait_for_sleep_after(lambda: self.assertRegex(
            self.browser.title, "I want to answer some questions on Q."))

        m = re.match(r"http://.*?/projects/(\d+)/", self.browser.current_url)
        self.current_project = Project.objects.get(id=m.group(1))
Exemple #9
0
    def test_import_tracker(self):
        """Tests that imports are tracked correctly."""

        self._login()
        url = self.url(f"/controls/components")  # component library
        self.browser.get(url)

        # Test initial import of Component(s) and Statement(s)
        self.click_element('a#import_records_link')

        current_path = urlparse(self.browser.current_url).path
        self.assertEqual('/controls/import_records', current_path)

        import_record_links = self.browser.find_elements_by_class_name(
            'import_record_detail_link')
        self.assertEqual(len(import_record_links), 0)

        # Create an Import Record with a component and statement
        helper = ControlTestHelper()
        helper.create_simple_import_record()

        self.browser.refresh()

        import_record_links = wait_for_sleep_after(
            lambda: self.browser.find_elements_by_class_name(
                'import_record_detail_link'))
        self.assertEqual(len(import_record_links), 1)
    def test_update_project_json_import(self):
        """
        Testing the update of a project through project JSON import and ingestion of components and their statements
        """

        # login as the first user and create a new project
        self._login()
        self._new_project()

        # Checks the number of projects and components before the import
        # The number of projects should be 2  to start:
        #  - the system project representing the organization (legacy)
        #  - the sample project created during setup of GovReady
        EXISTING_PROJECT_COUNT = 2
        self.assertEqual(Project.objects.all().count(), EXISTING_PROJECT_COUNT)
        self.assertEqual(
            Element.objects.all().exclude(element_type='system').count(), 0)

        ## Update current project
        # click import project button, opening the modal
        # wait_for_sleep_after(lambda: self.click_element("#menu-btn-project-import"))
        self.click_element("#menu-btn-project-import")

        file_input = self.browser.find_element_by_css_selector("#id_file")

        file_path = os.getcwd() + "/fixtures/test_project_import_data.json"
        # convert filepath if necessary and send keys
        self.filepath_conversion(file_input, file_path, "sendkeys")
        self.browser.find_element_by_id("import_project_submit").click()

        # Check the new number of projects, and validate that it's the same
        project_num = Project.objects.all().count()
        self.assertEqual(project_num, EXISTING_PROJECT_COUNT)
        # Has the updated name?
        wait_for_sleep_after(lambda: self.assertEqual(
            Project.objects.all()[project_num - 1].title, "New Test Project"))
        # Components and their statements?
        self.assertEqual(
            Element.objects.all().exclude(element_type='system').count(), 1)
        self.assertEqual(
            Element.objects.all().exclude(element_type='system')[0].name,
            "test component 1")

        try:
            self.assertEqual(Statement.objects.all().count(), 1)
        except:
            self.assertEqual(Statement.objects.all().count(), 4)
Exemple #11
0
    def test_update_project_json_import(self):
        """
        Testing the update of a project through project JSON import and ingestion of components and their statements
        """

        # login as the first user and create a new project
        self._login()
        self._new_project()

        # Checks the number of projects and components before the import
        self.assertEqual(Project.objects.all().count(), 3)
        self.assertEqual(
            Element.objects.all().exclude(element_type='system').count(), 0)

        ## Update current project
        # click import project button, opening the modal
        self.click_element("#btn-import-project")
        ## select through the modal information needed and browse for the import needed
        self.select_option_by_visible_text("#id_appsource_compapp", "project")

        # The selection variable found by id
        select = Select(
            self.browser.find_element_by_id("id_appsource_version_id"))
        # Select the last option by index
        selectLen = len(select.options)
        select.select_by_index(selectLen - 1)

        file_input = self.browser.find_element_by_css_selector("#id_file")

        file_path = os.getcwd() + "/fixtures/test_project_import_data.json"
        # convert filepath if necessary and send keys
        self.filepath_conversion(file_input, file_path, "sendkeys")
        self.browser.find_element_by_id("import_component_submit").click()

        # Check the new number of projects, and validate that it's the same
        project_num = Project.objects.all().count()
        self.assertEqual(project_num, 3)
        # Has the updated name?
        wait_for_sleep_after(lambda: self.assertEqual(
            Project.objects.all()[project_num - 1].title, "New Test Project"))
        # Components and their statements?
        self.assertEqual(
            Element.objects.all().exclude(element_type='system').count(), 1)
        try:
            self.assertEqual(Statement.objects.all().count(), 3)
        except:
            self.assertEqual(Statement.objects.all().count(), 6)
    def test_edit_portfolio(self):
        """
        Editing a portfolio's title and/or description provides appropriate validation and messaging
        """
        # journey to portfolios and ensure i have multiple portfolios if not then create new portfolios
        self._login()
        self.browser.get(self.url("/portfolios"))
        # Navigate to the portfolio form
        self.click_element_with_link_text("Portfolios")
        # Click Create Portfolio button
        self.click_element("#new-portfolio")
        var_sleep(0.5)
        # Fill in form
        wait_for_sleep_after(lambda: self.fill_field("#id_title", "Test 1"))
        self.fill_field("#id_description", "Test 1 portfolio")
        # Submit form
        self.click_element("#create-portfolio-button")
        # Test we are on portfolio page we just created
        var_sleep(0.35)
        wait_for_sleep_after(lambda: self.assertRegex(
            self.browser.title, "Test 1 Portfolio - GovReady-Q"))
        # Navigate to portfolios
        self.browser.get(self.url("/portfolios"))

        # Navigate to portfolios
        self.browser.get(self.url("/portfolios"))
        # Click on the pencil anchor tag to edit
        self.browser.find_elements_by_class_name(
            "portfolio-project-link")[-1].click()

        # Edit title to a real new name and press update
        self.clear_and_fill_field("#id_title", "new me")
        self.clear_and_fill_field("#id_description", "new me portfolio")
        # Submit form
        self.click_element("#edit_portfolio_submit")

        # Verify new portfolio name is listed under portfolios
        self.assertIn("new me", self._getNodeText("#portfolio_new\ me"))
        # Verify 'updated' message is correct
        self.assertIn("The portfolio 'new me' has been updated.",
                      self._getNodeText("div.alert.fade.in.alert-info"))

        # verify new description by journeying back to edit_form
        self.browser.find_elements_by_class_name(
            "portfolio-project-link")[-1].click()
Exemple #13
0
 def _upload_discussion_image(self, img_css_selector):
     """
     Upload an image in a discussion section
     """
     var_sleep(.5)
     self.click_element("#discussion .comment-input button.btn-primary")
     var_sleep(1.5)# Give time for the image to upload.
     img = wait_for_sleep_after(lambda: self.browser.find_element_by_css_selector(img_css_selector) )
     return img
    def test_portfolio_projects(self):
        """
        Ensure key parts of the portfolio page
        """
        # Login as authenticated user
        self.client.force_login(user=self.user)
        # Reset login
        self.browser.get(self.url("/accounts/logout/"))
        self._login()
        # If the above is not done a new project cannot be created
        self._new_project()

        portfolio_id = Project.objects.last().portfolio.id
        url = reverse('portfolio_projects', args=[portfolio_id])
        self.browser.get(self.url(url))

        wait_for_sleep_after(
            lambda: self.assertRegex(self.browser.title, "me-2 Portfolio"))
        self.assertInNodeText("I want to answer", '.portfolio-project-link')
Exemple #15
0
    def test_update_project_json_import(self):
        """
        Testing the update of a project through project JSON import and ingestion of components and their statements
        """

        # login as the first user and create a new project
        self._login()
        self._new_project()

        # Checks the number of projects and components before the import
        self.assertEqual(Project.objects.all().count(), 3)
        self.assertEqual(Element.objects.all().exclude(element_type='system').count(), 0)

        ## Update current project
        # click import project button, opening the modal
        self.click_element("#btn-import-project")


        file_input = self.browser.find_element_by_css_selector("#id_file")

        file_path = os.getcwd() + "/fixtures/test_project_import_data.json"
        # convert filepath if necessary and send keys
        self.filepath_conversion(file_input, file_path, "sendkeys")
        self.browser.find_element_by_id("import_component_submit").click()

        # Check the new number of projects, and validate that it's the same
        project_num = Project.objects.all().count()
        self.assertEqual(project_num, 3)
        # Has the updated name?
        wait_for_sleep_after(lambda: self.assertEqual(Project.objects.all()[project_num - 1].title, "New Test Project"))
        # Components and their statements?
        self.assertEqual(Element.objects.all().exclude(element_type='system').count(), 1)
        self.assertEqual(Element.objects.all().exclude(element_type='system')[0].name, "SecGet, Endpoint Security System")
        try:
            self.assertEqual(Statement.objects.all().count(), 4)
        except:
            self.assertEqual(Statement.objects.all().count(), 8)
Exemple #16
0
    def test_component_import_oscal_json(self):
        self._login()
        url = self.url(f"/controls/components")# component library
        self.browser.get(url)

        element_count_before_import = Element.objects.filter(element_type="system_element").count()
        statement_count_before_import = Statement.objects.filter(statement_type=StatementTypeEnum.CONTROL_IMPLEMENTATION_PROTOTYPE.value).count()

        # Test initial import of Component(s) and Statement(s)
        self.click_element('a#component-import-oscal')
        app_root = os.path.dirname(os.path.realpath(__file__))
        oscal_json_path = os.path.join(app_root, "data/test_data", "test_oscal_component.json")
        file_input = self.find_selected_option('input#id_file')
        oscal_json_path = self.filepath_conversion(file_input, oscal_json_path, "sendkeys")

        self.click_element('input#import_component_submit')
        var_sleep(2)
        element_count_after_import = wait_for_sleep_after(lambda: Element.objects.filter(element_type="system_element").count())

        wait_for_sleep_after(lambda: self.assertEqual(element_count_before_import + 2, element_count_after_import))

        statement_count_after_import = Statement.objects.filter(statement_type=StatementTypeEnum.CONTROL_IMPLEMENTATION_PROTOTYPE.value).count()
        self.assertEqual(statement_count_before_import + 4, statement_count_after_import)
        # Test file contains 6 Statements, but only 4 get imported
        # because one has an improper Catalog
        # and another has an improper Control
        # but we can't test individual statements because the UUIDs are randomly generated and not consistent
        # with the OSCAL JSON file. So we simply do a count.

        # Test that duplicate Components are re-imported with a different name and that Statements get reimported

        wait_for_sleep_after(lambda: self.click_element('a#component-import-oscal'))

        file_input = self.find_selected_option('input#id_file')
        # Using converted keys from above
        file_input.send_keys(oscal_json_path)

        self.click_element('input#import_component_submit')

        element_count_after_duplicate_import = wait_for_sleep_after(lambda: Element.objects.filter(element_type="system_element").count())

        self.assertEqual(element_count_after_import + 2, element_count_after_duplicate_import)

        original_import_element_count = Element.objects.filter(name='Test OSCAL Component1').count()
        self.assertEqual(original_import_element_count, 1)

        duplicate_import_element_count = Element.objects.filter(name='Test OSCAL Component1 (1)').count()
        self.assertEqual(duplicate_import_element_count, 1)

        statement_count_after_duplicate_import = Statement.objects.filter(
            statement_type=StatementTypeEnum.CONTROL_IMPLEMENTATION_PROTOTYPE.value).count()
        self.assertEqual(statement_count_after_import + 4, statement_count_after_duplicate_import)
    def test_create_portfolio_project(self):
        # Create new project within portfolio
        self._login()
        self._new_project()

        # Create new portfolio
        wait_for_sleep_after(lambda: self.browser.get(self.url("/portfolios")))
        wait_for_sleep_after(lambda: self.click_element("#new-portfolio"))
        self.fill_field("#id_title", "Security Projects")
        self.fill_field("#id_description", "Project Description")
        self.click_element("#create-portfolio-button")
        wait_for_sleep_after(
            lambda: self.assertRegex(self.browser.title, "Security Projects"))
Exemple #18
0
    def test_component_download_oscal_json(self):
        self._login()
        url = self.url(
            f"/systems/{self.system.id}/component/{self.component.id}")
        self.browser.get(url)
        self.click_element('a[href="#oscal"]')

        # sigh; selenium doesn't really let us find out the name of the
        # downloaded file, so let's make sure it doesn't exist before we
        # download
        # definite race condition possibility

        if self.json_download.is_file():
            self.json_download.unlink()
        elif os.path.isfile(self.json_download.name):
            os.remove(self.json_download.name)
        wait_for_sleep_after(
            lambda: self.click_element("a#oscal_download_json_link"))
        var_sleep(2)
        # assert download exists!
        try:
            # The following test FAILS on MacOS when tests run in HEADLESS mode.
            # Test passes when tests run in visible mode.
            # See: https://github.com/SeleniumHQ/selenium/issues/5292#issuecomment-544264234
            # To use visible mode, add to environment.json file ` "test_visible": true `
            # See: https://govready-q.readthedocs.io/en/latest/testing-for-govready-q/automated-testing.html#for-developers
            self.assertTrue(self.json_download.is_file())
            wait_for_sleep_after(
                lambda: self.assertTrue(self.json_download.is_file()))
            filetoopen = self.json_download
        except:
            wait_for_sleep_after(lambda: self.assertTrue(
                os.path.isfile(self.json_download.name)))
            # assert that it is valid JSON by trying to load it
            filetoopen = self.json_download.name
        with open(filetoopen, 'r') as f:
            json_data = json.load(f)
            self.assertIsNotNone(json_data)

        if self.json_download.is_file():
            self.json_download.unlink()
        elif os.path.isfile(self.json_download.name):
            os.remove(self.json_download.name)
 def reset_login():
     # Log out and back in as the original user.
     self.browser.get(self.url("/accounts/logout/"))
     self._login()
     wait_for_sleep_after(lambda: self.browser.get(project_page))
Exemple #20
0
    def test_discussion(self):
        # Log in and create a new project.
        self._login()
        self._new_project()
        wait_for_sleep_after(lambda: self._start_task())# wait for page to reload

        # Move past the introduction screen.
        self.assertRegex(self.browser.title, "Next Question: Module Introduction")
        self.click_element("#save-button")
        var_sleep(.8) # wait for page to reload

        # Click interstitial "Got it" button
        self.click_element("#save-button")
        var_sleep(.5)

        # We're now on the first actual question.
        # Start a team conversation.
        wait_for_sleep_after(lambda: self.click_element("#start-a-discussion"))
        wait_for_sleep_after(lambda: self.fill_field("#discussion-your-comment", "Hello is anyone *here*?"))
        wait_for_sleep_after(lambda: self.click_element("#discussion .comment-input button.btn-primary"))

        # Test Script injection
        script = "<script id='injectiontest2'>document.getElementsByTagName('body')[0]" \
                 ".appendChild('<div id=\\'injectiontest1\\'></div>');</script>"
        wait_for_sleep_after(lambda: self.fill_field("#discussion-your-comment", script))
        wait_for_sleep_after(lambda: self.click_element("#discussion .comment-input button.btn-primary"))

        # Check that the element was *not* added to the page.
        with self.assertRaises(NoSuchElementException):
            self.browser.find_element_by_css_selector('#injectiontest1')

        # Check that the script tag was removed entirely.
        with self.assertRaises(NoSuchElementException):
            self.browser.find_element_by_css_selector('#injectiontest2')

        # Test some special characters
        wait_for_sleep_after(lambda: self.fill_field("#discussion-your-comment", "¥"))
        wait_for_sleep_after(lambda: self.click_element("#discussion .comment-input button.btn-primary"))
        wait_for_sleep_after(lambda: self.assertInNodeText("¥", '.comment[data-id="3"] .comment-text p'))
Exemple #21
0
    def test_smt_autocomplete(self):
        """
        Testing if the textbox can autocomplete and filter for existing components
        """

        # login as the first user and create a new project
        self._login()
        self._new_project()

        # TODO: Why is system being overridden/conditional. system_id will be 1 in test class and 4 in full test suite
        systemid = System.objects.all().first()
        self.navigateToPage(f"/systems/{systemid.id}/controls/selected")

        # Select moderate
        self.navigateToPage(
            f"/systems/{systemid.id}/controls/baseline/NIST_SP-800-53_rev4/moderate/_assign"
        )
        # Head to the control ac-3
        self.navigateToPage(
            f"/systems/{systemid.id}/controls/catalogs/NIST_SP-800-53_rev4/control/ac-3"
        )

        # How many components are there currently?
        # Confirm the dropdown sees all components
        comps_dropdown = wait_for_sleep_after(
            lambda: self.dropdown_option("selected_producer_element_form_id"))
        num = len(comps_dropdown.options)

        # Create components
        self.create_fill_statement_form("Component 1", "Component body", 'a',
                                        'status_', "Planned",
                                        "Component remarks", num)
        num += 1
        wait_for_sleep_after(lambda: self.create_fill_statement_form(
            "Component 2", "Component body", 'b', 'status_', "Planned",
            "Component remarks", num))
        num += 1
        wait_for_sleep_after(lambda: self.create_fill_statement_form(
            "Component 3", "Component body", 'c', 'status_', "Planned",
            "Component remarks", num))
        num += 1
        wait_for_sleep_after(lambda: self.create_fill_statement_form(
            "Test name 1", "Component body", 'a', 'status_', "Planned",
            "Component remarks", num))
        num += 1
        wait_for_sleep_after(lambda: self.create_fill_statement_form(
            "Test name 2", "Component body", 'b', 'status_', "Planned",
            "Component remarks", num))
        num += 1
        wait_for_sleep_after(lambda: self.create_fill_statement_form(
            "Test name 3", "Component body", 'c', 'status_', "Planned",
            "Component remarks", num))

        # Refresh page to refresh items in selection
        self.navigateToPage(
            f"/systems/{systemid.id}/controls/catalogs/NIST_SP-800-53_rev4/control/ac-3"
        )

        wait_for_sleep_after(lambda: self.click_components_tab())

        # Confirm the dropdown sees all components
        comps_dropdown = wait_for_sleep_after(
            lambda: self.dropdown_option("selected_producer_element_form_id"))

        self.assertEquals(len(comps_dropdown.options), 7)

        # Click on search bar
        search_comps_txtbar = self.browser.find_elements_by_id(
            "producer_element_search")

        # Type a few text combinations and make sure filtering is working
        # Need to click the new dropdown after sending keys

        ## Search for Component
        search_comps_txtbar[-1].click()
        search_comps_txtbar[-1].clear()
        search_comps_txtbar[-1].send_keys("Component")
        self.browser.find_elements_by_id(
            "selected_producer_element_form_id")[-1].click()  # Ajax request
        var_sleep(1)
        assert len(comps_dropdown.options) == 3

        ## Search for 2
        search_comps_txtbar[-1].click()
        search_comps_txtbar[-1].clear()
        search_comps_txtbar[-1].send_keys("2")
        self.browser.find_elements_by_id(
            "selected_producer_element_form_id")[-1].click()  # Ajax request
        var_sleep(1)
        # print("####### len(comps_dropdown.options)", len(comps_dropdown.options))
        assert len(comps_dropdown.options) == 2
        # Use elements from database to avoid hard-coding element ids expected
        elements = Element.objects.all()
        testname2_ele = str(elements[5].id)
        component2_ele = str(elements[2].id)
        # Add a new component based on one of the options available in the filtered dropdown
        ## Test name 2 has a value of 6 and Component 2 has a value of 3
        self.select_option("select#selected_producer_element_form_id",
                           testname2_ele)
        assert self.find_selected_option(
            "select#selected_producer_element_form_id").get_property(
                "value") == testname2_ele

        ## Test name 2 has a value of 6 and Component 2 has a value of 3
        self.select_option("select#selected_producer_element_form_id",
                           component2_ele)
        assert self.find_selected_option(
            "select#selected_producer_element_form_id").get_property(
                "value") == component2_ele

        # Open a modal will with component statements related to the select component prototype
        add_related_statements_btn = self.browser.find_elements_by_id(
            "add_related_statements")
        add_related_statements_btn[-1].click()
        # Ensure we can't submit no component statements and that the alert pops up.
        wait_for_sleep_after(lambda: self.browser.find_element_by_xpath(
            "//*[@id='relatedcompModal']/div/div[1]/div[4]/button").click())

        # Open the first panel
        component_element_btn = self.browser.find_element_by_id(
            "related-panel-1")
        component_element_btn.click()
        select_comp_statement_check = wait_for_sleep_after(
            lambda: self.browser.find_element_by_name("relatedcomps"))
        var_sleep(1)
        wait_for_sleep_after(lambda: select_comp_statement_check.click())
        var_sleep(1)
        # Add component statement
        submit_comp_statement = wait_for_sleep_after(
            lambda: self.browser.find_element_by_xpath(
                "//*[@id='relatedcompModal']/div/div[1]/div[4]/button"))
        submit_comp_statement.click()
    def test_invitations(self):
        # Test a bunch of invitations.

        # Log in and create a new project.
        self._login()
        self._new_project()
        project_page = self.browser.current_url

        # And create a new task.
        self._start_task()
        task_page = self.browser.current_url

        # But now go back to the project page.
        self.browser.get(project_page)

        def start_invitation(username):
            # Fill out the invitation modal.
            # self.select_option_by_visible_text('#invite-user-select', username) # This is for selecting user from dropdown list
            wait_for_sleep_after(
                lambda: self.fill_field("input#invite-user-email", username))
            wait_for_sleep_after(lambda: self.click_element(
                "#invitation_modal button.btn-submit"))

        def do_invitation(username):
            start_invitation(username)
            var_sleep(.5)  # wait for invitation to be sent

            # Log out and accept the invitation as an anonymous user.
            self.browser.get(self.url("/accounts/logout/"))
            self._accept_invitation(username)

        def reset_login():
            # Log out and back in as the original user.
            self.browser.get(self.url("/accounts/logout/"))
            self._login()
            wait_for_sleep_after(lambda: self.browser.get(project_page))

        # Test an invitation to that project. For unknown reasons, when
        # executing this on CircleCI (but not locally), the click fails
        # because the element is not clickable -- it reports a coordinate
        # that's above the button in the site header. Not sure what's
        # happening. So load the modal using Javascript.
        wait_for_sleep_after(
            lambda: self.click_element("#menu-btn-show-project-invite"))
        self.browser.execute_script("invite_user_into_project()")
        # Toggle field to invite user by email
        self.browser.execute_script(
            "$('#invite-user-email').parent().toggle(true)")

        # Test an invalid email address.
        start_invitation("example")
        wait_for_sleep_after(lambda: self.assertInNodeText(
            "The email address is not valid.", "#global_modal")
                             )  # make sure we get a stern message.
        wait_for_sleep_after(lambda: self.click_element("#global_modal button")
                             )  # dismiss the warning.

        wait_for_sleep_after(lambda: self.click_element(
            "#menu-btn-show-project-invite"))  # Re-open the invite box.
        self.browser.execute_script(
            "invite_user_into_project()")  # See comment above.
        # Toggle field to invite user by email

        wait_for_sleep_after(lambda: self.browser.execute_script(
            "$('#invite-user-email').parent().toggle(true)"))
        var_sleep(3)  # Adding to avoid lock
        do_invitation(self.user2.email)
        self.fill_field("#id_login", self.user2.username)
        self.fill_field("#id_password", self.user2.clear_password)
        self.click_element("form button.primaryAction")

        self.assertRegex(self.browser.title,
                         "I want to answer some questions on Q"
                         )  # user is on the project page
        wait_for_sleep_after(lambda: self.click_element(
            '#question-simple_module'))  # go to the task page
        wait_for_sleep_after(lambda: self.assertRegex(
            self.browser.title, "Next Question: Module Introduction")
                             )  # user is on the task page

        # reset_login()

        # Test an invitation to take over editing a task but without joining the project.
        var_sleep(.5)
        wait_for_sleep_after(
            lambda: self.click_element("#save-button")
        )  # pass over the Introductory question because the Help link is suppressed on interstitials
        wait_for_sleep_after(lambda: self.click_element('#transfer-editorship')
                             )  # Toggle field to invite user by email

        self.browser.execute_script(
            "$('#invite-user-email').parent().toggle(true)")
        wait_for_sleep_after(lambda: do_invitation(self.user3.email)
                             )  # Toggle field to invite user by email

        self.fill_field("#id_login", self.user3.username)
        self.fill_field("#id_password", self.user3.clear_password)
        self.click_element("form button.primaryAction")
        wait_for_sleep_after(lambda: self.assertRegex(
            self.browser.title, "Next Question: The Question")
                             )  # user is on the task page

        # Test assigning existing user to a project.
        reset_login()
        self._new_project()
        project_page = self.browser.current_url

        # And create a new task.
        self._start_task()
        task_page = self.browser.current_url

        # But now go back to the project page.
        self.browser.get(project_page)
        wait_for_sleep_after(
            lambda: self.click_element("#menu-btn-show-project-invite"))

        # Select username "me3"
        wait_for_sleep_after(lambda: self.select_option_by_visible_text(
            '#invite-user-select', "me3"))
        wait_for_sleep_after(lambda: self.click_element("#invite_submit_btn"))
        wait_for_sleep_after(lambda: self.assertInNodeText(
            "me3 granted edit permission to project", ".alert"))
    def test_mini_dashboard(self):
        """ Tests for project page mini compliance dashboard """

        # Log in, create a new project.
        self._login()
        self._new_project()
        # On project page?
        # wait_for_sleep_after(lambda: self.assertInNodeText("I want to answer some questions", "#project-title"))
        wait_for_sleep_after(lambda: self.assertInNodeText(
            "I want to answer some questions", "h2"))

        # mini-dashboard content
        self.assertInNodeText("controls", "#status-box-controls")
        self.assertInNodeText("components", "#status-box-components")
        # TODO: Restore tests if #status-box-poam is displayed
        # self.assertInNodeText("POA&Ms", "#status-box-poams")
        self.assertInNodeText("compliance", "#status-box-compliance-piechart")

        # mini-dashbard links
        self.click_element('#status-box-controls')
        wait_for_sleep_after(lambda: self.assertInNodeText(
            "Selected controls", ".systems-selected-items"))
        # click project button
        wait_for_sleep_after(
            lambda: self.click_element("#menu-btn-project-home"))
        # wait_for_sleep_after(lambda: self.assertInNodeText("I want to answer some questions", "#project-title"))
        wait_for_sleep_after(lambda: self.assertInNodeText(
            "I want to answer some questions", "h2"))
        # test components
        self.click_element('#status-box-components')
        wait_for_sleep_after(lambda: self.assertInNodeText(
            "Selected components", ".systems-selected-items"))
        # click project button
        wait_for_sleep_after(
            lambda: self.click_element("#menu-btn-project-home"))
        # wait_for_sleep_after(lambda: self.assertInNodeText("I want to answer some questions", "#project-title"))
        wait_for_sleep_after(lambda: self.assertInNodeText(
            "I want to answer some questions", "h2"))
    def test_create_portfolios(self):
        # Create a new account
        self.browser.get(self.url("/"))
        self.click_element('#tab-register')
        self._fill_in_signup_form("*****@*****.**",
                                  "portfolio_user")
        self.click_element("#signup-button")
        if "Warning Message" in self.browser.title:
            self.click_element("#btn-accept")

        # Go to portfolio page
        self.browser.get(self.url("/portfolios"))

        # Navigate to portfolio created on signup
        self.click_element_with_link_text("portfolio_user")

        # Test creating a portfolio using the form
        # Navigate to the portfolio form
        wait_for_sleep_after(
            lambda: self.click_element_with_link_text("Portfolios"))
        # Click Create Portfolio button
        self.click_element("#new-portfolio")
        var_sleep(0.5)
        # Fill in form
        wait_for_sleep_after(lambda: self.fill_field("#id_title", "Test 1"))
        self.fill_field("#id_description", "Test 1 portfolio")
        # Submit form
        self.click_element("#create-portfolio-button")
        # Test we are on portfolio page we just created
        wait_for_sleep_after(lambda: self.assertRegex(
            self.browser.title, "Test 1 Portfolio - GovReady-Q"))

        # Test we cannot create a portfolio with the same name
        # Navigate to the portfolio form
        self.click_element_with_link_text("Portfolios")
        # Click Create Portfolio button
        self.click_element("#new-portfolio")
        var_sleep(0.5)
        # Fill in form
        wait_for_sleep_after(lambda: self.fill_field("#id_title", "Test 1"))
        self.fill_field("#id_description", "Test 1 portfolio")
        # Submit form
        self.click_element("#create-portfolio-button")
        # We should get an error

        # test error
        wait_for_sleep_after(lambda: self.assertIn(
            "Portfolio name Test 1 not available.",
            self._getNodeText(
                "div.alert.alert-danger.alert-dismissable.alert-link")))
        # Test uniqueness with case insensitivity
        # Navigate to the portfolio form
        self.click_element_with_link_text("Portfolios")
        # Click Create Portfolio button
        self.click_element("#new-portfolio")
        var_sleep(0.5)
        # Fill in form
        wait_for_sleep_after(lambda: self.fill_field("#id_title", "test 1"))
        # Submit form
        wait_for_sleep_after(
            lambda: self.click_element("#create-portfolio-button"))
        # We should get an error
        var_sleep(0.5)
        # test error
        wait_for_sleep_after(lambda: self.assertIn(
            "Portfolio name test 1 not available.",
            self._getNodeText(
                "div.alert.alert-danger.alert-dismissable.alert-link")))
    def test_grant_portfolio_access(self):
        # Grant another member access to portfolio
        self._login()
        self.browser.get(self.url("/portfolios"))
        self.click_element("#portfolio_{}".format(self.user.username))
        self.click_element("#grant-portfolio-access")
        var_sleep(.5)
        wait_for_sleep_after(lambda: self.select_option_by_visible_text(
            '#invite-user-select', 'me2'))
        wait_for_sleep_after(
            lambda: self.click_element("#invitation_modal button.btn-submit"))
        wait_for_sleep_after(
            lambda: self.assertInNodeText("me2", "#portfolio-member-me2"))

        # Grant another member ownership of portfolio
        wait_for_sleep_after(
            lambda: self.click_element("#me2_grant_owner_permission"))
        var_sleep(0.5)
        wait_for_sleep_after(lambda: self.assertInNodeText(
            "me2 (Owner)", "#portfolio-member-me2"))

        # Grant another member access to portfolio
        self.click_element("#grant-portfolio-access")
        self.select_option_by_visible_text('#invite-user-select', 'me3')
        self.click_element("#invitation_modal button.btn-submit")
        wait_for_sleep_after(
            lambda: self.assertInNodeText("me3", "#portfolio-member-me3"))

        # Remove another member access to portfolio
        self.click_element("#me3_remove_permissions")
        self.assertNotInNodeText("me3", "#portfolio-members")
        self.assertNodeNotVisible("#portfolio-member-me3")