def test_import_tracker(self): """Tests that imports are tracked correctly.""" self._login() url = self.url(f"/controls/components") 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() var_sleep(1) import_record_links = self.browser.find_elements_by_class_name('import_record_detail_link') self.assertEqual(len(import_record_links), 1)
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) self.click_element("a#oscal_download_json_link") var_sleep(2) # need to wait for download, alas # assert download exists! try: self.assertTrue(self.json_download.is_file()) filetoopen = self.json_download except: 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 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() var_sleep(2) # Fill out form 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 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 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 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")
def _new_project(self): self.browser.get(self.url("/projects")) self.click_element("#new-project") self.click_element(".app[data-app='fixture/simple_project'] .view-app") self.click_element("#start-project") var_sleep(1) self.assertRegex(self.browser.title, "I want to answer some questions on Q.")
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_component_import_oscal_json(self): self._login() url = self.url(f"/controls/components") self.browser.get(url) # 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') element_count = Element.objects.filter( name='Test OSCAL Component').count() self.assertEqual(element_count, 1) statement1_count = Statement.objects.filter( uuid='1ab0b252-90d3-4d2c-9785-0c4efb254dfc').count() self.assertEqual(statement1_count, 1) statement2_count = Statement.objects.filter( uuid='2ab0b252-90d3-4d2c-9785-0c4efb254dfc').count() self.assertEqual(statement2_count, 1) # Verify that statements without a proper Catalog don't get entered statement3_count = Statement.objects.filter( uuid='4ab0b252-90d3-4d2c-9785-0c4efb254dfc').count() self.assertEqual(statement3_count, 0) # Verify that statements without a proper Control don't get entered statement4_count = Statement.objects.filter( uuid='6ab0b252-90d3-4d2c-9785-0c4efb254dfc').count() self.assertEqual(statement4_count, 0) var_sleep(1) # Needed to allow page to refresh and messages to render # Test that duplicate Components and Statements are not re-imported 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 = Element.objects.filter( name='Test OSCAL Component').count() self.assertEqual(element_count, 1) statement1_count = Statement.objects.filter( uuid='1ab0b252-90d3-4d2c-9785-0c4efb254dfc').count() self.assertEqual(statement1_count, 1)
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_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*?")) var_sleep(.5) wait_for_sleep_after(lambda: self.click_element( "#discussion .comment-input button.btn-primary")) var_sleep(1.0) self.assertInNodeText("Hello", '.comment[data-id="1"] .comment-text p') # 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")) var_sleep(0.5) self.assertInNodeText("¥", '.comment[data-id="3"] .comment-text p')
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") var_sleep(2) self.click_element(".app[data-app='fixture/simple_project'] .view-app") self.click_element("#start-project") var_sleep(1) self.assertRegex(self.browser.title, "I want to answer some questions on Q.")
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))
def test_import_delete(self): """Tests that import deletions remove child components and statements.""" # Create an Import Record with a component and statement helper = ControlTestHelper() import_record = helper.create_simple_import_record() self._login() url = self.url(f"/controls/import_records") self.browser.get(url) self.click_element(f"a.import_record_detail_link") self.click_element(f"a#delete-import") # Test that cancel doesn't delete the import, and redirects to the component library self.click_element(f"a#cancel-import-delete") current_path = urlparse(self.browser.current_url).path self.assertEqual('/controls/components', current_path) import_records_count = ImportRecord.objects.all().count() self.assertEqual(import_records_count, 1) component_count = Element.objects.filter( import_record=import_record).count() self.assertEqual(component_count, 1) statement_count = Statement.objects.filter( import_record=import_record).count() self.assertEqual(statement_count, 1) # Test that confirming the deletion deletes the import, component, and statement url = self.url(f"/controls/import_records") self.browser.get(url) self.click_element(f"a.import_record_detail_link") self.click_element(f"a#delete-import") self.click_element(f"a#confirm-import-delete") var_sleep(1) current_path = urlparse(self.browser.current_url).path self.assertEqual('/controls/components', current_path) import_records_count = ImportRecord.objects.all().count() self.assertEqual(import_records_count, 0) component_count = Element.objects.filter( import_record=import_record).count() self.assertEqual(component_count, 0) statement_count = Statement.objects.filter( import_record=import_record).count() self.assertEqual(statement_count, 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( "#action-buttons\ action-row > div.btn-group > button:nth-child(4)" ) ## 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? var_sleep(5) 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(Statement.objects.all().count(), 3)
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()
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 _accept_invitation(self, email): # 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. self.click_element('#button-sign-in') var_sleep(.5) # wait for page to load # We're at the sign-in page. Go to the create account page # and register. Use a random username so that we submit something # unique, since a test may create multiple users. self.assertRegex(self.browser.title, "Sign In") self.click_element( "p a") # This isn't a very good targetting of the "sign up" link. var_sleep(.5) # wait for page to load self.fill_field("#id_username", "*****@*****.**" % get_random_string(6)) self.fill_field("#id_email", email) self.fill_field("#id_password1", "1234") self.fill_field("#id_password2", "1234") self.click_element( "form.signup button" ) # This isn't a very good targetting of the "sign up" link. var_sleep(.5) # wait for next page to load # Test that an allauth confirmation email was sent. self.assertIn( "Please confirm your email address at GovReady Q by following this link", self.pop_email().body)
def test_discussion(self): # Log in and create a new project. self._login() self._new_project() self._start_task() # Move past the introduction screen. self.assertRegex(self.browser.title, "Next Question: Introduction") self.click_element("#save-button") var_sleep(.5) # wait for page to reload # We're now on the first actual question. # Start a team conversation. self.click_element("#start-a-discussion") self.fill_field("#discussion-your-comment", "Hello is anyone *here*?") var_sleep(.5) self.click_element("#discussion .comment-input button.btn-primary") var_sleep(.5) # Test Script injection self.fill_field( "#discussion-your-comment", "<script id='injectiontest2'>document.getElementsByTagName('body')[0].appendChild('<div id=\\'injectiontest1\\'></div>');</script>" ) var_sleep(.5) self.click_element("#discussion .comment-input button.btn-primary") var_sleep(.5) # 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 self.fill_field("#discussion-your-comment", "¥") var_sleep(.5) self.click_element("#discussion .comment-input button.btn-primary") var_sleep(.5) self.assertInNodeText("¥", '.comment[data-id="3"] .comment-text p') # Test file attachments # We need to upload a file that we know exists. testFilePath = os.path.join( os.path.dirname(os.path.dirname(os.path.abspath(__file__))), 'fixtures', 'testimage.png') self.fill_field("#discussion-attach-file", testFilePath) var_sleep(1) self.click_element("#discussion .comment-input button.btn-primary") var_sleep(1) # Give time for the image to upload. # Test that we have an image. img = self.browser.find_element_by_css_selector( '.comment[data-id="4"] .comment-text p img') self.assertIsNotNone(img) # Test that the image actually exists. imageFile = img.get_attribute('src') result = self.browser.execute_script( """var http = new XMLHttpRequest(); http.open('HEAD', '{}', false); http.send(); return http.status!=404;""".format(imageFile)) self.assertTrue(result)
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() #print("systemid") #print(systemid.id) 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" ) statement_title_list = self.browser.find_elements_by_css_selector( "span#producer_element-panel_num-title") assert len(statement_title_list) == 0 # Starts at 4 num = 4 # Creating a few components self.create_fill_statement_form("Component 1", "Component body", 'a', 'status_', "Planned", "Component remarks", num) num += 1 var_sleep(.5) self.create_fill_statement_form("Component 2", "Component body", 'b', 'status_', "Planned", "Component remarks", num) num += 1 var_sleep(.5) self.create_fill_statement_form("Component 3", "Component body", 'c', 'status_', "Planned", "Component remarks", num) num += 1 var_sleep(.5) self.create_fill_statement_form("Test name 1", "Component body", 'a', 'status_', "Planned", "Component remarks", num) num += 1 var_sleep(.5) self.create_fill_statement_form("Test name 2", "Component body", 'b', 'status_', "Planned", "Component remarks", num) num += 1 var_sleep(.5) self.create_fill_statement_form("Test name 3", "Component body", 'c', 'status_', "Planned", "Component remarks", num) var_sleep(1) self.click_components_tab() var_sleep(1) # Confirm the dropdown sees all components comps_dropdown = self.dropdown_option( "selected_producer_element_form_id") assert len(comps_dropdown.options) == 6 # 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() var_sleep(3) 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() var_sleep(3) assert len(comps_dropdown.options) == 2 # Add a new component based on one of the options available in the filtered dropdown try: ## 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", "6") assert self.find_selected_option( "select#selected_producer_element_form_id").get_attribute( "value") == "6" except: self.select_option("select#selected_producer_element_form_id", "13") assert self.find_selected_option( "select#selected_producer_element_form_id").get_attribute( "value") == "13" try: ## 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", "3") assert self.find_selected_option( "select#selected_producer_element_form_id").get_attribute( "value") == "3" except: self.select_option("select#selected_producer_element_form_id", "10") assert self.find_selected_option( "select#selected_producer_element_form_id").get_attribute( "value") == "10" # 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() var_sleep(2) # Ensure we can't submit no component statements and that the alert pops up. 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() var_sleep(1) select_comp_statement_check = self.browser.find_element_by_name( "relatedcomps") select_comp_statement_check.click() var_sleep(1) # Add component statement submit_comp_statement = self.browser.find_element_by_xpath( "//*[@id='relatedcompModal']/div/div[1]/div[4]/button") submit_comp_statement.click() self.click_components_tab() statement_title_list = self.browser.find_elements_by_css_selector( "span#producer_element-panel_num-title") assert len(statement_title_list) == 7
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_control_lookup(self): self.browser.get( self.url("/controls/catalogs/NIST_SP-800-53_rev4/control/au-2")) var_sleep(2) self.assertInNodeText("AU-2", "#control-heading") self.assertInNodeText("Audit Events", "#control-heading")
def test_discussion(self): # Log in and create a new project. self._login() self._new_project() var_sleep(.5) # wait for page to reload self._start_task() # Move past the introduction screen. self.assertRegex(self.browser.title, "Next Question: Introduction") self.click_element("#save-button") var_sleep(.8) # wait for page to reload # Click interstital "Got it" button self.click_element("#save-button") var_sleep(.5) # We're now on the first actual question. # Start a team conversation. self.click_element("#start-a-discussion") var_sleep(1) self.fill_field("#discussion-your-comment", "Hello is anyone *here*?") var_sleep(.5) self.click_element("#discussion .comment-input button.btn-primary") var_sleep(.5) # Test Script injection script = "<script id='injectiontest2'>document.getElementsByTagName('body')[0]" \ ".appendChild('<div id=\\'injectiontest1\\'></div>');</script>" self.fill_field("#discussion-your-comment", script) var_sleep(.5) self.click_element("#discussion .comment-input button.btn-primary") var_sleep(.5) # 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 self.fill_field("#discussion-your-comment", "¥") var_sleep(.5) self.click_element("#discussion .comment-input button.btn-primary") var_sleep(.5) self.assertInNodeText("¥", '.comment[data-id="3"] .comment-text p') # Test file attachments upload successfully # We need to upload a file that we know exists. test_file_name = "".join([TEST_FILENAME, ".png"]) test_file_path = os.path.join( os.path.dirname(os.path.dirname(os.path.abspath(__file__))), FIXTURE_DIR, test_file_name) self.filepath_conversion("#discussion-attach-file", test_file_path, "fill") var_sleep(.5) self.click_element("#discussion .comment-input button.btn-primary") var_sleep(.5) # Give time for the image to upload. # Test that we have an image. img = self.browser.find_element_by_css_selector( '.comment[data-id="4"] .comment-text p img') # self.assertIsNotNone(img) # Test that valid PNG image actually exists with valid content type. image_url = img.get_attribute('src') cookies = self._get_browser_cookies() response = requests.get(image_url, cookies=cookies) image_contents = response.content file_model = SimpleUploadedFile(test_file_name, image_contents, content_type="image/png") image_file_valid = validate_file_extension(file_model) self.assertIsNone(image_file_valid) result = self.browser.execute_script( """var http = new XMLHttpRequest(); http.open('HEAD', '{}', false); http.send(); return http.status!=404;""".format(image_url)) self.assertTrue(result)
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_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")))