class TestSaveRequestBuilder(unittest.TestCase): dir_path = os.path.dirname(os.path.realpath(__file__)) record_action_launch_form_before_refresh = read_mock_file("record_action_launch_form_before_refresh.json") record_action_component_payload_json = read_mock_file("record_action_component_payload.json") record_action_trigger_payload_json = read_mock_file("record_action_trigger_payload.json") default_user_agent = "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_12_6) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/61.0.3163.100 Safari/537.36" mobile_user_agent = "AppianAndroid/20.2 (Google AOSP on IA Emulator, 9; Build 0-SNAPSHOT; AppianPhone)" def setUpWithPath(self, base_path_override: str = None) -> None: self.custom_locust = CustomLocust(Locust()) parent_task_set = TaskSet(self.custom_locust) setattr(parent_task_set, "host", "") setattr(parent_task_set, "credentials", [["", ""]]) setattr(parent_task_set, "auth", ["", ""]) if base_path_override: setattr(parent_task_set, "base_path_override", base_path_override) self.task_set = AppianTaskSet(parent_task_set) self.task_set.on_start() def setUp(self) -> None: self.setUpWithPath() def test_record_action_refresh_builder(self) -> None: # Test the interaction with _save_builder used by _interactor.refresh_after_record_action record_action_component = find_component_by_attribute_in_dict("label", "Update Table 1 (Dup) (PSF)", json.loads( self.record_action_launch_form_before_refresh )) record_action_trigger_component = find_component_by_attribute_in_dict( "_actionName", "sail:record-action-trigger", json.loads( self.record_action_launch_form_before_refresh )) context = find_component_by_attribute_in_dict("type", "stateful", json.loads( self.record_action_launch_form_before_refresh )) uuid = "345f89d4-b2b4-4c8c-a2a3-2b578e6292df" # Get the payload for the record action on submit record_action_payload = save_builder() \ .component(record_action_component) \ .context(context) \ .uuid(uuid) \ .value(dict()) \ .build() # Get the payload for the record action trigger record_action_trigger_payload = save_builder() \ .component(record_action_trigger_component) \ .context(context) \ .uuid(uuid) \ .value(dict()) \ .build() self.assertEqual(record_action_payload, json.loads(self.record_action_component_payload_json)) self.assertEqual(record_action_trigger_payload, json.loads(self.record_action_trigger_payload_json))
class TestAdmin(unittest.TestCase): def setUp(self) -> None: self.custom_locust = CustomLocust(Locust()) parent_task_set = TaskSet(self.custom_locust) setattr(parent_task_set, "host", "") setattr(parent_task_set, "auth", ["admin_user", ""]) self.task_set = AppianTaskSet(parent_task_set) self.task_set.host = "" # test_on_start_auth_success is covered here. self.custom_locust.set_response("auth?appian_environment=tempo", 200, '{}') self.task_set.on_start() def test_visit(self) -> None: self.custom_locust.set_response( "/suite/rest/a/applications/latest/app/admin", 200, read_mock_file("admin_console_landing_page.json")) ENV.stats.clear_all() sail_form = self.task_set.appian.admin.visit() self.assertEqual(type(sail_form), SailUiForm) self.assertEqual(0, len(ENV.stats.errors)) def test_visit_error(self) -> None: ENV.stats.clear_all() self.custom_locust.set_response( "/suite/rest/a/applications/latest/app/admin", 401, "") with self.assertRaises(Exception) as context: sail_form = self.task_set.appian.admin.visit() # Two errors will be logged, one at the get_page request level, and one at the visit self.assertEqual(2, len(ENV.stats.errors)) # Assert error structure error: locust.stats.StatsError = list(ENV.stats.errors.values())[1] self.assertEqual('DESC: No description', error.method) self.assertEqual('LOCATION: _admin.py/visit()', error.name) self.assertEqual( 'EXCEPTION: 401 Client Error: None for uri: /suite/rest/a/applications/latest/app/admin Username: admin_user', error.error) self.assertEqual(1, error.occurrences)
class TestAppianBase(unittest.TestCase): dir_path = os.path.dirname(os.path.realpath(__file__)) form_content = read_mock_file("form_content_response.json") form_content_2 = read_mock_file("sites_record_nav.json") form_content_3 = read_mock_file("sites_record_recordType_resp.json") nested_dynamic_link_json = read_mock_file( "nested_dynamic_link_response.json") def setUp(self) -> None: self.custom_locust = CustomLocust(Locust()) self.parent_task_set = TaskSet(self.custom_locust) setattr(self.parent_task_set, "host", "") setattr(self.parent_task_set, "credentials", [["", ""]]) setattr(self.parent_task_set, "auth", ["a", "b"]) self.task_set = AppianTaskSet(self.parent_task_set) self.task_set.host = "" self.task_set.on_start() def tearDown(self) -> None: if '__appianMultipartCsrfToken' in self.task_set.appian.client.cookies: self.task_set.on_stop() def test_determine_auth_with_only_auth_key(self) -> None: # Given for bad_creds in [[], "", None, 30]: setattr(self.parent_task_set, "credentials", bad_creds) # When auth = self.task_set.determine_auth() # Then self.assertEqual(["a", "b"], auth) def test_determine_auth_with_only_credentials_key(self) -> None: # Given setattr(self.parent_task_set, "auth", "") setattr(self.parent_task_set, "credentials", [["aa", "bb"], ["c", "d"]]) # When the first hit is done auth1 = self.task_set.determine_auth() auth2 = self.task_set.determine_auth() auth3 = self.task_set.determine_auth() auth4 = self.task_set.determine_auth() # Then self.assertEqual(["aa", "bb"], auth1) # Pop is FIFO self.assertEqual(["c", "d"], auth2) self.assertEqual(["c", "d"], auth3) self.assertEqual(["c", "d"], auth4) def test_determine_auth_with_credentials_and_auth_keys(self) -> None: # Given setattr(self.parent_task_set, "credentials", [["aa", "bb"], ["c", "d"]]) # When the first hit is done auth1 = self.task_set.determine_auth() auth2 = self.task_set.determine_auth() auth3 = self.task_set.determine_auth() auth4 = self.task_set.determine_auth() # Then self.assertEqual(["aa", "bb"], auth1) # Pop is FIFO self.assertEqual(["c", "d"], auth2) self.assertEqual(["a", "b"], auth3) self.assertEqual(["a", "b"], auth4) def test_login_good_auth(self) -> None: # Given init_cookies = {'JSESSIONID': 'abc', '__appianCsrfToken': '123'} cookies = { 'JSESSIONID': 'abc123', '__appianCsrfToken': 'different cookie', '__appianMultipartCsrfToken': 'these cookies' } self.custom_locust.set_response("/suite/", 200, '<html>A huge html blob</html>', cookies=init_cookies) self.custom_locust.set_response("/suite/auth?appian_environment=tempo", 200, '<html>A huge html blob</html>', cookies=cookies) self.task_set.appian.login(["", ""]) self.assertEqual(cookies, self.task_set.appian.client.cookies) def test_login_bad_auth(self) -> None: # Given self.custom_locust.set_response( "/suite/auth?appian_environment=tempo", 401, 'The username/password entered is invalid') with self.assertRaisesRegex(BadCredentialsException, "Could not log in"): self.task_set.appian.login(["", ""]) def test_login_bad_auth_bad_cookies(self) -> None: # Given cookies = {'JSESSIONID': 'abc', '__appianCsrfToken': '123'} self.custom_locust.set_response("/suite/", 200, '<html>A huge html blob</html>', cookies=cookies) self.custom_locust.set_response("/suite/auth?appian_environment=tempo", 200, '<html>A huge html blob</html>', cookies=cookies) with self.assertRaisesRegex( MissingCsrfTokenException, "Login unsuccessful, no multipart cookie found"): self.task_set.on_start() def test_instantiating_task_set(self) -> None: # Given ts = SampleAppianTaskSequence(self.custom_locust) # When task_name_1 = ts.get_next_task().__name__ # Then self.assertEqual("first_task", task_name_1) # When called again task_name_2 = ts.get_next_task().__name__ # Then the next task self.assertEqual("second_task", task_name_2) # When called the last time task_name_3 = ts.get_next_task().__name__ # Then it wraps around self.assertEqual("first_task", task_name_3) def test_appian_client_on_its_own(self) -> None: # Given inner_client = MockClient() dir_path = os.path.dirname(os.path.realpath(__file__)) actions = read_mock_file("actions_response.json") host = "https://my-fake-host.com" inner_client.set_response( f"{host}/suite/api/tempo/open-a-case/available-actions?ids=%5B%5D", 200, actions) appian_client = AppianClient(inner_client, "https://my-fake-host.com") # When client, resp = appian_client.login(["a", "1"]) appian_client.actions.get_all() # Then self.assertEqual(200, resp.status_code) def test_procedurally_generate_credentials(self) -> None: # Given CONFIG = { "procedural_credentials_prefix": "employee", "procedural_credentials_count": 3, "procedural_credentials_password": "******" } expected_credentials = [['employee1', 'pass'], ['employee2', 'pass'], ['employee3', 'pass']] # When procedurally_generate_credentials(CONFIG) # Then self.assertEqual(expected_credentials, CONFIG["credentials"]) def test_procedurally_generate_credentials_keys_missing(self) -> None: # Given CONFIG = { "procedural_credentials_prefix": "employee", "procedural_credentials_password": "******" } # When with self.assertRaisesRegex(MissingConfigurationException, '["procedural_credentials_count"]'): procedurally_generate_credentials(CONFIG) def test_procedurally_generate_credentials_multiple_keys_missing( self) -> None: # Given CONFIG2 = {'unrelated': 'config'} # When with self.assertRaisesRegex( MissingConfigurationException, '["procedural_credentials_prefix", "procedural_credentials_count", "procedural_credentials_password"]' ): procedurally_generate_credentials(CONFIG2) def test_setup_distributed_creds(self) -> None: # Given CONFIG = { "credentials": [['employee1', 'pass'], ['employee2', 'pass'], ['employee3', 'pass']] } os.environ["STY"] = "64331.locustdriver-2-0" expected_config = [['employee1', 'pass'], ['employee3', 'pass']] # When setup_distributed_creds(CONFIG) self.assertEqual(CONFIG["credentials"], expected_config) def test_setup_distributed_creds_2(self) -> None: # Given CONFIG = { "credentials": [['employee1', 'pass'], ['employee2', 'pass'], ['employee3', 'pass']] } os.environ["STY"] = "64331.locustdriver-2-1" expected_config = [['employee2', 'pass']] # When setup_distributed_creds(CONFIG) self.assertEqual(CONFIG["credentials"], expected_config) def test_setup_distributed_creds_fewer_credentials_than_workers( self) -> None: # Given CONFIG = {"credentials": [['employee1', 'pass']]} os.environ["STY"] = "64331.locustdriver-2-1" expected_config = [['employee1', 'pass']] # When setup_distributed_creds(CONFIG) self.assertEqual(CONFIG["credentials"], expected_config) def test_setup_distributed_creds_fails_missing_key(self) -> None: # Given CONFIG = {'unrelated': 'config'} # When with self.assertRaisesRegex(MissingConfigurationException, '["credentials"]'): setup_distributed_creds(CONFIG)
class TestAppImport(unittest.TestCase): def setUp(self) -> None: record_mode = True if integration_url else False self.custom_locust = CustomLocust(User(ENV), integration_url=integration_url, record_mode=record_mode) parent_task_set = TaskSet(self.custom_locust) setattr(parent_task_set, "host", integration_url) setattr(parent_task_set, "auth", auth) setattr(self.custom_locust, "record_mode", True) self.task_set = AppianTaskSet(parent_task_set) ENV.stats.clear_all() def test_app_importer_e_to_e(self) -> None: self.task_set.on_start() path_to_file = os.path.join(CURR_FILE_PATH, "resources", "Constant Test App.zip") if not os.path.exists(path_to_file): raise Exception(f"file not found {path_to_file}") # Order of execution is, navigate to /design, click import, upload doc, fill upload field, click import again if not integration_url: self.custom_locust.enqueue_response( 200, read_mock_file("design_landing_page.json")) self.custom_locust.enqueue_response( 200, read_mock_file("design_click_import_button_resp_init.json")) self.custom_locust.enqueue_response( 200, read_mock_file("design_soap_app_upload_response.json")) self.custom_locust.enqueue_response( 200, read_mock_file( "design_upload_to_file_upload_field_doc_resp.json")) self.custom_locust.enqueue_response( 200, read_mock_file("design_click_import_button_resp_final.json")) self.task_set.appian.app_importer.import_app(path_to_file) def test_app_importer_e_to_e_for_inspect_and_import(self) -> None: self.task_set.on_start() path_to_file = os.path.join(CURR_FILE_PATH, "resources", "Constant Test App.zip") if not os.path.exists(path_to_file): raise Exception(f"file not found {path_to_file}") # Order of execution is, navigate to /design, click import, upload doc, fill upload field, click import again if not integration_url: self.custom_locust.enqueue_response( 200, read_mock_file("design_landing_page.json")) self.custom_locust.enqueue_response( 200, read_mock_file("design_click_import_button_resp_init.json")) self.custom_locust.enqueue_response( 200, read_mock_file("design_soap_app_upload_response.json")) self.custom_locust.enqueue_response( 200, read_mock_file( "design_upload_to_file_upload_field_doc_resp.json")) self.custom_locust.enqueue_response( 200, read_mock_file("design_inspection_results_resp.json")) self.custom_locust.enqueue_response( 200, read_mock_file("design_click_import_button_resp_final.json")) self.task_set.appian.app_importer.import_app( app_file_path=path_to_file, inspect_and_import=True) def test_app_importer_e_to_e_with_cust_file(self) -> None: self.task_set.on_start() path_to_app = os.path.join(CURR_FILE_PATH, "resources", "Constant Test App.zip") path_to_cust_file = os.path.join(CURR_FILE_PATH, "resources", "Constant Test App.properties") for path_to_file in [path_to_app, path_to_cust_file]: if not os.path.exists(path_to_file): raise Exception(f"file not found {path_to_file}") if not integration_url: self.custom_locust.enqueue_response( 200, read_mock_file("design_landing_page.json")) self.custom_locust.enqueue_response( 200, read_mock_file("design_click_import_button_resp_init.json")) self.custom_locust.enqueue_response( 200, read_mock_file("design_soap_app_upload_response.json")) self.custom_locust.enqueue_response( 200, read_mock_file( "design_upload_to_file_upload_field_doc_resp.json")) self.custom_locust.enqueue_response( 200, read_mock_file("design_check_import_cust_box.json")) self.custom_locust.enqueue_response( 200, read_mock_file("design_constant_props_upload_response.json")) self.custom_locust.enqueue_response( 200, read_mock_file( "design_upload_to_file_upload_field_doc_resp.json")) self.custom_locust.enqueue_response( 200, read_mock_file("design_click_import_button_resp_final.json")) self.task_set.appian.app_importer.import_app( path_to_app, customization_file_path=path_to_cust_file) def test_app_importer_e_to_e_with_cust_file_error(self) -> None: self.task_set.on_start() path_to_app = os.path.join(CURR_FILE_PATH, "resources", "Constant Test App.zip") path_to_cust_file = os.path.join(CURR_FILE_PATH, "resources", "Constant Test App.properties") for path_to_file in [path_to_app, path_to_cust_file]: if not os.path.exists(path_to_file): raise Exception(f"file not found {path_to_file}") if not integration_url: self.custom_locust.enqueue_response( 200, read_mock_file("design_landing_page.json")) self.custom_locust.enqueue_response( 200, read_mock_file("design_click_import_button_resp_init.json")) self.custom_locust.enqueue_response( 200, read_mock_file("design_soap_app_upload_response.json")) self.custom_locust.enqueue_response( 200, read_mock_file( "design_upload_to_file_upload_field_doc_resp.json")) self.custom_locust.enqueue_response( 200, read_mock_file("design_check_import_cust_box.json")) self.custom_locust.enqueue_response( 200, read_mock_file("design_constant_props_upload_response.json")) self.custom_locust.enqueue_response( 200, read_mock_file( "design_upload_to_file_upload_field_doc_resp.json")) self.custom_locust.enqueue_response( 200, read_mock_file("design_click_import_failed_validation.json")) with self.assertRaises(Exception) as e: self.task_set.appian.app_importer.import_app( path_to_app, customization_file_path=path_to_cust_file)
class TestSites(unittest.TestCase): def setUp(self) -> None: self.custom_locust = CustomLocust(Locust()) parent_task_set = TaskSet(self.custom_locust) setattr(parent_task_set, "host", "") setattr(parent_task_set, "auth", ["", ""]) self.task_set = AppianTaskSet(parent_task_set) self.task_set.host = "" # test_on_start_auth_success is covered here. self.custom_locust.set_response("auth?appian_environment=tempo", 200, '{}') self.task_set.on_start() all_sites_str = read_mock_file("all_sites.json") self.custom_locust.set_response(_Sites.TEMPO_SITE_PAGE_NAV, 200, all_sites_str) # Default responses are page responses page_resp_json = read_mock_file("page_resp.json") self.custom_locust.client.set_default_response(200, page_resp_json) def tearDown(self) -> None: self.task_set.on_stop() def test_sites_get_all(self) -> None: page_resp_json = read_mock_file("page_resp.json") site_nav_resp = read_mock_file("sites_nav_resp.json") all_sites_str = read_mock_file("all_sites.json") self.custom_locust.client.enqueue_response(200, all_sites_str) for i in range(136): self.custom_locust.client.enqueue_response(200, site_nav_resp) for i in range(5): self.custom_locust.client.enqueue_response(200, page_resp_json) self.task_set.appian.sites.get_all() all_sites = self.task_set.appian.sites._sites self.assertEqual(len(all_sites.keys()), 136) self.assertTrue("rla" in all_sites, "rla not found in list of sites") # Spot check rla_site = all_sites["rla"] self.assertEqual(len(rla_site.pages.keys()), 5) self.assertEqual(rla_site.pages['create-mrn'].page_type, PageType.REPORT) def set_sites_json(self, site_name: str) -> None: sites_nav_resp = read_mock_file("sites_nav_resp.json") self.custom_locust.set_response( f"/suite/rest/a/sites/latest/{site_name}/nav", 200, sites_nav_resp) def test_sites_get(self) -> None: site_name = 'mrn' self.set_sites_json(site_name) site = self.task_set.appian.sites.get_site_data_by_site_name('mrn') def test_sites_link_type(self) -> None: for type_pair in [('InternalActionLink', 'action'), ('InternalReportLink', 'report'), ('SiteRecordTypeLink', 'recordType')]: original_link_type = type_pair[0] expected_link_type = type_pair[1] link_full = f"{{http://www.host.net/ae/types/2009}}{original_link_type}" link_type = self.task_set.appian.sites._get_type_from_link_type( link_full) self.assertEqual(link_type.value, expected_link_type) def test_sites_bad_link_type(self) -> None: with self.assertRaises(Exception) as e: bad_link_type = "this is garbage" self.task_set.appian.sites._get_type_from_link_type(bad_link_type) self.assertEqual(e.exception.args[0], f"Invalid Link Type: {bad_link_type}") def test_navigate_to_tab_error_cases(self) -> None: site_name = "abc" self.set_sites_json(site_name) with self.assertRaises(SiteNotFoundException): self.task_set.appian.sites.navigate_to_tab("other_site", "123") with self.assertRaises(PageNotFoundException): self.task_set.appian.sites.navigate_to_tab(site_name, "123") def test_navigate_to_tab_success(self) -> None: site_name = "abc" page_name = "create-mrn" link_type = "report" # Default Page Info self.set_sites_json(site_name) self.custom_locust.set_response( f"/suite/rest/a/sites/latest/{site_name}/pages/{page_name}/{link_type}", 200, '{"test":"abc"}') tab_resp = self.task_set.appian.sites.navigate_to_tab( site_name, page_name) self.assertEqual({'test': 'abc'}, tab_resp.json()) def test_visit_and_get_form_success(self) -> None: site_name = "abc" page_name = "create-mrn" link_type = "report" # Default Page Info self.set_sites_json(site_name) expected_uuid = 'abc123' expected_context = '{"abc":"123"}' form_content = f'{{"context":{expected_context}, "uuid":"{expected_uuid}"}}' expected_url = f"/suite/rest/a/sites/latest/{site_name}/pages/{page_name}/{link_type}" self.custom_locust.set_response(expected_url, 200, form_content) ui_form: SailUiForm = self.task_set.appian.sites.visit_and_get_form( site_name, page_name) self.assertEqual(expected_uuid, ui_form.uuid) self.assertEqual(json.loads(expected_context), ui_form.context) self.assertEqual(expected_url, ui_form.form_url) def test_navigate_to_tab_and_record_report_success(self) -> None: site_name = "abc" page_name = "create-mrn" link_type = "report" # Default Page Info self.set_sites_json(site_name) self.custom_locust.set_response( f"/suite/rest/a/sites/latest/{site_name}/pages/{page_name}/{link_type}", 200, '{"test":"abc"}') tab_resp = self.task_set.appian.sites.navigate_to_tab_and_record_if_applicable( site_name, page_name) self.assertEqual({'test': 'abc'}, tab_resp.json()) def test_get_sites_records(self) -> None: site_name = "orders" page_name = "orders" link_type = "recordType" nav_resp = read_mock_file("sites_record_nav.json") page_resp = read_mock_file("sites_record_page_resp.json") record_resp = read_mock_file("sites_record_recordType_resp.json") for endpoint in [ f"/suite/rest/a/sites/latest/{site_name}/nav", f"/suite/rest/a/sites/latest/{site_name}/pages/{page_name}/nav" ]: self.custom_locust.set_response(endpoint, 200, nav_resp) nav_ui = json.loads(nav_resp) for mocked_page_name in self.task_set.appian.sites.get_page_names_from_ui( nav_ui): self.custom_locust.set_response( f"/suite/rest/a/applications/latest/legacy/sites/{site_name}/page/{mocked_page_name}", 200, page_resp) self.custom_locust.set_response( f"/suite/rest/a/sites/latest/{site_name}/pages/{page_name}/{link_type}", 200, record_resp) self.custom_locust.set_default_response(200, record_resp) resp = self.task_set.appian.sites.navigate_to_tab_and_record_if_applicable( site_name, page_name) self.assertEqual(resp.text, record_resp)
class TestTask(unittest.TestCase): task_feed_resp = read_mock_file("tasks_response.json") task_feed_with_next = read_mock_file("tasks_response_with_next.json") def get_task_attributes(self, is_auto_acceptable: bool) -> str: return f""" {{ "isOfflineTask": false, "isSailTask": true, "isQuickTask": false, "taskId": "1", "isAutoAcceptable": {'true' if is_auto_acceptable else 'false'} }}""" def setUp(self) -> None: self.custom_locust = CustomLocust(Locust()) parent_task_set = TaskSet(self.custom_locust) setattr(parent_task_set, "host", "") setattr(parent_task_set, "auth", ["", ""]) self.task_set = AppianTaskSet(parent_task_set) self.task_set.host = "" # test_on_start_auth_success is covered here. self.custom_locust.set_response("auth?appian_environment=tempo", 200, '{}') self.custom_locust.set_default_response(200, "{}") self.task_set.on_start() self.custom_locust.set_response( "/suite/rest/a/task/latest/1/attributes", 200, self.get_task_attributes(is_auto_acceptable=True)) self.custom_locust.set_response(_Tasks.INITIAL_FEED_URI, 200, self.task_feed_resp) def tearDown(self) -> None: self.task_set.on_stop() def test_task_get_all(self) -> None: self.custom_locust.enqueue_response(200, self.task_feed_with_next) self.custom_locust.enqueue_response(200, self.task_feed_resp) all_task = self.task_set.appian.tasks.get_all() self.assertEqual(len(all_task.keys()), 21) # TODO: These keys are bad, as are the record/ report keys, consider just using the names/ IDs self.assertEqual( all_task['t-2109072_34 Task_Assign SR#0G56-W7N3 to Case Worker'] ['id'], 't-2109072') def test_task_get(self) -> None: task = self.task_set.appian.tasks.get_task("t-1", False) self.assertIsInstance(task, dict) def test_task_get_missing_task(self) -> None: with self.assertRaisesRegex( Exception, "There is no task with name .* in the system under test.*"): self.task_set.appian.tasks.get_task("some random word") def test_task_visit(self) -> None: output = self.task_set.appian.tasks.visit("t-1", False) self.assertEqual(output, {}) def test_task_visit_and_get_form(self) -> None: task_to_accept = read_mock_file('task_accept_resp.json') self.custom_locust.set_response("/suite/rest/a/task/latest/1/status", 200, task_to_accept) self.custom_locust.set_response( "/suite/rest/a/task/latest/1/attributes", 200, self.get_task_attributes(is_auto_acceptable=False)) output = self.task_set.appian.tasks.visit_and_get_form("t-1", False) self.assertEqual(output.form_url, "/suite/rest/a/task/latest/1/form")
class TestActions(unittest.TestCase): actions = read_mock_file("actions_response.json") action_under_test = "Create a Case::koBOPgHGLIgHRQzrdseY6-wW_trk0FY-87TIog3LDZ9dbSn9dYtlSaOQlWaz7PcZgV5FWdIgYk8QRlv1ARbE4czZL_8fj4ckCLzqA" def setUp(self) -> None: self.custom_locust = CustomLocust(Locust()) parent_task_set = TaskSet(self.custom_locust) setattr(parent_task_set, "host", "") setattr(parent_task_set, "auth", ["", ""]) self.task_set = AppianTaskSet(parent_task_set) self.task_set.host = "" # test_on_start_auth_success is covered here. self.custom_locust.set_response("auth?appian_environment=tempo", 200, '{}') self.task_set.on_start() self.custom_locust.set_response( "/suite/api/tempo/open-a-case/available-actions?ids=%5B%5D", 200, self.actions) def tearDown(self) -> None: self.task_set.on_stop() def test_actions_get_all(self) -> None: all_actions = self.task_set.appian.actions.get_all() self.assertTrue(len(list(all_actions.keys())) > 0) def test_actions_get(self) -> None: action = self.task_set.appian.actions.get_action( self.action_under_test) self.assertEqual(action['displayLabel'], 'Create a Case') def test_actions_get_corrupt_action(self) -> None: corrupt_actions = self.actions.replace( '"opaqueId": "koBOPgHGLIgHRQzrdseZ66wChtz5aQqM_RBTDeSBi9lWr4b18XPJqrikBSQYzzp8_e2Wgw0ku-apJjK94StAV1R3DU5zipwSXfCTA"', '"corrupt_opaqueId": "koBOPgHGLIgHRQzrdseZ66wChtz5aQqM_RBTDeSBi9lWr4b18XPJqrikBSQYzzp8_e2Wgw0ku-apJjK94StAV1R3DU5zipwSXfCTA"' ) self.custom_locust.set_response( "/suite/api/tempo/open-a-case/available-actions?ids=%5B%5D", 200, corrupt_actions) all_actions = self.task_set.appian.actions.get_all() self.assertTrue("ERROR::1" in str(all_actions)) self.assertTrue(self.task_set.appian.actions._errors == 1) def test_actions_zero_actions(self) -> None: corrupt_actions = self.actions.replace('"actions"', '"nonexistent_actions"') self.custom_locust.set_response( "/suite/api/tempo/open-a-case/available-actions?ids=%5B%5D", 200, corrupt_actions) all_actions = self.task_set.appian.actions.get_all() self.assertTrue(all_actions == {}) def test_actions_get_partial_match(self) -> None: action = self.task_set.appian.actions.get_action( "Create a Case", False) self.assertEqual(action['displayLabel'], 'Create a Case') def test_actions_get_multiple_matches(self) -> None: self.task_set.appian.actions._actions = dict() # Resetting the cache. action = self.task_set.appian.actions.get_action("Create a C", False) self.assertTrue("Create a C" in action['displayLabel']) def test_actions_get_missing_action(self) -> None: with self.assertRaisesRegex( Exception, "There is no action with name .* in the system under test.*"): self.task_set.appian.actions.get_action("Create a Case", exact_match=True) def setup_action_response_no_ui(self) -> None: action = self.task_set.appian.actions.get_action( "Create a Case", False) self.custom_locust.set_response(action['formHref'], 200, "{}") def setup_action_response_with_ui( self, file_name: str = "form_content_response.json") -> None: action = self.task_set.appian.actions.get_action( "Create a Case", False) resp_json = read_mock_file(file_name) self.custom_locust.set_response(action['formHref'], 200, resp_json) def test_actions_visit(self) -> None: self.setup_action_response_no_ui() action = self.task_set.appian.actions.visit("Create a Case", False) self.assertIsInstance(action, dict) def test_actions_start(self) -> None: self.setup_action_response_no_ui() self.task_set.appian.actions.start_action(self.action_under_test) def test_actions_start_skip_design_call(self) -> None: self.task_set.appian.actions.start_action(self.action_under_test, True) def test_actions_form_example_success(self) -> None: # output of get_page of a form (SAIL) self.setup_action_response_with_ui() self.custom_locust.set_response( '/suite/rest/a/model/latest/228/form', 200, '{"context":"12345","ui": {"#t": "UiComponentsDelta", "modifiedComponents":[]}}' ) sail_form: SailUiForm = self.task_set.appian.actions.visit_and_get_form( "Create a Case", False) label = 'Title' value = "Look at me, I am filling out a form" button_label = 'Submit' latest_form = sail_form.fill_text_field(label, value).click(button_label) resp = latest_form.get_response() self.assertEqual("12345", resp['context']) def test_actions_form_example_activity_chained(self) -> None: action = self.task_set.appian.actions.get_action( "Create a Case", False) resp_json = read_mock_file("form_content_response.json") self.custom_locust.set_response( action['formHref'], 200, '{"mobileEnabled": "false", "empty": "true", "formType": "START_FORM"}' ) self.custom_locust.set_response(action['initiateActionHref'], 200, resp_json) self.custom_locust.set_response( '/suite/rest/a/model/latest/228/form', 200, '{"context":"12345","ui": {"#t": "UiComponentsDelta", "modifiedComponents":[]}}' ) sail_form: SailUiForm = self.task_set.appian.actions.visit_and_get_form( "Create a Case") label = 'Title' value = "Look at me, I am filling out a form" button_label = 'Submit' latest_form = sail_form.fill_text_field(label, value).click(button_label) resp = latest_form.get_response() self.assertEqual("12345", resp['context']) def test_actions_form_example_missing_field(self) -> None: self.setup_action_response_with_ui() sail_form: SailUiForm = self.task_set.appian.actions.visit_and_get_form( "Create a Case", False) value = "Look at me, I am filling out a form" label = "missingText" with self.assertRaises(ComponentNotFoundException) as context: sail_form.fill_text_field(label, value) self.assertEqual( context.exception.args[0], f"Could not find the component with label '{label}' in the provided form" ) button_label = 'press me' with self.assertRaises(ComponentNotFoundException) as context: sail_form.click(button_label) self.assertEqual( context.exception.args[0], f"Could not find the component with label '{button_label}' in the provided form" ) def test_actions_form_example_bad_response(self) -> None: self.setup_action_response_with_ui() sail_form: SailUiForm = self.task_set.appian.actions.visit_and_get_form( "Create a Case", False) self.custom_locust.set_response('/suite/rest/a/model/latest/228/form', 200, 'null') value = "Look at me, I am filling out a form" label = "Title" with self.assertRaises(Exception) as context: sail_form.fill_text_field(label, value) self.assertEqual( context.exception.args[0], f"No response returned when trying to update field with label '{label}'" ) button_label = 'Submit' with self.assertRaises(Exception) as context: sail_form.click(button_label) self.assertEqual( context.exception.args[0], f"No response returned when trying to click button with label '{button_label}'" ) def test_actions_form_dropdown_errors(self) -> None: self.setup_action_response_with_ui('dropdown_test_ui.json') sail_form: SailUiForm = self.task_set.appian.actions.visit_and_get_form( "Create a Case", False) dropdown_label = "missing dropdown" with self.assertRaises(ComponentNotFoundException) as context: sail_form.select_dropdown_item(dropdown_label, 'some choice') self.assertEqual( context.exception.args[0], f"Could not find the component with label '{dropdown_label}' in the provided form" ) dropdown_label = "Name" with self.assertRaises(InvalidComponentException): sail_form.select_dropdown_item(dropdown_label, 'some choice') dropdown_label = "Customer Type" with self.assertRaises(ChoiceNotFoundException): sail_form.select_dropdown_item(dropdown_label, 'some missing choice') @patch('appian_locust.SailUiForm._get_update_url_for_reeval', return_value="/mocked/re-eval/url") @patch('appian_locust.uiform._Interactor.send_dropdown_update') def test_actions_form_dropdown_success( self, mock_send_dropdown_update: MagicMock, mock_get_update_url_for_reeval: MagicMock) -> None: self.setup_action_response_with_ui('dropdown_test_ui.json') sail_form: SailUiForm = self.task_set.appian.actions.visit_and_get_form( "Create a Case", False) initial_state = sail_form.state dropdown_label = "Customer Type" sail_form.select_dropdown_item(dropdown_label, 'Buy Side Asset Manager') mock_get_update_url_for_reeval.assert_called_once_with(initial_state) mock_send_dropdown_update.assert_called_once() args, kwargs = mock_send_dropdown_update.call_args self.assertEqual(args[0], "/mocked/re-eval/url") self.assertIsNone(kwargs["url_stub"]) self.assertNotEqual(sail_form.state, initial_state) @patch('appian_locust.SailUiForm._get_update_url_for_reeval', return_value="/mocked/re-eval/url") @patch('appian_locust.uiform._Interactor.send_dropdown_update') def test_actions_form_record_list_dropdown_success( self, mock_send_dropdown_update: MagicMock, mock_get_update_url_for_reeval: MagicMock) -> None: # 'dropdown_test_record_list_ui.json' contains a 'sail-application-url' field self.setup_action_response_with_ui('dropdown_test_record_list_ui.json') sail_form: SailUiForm = self.task_set.appian.actions.visit_and_get_form( "Create a Case", False) initial_state = sail_form.state dropdown_label = "Customer Type" sail_form.select_dropdown_item(dropdown_label, 'Buy Side Asset Manager') mock_get_update_url_for_reeval.assert_called_once_with(initial_state) mock_send_dropdown_update.assert_called_once() args, kwargs = mock_send_dropdown_update.call_args self.assertEqual(args[0], "/mocked/re-eval/url") self.assertEqual(kwargs["url_stub"], "url_stub123") self.assertNotEqual(sail_form.state, initial_state) @patch('appian_locust.uiform._Interactor.send_multiple_dropdown_update') def test_multiple_dropdown_not_found( self, mock_send_multiple_dropdown_update: MagicMock) -> None: self.setup_action_response_with_ui('dropdown_test_ui.json') sail_form: SailUiForm = self.task_set.appian.actions.visit_and_get_form( "Create a Case", False) dropdown_label = "Regions wrong label" with self.assertRaises(ComponentNotFoundException) as context: sail_form.select_multi_dropdown_item(dropdown_label, ["Asia"]) self.assertEqual( context.exception.args[0], f"Could not find the component with label '{dropdown_label}' in the provided form" ) dropdown_label = "Regions" sail_form.select_multi_dropdown_item(dropdown_label, ["Asia"]) mock_send_multiple_dropdown_update.assert_called_once() args, kwargs = mock_send_multiple_dropdown_update.call_args @patch('appian_locust.uiform.find_component_by_attribute_in_dict') @patch('appian_locust.uiform._Interactor.select_radio_button') def test_actions_form_radio_button_by_label_success( self, mock_select_radio_button: MagicMock, mock_find_component_by_label: MagicMock) -> None: self.setup_action_response_with_ui('dropdown_test_ui.json') sail_form: SailUiForm = self.task_set.appian.actions.visit_and_get_form( "Create a Case", False) state1 = sail_form.state button_label = "test-radio-button" sail_form.select_radio_button_by_test_label(button_label, 1) button_label = "Qualified Institutional Buyer" sail_form.select_radio_button_by_label(button_label, 1) args, kwargs = mock_find_component_by_label.call_args_list[0] self.assertEqual('testLabel', args[0]) args_next_call, kwargs_next_call = mock_find_component_by_label.call_args_list[ 1] self.assertEqual('label', args_next_call[0]) self.assertEqual(2, len(mock_select_radio_button.call_args_list)) def test_actions_form_radio_button_by_label_error(self) -> None: self.setup_action_response_with_ui('dropdown_test_ui.json') sail_form: SailUiForm = self.task_set.appian.actions.visit_and_get_form( "Create a Case", False) button_label = "missing button" with self.assertRaises(ComponentNotFoundException) as context: sail_form.select_radio_button_by_test_label(button_label, 1) self.assertEqual( context.exception.args[0], f"Could not find the component with label '{button_label}' in the provided form" ) with self.assertRaises(ComponentNotFoundException) as context: sail_form.select_radio_button_by_label(button_label, 1) self.assertEqual( context.exception.args[0], f"Could not find the component with label '{button_label}' in the provided form" ) @patch('appian_locust.uiform.find_component_by_index_in_dict') @patch('appian_locust.uiform._Interactor.select_radio_button') def test_actions_form_radio_button_by_index_success( self, mock_select_radio_button: MagicMock, mock_find_component_by_index: MagicMock) -> None: self.setup_action_response_with_ui('dropdown_test_ui.json') sail_form: SailUiForm = self.task_set.appian.actions.visit_and_get_form( "Create a Case", False) initial_state = sail_form.state button_index = 1 sail_form.select_radio_button_by_index(button_index, 1) mock_select_radio_button.assert_called_once() mock_find_component_by_index.assert_called_with( 'RadioButtonField', button_index, initial_state) self.assertNotEqual(sail_form.state, initial_state) def test_actions_form_radio_button_by_index_error(self) -> None: self.setup_action_response_with_ui('dropdown_test_ui.json') sail_form: SailUiForm = self.task_set.appian.actions.visit_and_get_form( "Create a Case", False) index_too_low = -1 with self.assertRaises(Exception) as context: sail_form.select_radio_button_by_index(index_too_low, 1) self.assertEqual( context.exception.args[0], f"Invalid index: '{index_too_low}'. Please enter a positive number" ) index_too_high = 4 with self.assertRaises(Exception) as context: sail_form.select_radio_button_by_index(index_too_high, 1) self.assertEqual( context.exception.args[0], f"Bad index: only '3' components of type 'RadioButtonField' found on page, requested '{index_too_high}'" ) index_invalid = "bad index" with self.assertRaises(Exception) as context: sail_form.select_radio_button_by_index(index_invalid, 1) self.assertEqual( context.exception.args[0], f"Invalid index: '{index_invalid}'. Please enter a positive number" )
class TestNews(unittest.TestCase): news = read_mock_file("news_response.json") def setUp(self) -> None: self.custom_locust = CustomLocust(Locust()) parent_task_set = TaskSet(self.custom_locust) setattr(parent_task_set, "host", "") setattr(parent_task_set, "auth", ["", ""]) self.task_set = AppianTaskSet(parent_task_set) self.task_set.host = "" # test_on_start_auth_success is covered here. self.custom_locust.set_response("auth?appian_environment=tempo", 200, '{}') self.task_set.on_start() self.custom_locust.set_response(NEWS_URI, 200, self.news) def tearDown(self) -> None: self.task_set.on_stop() def test_news_get_all(self) -> None: all_news = self.task_set.appian.news.get_all() self.assertIsInstance(all_news, dict) def test_news_search(self) -> None: self.custom_locust.set_response("/suite/api/feed/tempo?q=appian", 200, self.news) all_news = self.task_set.appian.news.search("appian") self.assertIsInstance(all_news, dict) def test_news_get(self) -> None: news = self.task_set.appian.news.get_news( "x-1::Administrator Custom") self.assertIsInstance(news, dict) def test_news_get_corrupt_news_post(self) -> None: corrupt_news = self.news.replace('"id": "x-3"', '"corrupt_id": "x-3"') self.custom_locust.set_response(NEWS_URI, 200, corrupt_news) all_news = self.task_set.appian.news.get_all() self.assertTrue("ERROR::1" in str(all_news)) self.assertTrue(self.task_set.appian.news._errors == 1) def test_actions_get_retry(self) -> None: self.task_set.appian.news._news = dict() # Resetting the cache. self.custom_locust.set_response("/suite/api/feed/tempo?q=Admin", 200, self.news) action = self.task_set.appian.news.get_news( "x-1::Administrator Custom", True, "Admin") self.assertIsInstance(action, dict) def test_news_get_missing_news(self) -> None: with self.assertRaisesRegex(Exception, "There is no news with name .* in the system under test.*"): self.task_set.appian.news.get_news("some random word") def test_news_visit(self) -> None: self.task_set.appian.news.visit("x-1", False) def test_news_visit_entry(self) -> None: self.custom_locust.set_response("/suite/api/feed/tempo?q=appian", 200, self.news) self.assertEqual((200, 200), self.task_set.appian.news.visit_news_entry("x-1", False)) def test_news_visit_entry_no_share_link(self) -> None: self.custom_locust.set_response("/suite/api/feed/tempo?q=appian", 200, self.news) self.assertEqual(self.task_set.appian.news.visit_news_entry("x-2", False), (None, 200)) def test_news_visit_entry_no_edit_link(self) -> None: self.custom_locust.set_response("/suite/api/feed/tempo?q=appian", 200, self.news) self.assertEqual(self.task_set.appian.news.visit_news_entry("x-3", False), (200, None)) def test_news_get_all_logic(self) -> None: test_cases = [ { "input": '{"feed":{"entries":[{"title": "valid_test", "id": "123"}]}}', "expected": {'123::valid_test': {'title': 'valid_test', 'id': '123'}} }, { "input": '{"feed":{"not_entries":[{"title": "valid_test", "id": "123"}]}}', "expected": {} }, { "input": '{"not_feed":{"entries":[{"title": "valid_test", "id": "123"}]}}', "expected": {} }, { "input": '{"feed":{"entries":[{"not_title": "valid_test", "id": "123"}]}}', "expected": {} } ] for test_case in test_cases: # Given self.custom_locust.set_response(NEWS_URI, 200, str(test_case['input'])) # When response = self.task_set.appian.news.get_all() # Then self.assertEqual(response, test_case['expected'])
class TestReports(unittest.TestCase): reports = read_mock_file("reports_response.json") def setUp(self) -> None: self.custom_locust = CustomLocust(Locust()) parent_task_set = TaskSet(self.custom_locust) setattr(parent_task_set, "host", "") setattr(parent_task_set, "auth", ["", ""]) self.task_set = AppianTaskSet(parent_task_set) self.task_set.host = "" # test_on_start_auth_success is covered here. self.custom_locust.set_response("auth?appian_environment=tempo", 200, '{}') self.task_set.on_start() self.custom_locust.set_response( "/suite/rest/a/uicontainer/latest/reports", 200, self.reports) def tearDown(self) -> None: self.task_set.on_stop() def test_reports_get_all(self) -> None: all_reports = self.task_set.appian.reports.get_all() self.assertIsInstance(all_reports, dict) def test_reports_get(self) -> None: reports = self.task_set.appian.reports.get_report( "RTE Basic Test Report::qdjDPA") self.assertIsInstance(reports, dict) def test_reports_get_corrupt_report(self) -> None: corrupt_reports = self.reports.replace( '"title": "!!SAIL test charts"', '"corrupt_title": "!!SAIL test charts"') self.custom_locust.set_response( "/suite/rest/a/uicontainer/latest/reports", 200, corrupt_reports) all_reports = self.task_set.appian.reports.get_all() self.assertTrue("ERROR::1" in str(all_reports)) self.assertEqual(1, self.task_set.appian.reports._errors) def test_reports_zero_reports(self) -> None: corrupt_reports = self.reports.replace('"entries"', '"nonexistent_entries"') self.custom_locust.set_response( "/suite/rest/a/uicontainer/latest/reports", 200, corrupt_reports) all_reports = self.task_set.appian.reports.get_all() self.assertTrue(all_reports == {}) def test_reports_get_missing_report(self) -> None: with self.assertRaisesRegex( Exception, "There is no report with name .* in the system under test.*"): self.task_set.appian.reports.get_report("some random word") def test_reports_visit(self) -> None: self.custom_locust.set_response( "/suite/rest/a/sites/latest/D6JMim/pages/reports/report/qdjDPA/reportlink", 200, "{}") output = self.task_set.appian.reports.visit( "RTE Basic Test Report::qdjDPA") self.assertEqual(output, dict()) def test_reports_form_example_success(self) -> None: self.custom_locust.set_response( "/suite/rest/a/sites/latest/D6JMim/pages/reports/report/qdjDPA/reportlink", 200, '{"context":123, "uuid":123}') sail_form = self.task_set.appian.reports.visit_and_get_form( "RTE Basic Test Report", False) self.assertTrue(isinstance(sail_form, SailUiForm)) def test_reports_form_example_failure(self) -> None: self.custom_locust.set_response( "/suite/rest/a/sites/latest/D6JMim/pages/reports/report/qdjDPA/reportlink", 200, '{"context":123, "uuid":123}') report_name = "Fake Report" exact_match = False with self.assertRaises(Exception) as context: self.task_set.appian.reports.visit_and_get_form( report_name, exact_match) self.assertEqual( context.exception.args[0], f"There is no report with name {report_name} in the system under test (Exact match = {exact_match})" )
class TestInteractor(unittest.TestCase): dir_path = os.path.dirname(os.path.realpath(__file__)) form_content = read_mock_file("form_content_response.json") form_content_2 = read_mock_file("sites_record_nav.json") form_content_3 = read_mock_file("sites_record_recordType_resp.json") nested_dynamic_link_json = read_mock_file( "nested_dynamic_link_response.json") response_with_start_process_link = read_mock_file( "start_process_link_response.json") record_action_launch_form_before_refresh = read_mock_file( "record_action_launch_form_before_refresh.json") record_action_refresh_response = read_mock_file( "record_action_refresh_response.json") site_with_record_search_button = read_mock_file( "site_with_record_search_button.json") default_user_agent = "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_12_6) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/61.0.3163.100 Safari/537.36" mobile_user_agent = "AppianAndroid/20.2 (Google AOSP on IA Emulator, 9; Build 0-SNAPSHOT; AppianPhone)" def setUpWithPath(self, base_path_override: str = None) -> None: self.custom_locust = CustomLocust(Locust()) parent_task_set = TaskSet(self.custom_locust) setattr(parent_task_set, "host", "") setattr(parent_task_set, "credentials", [["", ""]]) setattr(parent_task_set, "auth", ["", ""]) if base_path_override: setattr(parent_task_set, "base_path_override", base_path_override) self.task_set = AppianTaskSet(parent_task_set) self.task_set.on_start() def setUp(self) -> None: self.setUpWithPath() def test_get_primary_button_payload(self) -> None: output = self.task_set.appian.interactor.get_primary_button_payload( json.loads(self.form_content)) self.assertIsInstance(output, dict) def test_unauthed_get_page(self) -> None: # Given expected_requests = self.custom_locust.get_request_list_as_method_path_tuple( ) expected_requests.append(("get", "/suite/whatever")) expected_requests.append(("get", "/suite/?signin=native")) expected_requests.append( ("post", "/suite/auth?appian_environment=tempo")) # When self.task_set.appian.interactor.get_page("/suite/whatever") # Then self.assertEqual( expected_requests, self.custom_locust.get_request_list_as_method_path_tuple()) def test_authed_get_page(self) -> None: # Given expected_requests = self.custom_locust.get_request_list_as_method_path_tuple( ) expected_requests.append(("get", "/suite/whatever")) cookies = {'JSESSIONID': 'abc'} self.custom_locust.set_response("/suite/whatever", 200, '', cookies=cookies) self.custom_locust.set_response("/suite/", 200, '', cookies=cookies) # When self.task_set.appian.interactor.get_page("/suite/whatever") # Then self.assertEqual( expected_requests, self.custom_locust.get_request_list_as_method_path_tuple()) def test_500_but_still_logged_in_get_page(self) -> None: # Given expected_requests = self.custom_locust.get_request_list_as_method_path_tuple( ) expected_requests.append(("get", "/suite/500err")) expected_requests.append(("get", "/suite/")) self.custom_locust.set_response("/suite/500err", 500, '{}') self.custom_locust.set_response( "/suite/", 200, '', cookies={'fake': 'fakeVal'}) # No appiancsrf cookie returned # When try: self.task_set.appian.interactor.get_page("/suite/500err") # Then except Exception as e: self.assertEqual( expected_requests, self.custom_locust.get_request_list_as_method_path_tuple()) def test_base_path_override(self) -> None: # Given self.setUpWithPath('/ae') expected_requests = self.custom_locust.get_request_list_as_method_path_tuple( ) expected_requests.append(("get", "/ae/whatever")) cookies = {'JSESSIONID': 'abc'} self.custom_locust.set_response("/ae/whatever", 200, '', cookies=cookies) self.custom_locust.set_response("/ae/", 200, '', cookies=cookies) # When self.task_set.appian.interactor.get_page("/suite/whatever") # Then self.assertEqual( expected_requests, self.custom_locust.get_request_list_as_method_path_tuple()) def test_500_and_not_logged_in_get_page(self) -> None: # Given expected_requests = self.custom_locust.get_request_list_as_method_path_tuple( ) expected_requests.append(("get", "/suite/500err")) expected_requests.append(("get", "/suite/")) expected_requests.append(("get", "/suite/?signin=native")) expected_requests.append( ("post", "/suite/auth?appian_environment=tempo")) self.custom_locust.set_response("/suite/500err", 500, '{}') self.custom_locust.set_response("/suite/auth?appian_environment=tempo", 200, '') self.custom_locust.set_response( "/suite/?signin=native", 200, '', cookies={'__appianCsrfToken': 'abc'}) # Default cookies when not logged in # When try: self.task_set.appian.interactor.get_page("/suite/500err") # Then except Exception as e: self.assertEqual( expected_requests, self.custom_locust.get_request_list_as_method_path_tuple()) def test_click_record_link(self) -> None: record_link = find_component_by_attribute_in_dict( "label", "Profile", json.loads(self.form_content_2)) self.custom_locust.set_response( "/suite/sites/record/nkB0AwAXQzsQm2O6Of7dMdydaKrNT9uUisGhgFHLyZXpnCB2kjcXoiFJRK5SlL5Bt_GvQEcqlclEadcUWUJ9fCR6GnV1GcZA0cQDe2zoojxnd4W1rs06fDnxgqf" + "-Pa9TcPwsNOpNrv_mvgEFfGrsSLB4BALxCD8JZ--/view/summary", 200, "{}") output = self.task_set.appian.interactor.click_record_link( "/suite/sites/record/some_long_record_id/view/summary", record_link, {}, "") self.assertEqual(output, dict()) def test_record_link_sites_record(self) -> None: record_link = find_component_by_attribute_in_dict( "label", "Profile", json.loads(self.form_content_2)) mock = unittest.mock.Mock() setattr(self.task_set.appian.interactor, 'get_page', mock) self.task_set.appian.interactor.click_record_link( "/suite/sites/records/page/db/record/some-record-ref/view/summary", record_link, {}, "") mock.assert_called_once() # Assert get_page() called with first argument as the correct record link url recordRef = record_link.get("_recordRef") expected_record_link_url = f"('/suite/sites/records/page/db/record/{recordRef}/view/summary',)" self.assertEqual(f"{mock.call_args[0]}", expected_record_link_url) def test_record_link_sites_any_page(self) -> None: record_link = find_component_by_attribute_in_dict( "label", "DA0G-P2A6", json.loads(self.form_content_3)) mock = unittest.mock.Mock() setattr(self.task_set.appian.interactor, 'get_page', mock) self.task_set.appian.interactor.click_record_link( "/suite/sites/textcolumns/page/500", record_link, {}, "") mock.assert_called_once() # Assert get_page() called with first argument as the correct record link url recordRef = record_link.get("_recordRef") expected_record_link_url = f"('/suite/sites/textcolumns/page/500/record/{recordRef}/view/summary',)" self.assertEqual(f"{mock.call_args[0]}", expected_record_link_url) def test_record_link_tempo_report(self) -> None: record_link = find_component_by_attribute_in_dict( "label", "DA0G-P2A6", json.loads(self.form_content_3)) mock = unittest.mock.Mock() setattr(self.task_set.appian.interactor, 'get_page', mock) self.task_set.appian.interactor.click_record_link( "/suite/tempo/reports/view/oxy4ed", record_link, {}, "") mock.assert_called_once() # Assert get_page() called with first argument as the correct record link url recordRef = record_link.get("_recordRef") expected_record_link_url = f"('/suite/tempo/records/item/{recordRef}/view/summary',)" self.assertEqual(f"{mock.call_args[0]}", expected_record_link_url) def test_click_record_link_error(self) -> None: record_link = {"fake_component": "fake_attributes"} with self.assertRaises(Exception): self.task_set.appian.interactor.click_record_link( "", record_link, {}, "") def start_process_link_test_helper(self, is_mobile: bool = False) -> None: spl_component = find_component_by_attribute_in_dict( "label", "Check In", json.loads(self.response_with_start_process_link)) mock = unittest.mock.Mock() process_model_opaque_id = spl_component.get("processModelOpaqueId") cache_key = spl_component.get("cacheKey") site_name = "covid-19-response-management" page_name = "home" setattr(self.task_set.appian.interactor, 'post_page', mock) self.task_set.appian.interactor.click_start_process_link( spl_component, process_model_opaque_id, cache_key, site_name, page_name, is_mobile) mock.assert_called_once() if not is_mobile: expected_spl_link_url = f"('/suite/rest/a/sites/latest/{site_name}/page/{page_name}/startProcess/{process_model_opaque_id}?cacheKey={cache_key}',)" else: expected_spl_link_url = f"('/suite/rest/a/model/latest/startProcess/{process_model_opaque_id}?cacheKey={cache_key}',)" self.assertEqual(f"{mock.call_args[0]}", expected_spl_link_url) def test_start_process_link(self) -> None: self.start_process_link_test_helper(is_mobile=False) def test_click_start_process_link_mobile(self) -> None: self.start_process_link_test_helper(is_mobile=True) def test_click_record_link_error_fake_uri(self) -> None: record_link = find_component_by_attribute_in_dict( "label", "Profile", json.loads(self.form_content_2)) with self.assertRaises(Exception): self.task_set.appian.interactor.click_record_link( "fake_uri", record_link, {}, "") def test_click_dynamic_link(self) -> None: dyn_link = find_component_by_attribute_in_dict( "label", "Settings", json.loads(self.form_content_2)) self.custom_locust.set_response("", 200, "{}") output = self.task_set.appian.interactor.click_link( "", dyn_link, {}, "") self.assertEqual(output, dict()) def test_click_dynamic_link_error(self) -> None: dyn_link = {"fake_component": "fake_attributes"} with self.assertRaises(KeyError): self.task_set.appian.interactor.click_link("", dyn_link, {}, "") def test_click_nested_dynamic_link(self) -> None: dyn_link = find_component_by_attribute_in_dict( "label", "I need to update my Account details", json.loads(self.nested_dynamic_link_json)) self.custom_locust.set_response("", 200, "{}") output = self.task_set.appian.interactor.click_link( "", dyn_link, {}, "") self.assertEqual(output, dict()) def test_fill_textfield(self) -> None: text_title = find_component_by_attribute_in_dict( "label", "Title", json.loads(self.form_content)) self.custom_locust.set_response("", 200, "{}") output = self.task_set.appian.interactor.fill_textfield( "", text_title, "something", {}, "", "") self.assertEqual(output, dict()) def test_post_page(self) -> None: self.custom_locust.set_response("", 200, "{}") output = self.task_set.appian.interactor.post_page("", payload={}, headers=None, label=None) self.assertEqual(output.json(), dict()) def test_get_webapi(self) -> None: self.custom_locust.set_response("?query=val", 200, '{"query": "result"}') output = self.task_set.appian.interactor.get_webapi( "", queryparameters={"query": "val"}) self.assertEqual('{"query": "result"}', output.text) def test_change_user_to_mobile(self) -> None: # Given default_header = self.task_set.appian.interactor.setup_request_headers( ) self.assertEqual(default_header["User-Agent"], self.default_user_agent) # When self.task_set.appian.interactor.set_user_agent_to_mobile() new_header = self.task_set.appian.interactor.setup_request_headers() self.assertNotEqual(new_header, default_header) self.assertEqual(new_header["User-Agent"], self.mobile_user_agent) def test_change_default_user_to_desktop(self) -> None: # Given default_header = self.task_set.appian.interactor.setup_request_headers( ) self.assertEqual(default_header["User-Agent"], self.default_user_agent) # When self.task_set.appian.interactor.set_user_agent_to_desktop() new_header = self.task_set.appian.interactor.setup_request_headers() # Then self.assertEqual(new_header, default_header) def test_change_mobile_user_to_desktop(self) -> None: # Given default_header = self.task_set.appian.interactor.setup_request_headers( ) self.assertEqual(default_header["User-Agent"], self.default_user_agent) # Switch to mobile self.task_set.appian.interactor.set_user_agent_to_mobile() new_header = self.task_set.appian.interactor.setup_request_headers() self.assertNotEqual(new_header, default_header) self.assertEqual(new_header["User-Agent"], self.mobile_user_agent) # Switch back to desktop self.task_set.appian.interactor.set_user_agent_to_desktop() new_header = self.task_set.appian.interactor.setup_request_headers() # Then self.assertEqual(new_header, default_header) def test_click_record_search_button(self) -> None: component = find_component_by_index_in_dict( "SearchBoxWidget", 1, json.loads(self.site_with_record_search_button)) self.custom_locust.set_response("", 200, "{}") output = self.task_set.appian.interactor.click_record_search_button( "", component, {}, "my_uuid", "") self.assertEqual(output, dict())
class TestSailUiForm(unittest.TestCase): reports = read_mock_file("reports_response.json") record_instance_response = read_mock_file("record_summary_dashboard_response.json") related_action_response = read_mock_file("related_action_response.json") spl_response = read_mock_file("test_response.json") sites_task_report_resp = read_mock_file("sites_task_report.json") date_response = read_mock_file("date_task.json") multi_dropdown_response = read_mock_file("dropdown_test_ui.json") sail_ui_actions_response = read_mock_file("sail_ui_actions_cmf.json") record_action_launch_form_before_refresh = read_mock_file("record_action_launch_form_before_refresh.json") record_action_refresh_response = read_mock_file("record_action_refresh_response.json") site_with_record_search_button = read_mock_file("site_with_record_search_button.json") uiform_click_record_search_button_response = read_mock_file("uiform_click_record_search_button_response.json") design_uri = "/suite/rest/a/applications/latest/app/design" report_link_uri = "/suite/rest/a/sites/latest/D6JMim/pages/reports/report/nXLBqg/reportlink" date_task_uri = '/suite/rest/a/task/latest/EMlJYSQyFKe2tvm5/form' multi_dropdown_uri = "/suite/rest/a/sites/latest/io/page/onboarding-requests/action/34" report_name = "Batch Query Report" picker_label = '1. Select a Customer' picker_value = 'Antilles Transport' process_model_form_uri = "/suite/rest/a/model/latest/8/form" locust_label = "I am a label" def setUp(self) -> None: self.custom_locust = CustomLocust(User(ENV)) parent_task_set = TaskSet(self.custom_locust) setattr(parent_task_set, "host", "") setattr(parent_task_set, "auth", ["", ""]) self.task_set = AppianTaskSet(parent_task_set) self.task_set.host = "" # test_on_start_auth_success is covered here. self.custom_locust.set_response("auth?appian_environment=tempo", 200, '{}') self.task_set.on_start() self.custom_locust.set_response("/suite/rest/a/uicontainer/latest/reports", 200, self.reports) ENV.stats.clear_all() def test_reports_form_example_fail(self) -> None: self.custom_locust.set_response(self.report_link_uri, 500, '{}') with self.assertRaises(HTTPError): self.task_set.appian.reports.visit_and_get_form(self.report_name, False) def test_reports_form_modify_grid(self) -> None: form_label = 'Top Sales Reps by Total Sales' report_form = read_mock_file("report_with_rep_sales_grid.json") self.custom_locust.set_response(self.report_link_uri, 200, report_form) sail_form = self.task_set.appian.reports.visit_and_get_form(self.report_name, False) self.custom_locust.set_response("/suite/rest/a/sites/latest/D6JMim/pages/reports/report/yS9bXA/reportlink", 200, report_form) keyWords: List[dict] = [{'label': form_label}, {'index': 0}] for i in range(len(keyWords)): keyword_args: dict = keyWords[i] sail_form.move_to_beginning_of_paging_grid(**keyword_args) sail_form.move_to_end_of_paging_grid(**keyword_args) sail_form.move_to_left_in_paging_grid(**keyword_args) sail_form.move_to_right_in_paging_grid(**keyword_args) keyword_args['field_name'] = 'Total' sail_form.sort_paging_grid(**keyword_args) def test_reports_form_modify_grid_errors(self) -> None: report_form = read_mock_file("report_with_rep_sales_grid.json") self.custom_locust.set_response(self.report_link_uri, 200, report_form) sail_form = self.task_set.appian.reports.visit_and_get_form(self.report_name, False) with self.assertRaisesRegex(Exception, "Grid with label 'dummy_label'"): sail_form.move_to_beginning_of_paging_grid(label='dummy_label') with self.assertRaisesRegex(Exception, "Index 5 out of range"): sail_form.move_to_left_in_paging_grid(index=5) with self.assertRaisesRegex(Exception, "Cannot sort, field 'Abc' not found"): sail_form.sort_paging_grid(index=0, field_name='Abc') with self.assertRaisesRegex(Exception, "Field to sort cannot be blank"): sail_form.sort_paging_grid(index=0) self.assertEqual(4, len(ENV.stats.errors)) def test_datatype_caching(self) -> None: body_with_types = read_mock_file("page_resp.json") self.custom_locust.set_response(self.report_link_uri, 200, body_with_types) self.task_set.appian.reports.visit_and_get_form(self.report_name, False) self.assertEqual(len(self.task_set.appian.interactor.datatype_cache._cached_datatype), 105) self.task_set.appian.reports.visit_and_get_form(self.report_name, False) self.assertEqual(len(self.task_set.appian.interactor.datatype_cache._cached_datatype), 105) def test_deployments_click_tab(self) -> None: design_landing_page_response = read_mock_file("design_landing_page.json") deployment_tab_response = read_mock_file("design_deployments_ui.json") deployment_outgoing_tab_response = read_mock_file("design_deployments_outgoing_tab.json") self.custom_locust.set_response(self.design_uri, 200, design_landing_page_response) design_sail_form = self.task_set.appian.design.visit() self.custom_locust.set_response(self.design_uri, 200, deployment_tab_response) deployments_sail_form = design_sail_form.click("Deployments") self.custom_locust.set_response("/suite/rest/a/applications/latest/app/design/deployments", 200, deployment_outgoing_tab_response) outgoing_tab_form = deployments_sail_form.get_latest_form().click_tab_by_label("Outgoing", "deployment-secondary-tabs") component = find_component_by_attribute_in_dict("label", "OneApp", outgoing_tab_form.latest_state) self.assertEqual("OneApp", component.get('label')) def test_deployments_click_tab_exception(self) -> None: deployment_tab_response = read_mock_file("design_deployments_ui.json") design_landing_page_response = read_mock_file("design_landing_page.json") self.custom_locust.set_response(self.design_uri, 200, design_landing_page_response) design_sail_form = self.task_set.appian.design.visit() self.custom_locust.set_response(self.design_uri, 200, deployment_tab_response) deployments_sail_form = design_sail_form.click("Deployments") with self.assertRaisesRegex(Exception, "Cannot click a tab with label: 'DoesNotExistLabel' inside the TabButtonGroup component"): deployments_sail_form.get_latest_form().click_tab_by_label("DoesNotExistLabel", "deployment-secondary-tabs") def test_fill_picker_field_interaction(self) -> None: sail_ui_actions_cmf = json.loads(self.sail_ui_actions_response) picker_widget_suggestions = read_mock_file("picker_widget_suggestions.json") picker_widget_selected = read_mock_file("picker_widget_selected.json") self.custom_locust.enqueue_response(200, picker_widget_suggestions) self.custom_locust.enqueue_response(200, picker_widget_selected) sail_form = SailUiForm(self.task_set.appian.interactor, sail_ui_actions_cmf, self.process_model_form_uri) label = self.picker_label value = self.picker_value sail_form.fill_picker_field(label, value) def test_fill_picker_field_user(self) -> None: sail_ui_actions_cmf = json.loads(self.sail_ui_actions_response) picker_widget_selected = read_mock_file("picker_widget_selected.json") label = '1. Select a Customer' resp = { 'testLabel': f'test-{label}', '#t': 'PickerWidget', 'suggestions': [{'identifier': {'id': 1, "#t": "User"}}], 'saveInto': {}, '_cId': "abc" } self.custom_locust.enqueue_response(200, json.dumps(resp)) self.custom_locust.enqueue_response(200, picker_widget_selected) sail_form = SailUiForm(self.task_set.appian.interactor, sail_ui_actions_cmf, self.process_model_form_uri) value = 'Admin User' sail_form.fill_picker_field(label, value) def test_fill_picker_field_suggestions_identifier_is_code(self) -> None: sail_ui_actions_cmf = json.loads(self.sail_ui_actions_response) picker_widget_suggestions = read_mock_file("picker_widget_suggestions_code.json") picker_widget_selected = read_mock_file("picker_widget_selected.json") self.custom_locust.enqueue_response(200, picker_widget_suggestions) self.custom_locust.enqueue_response(200, picker_widget_selected) sail_form = SailUiForm(self.task_set.appian.interactor, sail_ui_actions_cmf, self.process_model_form_uri) label = self.picker_label value = 'GAC Guyana' sail_form.fill_picker_field(label, value, identifier='code') def test_fill_picker_field_no_suggestions(self) -> None: sail_ui_actions_cmf = json.loads(self.sail_ui_actions_response) picker_widget_suggestions = read_mock_file("picker_widget_no_suggestions.json") self.custom_locust.enqueue_response(200, picker_widget_suggestions) sail_form = SailUiForm(self.task_set.appian.interactor, sail_ui_actions_cmf, self.process_model_form_uri) label = self.picker_label value = 'You will not find me' with self.assertRaisesRegex(Exception, "No suggestions returned"): sail_form.fill_picker_field(label, value) def test_fill_picker_field_no_response(self) -> None: sail_ui_actions_cmf = json.loads(self.sail_ui_actions_response) self.custom_locust.enqueue_response(200, '{}') sail_form = SailUiForm(self.task_set.appian.interactor, sail_ui_actions_cmf, self.process_model_form_uri) label = self.picker_label value = 'You will not find me' with self.assertRaisesRegex(Exception, "No response returned"): sail_form.fill_picker_field(label, value) def test_fill_picker_field_no_identifiers(self) -> None: sail_ui_actions_cmf = json.loads(self.sail_ui_actions_response) label = self.picker_label resp = { 'testLabel': f'test-{label}', '#t': 'PickerWidget', 'suggestions': [{'a': 'b'}] } self.custom_locust.enqueue_response(200, json.dumps(resp)) sail_form = SailUiForm(self.task_set.appian.interactor, sail_ui_actions_cmf, self.process_model_form_uri) value = self.picker_value with self.assertRaisesRegex(Exception, "No identifiers found"): sail_form.fill_picker_field(label, value) def test_fill_picker_field_not_id_or_v(self) -> None: sail_ui_actions_cmf = json.loads(self.sail_ui_actions_response) label = self.picker_label resp = { 'testLabel': f'test-{label}', '#t': 'PickerWidget', 'suggestions': [{'identifier': {'idx': 1}}] } self.custom_locust.enqueue_response(200, json.dumps(resp)) sail_form = SailUiForm(self.task_set.appian.interactor, sail_ui_actions_cmf, self.process_model_form_uri) value = self.picker_value with self.assertRaisesRegex(Exception, "Could not extract picker values"): sail_form.fill_picker_field(label, value) def test_fill_picker_field_interaction_no_selection_resp(self) -> None: sail_ui_actions_cmf = json.loads(self.sail_ui_actions_response) picker_widget_suggestions = read_mock_file("picker_widget_suggestions.json") self.custom_locust.enqueue_response(200, picker_widget_suggestions) self.custom_locust.enqueue_response(200, '{}') sail_form = SailUiForm(self.task_set.appian.interactor, sail_ui_actions_cmf, self.process_model_form_uri) label = self.picker_label value = self.picker_value with self.assertRaisesRegex(Exception, 'No response returned'): sail_form.fill_picker_field(label, value) def test_upload_document_invalid_component(self) -> None: with self.assertRaisesRegex(Exception, 'Provided component was not a FileUploadWidget'): label = 'my_label' ui = { 'contents': [ { "contents": { "label": label, "#t": "Some other thing" }, "label": label, "labelPosition": "ABOVE", "instructions": "", "instructionsPosition": "", "helpTooltip": "Upload an application or a multi-patch package", "requiredStyle": "", "skinName": "", "marginBelow": "", "accessibilityText": "", "#t": "FieldLayout" }, ] } sail_form = SailUiForm(self.task_set.appian.interactor, ui, self.process_model_form_uri) sail_form.upload_document_to_upload_field(label, 'fake_file') def test_upload_document_missing_file(self) -> None: file = 'fake_file' with self.assertRaisesRegex(Exception, f"No such file or directory: '{file}'"): label = 'my_label' ui = { 'contents': [ { "label": label, "labelPosition": "ABOVE", "instructions": "", "instructionsPosition": "", "helpTooltip": "Upload an application or a multi-patch package", "requiredStyle": "", "skinName": "", "marginBelow": "", "accessibilityText": "", "#t": "FileUploadWidget" }, ] } sail_form = SailUiForm(self.task_set.appian.interactor, ui, self.process_model_form_uri) sail_form.upload_document_to_upload_field(label, file) def test_click_related_action_on_record_form(self) -> None: self.custom_locust.set_response('/suite/rest/a/record/latest/BE5pSw/ioBHer_bdD8Emw8hMSiA_CnpxaK0CVK61sPetEqM0lI_pHvjAsXVOlJtUo/actions/' 'ioBHer_bdD8Emw8hMSiA_CnpxaA0SVKp1kzE9BURlYvkxHjzPlX0d81Hmk', 200, self.related_action_response) sail_form = SailUiForm(self.task_set.appian.interactor, json.loads(self.record_instance_response), '/suite/rest/a/sites/latest/D6JMim/page/records/record/' 'lIBHer_bdD8Emw8hLPETeiApJ24AA5ZJilzpBmewf--PdHDSUx022ZVdk6bhtcs5w_3twr_z1drDBwn8DKfhPp90o_A4GrZbDSh09DYkh5Mfq48' '/view/summary') record_instance_header_form = sail_form.get_record_header_form() # perform a related action record_instance_related_action_form = record_instance_header_form.click_related_action("Discuss Case History") # Assert fields on the related action form text_component = find_component_by_attribute_in_dict('label', 'Action Type', record_instance_related_action_form.state) self.assertEqual(text_component.get("#t"), "TextField") @patch('appian_locust._interactor._Interactor.get_page') def test_filter_records_using_searchbox(self, mock_get_page: MagicMock) -> None: uri = 'suite/rest/a/sites/latest/D6JMim/pages/records/recordType/commit' record_type_list_form = SailUiForm(self.task_set.appian.interactor, json.loads(read_mock_file("records_response.json")), uri) record_type_list_form.filter_records_using_searchbox("Actions Page") mock_get_page.assert_called_once() args, kwargs = mock_get_page.call_args_list[0] self.assertEqual(kwargs['uri'], f"{uri}?searchTerm=Actions%20Page") self.assertEqual(kwargs['headers']['Accept'], "application/vnd.appian.tv.ui+json") @patch('appian_locust._interactor._Interactor.click_start_process_link') def test_click_start_process_link(self, mock_click_spl: MagicMock) -> None: uri = self.report_link_uri test_form = SailUiForm(self.task_set.appian.interactor, json.loads(self.spl_response), uri) mock_component_object = { "processModelOpaqueId": "iQB8GmxIr5iZT6YnVytCx9QKdJBPaRDdv_-hRj3HM747ZtRjSw", "cacheKey": "c93e2f33-06eb-42b2-9cfc-2c4a0e14088e" } test_form._click_start_process_link("z1ck30E1", "home", False, component=mock_component_object, locust_request_label="I am a label!") mock_click_spl.assert_called_once() args, kwargs = mock_click_spl.call_args_list[0] self.assertEqual(kwargs['component'], mock_component_object) self.assertEqual(kwargs['process_model_opaque_id'], "iQB8GmxIr5iZT6YnVytCx9QKdJBPaRDdv_-hRj3HM747ZtRjSw") self.assertEqual(kwargs['cache_key'], "c93e2f33-06eb-42b2-9cfc-2c4a0e14088e") self.assertEqual(kwargs['is_mobile'], False) self.assertEqual(kwargs['locust_request_label'], "I am a label!") @patch('appian_locust.uiform.SailUiForm._click_start_process_link') def test_click_card_layout_by_index_spl(self, mock_click_spl: MagicMock) -> None: uri = self.report_link_uri test_form = SailUiForm(self.task_set.appian.interactor, json.loads(self.spl_response), uri) component = find_component_by_label_and_type_dict('label', 'Request Pass', 'StartProcessLink', test_form.state) test_form.click_card_layout_by_index(1, locust_request_label=self.locust_label) mock_click_spl.assert_called_once() args, kwargs = mock_click_spl.call_args_list[0] self.assertTupleEqual(args, ('z1ck30E1', 'home', False, component)) self.assertEqual(kwargs["locust_request_label"], self.locust_label) @patch('appian_locust._interactor._Interactor.click_component') def test_click_card_layout_by_index_other_link(self, mock_click_component: MagicMock) -> None: uri = self.report_link_uri test_form = SailUiForm(self.task_set.appian.interactor, json.loads(self.spl_response), uri) def get_call(name: str) -> Optional[Any]: return { 'uuid': test_form.uuid, 'context': test_form.context }.get(name) mock_state = MagicMock() mock_state.get.side_effect = get_call mock_click_component.return_value = mock_state component = find_component_by_index_in_dict("DynamicLink", 3, test_form.state) test_form.click_card_layout_by_index(3, locust_request_label=self.locust_label) mock_click_component.assert_called_once() args, kwargs = mock_click_component.call_args_list[0] self.assertEqual(args[0], self.report_link_uri) self.assertEqual(args[1], component) self.assertEqual(args[2], test_form.context) self.assertEqual(args[3], test_form.uuid) self.assertEqual(kwargs["label"], self.locust_label) def test_click_card_layout_by_index_no_link(self) -> None: uri = self.report_link_uri test_form = SailUiForm(self.task_set.appian.interactor, json.loads(self.spl_response), uri) with self.assertRaisesRegex(Exception, "CardLayout found at index: 2 does not have a link on it"): test_form.click_card_layout_by_index(2) def _setup_date_form(self) -> SailUiForm: uri = self.date_task_uri self.custom_locust.set_response(self.date_task_uri, 200, self.date_response) test_form = SailUiForm(self.task_set.appian.interactor, json.loads(self.date_response), uri) return test_form def _setup_multi_dropdown_form(self) -> SailUiForm: uri = self.multi_dropdown_uri self.custom_locust.set_response(self.multi_dropdown_uri, 200, self.multi_dropdown_response) test_form = SailUiForm(self.task_set.appian.interactor, json.loads(self.multi_dropdown_response), uri) return test_form def _setup_action_response_with_ui(self, file_name: str = "form_content_response.json") -> None: action = self.task_set.appian.actions.get_action("Create a Case", False) resp_json = read_mock_file(file_name) self.custom_locust.set_response(action['formHref'], 200, resp_json) def test_reconcile_ui_changes_context(self) -> None: # State one test_form = self._setup_date_form() original_uuid = test_form.uuid original_context = test_form.context # State two, different uuid new_state = json.loads(self.spl_response) test_form._reconcile_state(new_state) self.assertNotEqual(test_form.uuid, original_uuid) self.assertNotEqual(test_form.context, original_context) self.assertEqual(test_form.uuid, new_state['uuid']) self.assertEqual(test_form.context, new_state['context']) def _unwrap_value(self, json_str: str) -> str: return json.loads(json_str)['updates']['#v'][0]['value']['#v'] def test_fill_datefield_not_found(self) -> None: test_form = self._setup_date_form() with self.assertRaisesRegex(Exception, "Could not find the component with label 'Datey' of type 'DatePickerField'"): test_form.fill_date_field('Datey', datetime.date.today()) def test_fill_datefield_bad_input(self) -> None: test_form = self._setup_date_form() with self.assertRaisesRegex(Exception, "Input must be of type date"): test_form.fill_date_field('Dt', 'abc') def test_fill_datefield_success(self) -> None: test_form = self._setup_date_form() test_form.fill_date_field('Date', datetime.date(1990, 1, 5)) last_request = self.custom_locust.get_request_list().pop() self.assertEqual('post', last_request['method']) self.assertEqual(self.date_task_uri, last_request['path']) self.assertEqual('1990-01-05Z', self._unwrap_value(last_request['data'])) def test_select_multi_dropdown_success(self) -> None: test_form = self._setup_multi_dropdown_form() test_form.select_multi_dropdown_item('Regions', ["Asia", "Africa and Middle East"]) last_request = self.custom_locust.get_request_list().pop() self.assertEqual('post', last_request['method']) self.assertEqual(self.multi_dropdown_uri, last_request['path']) self.assertEqual([1, 2], self._unwrap_value(last_request["data"])) def test_fill_datetimefield_bad_input(self) -> None: test_form = self._setup_date_form() with self.assertRaisesRegex(Exception, "Input must be of type datetime"): test_form.fill_datetime_field('Dt', 'abc') def test_fill_datetimefield_not_found(self) -> None: test_form = self._setup_date_form() with self.assertRaisesRegex(Exception, "Could not find the component with label 'Dt' of type 'DateTimePickerField'"): test_form.fill_datetime_field('Dt', datetime.datetime.now()) def test_fill_datetimefield_success(self) -> None: test_form = self._setup_date_form() test_form.fill_datetime_field('Date Time', datetime.datetime(1990, 1, 2, 1, 30, 50)) last_request = self.custom_locust.get_request_list().pop() self.assertEqual('post', last_request['method']) self.assertEqual(self.date_task_uri, last_request['path']) self.assertEqual('1990-01-02T01:30:00Z', self._unwrap_value(last_request['data'])) def test_dispatch_click_task_no_id(self) -> None: uri = self.report_link_uri sites_task_report = SailUiForm(self.task_set.appian.interactor, json.loads(self.sites_task_report_resp), uri) component = {'#t': PROCESS_TASK_LINK_TYPE, 'label': "my task"} with self.assertRaisesRegex(Exception, "No task id found for task with name 'my task'"): sites_task_report._dispatch_click(component, 'no label') def test_dispatch_click_task_with_id(self) -> None: uri = self.report_link_uri sites_task_report = SailUiForm(self.task_set.appian.interactor, json.loads(self.sites_task_report_resp), uri) initial_uuid = sites_task_report.uuid initial_context = sites_task_report.context task_to_accept = read_mock_file('task_accept_resp.json') self.custom_locust.set_response( "/suite/rest/a/task/latest/Bs3k2OfS55jCOcMb5D/status", 200, task_to_accept ) self.custom_locust.set_response( "/suite/rest/a/task/latest/Bs3k2OfS55jCOcMb5D/attributes", 200, """{ "isOfflineTask": false, "isSailTask": true, "isQuickTask": false, "taskId": "Bs3k2OfS55jCOcMb5D", "isAutoAcceptable": "true" }""") sites_task_report.click('Issue recommendation') task_to_accept_state = json.loads(task_to_accept) self.assertNotEqual(initial_uuid, sites_task_report.uuid) self.assertNotEqual(initial_context, sites_task_report.context) self.assertEqual(task_to_accept_state['uuid'], sites_task_report.uuid) self.assertEqual(task_to_accept_state['context'], sites_task_report.context) # Assert ui state updated self.assertEqual('Available Case Workers', find_component_by_attribute_in_dict('label', 'Available Case Workers', sites_task_report.state).get('label') ) def test_refresh_after_record_action_interaction(self) -> None: sail_ui_record_action_before = json.loads(self.record_action_launch_form_before_refresh) self.custom_locust.enqueue_response(200, self.record_action_refresh_response) sail_form = SailUiForm(self.task_set.appian.interactor, sail_ui_record_action_before, "http://localhost.com") sail_form.refresh_after_record_action("Update Table 1 (Dup) (PSF)") def test_click_record_search_button_by_index(self) -> None: sail_ui_site_with_record_search_button = json.loads(self.site_with_record_search_button) self.custom_locust.enqueue_response(200, self.uiform_click_record_search_button_response) sail_form = SailUiForm(self.task_set.appian.interactor, sail_ui_site_with_record_search_button, "http://localhost.com") sail_form.click_record_search_button_by_index()
class TestRecords(unittest.TestCase): record_types = read_mock_file("record_types_response.json") # Record Insance List for a specific RecordType records = read_mock_file("records_response.json") # Record Summary dashboard response for a specific Record Instance record_summary_view = read_mock_file("record_summary_view_response.json") record_instance_name = "Actions Page" def setUp(self) -> None: self.custom_locust = CustomLocust(Locust()) parent_task_set = TaskSet(self.custom_locust) setattr(parent_task_set, "host", "") setattr(parent_task_set, "auth", ["", ""]) self.task_set = AppianTaskSet(parent_task_set) self.task_set.host = "" # test_on_start_auth_success is covered here. self.custom_locust.set_response("auth?appian_environment=tempo", 200, '{}') if not hasattr(self.task_set, 'appian'): self.task_set.on_start() self.custom_locust.set_response( "/suite/rest/a/applications/latest/app/records/view/all", 200, self.record_types) self.custom_locust.set_response( "/suite/rest/a/sites/latest/D6JMim/pages/records/recordType/commit", 200, self.records) self.custom_locust.set_response( "/suite/rest/a/applications/latest/legacy/tempo/records/type/commit/view/all", 200, self.records) self.custom_locust.set_response( "/suite/rest/a/sites/latest/D6JMim/page/records/record/lQB0K7YxC0UQ2Fhx4pmY1F49C_MjItD4hbtRdKDmOo6V3MOBxI47ipGa_bJKZf86CLtvOCp1cfX-sa2O9hp6WTKZpbGo5MxRaaTwMkcYMeDl8kN8Hg/view/summary", 200, self.record_summary_view) def tearDown(self) -> None: self.task_set.on_stop() def test_records_get_all(self) -> None: all_records = self.task_set.appian.records.get_all() self.assertIsInstance(all_records, dict) def test_records_get_all_http_error(self) -> None: self.custom_locust.set_response( "/suite/rest/a/sites/latest/D6JMim/pages/records/recordType/commit", 500, self.records) with self.assertLogs(level="WARN") as msg: self.task_set.appian.records.get_all() self.assertIn("500 Server Error", msg.output[0]) def test_records_get_all_bad_response(self) -> None: # setting up bad response temp_record_types = self.record_types.replace( '"rel":"x-web-bookmark"', '"rel":"bad_x-web-bookmark_bad"').replace( '"#t":"CardLayout"', '"#t":"bad_CardLayout_bad"') self.custom_locust.set_response( "/suite/rest/a/applications/latest/app/records/view/all", 200, temp_record_types) with (self.assertRaisesRegex( Exception, "Unexpected response on Get call of All Records")): self.task_set.appian.records.get_all() def test_records_get_corrupt_records(self) -> None: # setting up bad response corrupt_records = self.records.replace( '"_recordRef": "lQB0K7YxC0UQ2Fhx4pmY1F49C_MjItD4hbtRdKDmOo6V3MOBxI47ipGa_bJKZf86CLtvOCp1cfX-sa2O9hu7mTKKv82PEWF9q1lBcroZD_VQpwcQDs"', '"corrupt_recordRef": "lQB0K7YxC0UQ2Fhx4pmY1F49C_MjItD4hbtRdKDmOo6V3MOBxI47ipGa_bJKZf86CLtvOCp1cfX-sa2O9hu7mTKKv82PEWF9q1lBcroZD_VQpwcQDs"' ) self.custom_locust.set_response( "/suite/rest/a/sites/latest/D6JMim/pages/records/recordType/commit", 200, corrupt_records) all_records = self.task_set.appian.records.get_all() self.assertTrue("ERROR::1" in str(all_records)) self.assertTrue(self.task_set.appian.records._errors == 1) def test_records_get_all_mobile(self) -> None: all_records = self.task_set.appian.records.get_all_mobile() self.assertIsInstance(all_records, dict) def test_records_get_by_type_mobile(self) -> None: # Given record_type = 'Commits' self.task_set.appian.records.get_all_record_types() # When all_records = self.task_set.appian.records.get_all_records_of_record_type_mobile( record_type) # Then self.assertIsInstance(all_records, dict) def test_records_fetch_record_instance(self) -> None: record = self.task_set.appian.records.fetch_record_instance( "Commits", self.record_instance_name, False) self.assertIsInstance(record, dict) def test_records_fetch_record_instance_no_record_type(self) -> None: with self.assertRaisesRegex( Exception, "There is no record type with name .* in the system under test" ): self.task_set.appian.records.fetch_record_instance( "something else 1", self.record_instance_name, False) def test_records_fetch_record_instance_missing(self) -> None: with self.assertRaisesRegex( Exception, "There is no record with name .* found in record type .*"): self.task_set.appian.records.fetch_record_instance( "Commits", "something else", False) def test_records_fetch_record_type(self) -> None: self.task_set.appian.records.get_all() output = self.task_set.appian.records.fetch_record_type("Commits") self.assertIsInstance(output, dict) def test_records_fetch_record_type_recaching(self) -> None: self.task_set.appian.records._record_types = dict( ) # Resetting the cache. output = self.task_set.appian.records.fetch_record_type("Commits") self.assertIsInstance(output, dict) def test_records_fetch_record_type_missing_record_type(self) -> None: with self.assertRaisesRegex( Exception, "There is no record type with name .* in the system under test" ): self.task_set.appian.records.fetch_record_type("something else") def test_records_visit(self) -> None: output_json, output_uri = self.task_set.appian.records.visit_record_instance( "Commits", self.record_instance_name, exact_match=False) self.assertIsInstance(output_json, dict) self.assertTrue("summary" in output_uri) def test_records_visit_random_success(self) -> None: self.custom_locust.set_default_response(200, self.record_summary_view) output_json, output_uri = self.task_set.appian.records.visit_record_instance( ) self.assertIsInstance(output_json, dict) self.assertTrue("summary" in output_uri) def test_records_visit_random_of_selected_record_type_success( self) -> None: self.custom_locust.set_default_response(200, self.record_summary_view) output_json, output_uri = self.task_set.appian.records.visit_record_instance( record_type="Commits") self.assertIsInstance(output_json, dict) self.assertTrue("summary" in output_uri) def test_records_visit_random_no_record_type_failure(self) -> None: with self.assertRaisesRegex( Exception, "If record_name parameter is specified, record_type must also be included" ): self.task_set.appian.records.visit_record_instance( record_name=self.record_instance_name, exact_match=False) def test_records_visit_with_urlstub(self) -> None: output_json, output_uri = self.task_set.appian.records.visit_record_instance( "Commits", self.record_instance_name, "summary", exact_match=False) self.assertIsInstance(output_json, dict) self.assertTrue("summary" in output_uri) def test_record_types_visit(self) -> None: output_json, output_uri = self.task_set.appian.records.visit_record_type( "Commits", exact_match=False) self.assertIsInstance(output_json, dict) self.assertTrue("commit" in output_uri) def test_record_type_visit_random_success(self) -> None: self.custom_locust.set_default_response(200, self.records) output_json, output_uri = self.task_set.appian.records.visit_record_type( ) self.assertIsInstance(output_json, dict) self.assertEqual(output_json.get("#t"), "UiConfig") self.assertTrue("commit" in output_uri) def test_record_type_visit_failure(self) -> None: with self.assertRaises(Exception) as e: self.task_set.appian.records.visit_record_type( record_type="fake type") @unittest.mock.patch( 'appian_locust.records_helper.find_component_by_attribute_in_dict', return_value={'children': [json.dumps({"a": "b"})]}) def test_records_form_example_success( self, find_component_by_attribute_in_dict_function: Any) -> None: sail_form = self.task_set.appian.records.visit_record_instance_and_get_form( "Commits", self.record_instance_name, view_url_stub="summary", exact_match=False) self.assertTrue(isinstance(sail_form, SailUiForm)) self.assertEqual(sail_form.get_response(), {"a": "b"}) def test_records_form_incorrect_name(self) -> None: record_name = "Fake Record" record_type = "Commits" exact_match = False with self.assertRaises(Exception) as context: self.task_set.appian.records.visit_record_instance_and_get_form( record_type, record_name, view_url_stub="summary", exact_match=exact_match) self.assertEqual( context.exception.args[0], f"There is no record with name {record_name} found in record type {record_type} (Exact match = {exact_match})" ) def test_records_form_incorrect_type(self) -> None: exact_match = False with self.assertRaises(Exception) as context: self.task_set.appian.records.visit_record_instance_and_get_form( "Fake Type", self.record_instance_name, view_url_stub="summary", exact_match=exact_match) self.assertEqual( context.exception.args[0], f"There is no record type with name Fake Type in the system under test (Exact match = {exact_match})" ) @unittest.mock.patch( 'appian_locust.records_helper.find_component_by_attribute_in_dict', return_value={'children': None}) def test_records_form_no_embedded_summary( self, find_component_by_attribute_in_dict_function: Any) -> None: with self.assertRaises(Exception) as context: self.task_set.appian.records.visit_record_instance_and_get_form( record_type="Commits", record_name=self.record_instance_name, view_url_stub="summary", exact_match=False) self.assertEqual( context.exception.args[0], "Parser was not able to find embedded SAIL code within JSON response for the requested Record Instance." ) def test_record_types_form_example_success(self) -> None: sail_form = self.task_set.appian.records.visit_record_type_and_get_form( "Commits", exact_match=False) self.assertTrue(isinstance(sail_form, SailUiForm)) def test_record_type_random_form_example_success(self) -> None: sail_form = self.task_set.appian.records.visit_record_type_and_get_form( exact_match=False) self.assertTrue(isinstance(sail_form, SailUiForm)) def test_record_type_form_incorrect_type(self) -> None: record_type = "Fake Type" exact_match = True with self.assertRaises(Exception) as context: self.task_set.appian.records.visit_record_type_and_get_form( record_type, exact_match) self.assertEqual( context.exception.args[0], f"There is no record type with name {record_type} in the system under test" ) def test_get_random_record(self) -> None: self.task_set.appian.records._record_types = dict() self.task_set.appian.records._records = dict() record_type, record_name = self.task_set.appian.records._get_random_record_instance( ) self.assertEqual(record_type, "Commits") self.assertIn( record_name, list(self.task_set.appian.records._records[record_type].keys())) def test_get_random_record_get_all(self) -> None: mock_get_all = mock.Mock() setattr(self.task_set.appian.records, 'get_all', mock_get_all) with self.assertRaises(Exception): self.task_set.appian.records._get_random_record_instance() mock_get_all.assert_called_once() def test_get_record_instance_feed_Response(self) -> None: sail_form = self.task_set.appian.records.visit_record_instance_and_get_feed_form( "Commits", self.record_instance_name, exact_match=False) self.assertTrue(isinstance(sail_form, SailUiForm)) self.assertEqual( sail_form.state.get("feed", {}).get("title", ""), self.record_instance_name)
class FeatureToggleHelperTest(unittest.TestCase): html_snippet = """ </script><script src="/suite/tempo/ui/sail-client/sites-05d032ca6319b11b6fc9.cache.js?\ appian_environment=sites"> </script><script src="/suite/tempo/ui/sail-client/omnibox-05d032ca6319b11b6fc9.cache.js?\ appian_environment=sites" defer="true"> </script></body></html> """ js_snippet = """ ADERS=exports.LEGACY_FEATURE_FLAGS=exports.DEFAULT_FEATURE_FLAGS=undefined; var RAW_DEFAULT_FEATURE_FLAGS={};var RAW_LEGACY_FEATURE_FLAGS=RAW_DEFAULT_FEATURE_FLAGS&2147483647; var DEFAULT_FEATURE_FLAGS=exports.DEFAULT_FEATURE_FLAGS=RAW_DEFAULT_FEATURE_FLAGS.toString(16); var LEGACY_FEATURE_FLAGS=exports.LEGACY_FEATURE_FLAGS=RAW_LEGACY_FEATURE_FLAGS.toString(16);var """ def setUp(self) -> None: self.custom_locust = CustomLocust(Locust()) parent_task_set = TaskSet(self.custom_locust) setattr(parent_task_set, "host", "") setattr(parent_task_set, "credentials", [["", ""]]) setattr(parent_task_set, "auth", ["", ""]) self.task_set = AppianTaskSet(parent_task_set) self.task_set.host = "" # test_on_start_auth_success is covered here. self.custom_locust.set_response("auth?appian_environment=tempo", 200, '{}') self.task_set.on_start() def tearDown(self) -> None: self.task_set.on_stop() def test_get_javascript_uri_missing(self) -> None: # Given self.custom_locust.set_response("/suite/sites", 200, "abc") # When uri = feature_toggle_helper._get_javascript_uri(self.task_set.appian.interactor, {}) # Then self.assertEqual(uri, None) def test_get_javascript_uri_present(self) -> None: # Given a snippet of the sites page self.custom_locust.set_response("/suite/sites", 200, self.html_snippet) # When uri = feature_toggle_helper._get_javascript_uri(self.task_set.appian.interactor, {}) # Then self.assertEqual( uri, "/suite/tempo/ui/sail-client/sites-05d032ca6319b11b6fc9.cache.js") def test_get_javascript_and_find_feature_flag_missing_value(self) -> None: # Given self.custom_locust.set_response("abc", 200, "body") # When flag = feature_toggle_helper._get_javascript_and_find_feature_flag( self.task_set.appian.client, "abc", {}) # Then self.assertEqual(flag, None) def test_get_javascript_and_find_feature_flag_value_present_hex(self) -> None: # Given a snippet of the minified js self.custom_locust.set_response("/suite/file.js", 200, self.js_snippet.format("0xdc9fffceebc")) # When uri = feature_toggle_helper._get_javascript_and_find_feature_flag(self.task_set.appian.client, "/suite/file.js", {}) # Then self.assertEqual( uri, "0xdc9fffceebc") def test_get_javascript_and_find_feature_flag_value_present_big_int(self) -> None: # Given a snippet of the minified js for i in [9, 10]: self.custom_locust.set_response("/suite/file.js", 200, self.js_snippet.format( f'jsbi__WEBPACK_IMPORTED_MODULE_{i}__["default"].BigInt("0b110100100111011100000111111111111111001110111010111100")')) # When binVal = feature_toggle_helper._get_javascript_and_find_feature_flag(self.task_set.appian.client, "/suite/file.js", {}) # Then self.assertEqual( binVal, "0b110100100111011100000111111111111111001110111010111100") def test_get_javascript_and_find_feature_flag_value_present_integer(self) -> None: # Given a snippet of the minified js self.custom_locust.set_response("/suite/file.js", 200, self.js_snippet.format("5802956083228348")) # When uri = feature_toggle_helper._get_javascript_and_find_feature_flag(self.task_set.appian.client, "/suite/file.js", {}) # Then self.assertEqual( uri, "5802956083228348") def test_get_feature_flags_from_regex_match_hex(self) -> None: # Given hex_val = "0xdc9fffceebc" # When flag, flag_extended = feature_toggle_helper._get_feature_flags_from_regex_match( hex_val) # Then self.assertEqual(flag, "7ffceebc") self.assertEqual(flag_extended, "dc9fffceebc") def test_get_feature_flags_from_regex_match_big_int(self) -> None: # Given hex_val = "0b110100100111011100000111111111111111001110111010111100" # When flag, flag_extended = feature_toggle_helper._get_feature_flags_from_regex_match( hex_val) # Then self.assertEqual(flag, "7ffceebc") self.assertEqual(flag_extended, "349dc1fffceebc") def test_get_feature_flags_from_regex_match_integer(self) -> None: # Given int_val = "5802956083228348" # When flag, flag_extended = feature_toggle_helper._get_feature_flags_from_regex_match( int_val) # Then self.assertEqual(flag, "7ffceebc") self.assertEqual(flag_extended, "149dc1fffceebc") def test_end_to_end_get_feature_flags(self) -> None: # Given a snippet of the sites page and js snippet self.custom_locust.set_response("/suite/sites", 200, self.html_snippet) self.custom_locust.set_response("/suite/tempo/ui/sail-client/sites-05d032ca6319b11b6fc9.cache.js", 200, self.js_snippet.format("5802956083228348")) # When flag, flag_extended = feature_toggle_helper.get_client_feature_toggles( self.task_set.appian.interactor, self.task_set.appian.client ) # Then self.assertEqual(flag, "7ffceebc") self.assertEqual(flag_extended, "149dc1fffceebc") def test_end_to_end_get_feature_flags_fail_no_sites_link(self) -> None: # Given a missing js snippet self.custom_locust.set_response("/suite/sites", 200, '') # When and Then with self.assertRaisesRegex(Exception, "Could not find script uri to retrieve client feature"): feature_toggle_helper.get_client_feature_toggles( self.task_set.appian.interactor, self.task_set.appian.client ) def test_end_to_end_get_feature_flags_fail_no_feature_toggles_found(self) -> None: # Given a missing feature toggle self.custom_locust.set_response("/suite/sites", 200, self.html_snippet) self.custom_locust.set_response("/suite/tempo/ui/sail-client/sites-05d032ca6319b11b6fc9.cache.js", 200, 'missin') # When and Then with self.assertRaisesRegex(Exception, "Could not find flag string within uri /suite/tempo/ui"): feature_toggle_helper.get_client_feature_toggles( self.task_set.appian.interactor, self.task_set.appian.client ) def test_to_hex_str(self) -> None: # Given hex_val = "0xdc9fffceebc" intVal = int(hex_val, 16) # When flagHexStr = feature_toggle_helper._to_hex_str(intVal) # Then self.assertEqual(flagHexStr, "dc9fffceebc") def test_truncate_flag_extended_long_input(self) -> None: # Given longHexVal = 0xdc9fffceebc # When shortVal = feature_toggle_helper._truncate_flag_extended(longHexVal) # Then self.assertEqual(shortVal, 0x7ffceebc) def test_truncate_flag_extended_short_input(self) -> None: # Given shortHexVal = 0x7ffceebc # When shortVal = feature_toggle_helper._truncate_flag_extended(shortHexVal) # Then self.assertEqual(shortVal, 0x7ffceebc) def create_override_flag_mask_runner(self, flags: List[FeatureFlag], expectedResult: int) -> None: # When feature_flag_mask = feature_toggle_helper._create_override_flag_mask(flags) # Then self.assertEqual(feature_flag_mask, expectedResult) def test_create_override_flag_mask_no_flag(self) -> None: # Given flags: List[FeatureFlag] = [] expectedResult = 0 # Then self.create_override_flag_mask_runner(flags, expectedResult) def test_create_override_flag_mask_one_flag(self) -> None: # Given flags = [FeatureFlag.SAIL_FORMS] expectedResult = 4 # Then self.create_override_flag_mask_runner(flags, expectedResult) def test_create_override_flag_mask_multiple_flags(self) -> None: # Given flags = [FeatureFlag.SAIL_FORMS, FeatureFlag.COMPACT_URI_TEMPLATES] expectedResult = 1028 # Then self.create_override_flag_mask_runner(flags, expectedResult) def override_default_flags_runner(self, flags: List[FeatureFlag], expected_featured_flag_extended: str, expected_feature_flag: str) -> None: # Given a snippet of the sites page self.task_set.appian.interactor.client.feature_flag_extended = "149dc1fffceebc" self.task_set.appian.interactor.client.feature_flag = "7ffceebc" # When feature_toggle_helper.override_default_flags(self.task_set.appian.interactor, flags) # Then self.assertEqual(self.task_set.appian.interactor.client.feature_flag_extended, expected_featured_flag_extended) self.assertEqual(self.task_set.appian.interactor.client.feature_flag, expected_feature_flag) def test_override_default_flags_no_flags(self) -> None: # Given a snippet of the sites page flags: List[FeatureFlag] = [] self.override_default_flags_runner(flags, "149dc1fffceebc", "7ffceebc") def test_override_default_flags_one_flag(self) -> None: # Given a snippet of the sites page flags = [FeatureFlag.SHORT_CIRCUIT_PARTIAL_RENDERING] self.override_default_flags_runner(flags, "149dc1fffcefbc", "7ffcefbc") def test_override_default_flags_multiple_flags(self) -> None: # Given a snippet of the sites page flags = [FeatureFlag.SHORT_CIRCUIT_PARTIAL_RENDERING, FeatureFlag.INLINE_TASK_CONTROLS] self.override_default_flags_runner(flags, "149dc1fffcffbc", "7ffcffbc") def test_declare_device_as_mobile(self) -> None: # Given a snippet of the sites page self.custom_locust.set_response("/suite/sites", 200, self.html_snippet) flags = [FeatureFlag.RECORD_LIST_FEED_ITEM_DTO] self.override_default_flags_runner(flags, "149dd1fffceebc", "7ffceebc")