Beispiel #1
0
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)
Beispiel #3
0
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)
Beispiel #5
0
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)
Beispiel #6
0
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"
        )
Beispiel #8
0
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()
Beispiel #12
0
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)
Beispiel #13
0
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")