cumulusci-plus 5.0.0__py3-none-any.whl
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Potentially problematic release.
This version of cumulusci-plus might be problematic. Click here for more details.
- cumulusci/__about__.py +1 -0
- cumulusci/__init__.py +22 -0
- cumulusci/__main__.py +3 -0
- cumulusci/cli/__init__.py +0 -0
- cumulusci/cli/cci.py +244 -0
- cumulusci/cli/error.py +125 -0
- cumulusci/cli/flow.py +185 -0
- cumulusci/cli/logger.py +72 -0
- cumulusci/cli/org.py +692 -0
- cumulusci/cli/plan.py +181 -0
- cumulusci/cli/project.py +391 -0
- cumulusci/cli/robot.py +116 -0
- cumulusci/cli/runtime.py +190 -0
- cumulusci/cli/service.py +521 -0
- cumulusci/cli/task.py +295 -0
- cumulusci/cli/tests/__init__.py +0 -0
- cumulusci/cli/tests/test_cci.py +545 -0
- cumulusci/cli/tests/test_error.py +170 -0
- cumulusci/cli/tests/test_flow.py +276 -0
- cumulusci/cli/tests/test_logger.py +25 -0
- cumulusci/cli/tests/test_org.py +1438 -0
- cumulusci/cli/tests/test_plan.py +245 -0
- cumulusci/cli/tests/test_project.py +235 -0
- cumulusci/cli/tests/test_robot.py +177 -0
- cumulusci/cli/tests/test_runtime.py +197 -0
- cumulusci/cli/tests/test_service.py +853 -0
- cumulusci/cli/tests/test_task.py +266 -0
- cumulusci/cli/tests/test_ui.py +310 -0
- cumulusci/cli/tests/test_utils.py +122 -0
- cumulusci/cli/tests/utils.py +52 -0
- cumulusci/cli/ui.py +234 -0
- cumulusci/cli/utils.py +150 -0
- cumulusci/conftest.py +181 -0
- cumulusci/core/__init__.py +0 -0
- cumulusci/core/config/BaseConfig.py +5 -0
- cumulusci/core/config/BaseTaskFlowConfig.py +5 -0
- cumulusci/core/config/OrgConfig.py +5 -0
- cumulusci/core/config/ScratchOrgConfig.py +5 -0
- cumulusci/core/config/__init__.py +125 -0
- cumulusci/core/config/base_config.py +111 -0
- cumulusci/core/config/base_task_flow_config.py +82 -0
- cumulusci/core/config/marketing_cloud_service_config.py +83 -0
- cumulusci/core/config/oauth2_service_config.py +17 -0
- cumulusci/core/config/org_config.py +604 -0
- cumulusci/core/config/project_config.py +782 -0
- cumulusci/core/config/scratch_org_config.py +251 -0
- cumulusci/core/config/sfdx_org_config.py +220 -0
- cumulusci/core/config/tests/_test_config_backwards_compatibility.py +33 -0
- cumulusci/core/config/tests/test_config.py +1895 -0
- cumulusci/core/config/tests/test_config_expensive.py +839 -0
- cumulusci/core/config/tests/test_config_util.py +91 -0
- cumulusci/core/config/universal_config.py +88 -0
- cumulusci/core/config/util.py +18 -0
- cumulusci/core/datasets.py +303 -0
- cumulusci/core/debug.py +33 -0
- cumulusci/core/dependencies/__init__.py +55 -0
- cumulusci/core/dependencies/base.py +561 -0
- cumulusci/core/dependencies/dependencies.py +273 -0
- cumulusci/core/dependencies/github.py +177 -0
- cumulusci/core/dependencies/github_resolvers.py +244 -0
- cumulusci/core/dependencies/resolvers.py +580 -0
- cumulusci/core/dependencies/tests/__init__.py +0 -0
- cumulusci/core/dependencies/tests/conftest.py +385 -0
- cumulusci/core/dependencies/tests/test_dependencies.py +950 -0
- cumulusci/core/dependencies/tests/test_github.py +83 -0
- cumulusci/core/dependencies/tests/test_resolvers.py +1027 -0
- cumulusci/core/dependencies/utils.py +13 -0
- cumulusci/core/enums.py +11 -0
- cumulusci/core/exceptions.py +311 -0
- cumulusci/core/flowrunner.py +888 -0
- cumulusci/core/github.py +665 -0
- cumulusci/core/keychain/__init__.py +24 -0
- cumulusci/core/keychain/base_project_keychain.py +441 -0
- cumulusci/core/keychain/encrypted_file_project_keychain.py +945 -0
- cumulusci/core/keychain/environment_project_keychain.py +7 -0
- cumulusci/core/keychain/serialization.py +152 -0
- cumulusci/core/keychain/subprocess_keychain.py +24 -0
- cumulusci/core/keychain/tests/conftest.py +50 -0
- cumulusci/core/keychain/tests/test_base_project_keychain.py +299 -0
- cumulusci/core/keychain/tests/test_encrypted_file_project_keychain.py +1228 -0
- cumulusci/core/metadeploy/__init__.py +0 -0
- cumulusci/core/metadeploy/api.py +88 -0
- cumulusci/core/metadeploy/plans.py +25 -0
- cumulusci/core/metadeploy/tests/test_api.py +276 -0
- cumulusci/core/runtime.py +115 -0
- cumulusci/core/sfdx.py +162 -0
- cumulusci/core/source/__init__.py +16 -0
- cumulusci/core/source/github.py +50 -0
- cumulusci/core/source/local_folder.py +35 -0
- cumulusci/core/source_transforms/__init__.py +0 -0
- cumulusci/core/source_transforms/tests/test_transforms.py +1091 -0
- cumulusci/core/source_transforms/transforms.py +532 -0
- cumulusci/core/tasks.py +404 -0
- cumulusci/core/template_utils.py +59 -0
- cumulusci/core/tests/__init__.py +0 -0
- cumulusci/core/tests/cassettes/TestDatasetsE2E.test_datasets_e2e.yaml +215 -0
- cumulusci/core/tests/cassettes/TestDatasetsE2E.test_datasets_extract_standard_objects.yaml +199 -0
- cumulusci/core/tests/cassettes/TestDatasetsE2E.test_datasets_read_explicit_extract_declaration.yaml +3 -0
- cumulusci/core/tests/fake_remote_repo/cumulusci.yml +32 -0
- cumulusci/core/tests/fake_remote_repo/tasks/directory/example_2.py +6 -0
- cumulusci/core/tests/fake_remote_repo/tasks/example.py +43 -0
- cumulusci/core/tests/fake_remote_repo_2/cumulusci.yml +11 -0
- cumulusci/core/tests/fake_remote_repo_2/tasks/example_3.py +6 -0
- cumulusci/core/tests/test_datasets_e2e.py +386 -0
- cumulusci/core/tests/test_exceptions.py +11 -0
- cumulusci/core/tests/test_flowrunner.py +836 -0
- cumulusci/core/tests/test_github.py +942 -0
- cumulusci/core/tests/test_sfdx.py +138 -0
- cumulusci/core/tests/test_source.py +678 -0
- cumulusci/core/tests/test_tasks.py +262 -0
- cumulusci/core/tests/test_utils.py +141 -0
- cumulusci/core/tests/test_utils_merge_config.py +276 -0
- cumulusci/core/tests/test_versions.py +76 -0
- cumulusci/core/tests/untrusted_repo_child/cumulusci.yml +7 -0
- cumulusci/core/tests/untrusted_repo_child/tasks/untrusted_child.py +6 -0
- cumulusci/core/tests/untrusted_repo_parent/cumulusci.yml +26 -0
- cumulusci/core/tests/untrusted_repo_parent/tasks/untrusted_parent.py +6 -0
- cumulusci/core/tests/utils.py +116 -0
- cumulusci/core/tests/yaml/global.yaml +0 -0
- cumulusci/core/utils.py +402 -0
- cumulusci/core/versions.py +149 -0
- cumulusci/cumulusci.yml +1621 -0
- cumulusci/files/admin_profile.xml +20 -0
- cumulusci/files/delete_excludes.txt +424 -0
- cumulusci/files/templates/project/README.md +12 -0
- cumulusci/files/templates/project/cumulusci.yml +63 -0
- cumulusci/files/templates/project/dot-gitignore +60 -0
- cumulusci/files/templates/project/mapping.yml +45 -0
- cumulusci/files/templates/project/scratch_def.json +25 -0
- cumulusci/oauth/__init__.py +0 -0
- cumulusci/oauth/client.py +400 -0
- cumulusci/oauth/exceptions.py +9 -0
- cumulusci/oauth/salesforce.py +95 -0
- cumulusci/oauth/tests/__init__.py +0 -0
- cumulusci/oauth/tests/cassettes/test_get_device_code.yaml +22 -0
- cumulusci/oauth/tests/cassettes/test_get_device_oauth_token.yaml +74 -0
- cumulusci/oauth/tests/test_client.py +308 -0
- cumulusci/oauth/tests/test_salesforce.py +46 -0
- cumulusci/plugins/__init__.py +3 -0
- cumulusci/plugins/plugin_base.py +93 -0
- cumulusci/plugins/plugin_loader.py +59 -0
- cumulusci/robotframework/CumulusCI.py +340 -0
- cumulusci/robotframework/CumulusCI.robot +7 -0
- cumulusci/robotframework/Performance.py +165 -0
- cumulusci/robotframework/Salesforce.py +936 -0
- cumulusci/robotframework/Salesforce.robot +192 -0
- cumulusci/robotframework/SalesforceAPI.py +416 -0
- cumulusci/robotframework/SalesforcePlaywright.py +220 -0
- cumulusci/robotframework/SalesforcePlaywright.robot +40 -0
- cumulusci/robotframework/__init__.py +2 -0
- cumulusci/robotframework/base_library.py +39 -0
- cumulusci/robotframework/faker_mixin.py +89 -0
- cumulusci/robotframework/form_handlers.py +222 -0
- cumulusci/robotframework/javascript/cci_init.js +34 -0
- cumulusci/robotframework/javascript/cumulusci.js +4 -0
- cumulusci/robotframework/locator_manager.py +197 -0
- cumulusci/robotframework/locators_56.py +88 -0
- cumulusci/robotframework/locators_57.py +5 -0
- cumulusci/robotframework/pageobjects/BasePageObjects.py +433 -0
- cumulusci/robotframework/pageobjects/ObjectManagerPageObject.py +246 -0
- cumulusci/robotframework/pageobjects/PageObjectLibrary.py +45 -0
- cumulusci/robotframework/pageobjects/PageObjects.py +351 -0
- cumulusci/robotframework/pageobjects/__init__.py +12 -0
- cumulusci/robotframework/pageobjects/baseobjects.py +120 -0
- cumulusci/robotframework/perftests/short/collection_perf.robot +105 -0
- cumulusci/robotframework/tests/CustomObjectTestPage.py +10 -0
- cumulusci/robotframework/tests/FooTestPage.py +8 -0
- cumulusci/robotframework/tests/cumulusci/base.robot +40 -0
- cumulusci/robotframework/tests/cumulusci/bulkdata.robot +38 -0
- cumulusci/robotframework/tests/cumulusci/communities.robot +57 -0
- cumulusci/robotframework/tests/cumulusci/datagen.robot +84 -0
- cumulusci/robotframework/tests/salesforce/TestLibraryA.py +24 -0
- cumulusci/robotframework/tests/salesforce/TestLibraryB.py +20 -0
- cumulusci/robotframework/tests/salesforce/TestListener.py +93 -0
- cumulusci/robotframework/tests/salesforce/api.robot +178 -0
- cumulusci/robotframework/tests/salesforce/browsers.robot +143 -0
- cumulusci/robotframework/tests/salesforce/classic.robot +51 -0
- cumulusci/robotframework/tests/salesforce/create_contact.robot +59 -0
- cumulusci/robotframework/tests/salesforce/faker.robot +68 -0
- cumulusci/robotframework/tests/salesforce/forms.robot +172 -0
- cumulusci/robotframework/tests/salesforce/label_locator.robot +244 -0
- cumulusci/robotframework/tests/salesforce/labels.html +33 -0
- cumulusci/robotframework/tests/salesforce/locators.robot +149 -0
- cumulusci/robotframework/tests/salesforce/pageobjects/base_pageobjects.robot +100 -0
- cumulusci/robotframework/tests/salesforce/pageobjects/example_page_object.py +25 -0
- cumulusci/robotframework/tests/salesforce/pageobjects/listing_page.robot +115 -0
- cumulusci/robotframework/tests/salesforce/pageobjects/objectmanager.robot +74 -0
- cumulusci/robotframework/tests/salesforce/pageobjects/pageobjects.robot +171 -0
- cumulusci/robotframework/tests/salesforce/performance.robot +109 -0
- cumulusci/robotframework/tests/salesforce/playwright/javascript_keywords.robot +33 -0
- cumulusci/robotframework/tests/salesforce/playwright/open_test_browser.robot +48 -0
- cumulusci/robotframework/tests/salesforce/playwright/playwright.robot +24 -0
- cumulusci/robotframework/tests/salesforce/playwright/ui.robot +32 -0
- cumulusci/robotframework/tests/salesforce/populate.robot +89 -0
- cumulusci/robotframework/tests/salesforce/test_testlistener.py +37 -0
- cumulusci/robotframework/tests/salesforce/ui.robot +361 -0
- cumulusci/robotframework/tests/test_cumulusci_library.py +304 -0
- cumulusci/robotframework/tests/test_locator_manager.py +158 -0
- cumulusci/robotframework/tests/test_pageobjects.py +291 -0
- cumulusci/robotframework/tests/test_performance.py +38 -0
- cumulusci/robotframework/tests/test_salesforce.py +79 -0
- cumulusci/robotframework/tests/test_salesforce_locators.py +73 -0
- cumulusci/robotframework/tests/test_template_util.py +53 -0
- cumulusci/robotframework/tests/test_utils.py +106 -0
- cumulusci/robotframework/utils.py +283 -0
- cumulusci/salesforce_api/__init__.py +0 -0
- cumulusci/salesforce_api/exceptions.py +23 -0
- cumulusci/salesforce_api/filterable_objects.py +96 -0
- cumulusci/salesforce_api/mc_soap_envelopes.py +89 -0
- cumulusci/salesforce_api/metadata.py +721 -0
- cumulusci/salesforce_api/org_schema.py +571 -0
- cumulusci/salesforce_api/org_schema_models.py +226 -0
- cumulusci/salesforce_api/package_install.py +265 -0
- cumulusci/salesforce_api/package_zip.py +301 -0
- cumulusci/salesforce_api/rest_deploy.py +148 -0
- cumulusci/salesforce_api/retrieve_profile_api.py +301 -0
- cumulusci/salesforce_api/soap_envelopes.py +177 -0
- cumulusci/salesforce_api/tests/__init__.py +0 -0
- cumulusci/salesforce_api/tests/metadata_test_strings.py +24 -0
- cumulusci/salesforce_api/tests/test_metadata.py +1015 -0
- cumulusci/salesforce_api/tests/test_package_install.py +219 -0
- cumulusci/salesforce_api/tests/test_package_zip.py +380 -0
- cumulusci/salesforce_api/tests/test_rest_deploy.py +264 -0
- cumulusci/salesforce_api/tests/test_retrieve_profile_api.py +337 -0
- cumulusci/salesforce_api/tests/test_utils.py +124 -0
- cumulusci/salesforce_api/utils.py +51 -0
- cumulusci/schema/cumulusci.jsonschema.json +782 -0
- cumulusci/tasks/__init__.py +0 -0
- cumulusci/tasks/apex/__init__.py +0 -0
- cumulusci/tasks/apex/anon.py +157 -0
- cumulusci/tasks/apex/batch.py +180 -0
- cumulusci/tasks/apex/testrunner.py +835 -0
- cumulusci/tasks/apex/tests/cassettes/ManualEditTestApexIntegrationTests.test_run_tests__integration_test.yaml +703 -0
- cumulusci/tasks/apex/tests/test_apex_tasks.py +1558 -0
- cumulusci/tasks/base_source_control_task.py +17 -0
- cumulusci/tasks/bulkdata/__init__.py +15 -0
- cumulusci/tasks/bulkdata/base_generate_data_task.py +96 -0
- cumulusci/tasks/bulkdata/dates.py +97 -0
- cumulusci/tasks/bulkdata/delete.py +156 -0
- cumulusci/tasks/bulkdata/extract.py +441 -0
- cumulusci/tasks/bulkdata/extract_dataset_utils/calculate_dependencies.py +117 -0
- cumulusci/tasks/bulkdata/extract_dataset_utils/extract_yml.py +123 -0
- cumulusci/tasks/bulkdata/extract_dataset_utils/hardcoded_default_declarations.py +49 -0
- cumulusci/tasks/bulkdata/extract_dataset_utils/synthesize_extract_declarations.py +283 -0
- cumulusci/tasks/bulkdata/extract_dataset_utils/tests/test_extract_yml.py +142 -0
- cumulusci/tasks/bulkdata/extract_dataset_utils/tests/test_synthesize_extract_declarations.py +575 -0
- cumulusci/tasks/bulkdata/factory_utils.py +134 -0
- cumulusci/tasks/bulkdata/generate.py +4 -0
- cumulusci/tasks/bulkdata/generate_and_load_data.py +232 -0
- cumulusci/tasks/bulkdata/generate_and_load_data_from_yaml.py +19 -0
- cumulusci/tasks/bulkdata/generate_from_yaml.py +183 -0
- cumulusci/tasks/bulkdata/generate_mapping.py +434 -0
- cumulusci/tasks/bulkdata/generate_mapping_utils/dependency_map.py +169 -0
- cumulusci/tasks/bulkdata/generate_mapping_utils/extract_mapping_file_generator.py +45 -0
- cumulusci/tasks/bulkdata/generate_mapping_utils/generate_mapping_from_declarations.py +121 -0
- cumulusci/tasks/bulkdata/generate_mapping_utils/load_mapping_file_generator.py +127 -0
- cumulusci/tasks/bulkdata/generate_mapping_utils/mapping_generator_post_processes.py +53 -0
- cumulusci/tasks/bulkdata/generate_mapping_utils/mapping_transforms.py +139 -0
- cumulusci/tasks/bulkdata/generate_mapping_utils/tests/test_generate_extract_mapping_from_declarations.py +135 -0
- cumulusci/tasks/bulkdata/generate_mapping_utils/tests/test_generate_load_mapping_from_declarations.py +330 -0
- cumulusci/tasks/bulkdata/generate_mapping_utils/tests/test_mapping_generator_post_processes.py +60 -0
- cumulusci/tasks/bulkdata/generate_mapping_utils/tests/test_mapping_transforms.py +188 -0
- cumulusci/tasks/bulkdata/load.py +1196 -0
- cumulusci/tasks/bulkdata/mapping_parser.py +811 -0
- cumulusci/tasks/bulkdata/query_transformers.py +264 -0
- cumulusci/tasks/bulkdata/select_utils.py +792 -0
- cumulusci/tasks/bulkdata/snowfakery.py +753 -0
- cumulusci/tasks/bulkdata/snowfakery_utils/queue_manager.py +478 -0
- cumulusci/tasks/bulkdata/snowfakery_utils/snowfakery_run_until.py +141 -0
- cumulusci/tasks/bulkdata/snowfakery_utils/snowfakery_working_directory.py +53 -0
- cumulusci/tasks/bulkdata/snowfakery_utils/subtask_configurator.py +64 -0
- cumulusci/tasks/bulkdata/step.py +1242 -0
- cumulusci/tasks/bulkdata/tests/__init__.py +0 -0
- cumulusci/tasks/bulkdata/tests/cassettes/TestSelect.test_select_random_strategy.yaml +147 -0
- cumulusci/tasks/bulkdata/tests/cassettes/TestSelect.test_select_similarity_annoy_strategy.yaml +123 -0
- cumulusci/tasks/bulkdata/tests/cassettes/TestSelect.test_select_similarity_select_and_insert_strategy.yaml +313 -0
- cumulusci/tasks/bulkdata/tests/cassettes/TestSelect.test_select_similarity_select_and_insert_strategy_bulk.yaml +550 -0
- cumulusci/tasks/bulkdata/tests/cassettes/TestSelect.test_select_similarity_strategy.yaml +175 -0
- cumulusci/tasks/bulkdata/tests/cassettes/TestSelect.test_select_standard_strategy.yaml +147 -0
- cumulusci/tasks/bulkdata/tests/cassettes/TestSnowfakery.test_run_until_records_in_org__multiple_needed.yaml +69 -0
- cumulusci/tasks/bulkdata/tests/cassettes/TestSnowfakery.test_run_until_records_in_org__none_needed.yaml +22 -0
- cumulusci/tasks/bulkdata/tests/cassettes/TestSnowfakery.test_run_until_records_in_org__one_needed.yaml +24 -0
- cumulusci/tasks/bulkdata/tests/cassettes/TestSnowfakery.test_snowfakery_query_salesforce.yaml +25 -0
- cumulusci/tasks/bulkdata/tests/cassettes/TestUpdatesIntegrationTests.test_updates_task.yaml +80 -0
- cumulusci/tasks/bulkdata/tests/cassettes/TestUpsert.test_simple_upsert__rest.yaml +270 -0
- cumulusci/tasks/bulkdata/tests/cassettes/TestUpsert.test_upsert__rest.yaml +267 -0
- cumulusci/tasks/bulkdata/tests/cassettes/TestUpsert.test_upsert_complex_external_id_field__rest.yaml +369 -0
- cumulusci/tasks/bulkdata/tests/cassettes/TestUpsert.test_upsert_complex_external_id_field_rest__duplicate_error.yaml +204 -0
- cumulusci/tasks/bulkdata/tests/cassettes/TestUpsert.test_upsert_complex_fields__bulk.yaml +675 -0
- cumulusci/tasks/bulkdata/tests/dummy_data_factory.py +36 -0
- cumulusci/tasks/bulkdata/tests/integration_test_utils.py +49 -0
- cumulusci/tasks/bulkdata/tests/mapping-oid.yml +87 -0
- cumulusci/tasks/bulkdata/tests/mapping_after.yml +38 -0
- cumulusci/tasks/bulkdata/tests/mapping_poly.yml +34 -0
- cumulusci/tasks/bulkdata/tests/mapping_poly_incomplete.yml +20 -0
- cumulusci/tasks/bulkdata/tests/mapping_poly_wrong.yml +21 -0
- cumulusci/tasks/bulkdata/tests/mapping_select.yml +20 -0
- cumulusci/tasks/bulkdata/tests/mapping_select_invalid_strategy.yml +20 -0
- cumulusci/tasks/bulkdata/tests/mapping_select_invalid_threshold__invalid_number.yml +21 -0
- cumulusci/tasks/bulkdata/tests/mapping_select_invalid_threshold__invalid_strategy.yml +21 -0
- cumulusci/tasks/bulkdata/tests/mapping_select_invalid_threshold__non_float.yml +21 -0
- cumulusci/tasks/bulkdata/tests/mapping_select_missing_priority_fields.yml +22 -0
- cumulusci/tasks/bulkdata/tests/mapping_select_no_priority_fields.yml +18 -0
- cumulusci/tasks/bulkdata/tests/mapping_simple.yml +27 -0
- cumulusci/tasks/bulkdata/tests/mapping_v1.yml +28 -0
- cumulusci/tasks/bulkdata/tests/mapping_v2.yml +21 -0
- cumulusci/tasks/bulkdata/tests/mapping_v3.yml +32 -0
- cumulusci/tasks/bulkdata/tests/mapping_vanilla_sf.yml +69 -0
- cumulusci/tasks/bulkdata/tests/mock_data_factory_without_mapping.py +12 -0
- cumulusci/tasks/bulkdata/tests/person_accounts.yml +23 -0
- cumulusci/tasks/bulkdata/tests/person_accounts_minimal.yml +15 -0
- cumulusci/tasks/bulkdata/tests/recordtypes.yml +8 -0
- cumulusci/tasks/bulkdata/tests/recordtypes_2.yml +6 -0
- cumulusci/tasks/bulkdata/tests/recordtypes_with_ispersontype.yml +8 -0
- cumulusci/tasks/bulkdata/tests/snowfakery/child/child2.yml +3 -0
- cumulusci/tasks/bulkdata/tests/snowfakery/child.yml +4 -0
- cumulusci/tasks/bulkdata/tests/snowfakery/gen_npsp_standard_objects.recipe.yml +89 -0
- cumulusci/tasks/bulkdata/tests/snowfakery/include_parent.yml +3 -0
- cumulusci/tasks/bulkdata/tests/snowfakery/npsp_standard_objects_macros.yml +34 -0
- cumulusci/tasks/bulkdata/tests/snowfakery/options.recipe.yml +6 -0
- cumulusci/tasks/bulkdata/tests/snowfakery/query_snowfakery.recipe.yml +16 -0
- cumulusci/tasks/bulkdata/tests/snowfakery/sf_standard_object_macros.yml +83 -0
- cumulusci/tasks/bulkdata/tests/snowfakery/simple_snowfakery.load.yml +2 -0
- cumulusci/tasks/bulkdata/tests/snowfakery/simple_snowfakery.recipe.yml +13 -0
- cumulusci/tasks/bulkdata/tests/snowfakery/simple_snowfakery_2.load.yml +5 -0
- cumulusci/tasks/bulkdata/tests/snowfakery/simple_snowfakery_channels.load.yml +13 -0
- cumulusci/tasks/bulkdata/tests/snowfakery/simple_snowfakery_channels.recipe.yml +12 -0
- cumulusci/tasks/bulkdata/tests/snowfakery/simple_snowfakery_channels_2.load.yml +13 -0
- cumulusci/tasks/bulkdata/tests/snowfakery/unique_values.recipe.yml +4 -0
- cumulusci/tasks/bulkdata/tests/snowfakery/upsert.recipe.yml +23 -0
- cumulusci/tasks/bulkdata/tests/snowfakery/upsert_2.recipe.yml +29 -0
- cumulusci/tasks/bulkdata/tests/snowfakery/upsert_before.yml +10 -0
- cumulusci/tasks/bulkdata/tests/test_base_generate_data_tasks.py +61 -0
- cumulusci/tasks/bulkdata/tests/test_dates.py +99 -0
- cumulusci/tasks/bulkdata/tests/test_delete.py +404 -0
- cumulusci/tasks/bulkdata/tests/test_extract.py +1311 -0
- cumulusci/tasks/bulkdata/tests/test_factory_utils.py +55 -0
- cumulusci/tasks/bulkdata/tests/test_generate_and_load.py +252 -0
- cumulusci/tasks/bulkdata/tests/test_generate_from_snowfakery_task.py +343 -0
- cumulusci/tasks/bulkdata/tests/test_generatemapping.py +1039 -0
- cumulusci/tasks/bulkdata/tests/test_load.py +3175 -0
- cumulusci/tasks/bulkdata/tests/test_mapping_parser.py +1658 -0
- cumulusci/tasks/bulkdata/tests/test_query_db__joins_self_lookups.yml +12 -0
- cumulusci/tasks/bulkdata/tests/test_query_db_joins_lookups.yml +26 -0
- cumulusci/tasks/bulkdata/tests/test_query_db_joins_lookups_select.yml +48 -0
- cumulusci/tasks/bulkdata/tests/test_select.py +171 -0
- cumulusci/tasks/bulkdata/tests/test_select_utils.py +1057 -0
- cumulusci/tasks/bulkdata/tests/test_snowfakery.py +1153 -0
- cumulusci/tasks/bulkdata/tests/test_step.py +3957 -0
- cumulusci/tasks/bulkdata/tests/test_updates.py +513 -0
- cumulusci/tasks/bulkdata/tests/test_upsert.py +1015 -0
- cumulusci/tasks/bulkdata/tests/test_utils.py +158 -0
- cumulusci/tasks/bulkdata/tests/testdata.db +0 -0
- cumulusci/tasks/bulkdata/tests/update_describe.py +50 -0
- cumulusci/tasks/bulkdata/tests/update_person_accounts.yml +23 -0
- cumulusci/tasks/bulkdata/tests/utils.py +114 -0
- cumulusci/tasks/bulkdata/update_data.py +260 -0
- cumulusci/tasks/bulkdata/upsert_utils.py +130 -0
- cumulusci/tasks/bulkdata/utils.py +249 -0
- cumulusci/tasks/command.py +178 -0
- cumulusci/tasks/connectedapp.py +186 -0
- cumulusci/tasks/create_package_version.py +778 -0
- cumulusci/tasks/datadictionary.py +745 -0
- cumulusci/tasks/dx_convert_from.py +26 -0
- cumulusci/tasks/github/__init__.py +17 -0
- cumulusci/tasks/github/base.py +16 -0
- cumulusci/tasks/github/commit_status.py +13 -0
- cumulusci/tasks/github/merge.py +11 -0
- cumulusci/tasks/github/publish.py +11 -0
- cumulusci/tasks/github/pull_request.py +11 -0
- cumulusci/tasks/github/release.py +11 -0
- cumulusci/tasks/github/release_report.py +11 -0
- cumulusci/tasks/github/tag.py +11 -0
- cumulusci/tasks/github/tests/__init__.py +0 -0
- cumulusci/tasks/github/tests/test_util.py +202 -0
- cumulusci/tasks/github/tests/test_vcs_migration.py +44 -0
- cumulusci/tasks/github/tests/util_github_api.py +666 -0
- cumulusci/tasks/github/util.py +252 -0
- cumulusci/tasks/marketing_cloud/__init__.py +0 -0
- cumulusci/tasks/marketing_cloud/api.py +188 -0
- cumulusci/tasks/marketing_cloud/base.py +38 -0
- cumulusci/tasks/marketing_cloud/deploy.py +345 -0
- cumulusci/tasks/marketing_cloud/get_user_info.py +40 -0
- cumulusci/tasks/marketing_cloud/mc_constants.py +1 -0
- cumulusci/tasks/marketing_cloud/tests/__init__.py +0 -0
- cumulusci/tasks/marketing_cloud/tests/conftest.py +46 -0
- cumulusci/tasks/marketing_cloud/tests/expected-payload.json +110 -0
- cumulusci/tasks/marketing_cloud/tests/test_api.py +97 -0
- cumulusci/tasks/marketing_cloud/tests/test_api_soap_envelopes.py +145 -0
- cumulusci/tasks/marketing_cloud/tests/test_base.py +14 -0
- cumulusci/tasks/marketing_cloud/tests/test_deploy.py +400 -0
- cumulusci/tasks/marketing_cloud/tests/test_get_user_info.py +141 -0
- cumulusci/tasks/marketing_cloud/tests/validation-response.json +39 -0
- cumulusci/tasks/metadata/__init__.py +0 -0
- cumulusci/tasks/metadata/ee_src.py +94 -0
- cumulusci/tasks/metadata/managed_src.py +100 -0
- cumulusci/tasks/metadata/metadata_map.yml +868 -0
- cumulusci/tasks/metadata/modify.py +99 -0
- cumulusci/tasks/metadata/package.py +684 -0
- cumulusci/tasks/metadata/tests/__init__.py +0 -0
- cumulusci/tasks/metadata/tests/package_metadata/namespaced_report_folder/.hidden/.keep +0 -0
- cumulusci/tasks/metadata/tests/package_metadata/namespaced_report_folder/destructiveChanges.xml +9 -0
- cumulusci/tasks/metadata/tests/package_metadata/namespaced_report_folder/package.xml +9 -0
- cumulusci/tasks/metadata/tests/package_metadata/namespaced_report_folder/package_install_uninstall.xml +11 -0
- cumulusci/tasks/metadata/tests/package_metadata/namespaced_report_folder/reports/namespace__TestFolder/TestReport.report +3 -0
- cumulusci/tasks/metadata/tests/sample_package.xml +9 -0
- cumulusci/tasks/metadata/tests/test_ee_src.py +112 -0
- cumulusci/tasks/metadata/tests/test_managed_src.py +111 -0
- cumulusci/tasks/metadata/tests/test_modify.py +123 -0
- cumulusci/tasks/metadata/tests/test_package.py +476 -0
- cumulusci/tasks/metadata_etl/__init__.py +29 -0
- cumulusci/tasks/metadata_etl/base.py +436 -0
- cumulusci/tasks/metadata_etl/duplicate_rules.py +24 -0
- cumulusci/tasks/metadata_etl/field_sets.py +70 -0
- cumulusci/tasks/metadata_etl/help_text.py +92 -0
- cumulusci/tasks/metadata_etl/layouts.py +550 -0
- cumulusci/tasks/metadata_etl/objects.py +68 -0
- cumulusci/tasks/metadata_etl/permissions.py +167 -0
- cumulusci/tasks/metadata_etl/picklists.py +221 -0
- cumulusci/tasks/metadata_etl/remote_site_settings.py +99 -0
- cumulusci/tasks/metadata_etl/sharing.py +138 -0
- cumulusci/tasks/metadata_etl/tests/test_base.py +512 -0
- cumulusci/tasks/metadata_etl/tests/test_duplicate_rules.py +22 -0
- cumulusci/tasks/metadata_etl/tests/test_field_sets.py +156 -0
- cumulusci/tasks/metadata_etl/tests/test_help_text.py +387 -0
- cumulusci/tasks/metadata_etl/tests/test_ip_ranges.py +85 -0
- cumulusci/tasks/metadata_etl/tests/test_layouts.py +858 -0
- cumulusci/tasks/metadata_etl/tests/test_objects.py +236 -0
- cumulusci/tasks/metadata_etl/tests/test_permissions.py +223 -0
- cumulusci/tasks/metadata_etl/tests/test_picklists.py +547 -0
- cumulusci/tasks/metadata_etl/tests/test_remote_site_settings.py +46 -0
- cumulusci/tasks/metadata_etl/tests/test_sharing.py +333 -0
- cumulusci/tasks/metadata_etl/tests/test_value_sets.py +298 -0
- cumulusci/tasks/metadata_etl/value_sets.py +106 -0
- cumulusci/tasks/metadeploy.py +393 -0
- cumulusci/tasks/metaxml.py +88 -0
- cumulusci/tasks/preflight/__init__.py +0 -0
- cumulusci/tasks/preflight/dataset_load.py +49 -0
- cumulusci/tasks/preflight/licenses.py +86 -0
- cumulusci/tasks/preflight/packages.py +14 -0
- cumulusci/tasks/preflight/permsets.py +23 -0
- cumulusci/tasks/preflight/recordtypes.py +16 -0
- cumulusci/tasks/preflight/retrieve_tasks.py +30 -0
- cumulusci/tasks/preflight/settings.py +77 -0
- cumulusci/tasks/preflight/sobjects.py +202 -0
- cumulusci/tasks/preflight/tests/test_dataset_load.py +85 -0
- cumulusci/tasks/preflight/tests/test_licenses.py +174 -0
- cumulusci/tasks/preflight/tests/test_packages.py +14 -0
- cumulusci/tasks/preflight/tests/test_permset_preflights.py +51 -0
- cumulusci/tasks/preflight/tests/test_recordtypes.py +30 -0
- cumulusci/tasks/preflight/tests/test_retrieve_tasks.py +62 -0
- cumulusci/tasks/preflight/tests/test_settings.py +130 -0
- cumulusci/tasks/preflight/tests/test_sobjects.py +231 -0
- cumulusci/tasks/push/README.md +59 -0
- cumulusci/tasks/push/__init__.py +0 -0
- cumulusci/tasks/push/push_api.py +659 -0
- cumulusci/tasks/push/pushfails.py +136 -0
- cumulusci/tasks/push/tasks.py +476 -0
- cumulusci/tasks/push/tests/conftest.py +263 -0
- cumulusci/tasks/push/tests/test_push_api.py +951 -0
- cumulusci/tasks/push/tests/test_push_tasks.py +659 -0
- cumulusci/tasks/release_notes/README.md +63 -0
- cumulusci/tasks/release_notes/__init__.py +0 -0
- cumulusci/tasks/release_notes/exceptions.py +5 -0
- cumulusci/tasks/release_notes/generator.py +137 -0
- cumulusci/tasks/release_notes/parser.py +232 -0
- cumulusci/tasks/release_notes/provider.py +44 -0
- cumulusci/tasks/release_notes/task.py +300 -0
- cumulusci/tasks/release_notes/tests/__init__.py +0 -0
- cumulusci/tasks/release_notes/tests/change_notes/full/example1.md +17 -0
- cumulusci/tasks/release_notes/tests/change_notes/multi/1.txt +1 -0
- cumulusci/tasks/release_notes/tests/change_notes/multi/2.txt +1 -0
- cumulusci/tasks/release_notes/tests/change_notes/multi/3.txt +1 -0
- cumulusci/tasks/release_notes/tests/change_notes/single/1.txt +1 -0
- cumulusci/tasks/release_notes/tests/test_generator.py +582 -0
- cumulusci/tasks/release_notes/tests/test_parser.py +867 -0
- cumulusci/tasks/release_notes/tests/test_provider.py +512 -0
- cumulusci/tasks/release_notes/tests/test_task.py +461 -0
- cumulusci/tasks/release_notes/tests/utils.py +153 -0
- cumulusci/tasks/robotframework/__init__.py +3 -0
- cumulusci/tasks/robotframework/debugger/DebugListener.py +100 -0
- cumulusci/tasks/robotframework/debugger/__init__.py +10 -0
- cumulusci/tasks/robotframework/debugger/model.py +87 -0
- cumulusci/tasks/robotframework/debugger/ui.py +259 -0
- cumulusci/tasks/robotframework/libdoc.py +269 -0
- cumulusci/tasks/robotframework/robotframework.py +392 -0
- cumulusci/tasks/robotframework/stylesheet.css +130 -0
- cumulusci/tasks/robotframework/template.html +109 -0
- cumulusci/tasks/robotframework/tests/TestLibrary.py +18 -0
- cumulusci/tasks/robotframework/tests/TestPageObjects.py +31 -0
- cumulusci/tasks/robotframework/tests/TestResource.robot +8 -0
- cumulusci/tasks/robotframework/tests/failing_tests.robot +16 -0
- cumulusci/tasks/robotframework/tests/performance.robot +23 -0
- cumulusci/tasks/robotframework/tests/test_browser_proxies.py +137 -0
- cumulusci/tasks/robotframework/tests/test_debugger.py +360 -0
- cumulusci/tasks/robotframework/tests/test_robot_parallel.py +141 -0
- cumulusci/tasks/robotframework/tests/test_robotframework.py +860 -0
- cumulusci/tasks/salesforce/BaseRetrieveMetadata.py +58 -0
- cumulusci/tasks/salesforce/BaseSalesforceApiTask.py +45 -0
- cumulusci/tasks/salesforce/BaseSalesforceMetadataApiTask.py +18 -0
- cumulusci/tasks/salesforce/BaseSalesforceTask.py +4 -0
- cumulusci/tasks/salesforce/BaseUninstallMetadata.py +41 -0
- cumulusci/tasks/salesforce/CreateCommunity.py +124 -0
- cumulusci/tasks/salesforce/CreatePackage.py +29 -0
- cumulusci/tasks/salesforce/Deploy.py +240 -0
- cumulusci/tasks/salesforce/DeployBundles.py +88 -0
- cumulusci/tasks/salesforce/DescribeMetadataTypes.py +26 -0
- cumulusci/tasks/salesforce/EnsureRecordTypes.py +202 -0
- cumulusci/tasks/salesforce/GetInstalledPackages.py +8 -0
- cumulusci/tasks/salesforce/ListCommunities.py +40 -0
- cumulusci/tasks/salesforce/ListCommunityTemplates.py +19 -0
- cumulusci/tasks/salesforce/PublishCommunity.py +62 -0
- cumulusci/tasks/salesforce/RetrievePackaged.py +41 -0
- cumulusci/tasks/salesforce/RetrieveReportsAndDashboards.py +82 -0
- cumulusci/tasks/salesforce/RetrieveUnpackaged.py +36 -0
- cumulusci/tasks/salesforce/SOQLQuery.py +39 -0
- cumulusci/tasks/salesforce/UninstallLocal.py +15 -0
- cumulusci/tasks/salesforce/UninstallLocalBundles.py +28 -0
- cumulusci/tasks/salesforce/UninstallLocalNamespacedBundles.py +58 -0
- cumulusci/tasks/salesforce/UninstallPackage.py +32 -0
- cumulusci/tasks/salesforce/UninstallPackaged.py +56 -0
- cumulusci/tasks/salesforce/UpdateAdminProfile.py +8 -0
- cumulusci/tasks/salesforce/__init__.py +79 -0
- cumulusci/tasks/salesforce/activate_flow.py +74 -0
- cumulusci/tasks/salesforce/check_components.py +324 -0
- cumulusci/tasks/salesforce/composite.py +142 -0
- cumulusci/tasks/salesforce/create_permission_sets.py +35 -0
- cumulusci/tasks/salesforce/custom_settings.py +134 -0
- cumulusci/tasks/salesforce/custom_settings_wait.py +132 -0
- cumulusci/tasks/salesforce/enable_prediction.py +107 -0
- cumulusci/tasks/salesforce/insert_record.py +40 -0
- cumulusci/tasks/salesforce/install_package_version.py +242 -0
- cumulusci/tasks/salesforce/license_preflights.py +8 -0
- cumulusci/tasks/salesforce/network_member_group.py +178 -0
- cumulusci/tasks/salesforce/nonsourcetracking.py +228 -0
- cumulusci/tasks/salesforce/org_settings.py +193 -0
- cumulusci/tasks/salesforce/package_upload.py +328 -0
- cumulusci/tasks/salesforce/profiles.py +74 -0
- cumulusci/tasks/salesforce/promote_package_version.py +376 -0
- cumulusci/tasks/salesforce/retrieve_profile.py +195 -0
- cumulusci/tasks/salesforce/salesforce_files.py +244 -0
- cumulusci/tasks/salesforce/sourcetracking.py +507 -0
- cumulusci/tasks/salesforce/tests/__init__.py +3 -0
- cumulusci/tasks/salesforce/tests/test_CreateCommunity.py +278 -0
- cumulusci/tasks/salesforce/tests/test_CreatePackage.py +22 -0
- cumulusci/tasks/salesforce/tests/test_Deploy.py +470 -0
- cumulusci/tasks/salesforce/tests/test_DeployBundles.py +76 -0
- cumulusci/tasks/salesforce/tests/test_EnsureRecordTypes.py +345 -0
- cumulusci/tasks/salesforce/tests/test_ListCommunities.py +84 -0
- cumulusci/tasks/salesforce/tests/test_ListCommunityTemplates.py +49 -0
- cumulusci/tasks/salesforce/tests/test_PackageUpload.py +547 -0
- cumulusci/tasks/salesforce/tests/test_ProfileGrantAllAccess.py +699 -0
- cumulusci/tasks/salesforce/tests/test_PublishCommunity.py +181 -0
- cumulusci/tasks/salesforce/tests/test_RetrievePackaged.py +24 -0
- cumulusci/tasks/salesforce/tests/test_RetrieveReportsAndDashboards.py +56 -0
- cumulusci/tasks/salesforce/tests/test_RetrieveUnpackaged.py +21 -0
- cumulusci/tasks/salesforce/tests/test_SOQLQuery.py +30 -0
- cumulusci/tasks/salesforce/tests/test_UninstallLocal.py +15 -0
- cumulusci/tasks/salesforce/tests/test_UninstallLocalBundles.py +19 -0
- cumulusci/tasks/salesforce/tests/test_UninstallLocalNamespacedBundles.py +22 -0
- cumulusci/tasks/salesforce/tests/test_UninstallPackage.py +19 -0
- cumulusci/tasks/salesforce/tests/test_UninstallPackaged.py +66 -0
- cumulusci/tasks/salesforce/tests/test_UninstallPackagedIncremental.py +127 -0
- cumulusci/tasks/salesforce/tests/test_activate_flow.py +132 -0
- cumulusci/tasks/salesforce/tests/test_base_tasks.py +110 -0
- cumulusci/tasks/salesforce/tests/test_check_components.py +445 -0
- cumulusci/tasks/salesforce/tests/test_composite.py +250 -0
- cumulusci/tasks/salesforce/tests/test_create_permission_sets.py +41 -0
- cumulusci/tasks/salesforce/tests/test_custom_settings.py +227 -0
- cumulusci/tasks/salesforce/tests/test_custom_settings_wait.py +174 -0
- cumulusci/tasks/salesforce/tests/test_describemetadatatypes.py +18 -0
- cumulusci/tasks/salesforce/tests/test_enable_prediction.py +240 -0
- cumulusci/tasks/salesforce/tests/test_insert_record.py +110 -0
- cumulusci/tasks/salesforce/tests/test_install_package_version.py +464 -0
- cumulusci/tasks/salesforce/tests/test_network_member_group.py +444 -0
- cumulusci/tasks/salesforce/tests/test_nonsourcetracking.py +235 -0
- cumulusci/tasks/salesforce/tests/test_org_settings.py +407 -0
- cumulusci/tasks/salesforce/tests/test_profiles.py +202 -0
- cumulusci/tasks/salesforce/tests/test_retrieve_profile.py +287 -0
- cumulusci/tasks/salesforce/tests/test_salesforce_files.py +228 -0
- cumulusci/tasks/salesforce/tests/test_sourcetracking.py +350 -0
- cumulusci/tasks/salesforce/tests/test_trigger_handlers.py +300 -0
- cumulusci/tasks/salesforce/tests/test_update_dependencies.py +509 -0
- cumulusci/tasks/salesforce/tests/util.py +79 -0
- cumulusci/tasks/salesforce/trigger_handlers.py +119 -0
- cumulusci/tasks/salesforce/uninstall_packaged_incremental.py +136 -0
- cumulusci/tasks/salesforce/update_dependencies.py +290 -0
- cumulusci/tasks/salesforce/update_profile.py +339 -0
- cumulusci/tasks/salesforce/users/permsets.py +227 -0
- cumulusci/tasks/salesforce/users/photos.py +162 -0
- cumulusci/tasks/salesforce/users/tests/photo.mock.txt +1 -0
- cumulusci/tasks/salesforce/users/tests/test_permsets.py +950 -0
- cumulusci/tasks/salesforce/users/tests/test_photos.py +373 -0
- cumulusci/tasks/sample_data/capture_sample_data.py +77 -0
- cumulusci/tasks/sample_data/load_sample_data.py +85 -0
- cumulusci/tasks/sample_data/test_capture_sample_data.py +117 -0
- cumulusci/tasks/sample_data/test_load_sample_data.py +121 -0
- cumulusci/tasks/sfdx.py +83 -0
- cumulusci/tasks/tests/__init__.py +1 -0
- cumulusci/tasks/tests/conftest.py +30 -0
- cumulusci/tasks/tests/test_command.py +129 -0
- cumulusci/tasks/tests/test_connectedapp.py +236 -0
- cumulusci/tasks/tests/test_create_package_version.py +847 -0
- cumulusci/tasks/tests/test_datadictionary.py +1575 -0
- cumulusci/tasks/tests/test_dx_convert_from.py +60 -0
- cumulusci/tasks/tests/test_metadeploy.py +624 -0
- cumulusci/tasks/tests/test_metaxml.py +99 -0
- cumulusci/tasks/tests/test_promote_package_version.py +488 -0
- cumulusci/tasks/tests/test_pushfails.py +96 -0
- cumulusci/tasks/tests/test_salesforce.py +72 -0
- cumulusci/tasks/tests/test_sfdx.py +105 -0
- cumulusci/tasks/tests/test_util.py +207 -0
- cumulusci/tasks/util.py +261 -0
- cumulusci/tasks/vcs/__init__.py +19 -0
- cumulusci/tasks/vcs/commit_status.py +58 -0
- cumulusci/tasks/vcs/create_commit_status.py +37 -0
- cumulusci/tasks/vcs/download_extract.py +199 -0
- cumulusci/tasks/vcs/merge.py +298 -0
- cumulusci/tasks/vcs/publish.py +207 -0
- cumulusci/tasks/vcs/pull_request.py +9 -0
- cumulusci/tasks/vcs/release.py +134 -0
- cumulusci/tasks/vcs/release_report.py +105 -0
- cumulusci/tasks/vcs/tag.py +31 -0
- cumulusci/tasks/vcs/tests/github/test_commit_status.py +196 -0
- cumulusci/tasks/vcs/tests/github/test_download_extract.py +896 -0
- cumulusci/tasks/vcs/tests/github/test_merge.py +1118 -0
- cumulusci/tasks/vcs/tests/github/test_publish.py +823 -0
- cumulusci/tasks/vcs/tests/github/test_pull_request.py +29 -0
- cumulusci/tasks/vcs/tests/github/test_release.py +390 -0
- cumulusci/tasks/vcs/tests/github/test_release_report.py +109 -0
- cumulusci/tasks/vcs/tests/github/test_tag.py +90 -0
- cumulusci/tasks/vlocity/exceptions.py +2 -0
- cumulusci/tasks/vlocity/tests/test_vlocity.py +283 -0
- cumulusci/tasks/vlocity/vlocity.py +342 -0
- cumulusci/tests/__init__.py +1 -0
- cumulusci/tests/cassettes/GET_sobjects_Account_PersonAccount_describe.yaml +18 -0
- cumulusci/tests/cassettes/TestIntegrationInfrastructure.test_integration_tests.yaml +19 -0
- cumulusci/tests/pytest_plugins/pytest_sf_orgconnect.py +307 -0
- cumulusci/tests/pytest_plugins/pytest_sf_vcr.py +275 -0
- cumulusci/tests/pytest_plugins/pytest_sf_vcr_serializer.py +160 -0
- cumulusci/tests/pytest_plugins/pytest_typeguard.py +5 -0
- cumulusci/tests/pytest_plugins/test_vcr_string_compressor.py +49 -0
- cumulusci/tests/pytest_plugins/vcr_string_compressor.py +97 -0
- cumulusci/tests/shared_cassettes/GET_sobjects_Account_describe.yaml +18 -0
- cumulusci/tests/shared_cassettes/GET_sobjects_Case_describe.yaml +18 -0
- cumulusci/tests/shared_cassettes/GET_sobjects_Contact_describe.yaml +4838 -0
- cumulusci/tests/shared_cassettes/GET_sobjects_Custom__c_describe.yaml +242 -0
- cumulusci/tests/shared_cassettes/GET_sobjects_Event_describe.yaml +19 -0
- cumulusci/tests/shared_cassettes/GET_sobjects_Global_describe.yaml +1338 -0
- cumulusci/tests/shared_cassettes/GET_sobjects_Lead_describe.yaml +18 -0
- cumulusci/tests/shared_cassettes/GET_sobjects_OpportunityContactRole_describe.yaml +34 -0
- cumulusci/tests/shared_cassettes/GET_sobjects_Opportunity_describe.yaml +1261 -0
- cumulusci/tests/shared_cassettes/GET_sobjects_Organization.yaml +49 -0
- cumulusci/tests/shared_cassettes/vcr_string_templates/batchInfoList_xml.tpl +15 -0
- cumulusci/tests/shared_cassettes/vcr_string_templates/batchInfo_xml.tpl +13 -0
- cumulusci/tests/shared_cassettes/vcr_string_templates/jobInfo_insert_xml.tpl +24 -0
- cumulusci/tests/shared_cassettes/vcr_string_templates/jobInfo_upsert_xml.tpl +25 -0
- cumulusci/tests/test_entry_points.py +20 -0
- cumulusci/tests/test_integration_infrastructure.py +131 -0
- cumulusci/tests/test_main.py +9 -0
- cumulusci/tests/test_schema.py +32 -0
- cumulusci/tests/test_utils.py +657 -0
- cumulusci/tests/test_vcr_serializer.py +134 -0
- cumulusci/tests/uncompressed_cassette.yaml +83 -0
- cumulusci/tests/util.py +344 -0
- cumulusci/utils/__init__.py +731 -0
- cumulusci/utils/classutils.py +9 -0
- cumulusci/utils/collections.py +32 -0
- cumulusci/utils/deprecation.py +11 -0
- cumulusci/utils/encryption.py +31 -0
- cumulusci/utils/fileutils.py +295 -0
- cumulusci/utils/git.py +142 -0
- cumulusci/utils/http/multi_request.py +214 -0
- cumulusci/utils/http/requests_utils.py +103 -0
- cumulusci/utils/http/tests/cassettes/ManualEditTestCompositeParallelSalesforce.test_http_headers.yaml +32 -0
- cumulusci/utils/http/tests/cassettes/TestCompositeParallelSalesforce.test_composite_parallel_salesforce.yaml +65 -0
- cumulusci/utils/http/tests/cassettes/TestCompositeParallelSalesforce.test_errors.yaml +24 -0
- cumulusci/utils/http/tests/cassettes/TestCompositeParallelSalesforce.test_reference_ids.yaml +49 -0
- cumulusci/utils/http/tests/test_multi_request.py +255 -0
- cumulusci/utils/iterators.py +21 -0
- cumulusci/utils/logging.py +128 -0
- cumulusci/utils/metaprogramming.py +10 -0
- cumulusci/utils/options.py +138 -0
- cumulusci/utils/parallel/queries_in_parallel/run_queries_in_parallel.py +29 -0
- cumulusci/utils/parallel/queries_in_parallel/tests/test_run_queries_in_parallel.py +50 -0
- cumulusci/utils/parallel/task_worker_queues/parallel_worker.py +238 -0
- cumulusci/utils/parallel/task_worker_queues/parallel_worker_queue.py +243 -0
- cumulusci/utils/parallel/task_worker_queues/tests/test_parallel_worker.py +353 -0
- cumulusci/utils/salesforce/count_sobjects.py +46 -0
- cumulusci/utils/salesforce/soql.py +17 -0
- cumulusci/utils/salesforce/tests/cassettes/ManualEdit_TestCountSObjects.test_count_sobjects__network_errors.yaml +23 -0
- cumulusci/utils/salesforce/tests/cassettes/TestCountSObjects.test_count_sobjects__errors.yaml +33 -0
- cumulusci/utils/salesforce/tests/cassettes/TestCountSObjects.test_count_sobjects_simple.yaml +29 -0
- cumulusci/utils/salesforce/tests/test_count_sobjects.py +29 -0
- cumulusci/utils/salesforce/tests/test_soql.py +30 -0
- cumulusci/utils/tests/cassettes/ManualEditTestDescribeOrg.test_minimal_schema.yaml +36 -0
- cumulusci/utils/tests/cassettes/ManualEdit_test_describe_to_sql.yaml +191 -0
- cumulusci/utils/tests/test_fileutils.py +284 -0
- cumulusci/utils/tests/test_git.py +85 -0
- cumulusci/utils/tests/test_logging.py +70 -0
- cumulusci/utils/tests/test_option_parsing.py +188 -0
- cumulusci/utils/tests/test_org_schema.py +691 -0
- cumulusci/utils/tests/test_org_schema_models.py +79 -0
- cumulusci/utils/tests/test_waiting.py +25 -0
- cumulusci/utils/version_strings.py +391 -0
- cumulusci/utils/waiting.py +42 -0
- cumulusci/utils/xml/__init__.py +91 -0
- cumulusci/utils/xml/metadata_tree.py +299 -0
- cumulusci/utils/xml/robot_xml.py +114 -0
- cumulusci/utils/xml/salesforce_encoding.py +100 -0
- cumulusci/utils/xml/test/test_metadata_tree.py +251 -0
- cumulusci/utils/xml/test/test_salesforce_encoding.py +173 -0
- cumulusci/utils/yaml/cumulusci_yml.py +401 -0
- cumulusci/utils/yaml/model_parser.py +156 -0
- cumulusci/utils/yaml/safer_loader.py +74 -0
- cumulusci/utils/yaml/tests/bad_cci.yml +5 -0
- cumulusci/utils/yaml/tests/cassettes/TestCumulusciYml.test_validate_url__with_errors.yaml +20 -0
- cumulusci/utils/yaml/tests/test_cumulusci_yml.py +286 -0
- cumulusci/utils/yaml/tests/test_model_parser.py +175 -0
- cumulusci/utils/yaml/tests/test_safer_loader.py +88 -0
- cumulusci/utils/ziputils.py +61 -0
- cumulusci/vcs/base.py +143 -0
- cumulusci/vcs/bootstrap.py +272 -0
- cumulusci/vcs/github/__init__.py +24 -0
- cumulusci/vcs/github/adapter.py +689 -0
- cumulusci/vcs/github/release_notes/generator.py +219 -0
- cumulusci/vcs/github/release_notes/parser.py +151 -0
- cumulusci/vcs/github/release_notes/provider.py +143 -0
- cumulusci/vcs/github/service.py +569 -0
- cumulusci/vcs/github/tests/test_adapter.py +138 -0
- cumulusci/vcs/github/tests/test_service.py +408 -0
- cumulusci/vcs/models.py +586 -0
- cumulusci/vcs/tests/conftest.py +41 -0
- cumulusci/vcs/tests/dummy_service.py +241 -0
- cumulusci/vcs/tests/test_vcs_base.py +687 -0
- cumulusci/vcs/tests/test_vcs_bootstrap.py +727 -0
- cumulusci/vcs/utils/__init__.py +31 -0
- cumulusci/vcs/vcs_source.py +287 -0
- cumulusci_plus-5.0.0.dist-info/METADATA +145 -0
- cumulusci_plus-5.0.0.dist-info/RECORD +744 -0
- cumulusci_plus-5.0.0.dist-info/WHEEL +4 -0
- cumulusci_plus-5.0.0.dist-info/entry_points.txt +3 -0
- cumulusci_plus-5.0.0.dist-info/licenses/AUTHORS.rst +41 -0
- cumulusci_plus-5.0.0.dist-info/licenses/LICENSE +30 -0
|
@@ -0,0 +1,433 @@
|
|
|
1
|
+
# Note: Unlike in traditional robot libraries, this docstring will end
|
|
2
|
+
# up in output from the libdoc task. For that to happen, it must be
|
|
3
|
+
# before the imports.
|
|
4
|
+
|
|
5
|
+
"""
|
|
6
|
+
The following page objects are automatically included when
|
|
7
|
+
importing the PageObject library. You should not directly import this
|
|
8
|
+
file.
|
|
9
|
+
|
|
10
|
+
"""
|
|
11
|
+
|
|
12
|
+
import re
|
|
13
|
+
|
|
14
|
+
from selenium.common.exceptions import NoSuchElementException, TimeoutException
|
|
15
|
+
from SeleniumLibrary.errors import ElementNotFound
|
|
16
|
+
|
|
17
|
+
from cumulusci.robotframework.form_handlers import get_form_handler
|
|
18
|
+
from cumulusci.robotframework.pageobjects import BasePage, pageobject
|
|
19
|
+
from cumulusci.robotframework.utils import capture_screenshot_on_error
|
|
20
|
+
|
|
21
|
+
# This will appear in the generated documentation in place of
|
|
22
|
+
# the filename.
|
|
23
|
+
TITLE = "Base Page Objects"
|
|
24
|
+
|
|
25
|
+
|
|
26
|
+
@pageobject(page_type="Listing")
|
|
27
|
+
class ListingPage(BasePage):
|
|
28
|
+
"""Page object representing a Listing page
|
|
29
|
+
|
|
30
|
+
When going to the Listing page, you need to specify the object name. You
|
|
31
|
+
may also specify the name of a filter.
|
|
32
|
+
|
|
33
|
+
Example
|
|
34
|
+
|
|
35
|
+
| Go to page Listing Contact filterName=Recent
|
|
36
|
+
|
|
37
|
+
"""
|
|
38
|
+
|
|
39
|
+
def _go_to_page(self, filter_name=None, locator=None):
|
|
40
|
+
url_template = "{root}/lightning/o/{object_name}/list"
|
|
41
|
+
url = url_template.format(
|
|
42
|
+
root=self.cumulusci.org.lightning_base_url, object_name=self.object_name
|
|
43
|
+
)
|
|
44
|
+
if filter_name:
|
|
45
|
+
url += "?filterName={}".format(filter_name)
|
|
46
|
+
self.selenium.go_to(url)
|
|
47
|
+
self.salesforce.wait_until_loading_is_complete(locator=locator)
|
|
48
|
+
|
|
49
|
+
def _is_current_page(self):
|
|
50
|
+
self.selenium.location_should_contain(
|
|
51
|
+
"/lightning/o/{}/list".format(self.object_name)
|
|
52
|
+
)
|
|
53
|
+
|
|
54
|
+
@capture_screenshot_on_error
|
|
55
|
+
def select_rows(self, *items):
|
|
56
|
+
"""Check the checkbutton for one or more rows
|
|
57
|
+
|
|
58
|
+
Arguments are one or more strings. Each row that contains one
|
|
59
|
+
of the strings in any column will be clicked. Rows that have
|
|
60
|
+
already been checked will remain checked.
|
|
61
|
+
|
|
62
|
+
If no elements are found to match, this keyword will raise an error.
|
|
63
|
+
|
|
64
|
+
Example
|
|
65
|
+
|
|
66
|
+
The following example selects all rows that contain either
|
|
67
|
+
John Doe or Jane Doe in any column.
|
|
68
|
+
|
|
69
|
+
| Select Rows John Doe Jane Doe
|
|
70
|
+
"""
|
|
71
|
+
for item in items:
|
|
72
|
+
xpath = self.salesforce.get_locator("object_list.checkbutton", item)
|
|
73
|
+
elements = self.selenium.get_webelements(xpath)
|
|
74
|
+
if elements:
|
|
75
|
+
for element in elements:
|
|
76
|
+
cb = element.find_element_by_tag_name("input")
|
|
77
|
+
if not cb.is_selected():
|
|
78
|
+
element.click()
|
|
79
|
+
else:
|
|
80
|
+
raise Exception(f"No rows matched '{item}'")
|
|
81
|
+
|
|
82
|
+
@capture_screenshot_on_error
|
|
83
|
+
def deselect_rows(self, *items):
|
|
84
|
+
"""Uncheck the checkbutton for one or more rows
|
|
85
|
+
|
|
86
|
+
Arguments are one or more strings. Each row that contains one
|
|
87
|
+
of the strings in any column will be delselected. Rows that are
|
|
88
|
+
unchecked will remain unchecked.
|
|
89
|
+
|
|
90
|
+
If no elements are found to match, this keyword will raise an error.
|
|
91
|
+
|
|
92
|
+
Example
|
|
93
|
+
|
|
94
|
+
The following example deselects all rows that contain either
|
|
95
|
+
John Doe or Jane Doe in any column.
|
|
96
|
+
|
|
97
|
+
| Select Rows John Doe Jane Doe
|
|
98
|
+
|
|
99
|
+
"""
|
|
100
|
+
for item in items:
|
|
101
|
+
xpath = self.salesforce.get_locator("object_list.checkbutton", item)
|
|
102
|
+
elements = self.selenium.get_webelements(xpath)
|
|
103
|
+
|
|
104
|
+
if elements:
|
|
105
|
+
for element in elements:
|
|
106
|
+
cb = element.find_element_by_tag_name("input")
|
|
107
|
+
if cb.is_selected():
|
|
108
|
+
self.builtin.log(f"clicking on element for {item}")
|
|
109
|
+
element.click()
|
|
110
|
+
else:
|
|
111
|
+
self.builtin.log(f"NOT clicking on element for {item}")
|
|
112
|
+
else:
|
|
113
|
+
raise Exception(f"No rows matched '{item}'")
|
|
114
|
+
|
|
115
|
+
|
|
116
|
+
class ModalMixin:
|
|
117
|
+
def _wait_to_appear(self, expected_heading=None):
|
|
118
|
+
"""Waits until the modal is visible"""
|
|
119
|
+
locator = "//div[contains(@class, 'uiModal')]"
|
|
120
|
+
if expected_heading:
|
|
121
|
+
locator += f"//h2[text()='{expected_heading}']"
|
|
122
|
+
error = f"A modal with the heading {expected_heading} did not appear before the timeout"
|
|
123
|
+
else:
|
|
124
|
+
error = "The modal did not appear before the timeout"
|
|
125
|
+
|
|
126
|
+
self.salesforce.wait_for_aura()
|
|
127
|
+
self.selenium.wait_until_element_is_visible(locator, error=error)
|
|
128
|
+
|
|
129
|
+
@capture_screenshot_on_error
|
|
130
|
+
def close_the_modal(self):
|
|
131
|
+
"""Closes the open modal"""
|
|
132
|
+
|
|
133
|
+
locator = "css: button.slds-modal__close"
|
|
134
|
+
self.selenium.wait_until_element_is_enabled(locator)
|
|
135
|
+
self.selenium.click_element(locator)
|
|
136
|
+
self.wait_until_modal_is_closed()
|
|
137
|
+
self._remove_from_library_search_order()
|
|
138
|
+
|
|
139
|
+
@capture_screenshot_on_error
|
|
140
|
+
def click_modal_button(self, button_label):
|
|
141
|
+
"""Click the named modal button (Save, Save & New, Cancel, etc)"""
|
|
142
|
+
# stolen from Salesforce.py:click_modal_button
|
|
143
|
+
locator = f"sf:modal.button:{button_label}"
|
|
144
|
+
self.selenium.wait_until_page_contains_element(locator)
|
|
145
|
+
self.selenium.wait_until_element_is_enabled(locator)
|
|
146
|
+
self.salesforce._jsclick(locator)
|
|
147
|
+
|
|
148
|
+
@capture_screenshot_on_error
|
|
149
|
+
def modal_should_contain_errors(self, *messages):
|
|
150
|
+
"""Verify that the modal contains the following errors
|
|
151
|
+
|
|
152
|
+
This will look for the given message in the standard SLDS
|
|
153
|
+
component (<ul class='errorsList'>)
|
|
154
|
+
"""
|
|
155
|
+
for message in messages:
|
|
156
|
+
locator = "//ul[@class='errorsList']//li[contains(., \"{}\")]".format(
|
|
157
|
+
message
|
|
158
|
+
)
|
|
159
|
+
self.selenium.page_should_contain_element(
|
|
160
|
+
locator,
|
|
161
|
+
'The page did not contain an error with the text "{}"'.format(message),
|
|
162
|
+
)
|
|
163
|
+
|
|
164
|
+
@capture_screenshot_on_error
|
|
165
|
+
def modal_should_show_edit_error_for_fields(self, *field_names):
|
|
166
|
+
"""Verify that a dialog is showing requiring a review of the given fields
|
|
167
|
+
|
|
168
|
+
This works by looking for a the "we hit a snag" popup, and
|
|
169
|
+
then looking for an anchor tag with the attribute
|
|
170
|
+
force-recordediterror_recordediterror, along with the given
|
|
171
|
+
text.
|
|
172
|
+
|
|
173
|
+
"""
|
|
174
|
+
self.selenium.wait_until_page_contains_element("sf:modal.field_alert")
|
|
175
|
+
for field_name in field_names:
|
|
176
|
+
locator = f"sf:modal.review_alert:{field_name}"
|
|
177
|
+
self.selenium.page_should_contain_element(
|
|
178
|
+
locator, f"Unable to find alert with field '{field_name}'"
|
|
179
|
+
)
|
|
180
|
+
|
|
181
|
+
@capture_screenshot_on_error
|
|
182
|
+
def populate_field(self, name, value):
|
|
183
|
+
"""Populate a field on the modal form
|
|
184
|
+
|
|
185
|
+
Name must the the label of a field as it appears on the modal form.
|
|
186
|
+
|
|
187
|
+
Example
|
|
188
|
+
|
|
189
|
+
| Populate field First Name Connor
|
|
190
|
+
| Populate field Last Name MacLeod
|
|
191
|
+
"""
|
|
192
|
+
# For now, call the same keyword in Salesforce.py. Eventually
|
|
193
|
+
# that keyword may get moved here and deprecated from that
|
|
194
|
+
# library.
|
|
195
|
+
self.salesforce.populate_field(name, value)
|
|
196
|
+
|
|
197
|
+
@capture_screenshot_on_error
|
|
198
|
+
def populate_form(self, *args, **kwargs):
|
|
199
|
+
"""Populate the modal form
|
|
200
|
+
|
|
201
|
+
Arguments are of the form key=value, where 'key' represents
|
|
202
|
+
a field name as it appears on the form (specifically, the text
|
|
203
|
+
of a label with the class 'uiLabel').
|
|
204
|
+
|
|
205
|
+
Example:
|
|
206
|
+
|
|
207
|
+
| Populate form
|
|
208
|
+
| ... First Name=Connor
|
|
209
|
+
| ... Last Name=MacLeod
|
|
210
|
+
"""
|
|
211
|
+
# For now, call the same keyword in Salesforce.py. Eventually
|
|
212
|
+
# that keyword may get moved here and deprecated from that
|
|
213
|
+
# library.
|
|
214
|
+
self.salesforce.populate_form(*args, **kwargs)
|
|
215
|
+
|
|
216
|
+
@capture_screenshot_on_error
|
|
217
|
+
def select_dropdown_value(self, label, value):
|
|
218
|
+
"""Sets the value of a dropdown form field from one of the values in the dropdown
|
|
219
|
+
|
|
220
|
+
``label`` represents the label on the form field (eg: Lead Source)
|
|
221
|
+
|
|
222
|
+
If a modal is present, the modal will be searched for the dropdown. Otherwise
|
|
223
|
+
the first matching dropdown on the entire web page will be used.
|
|
224
|
+
"""
|
|
225
|
+
locator = f"label:{label}"
|
|
226
|
+
try:
|
|
227
|
+
element = self.selenium.get_webelement(locator)
|
|
228
|
+
except (NoSuchElementException, TimeoutException, ElementNotFound):
|
|
229
|
+
raise ElementNotFound(f"Form element with label '{label}' was not found")
|
|
230
|
+
|
|
231
|
+
self.salesforce.scroll_element_into_view(locator)
|
|
232
|
+
handler = get_form_handler(element, locator)
|
|
233
|
+
try:
|
|
234
|
+
handler.set(value)
|
|
235
|
+
except (NoSuchElementException, TimeoutException, ElementNotFound):
|
|
236
|
+
raise ElementNotFound(f"Dropdown value '{value}' not found")
|
|
237
|
+
|
|
238
|
+
@capture_screenshot_on_error
|
|
239
|
+
def wait_until_modal_is_closed(self, timeout=None):
|
|
240
|
+
"""Waits until the modal is no longer visible
|
|
241
|
+
|
|
242
|
+
If the modal isn't open, this will not throw an error.
|
|
243
|
+
"""
|
|
244
|
+
locator = "//div[contains(@class, 'uiModal')]"
|
|
245
|
+
|
|
246
|
+
self.selenium.wait_until_page_does_not_contain_element(locator)
|
|
247
|
+
|
|
248
|
+
def _get_form_element_for_label(self, label):
|
|
249
|
+
"""Returns an element of class 'slds-form-element' which contains the given label.
|
|
250
|
+
|
|
251
|
+
If you use this to find an item on a modal, you're responsible for waiting for the
|
|
252
|
+
modal to appear before calling this function.
|
|
253
|
+
"""
|
|
254
|
+
# search from the root of the document, unless a modal
|
|
255
|
+
# is open
|
|
256
|
+
root = self.selenium.driver.find_element_by_tag_name("body")
|
|
257
|
+
with self._no_implicit_wait():
|
|
258
|
+
# We don't want to wait, we just want to know if the
|
|
259
|
+
# modal is alredy there or not. The caller should have
|
|
260
|
+
# already waited for the modal.
|
|
261
|
+
|
|
262
|
+
# also, we use find_elements (plural) here because it will
|
|
263
|
+
# return an empty list rather than throwing an error
|
|
264
|
+
modals = root.find_elements_by_xpath("//div[contains(@class, 'uiModal')]")
|
|
265
|
+
# There should only ever be zero or one, but the Salesforce
|
|
266
|
+
# UI never ceases to surprise me.
|
|
267
|
+
modals = [m for m in modals if m.is_displayed()]
|
|
268
|
+
if modals:
|
|
269
|
+
root = modals[0]
|
|
270
|
+
try:
|
|
271
|
+
# As salesforce evolves, more and more fields use <label for='some-id'>
|
|
272
|
+
# where "for" points to the associated input field. w00t! If we can,
|
|
273
|
+
# use that. If not, fall back to an older strategy
|
|
274
|
+
try:
|
|
275
|
+
label_element = root.find_element_by_xpath(f'//label[text()="{label}"]')
|
|
276
|
+
input_id = label_element.get_attribute("for")
|
|
277
|
+
element = root.find_element_by_id(input_id)
|
|
278
|
+
return element
|
|
279
|
+
|
|
280
|
+
except NoSuchElementException:
|
|
281
|
+
pass
|
|
282
|
+
|
|
283
|
+
# gnarly, but effective.
|
|
284
|
+
# this finds an element with the class slds-form-element which
|
|
285
|
+
# has a child element with the class 'form-element__label' and
|
|
286
|
+
# text that matches the given label.
|
|
287
|
+
locator = f".//*[contains(@class, 'slds-form-element') and .//*[contains(@class, 'form-element__label')]/descendant-or-self::text()='{label}']"
|
|
288
|
+
element = root.find_element_by_xpath(locator)
|
|
289
|
+
return element
|
|
290
|
+
|
|
291
|
+
except NoSuchElementException:
|
|
292
|
+
raise ElementNotFound(f"Form element with label '{label}' was not found")
|
|
293
|
+
|
|
294
|
+
|
|
295
|
+
@pageobject("New")
|
|
296
|
+
class NewModal(ModalMixin, BasePage):
|
|
297
|
+
"""A page object representing the New Object modal
|
|
298
|
+
|
|
299
|
+
Note: You should not use this page object with 'Go to page'. Instead,
|
|
300
|
+
you can use 'Wait for modal to appear' after performing an action
|
|
301
|
+
that causes the new object modal to appear (eg: clicking the
|
|
302
|
+
"New" button). Once the modal appears, the keywords for that
|
|
303
|
+
modal will be available for use in the test.
|
|
304
|
+
|
|
305
|
+
Example:
|
|
306
|
+
|
|
307
|
+
| Go to page Home Contact
|
|
308
|
+
| Click object button New
|
|
309
|
+
| Wait for modal to appear New Contact
|
|
310
|
+
"""
|
|
311
|
+
|
|
312
|
+
|
|
313
|
+
@pageobject("Edit")
|
|
314
|
+
class EditModal(ModalMixin, BasePage):
|
|
315
|
+
"""A page object representing the Edit Object modal
|
|
316
|
+
|
|
317
|
+
Note: You should not use this page object with 'Go to page'. Instead,
|
|
318
|
+
you can use 'Wait for modal to appear' after performing an action
|
|
319
|
+
that causes the new object modal to appear (eg: clicking the
|
|
320
|
+
"Edit" button). Once the modal appears, the keywords for that
|
|
321
|
+
modal will be available for use in the test.
|
|
322
|
+
|
|
323
|
+
Example:
|
|
324
|
+
|
|
325
|
+
| Click object button Edit
|
|
326
|
+
| Wait for modal to appear Edit Contact
|
|
327
|
+
|
|
328
|
+
"""
|
|
329
|
+
|
|
330
|
+
|
|
331
|
+
@pageobject("Home")
|
|
332
|
+
class HomePage(BasePage):
|
|
333
|
+
"""A page object representing the home page of an object.
|
|
334
|
+
|
|
335
|
+
When going to the Home page, you need to specify the object name.
|
|
336
|
+
|
|
337
|
+
Note: The home page of an object may automatically redirect you to
|
|
338
|
+
some other page, such as a Listing page. If you are working with
|
|
339
|
+
such a page, you might need to use `page should be` to load the
|
|
340
|
+
keywords for the page you expect to be redirected to.
|
|
341
|
+
|
|
342
|
+
Example
|
|
343
|
+
|
|
344
|
+
| Go to page Home Contact
|
|
345
|
+
|
|
346
|
+
"""
|
|
347
|
+
|
|
348
|
+
def _go_to_page(self, locator=None):
|
|
349
|
+
url_template = "{root}/lightning/o/{object_name}/home"
|
|
350
|
+
url = url_template.format(
|
|
351
|
+
root=self.cumulusci.org.lightning_base_url, object_name=self.object_name
|
|
352
|
+
)
|
|
353
|
+
self.selenium.go_to(url)
|
|
354
|
+
self.salesforce.wait_until_loading_is_complete(locator=locator)
|
|
355
|
+
|
|
356
|
+
def _is_current_page(self):
|
|
357
|
+
self.selenium.location_should_contain(
|
|
358
|
+
"/lightning/o/{}/home".format(self.object_name)
|
|
359
|
+
)
|
|
360
|
+
|
|
361
|
+
|
|
362
|
+
@pageobject("Detail")
|
|
363
|
+
class DetailPage(BasePage):
|
|
364
|
+
"""A page object representing the standard Detail page.
|
|
365
|
+
|
|
366
|
+
When going to this page via the standard `Go to page` keyword, you
|
|
367
|
+
can specify either an object id, or a set of keyword arguments which
|
|
368
|
+
will be used to look up the object id. When using keyword arguments,
|
|
369
|
+
they need to represent a unique user.
|
|
370
|
+
|
|
371
|
+
Example
|
|
372
|
+
|
|
373
|
+
| ${contact_id} = Salesforce Insert Contact
|
|
374
|
+
| ... FirstName=${first_name}
|
|
375
|
+
| ... LastName=${last_name}
|
|
376
|
+
|
|
|
377
|
+
| # Using the id:
|
|
378
|
+
| Go to page Detail Contact ${contact_id}
|
|
379
|
+
|
|
|
380
|
+
| # Using lookup parameters
|
|
381
|
+
| Go to page Detail Contact FirstName=${first_name} LastName=${last_name}
|
|
382
|
+
|
|
383
|
+
"""
|
|
384
|
+
|
|
385
|
+
def _go_to_page(self, object_id=None, locator=None, **kwargs):
|
|
386
|
+
"""Go to the detail page for the given record.
|
|
387
|
+
|
|
388
|
+
You may pass in an object id, or you may pass in keyword arguments
|
|
389
|
+
which can be used to look up the object.
|
|
390
|
+
|
|
391
|
+
Example
|
|
392
|
+
|
|
393
|
+
| Go to page Detail Contact firstName=John lastName=Smith
|
|
394
|
+
"""
|
|
395
|
+
|
|
396
|
+
if kwargs and object_id:
|
|
397
|
+
raise Exception("Specify an object id or keyword arguments, but not both")
|
|
398
|
+
|
|
399
|
+
if kwargs:
|
|
400
|
+
# note: this will raise an exception if no object is found,
|
|
401
|
+
# or if multiple objects are found.
|
|
402
|
+
object_id = self._get_object(**kwargs)["Id"]
|
|
403
|
+
|
|
404
|
+
url_template = "{root}/lightning/r/{object_name}/{object_id}/view"
|
|
405
|
+
url = url_template.format(
|
|
406
|
+
root=self.cumulusci.org.lightning_base_url,
|
|
407
|
+
object_name=self.object_name,
|
|
408
|
+
object_id=object_id,
|
|
409
|
+
)
|
|
410
|
+
self.selenium.go_to(url)
|
|
411
|
+
self.salesforce.wait_until_loading_is_complete(locator=locator)
|
|
412
|
+
|
|
413
|
+
def _is_current_page(self, **kwargs):
|
|
414
|
+
"""Verify we are on a detail page.
|
|
415
|
+
|
|
416
|
+
If keyword arguments are present, this function will go a query
|
|
417
|
+
on the given parameters, assert that the query returns a single
|
|
418
|
+
result, and the verify that the returned object id is part of the url.
|
|
419
|
+
"""
|
|
420
|
+
if kwargs:
|
|
421
|
+
# do a lookup to get the object id
|
|
422
|
+
object_id = self._get_object(**kwargs)["Id"]
|
|
423
|
+
pattern = r"/lightning/r/{}/{}/view$".format(self.object_name, object_id)
|
|
424
|
+
else:
|
|
425
|
+
# no kwargs means we should just verify we are on a detail
|
|
426
|
+
# page without regard to which object
|
|
427
|
+
pattern = r"/lightning/r/{}/.*/view$".format(self.object_name)
|
|
428
|
+
|
|
429
|
+
location = self.selenium.get_location()
|
|
430
|
+
if not re.search(pattern, location):
|
|
431
|
+
raise Exception(
|
|
432
|
+
"Location '{}' didn't match pattern {}".format(location, pattern)
|
|
433
|
+
)
|
|
@@ -0,0 +1,246 @@
|
|
|
1
|
+
from selenium.webdriver.common.keys import Keys
|
|
2
|
+
|
|
3
|
+
from cumulusci.robotframework.pageobjects import BasePage, pageobject
|
|
4
|
+
from cumulusci.robotframework.utils import capture_screenshot_on_error
|
|
5
|
+
|
|
6
|
+
object_manager = {
|
|
7
|
+
"button": "//input[@title='{}']",
|
|
8
|
+
"input": "//input[@id='{}']",
|
|
9
|
+
"select_related": "//select[@id = '{}']",
|
|
10
|
+
"select_related_option": "//select[@id = 'DomainEnumOrId']/option[@value='{}']",
|
|
11
|
+
"search_result": "//section[@class='related-list-card']//a[.=\"{}\"]",
|
|
12
|
+
"formula_txtarea": "//textarea[@id = '{}']",
|
|
13
|
+
"object_result": "//th/a[text()='{}']",
|
|
14
|
+
"link-text": "//a[contains(text(),'{}')]",
|
|
15
|
+
"button-with-text": "//button[contains(text(),'{}')]",
|
|
16
|
+
"frame_new": "//iframe[contains(@name, '{}') or contains(@title, '{}')]",
|
|
17
|
+
"action_menu": "//tr[.//a[.='{}']]//div[contains(@class, 'objectManagerVirtualActionMenu')]//a",
|
|
18
|
+
"action_menu_item": "//div[@class='actionMenu']//a[@role='menuitem' and .='{}']",
|
|
19
|
+
"delete_confirm_btn": "//button[contains(@class,'forceActionButton')]",
|
|
20
|
+
}
|
|
21
|
+
# All common elements
|
|
22
|
+
search_button = object_manager["input"].format("globalQuickfind")
|
|
23
|
+
currency_locator = object_manager["input"].format("dtypeC")
|
|
24
|
+
next_button = object_manager["button"].format("Next")
|
|
25
|
+
save_button = object_manager["button"].format("Save")
|
|
26
|
+
text_locator = object_manager["input"].format("dtypeS")
|
|
27
|
+
formula_locator = object_manager["input"].format("dtypeZ")
|
|
28
|
+
checkbox_option = object_manager["input"].format("fdtypeB")
|
|
29
|
+
formula_txtarea = object_manager["formula_txtarea"].format("CalculatedFormula")
|
|
30
|
+
check_syntax = object_manager["button"].format("Check Syntax")
|
|
31
|
+
actions_menu = object_manager["action_menu"]
|
|
32
|
+
action_item_delete = object_manager["action_menu_item"].format("Delete")
|
|
33
|
+
confirm_delete = object_manager["delete_confirm_btn"]
|
|
34
|
+
lookup_locator = object_manager["input"].format("dtypeY")
|
|
35
|
+
|
|
36
|
+
|
|
37
|
+
@pageobject(page_type="ObjectManager")
|
|
38
|
+
class ObjectManagerPage(BasePage):
|
|
39
|
+
"""A page object representing the Object Manager of an object.
|
|
40
|
+
Example
|
|
41
|
+
| Go to page ObjectManager Contact
|
|
42
|
+
"""
|
|
43
|
+
|
|
44
|
+
def _go_to_page(self):
|
|
45
|
+
url_template = "{root}/lightning/setup/ObjectManager/home"
|
|
46
|
+
url = url_template.format(root=self.cumulusci.org.lightning_base_url)
|
|
47
|
+
self.selenium.go_to(url)
|
|
48
|
+
object_name = self.object_name
|
|
49
|
+
self.salesforce.wait_until_loading_is_complete()
|
|
50
|
+
self.selenium.wait_until_page_contains_element(search_button)
|
|
51
|
+
self.selenium.press_keys(search_button, object_name, "RETURN")
|
|
52
|
+
object_locator = object_manager["object_result"].format(object_name)
|
|
53
|
+
self.selenium.wait_until_element_is_visible(object_locator)
|
|
54
|
+
self.salesforce._jsclick(object_locator)
|
|
55
|
+
self.selenium.wait_until_location_contains("Details/view", timeout=90)
|
|
56
|
+
|
|
57
|
+
def _is_current_page(self):
|
|
58
|
+
self.selenium.location_should_contain("Details/view")
|
|
59
|
+
|
|
60
|
+
@capture_screenshot_on_error
|
|
61
|
+
def switch_tab_to(self, tab):
|
|
62
|
+
"""Clicks on the name of the tab specified and sets the page view to be on the tab specified
|
|
63
|
+
Example
|
|
64
|
+
| Switch Tab To Fields & Relationships
|
|
65
|
+
"""
|
|
66
|
+
leftnavoption = object_manager["link-text"].format(tab)
|
|
67
|
+
self.selenium.click_element(leftnavoption)
|
|
68
|
+
|
|
69
|
+
def _is_current_tab(self, tab):
|
|
70
|
+
tab_view = f"{tab}/view"
|
|
71
|
+
self.selenium.location_should_contain(tab_view)
|
|
72
|
+
|
|
73
|
+
@capture_screenshot_on_error
|
|
74
|
+
def create_currency_field(self, field_name):
|
|
75
|
+
"""Creates a currency field by taking in the field name"""
|
|
76
|
+
self.selenium.wait_until_page_contains_element(currency_locator, timeout=60)
|
|
77
|
+
self.selenium.click_element(currency_locator)
|
|
78
|
+
self.selenium.wait_until_page_contains_element(next_button, 60)
|
|
79
|
+
self.selenium.click_element(next_button)
|
|
80
|
+
self.salesforce.populate_field("Field Label", field_name)
|
|
81
|
+
self.salesforce.populate_field("Length", "16")
|
|
82
|
+
self.salesforce.populate_field("Decimal Places", "2")
|
|
83
|
+
self.salesforce.populate_field(
|
|
84
|
+
"Description", "This is a custom field generated during automation"
|
|
85
|
+
)
|
|
86
|
+
self.selenium.click_element(next_button)
|
|
87
|
+
self.selenium.click_element(next_button)
|
|
88
|
+
self.selenium.click_element(save_button)
|
|
89
|
+
self.selenium.wait_until_location_contains(
|
|
90
|
+
"FieldsAndRelationships/view",
|
|
91
|
+
timeout=90,
|
|
92
|
+
message="Fields And Relationships page did not load in 1 min",
|
|
93
|
+
)
|
|
94
|
+
|
|
95
|
+
@capture_screenshot_on_error
|
|
96
|
+
def create_text_field(self, field_name):
|
|
97
|
+
"""Creates a text field by taking in the field name"""
|
|
98
|
+
self.selenium.wait_until_page_contains_element(text_locator, timeout=60)
|
|
99
|
+
self.selenium.click_element(text_locator)
|
|
100
|
+
self.selenium.click_element(next_button)
|
|
101
|
+
self.salesforce.populate_field("Field Label", field_name)
|
|
102
|
+
self.salesforce.populate_field("Length", "255")
|
|
103
|
+
self.salesforce.populate_field(
|
|
104
|
+
"Description", "This is a custom field generated during automation"
|
|
105
|
+
)
|
|
106
|
+
self.selenium.click_element(next_button)
|
|
107
|
+
self.selenium.click_element(next_button)
|
|
108
|
+
self.selenium.click_element(save_button)
|
|
109
|
+
self.selenium.wait_until_location_contains(
|
|
110
|
+
"FieldsAndRelationships/view",
|
|
111
|
+
timeout=90,
|
|
112
|
+
message="Fields And Relationships page did not load in 1 min",
|
|
113
|
+
)
|
|
114
|
+
|
|
115
|
+
@capture_screenshot_on_error
|
|
116
|
+
def create_formula_field(self, field_name, formula):
|
|
117
|
+
"""Creates a formula field by providing the field_name, formula and forumla fields"""
|
|
118
|
+
self.selenium.wait_until_page_contains_element(formula_locator, 60)
|
|
119
|
+
self.selenium.click_element(formula_locator)
|
|
120
|
+
self.selenium.wait_until_page_contains_element(next_button, 60)
|
|
121
|
+
self.selenium.click_element(next_button)
|
|
122
|
+
self.salesforce.populate_field("Field Label", field_name)
|
|
123
|
+
self.selenium.wait_until_page_contains_element(checkbox_option, 60)
|
|
124
|
+
self.selenium.click_element(checkbox_option)
|
|
125
|
+
self.selenium.click_element(next_button)
|
|
126
|
+
self.selenium.wait_until_page_contains_element(formula_txtarea, 60)
|
|
127
|
+
self.selenium.get_webelement(formula_txtarea).send_keys(formula)
|
|
128
|
+
self.selenium.click_element(check_syntax)
|
|
129
|
+
self.selenium.click_element(next_button)
|
|
130
|
+
self.selenium.click_element(next_button)
|
|
131
|
+
self.selenium.click_element(save_button)
|
|
132
|
+
self.selenium.wait_until_location_contains(
|
|
133
|
+
"FieldsAndRelationships/view",
|
|
134
|
+
timeout=90,
|
|
135
|
+
message="Detail page did not load in 1 min",
|
|
136
|
+
)
|
|
137
|
+
|
|
138
|
+
def create_lookup_field(self, field_name, related):
|
|
139
|
+
"""Creates a Lookup field by taking in the inputs field_name and related field"""
|
|
140
|
+
option = object_manager["select_related_option"].format(related)
|
|
141
|
+
related = object_manager["select_related"].format("DomainEnumOrId")
|
|
142
|
+
self.selenium.wait_until_page_contains_element(lookup_locator, 60)
|
|
143
|
+
self.selenium.click_element(lookup_locator)
|
|
144
|
+
self.selenium.wait_until_page_contains_element(next_button, 60)
|
|
145
|
+
self.selenium.click_element(next_button)
|
|
146
|
+
self.selenium.wait_until_page_contains_element(related, 60)
|
|
147
|
+
self.salesforce.scroll_element_into_view(related)
|
|
148
|
+
self.selenium.get_webelement(related).click()
|
|
149
|
+
self.selenium.click_element(option)
|
|
150
|
+
self.selenium.wait_until_page_contains_element(next_button, 60)
|
|
151
|
+
self.selenium.click_element(next_button)
|
|
152
|
+
self.salesforce.populate_field("Field Label", field_name)
|
|
153
|
+
self.salesforce.populate_field(
|
|
154
|
+
"Description", "This is a custom field generated during automation"
|
|
155
|
+
)
|
|
156
|
+
self.selenium.click_element(next_button)
|
|
157
|
+
self.selenium.click_element(next_button)
|
|
158
|
+
self.selenium.click_element(next_button)
|
|
159
|
+
self.selenium.click_element(save_button)
|
|
160
|
+
self.selenium.wait_until_location_contains(
|
|
161
|
+
"FieldsAndRelationships/view",
|
|
162
|
+
timeout=90,
|
|
163
|
+
message="Detail page did not load in 1 min",
|
|
164
|
+
)
|
|
165
|
+
|
|
166
|
+
@capture_screenshot_on_error
|
|
167
|
+
def is_field_present(self, field_name):
|
|
168
|
+
"""Searches for the field name (field_name) and asserts the field got created"""
|
|
169
|
+
self.selenium.wait_until_page_contains_element(search_button)
|
|
170
|
+
self.selenium.clear_element_text(search_button)
|
|
171
|
+
self.selenium.press_keys(search_button, field_name, "ENTER")
|
|
172
|
+
self.selenium.wait_until_element_is_not_visible("sf:spinner")
|
|
173
|
+
search_results = object_manager["search_result"].format(field_name)
|
|
174
|
+
self.selenium.wait_until_page_contains_element(search_results)
|
|
175
|
+
|
|
176
|
+
@capture_screenshot_on_error
|
|
177
|
+
def delete_custom_field(self, field_name):
|
|
178
|
+
"""Searches for the custom field and performs the delete action from the actions menu next to the field"""
|
|
179
|
+
action_menu_button = actions_menu.format(field_name)
|
|
180
|
+
self.is_field_present(field_name)
|
|
181
|
+
|
|
182
|
+
self.selenium.wait_until_page_contains_element(action_menu_button)
|
|
183
|
+
self.salesforce.scroll_element_into_view(action_menu_button)
|
|
184
|
+
|
|
185
|
+
# I don't know why, but sometimes clicking the action menu just
|
|
186
|
+
# doesn't work. The menu doesn't appear, or clicking the item on
|
|
187
|
+
# the menu does nothing. So, we'll try and handful of times.
|
|
188
|
+
# Yes, this feels icky.
|
|
189
|
+
for tries in range(5):
|
|
190
|
+
try:
|
|
191
|
+
self.selenium.wait_until_element_is_visible(action_menu_button)
|
|
192
|
+
self.selenium.click_element(action_menu_button)
|
|
193
|
+
self.selenium.wait_until_element_is_visible(
|
|
194
|
+
action_item_delete, timeout="5 seconds"
|
|
195
|
+
)
|
|
196
|
+
self.selenium.click_element(action_item_delete, action_chain=True)
|
|
197
|
+
self.selenium.wait_until_element_is_visible(
|
|
198
|
+
confirm_delete, timeout="5 seconds"
|
|
199
|
+
)
|
|
200
|
+
self.selenium.click_element(confirm_delete, action_chain=True)
|
|
201
|
+
self.selenium.wait_until_location_contains("/view", timeout=90)
|
|
202
|
+
return
|
|
203
|
+
|
|
204
|
+
except Exception as e:
|
|
205
|
+
self.builtin.log(
|
|
206
|
+
f"on try #{tries+1} we caught this error: {e}", "DEBUG"
|
|
207
|
+
)
|
|
208
|
+
self.builtin.sleep("1 second")
|
|
209
|
+
last_error = e
|
|
210
|
+
raise (last_error)
|
|
211
|
+
|
|
212
|
+
@capture_screenshot_on_error
|
|
213
|
+
def create_custom_field(self, **kwargs):
|
|
214
|
+
"""creates a custom field if one doesn't already exist by the given name (Field_Name)
|
|
215
|
+
| Example
|
|
216
|
+
| Create custom field
|
|
217
|
+
| ... Object=Payment
|
|
218
|
+
| ... Field_Type=Formula
|
|
219
|
+
| ... Field_Name=Is Opportunity From Prior Year
|
|
220
|
+
| ... Formula=YEAR( npe01__Opportunity__r.CloseDate ) < YEAR( npe01__Payment_Date__c )
|
|
221
|
+
"""
|
|
222
|
+
self.selenium.wait_until_page_contains_element(search_button, 60)
|
|
223
|
+
self.selenium.get_webelement(search_button).send_keys(kwargs["Field_Name"])
|
|
224
|
+
self.selenium.get_webelement(search_button).send_keys(Keys.ENTER)
|
|
225
|
+
self.salesforce.wait_until_loading_is_complete()
|
|
226
|
+
search_results = object_manager["search_result"].format(kwargs["Field_Name"])
|
|
227
|
+
count = len(self.selenium.get_webelements(search_results))
|
|
228
|
+
if count != 1:
|
|
229
|
+
locator = object_manager["button-with-text"].format("New")
|
|
230
|
+
self.selenium.wait_until_page_contains_element(locator, 60)
|
|
231
|
+
self.selenium.get_webelement(locator).click()
|
|
232
|
+
self.salesforce.wait_until_loading_is_complete()
|
|
233
|
+
framelocator = object_manager["frame_new"].format("vfFrameId", "vfFrameId")
|
|
234
|
+
self.selenium.wait_until_element_is_visible(framelocator, timeout=60)
|
|
235
|
+
frame = self.selenium.get_webelement(framelocator)
|
|
236
|
+
self.selenium.select_frame(frame)
|
|
237
|
+
type = kwargs["Field_Type"]
|
|
238
|
+
if type.lower() == "lookup":
|
|
239
|
+
self.create_lookup_field(kwargs["Field_Name"], kwargs["Related_To"])
|
|
240
|
+
elif type.lower() == "currency":
|
|
241
|
+
self.create_currency_field(kwargs["Field_Name"])
|
|
242
|
+
elif type.lower() == "formula":
|
|
243
|
+
self.create_formula_field(kwargs["Field_Name"], kwargs["Formula"])
|
|
244
|
+
elif type.lower() == "text":
|
|
245
|
+
self.create_text_field(kwargs["Field_Name"])
|
|
246
|
+
self.selenium.unselect_frame()
|