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,158 @@
|
|
|
1
|
+
from unittest import mock
|
|
2
|
+
|
|
3
|
+
import pytest
|
|
4
|
+
|
|
5
|
+
from cumulusci.robotframework.locator_manager import (
|
|
6
|
+
LOCATORS,
|
|
7
|
+
locate_element,
|
|
8
|
+
register_locators,
|
|
9
|
+
translate_locator,
|
|
10
|
+
)
|
|
11
|
+
|
|
12
|
+
mock_libs = {}
|
|
13
|
+
|
|
14
|
+
|
|
15
|
+
def mock_get_library_instance(name):
|
|
16
|
+
mock_libs[name] = mock.Mock(name=name)
|
|
17
|
+
return mock_libs[name]
|
|
18
|
+
|
|
19
|
+
|
|
20
|
+
class TestTranslateLocator:
|
|
21
|
+
@classmethod
|
|
22
|
+
def setup_class(cls):
|
|
23
|
+
LOCATORS.clear()
|
|
24
|
+
register_locators(
|
|
25
|
+
prefix="test",
|
|
26
|
+
locators={
|
|
27
|
+
"foo": {
|
|
28
|
+
"message": "{} {}",
|
|
29
|
+
"bar": {
|
|
30
|
+
"baz": "//div[@class='baz']",
|
|
31
|
+
"hello": "//span[text()='Hello, {}']",
|
|
32
|
+
},
|
|
33
|
+
},
|
|
34
|
+
"action": "//span[@name='{title}' or @title='{title}']//a[.='{link}']",
|
|
35
|
+
},
|
|
36
|
+
)
|
|
37
|
+
|
|
38
|
+
def test_named_format_fields(self):
|
|
39
|
+
"""This tests that named format fields are given positional arguments in the correct order"""
|
|
40
|
+
loc = translate_locator("test", "action:User,Clear")
|
|
41
|
+
assert loc == "//span[@name='User' or @title='User']//a[.='Clear']"
|
|
42
|
+
|
|
43
|
+
def test_strip_whitespace_from_locator(self):
|
|
44
|
+
"""Verify whitespace is stripped from locator key and args"""
|
|
45
|
+
loc = translate_locator("test", "foo . bar . baz")
|
|
46
|
+
assert loc == "//div[@class='baz']"
|
|
47
|
+
|
|
48
|
+
def test_nested_locators(self):
|
|
49
|
+
"""Verify dot notation can be used to drill into nested structure"""
|
|
50
|
+
loc = translate_locator("test", "foo.bar.baz")
|
|
51
|
+
assert loc == "//div[@class='baz']"
|
|
52
|
+
|
|
53
|
+
def test_arguments(self):
|
|
54
|
+
"""Verify arguments appear in the final locator"""
|
|
55
|
+
loc = translate_locator("test", "foo.bar.hello:world")
|
|
56
|
+
assert loc == "//span[text()='Hello, world']"
|
|
57
|
+
|
|
58
|
+
def test_multiple_arguments(self):
|
|
59
|
+
"""Verify we support more than a single argument"""
|
|
60
|
+
loc = translate_locator("test", "foo.message:hello,world")
|
|
61
|
+
assert loc == "hello world"
|
|
62
|
+
|
|
63
|
+
def test_extra_args(self):
|
|
64
|
+
"""Verify extra args are ignored
|
|
65
|
+
|
|
66
|
+
Maybe we should be throwing an error, but since `.format()`
|
|
67
|
+
doesn't throw an error, we would have to add our own argument
|
|
68
|
+
checking which I think is more trouble than its worth
|
|
69
|
+
"""
|
|
70
|
+
loc = translate_locator("test", "foo.message:testing,one,two,three")
|
|
71
|
+
assert loc == "testing one"
|
|
72
|
+
|
|
73
|
+
def test_missing_args(self):
|
|
74
|
+
"""Verify a friendly exception is thrown for missing arguments"""
|
|
75
|
+
expected_error = "Not enough arguments were supplied"
|
|
76
|
+
with pytest.raises(Exception, match=expected_error):
|
|
77
|
+
translate_locator("test", "foo.bar.hello")
|
|
78
|
+
|
|
79
|
+
def test_bad_locator(self):
|
|
80
|
+
"""Verify a locator that resolves to a non-string raises an error"""
|
|
81
|
+
expected_error = "Expected locator to be of type string, but was <class 'dict'>"
|
|
82
|
+
with pytest.raises(TypeError, match=expected_error):
|
|
83
|
+
translate_locator("test", "foo.bar")
|
|
84
|
+
|
|
85
|
+
def test_unknown_locator(self):
|
|
86
|
+
"""Verify that an invalid locator path throws a useful error
|
|
87
|
+
|
|
88
|
+
Not only that, but verify that what appears in the error is
|
|
89
|
+
the first part of the locator key that wasn't found.
|
|
90
|
+
"""
|
|
91
|
+
expected_error = "locator test:foo.not not found"
|
|
92
|
+
with pytest.raises(Exception, match=expected_error):
|
|
93
|
+
translate_locator("test", "foo.not.valid")
|
|
94
|
+
|
|
95
|
+
|
|
96
|
+
class TestLocateElement:
|
|
97
|
+
@classmethod
|
|
98
|
+
def setup_class(cls):
|
|
99
|
+
LOCATORS.clear()
|
|
100
|
+
register_locators(
|
|
101
|
+
prefix="test",
|
|
102
|
+
locators={"foo": {"bar": {"hello": "//span[text()='Hello, {}']"}}},
|
|
103
|
+
)
|
|
104
|
+
|
|
105
|
+
def test_locate_element(self):
|
|
106
|
+
"""Verify that the locate_element function translates the
|
|
107
|
+
locator and calls SeleniumLibrary.get_webelement with the
|
|
108
|
+
translated locator.
|
|
109
|
+
|
|
110
|
+
That is to say, this verifies that our registered locators
|
|
111
|
+
are actually usable with Selenium keywords.
|
|
112
|
+
"""
|
|
113
|
+
|
|
114
|
+
locator = "foo.bar.hello:world"
|
|
115
|
+
parent = mock.Mock()
|
|
116
|
+
tag = ""
|
|
117
|
+
constraints = {}
|
|
118
|
+
|
|
119
|
+
with mock.patch(
|
|
120
|
+
"robot.libraries.BuiltIn.BuiltIn.get_library_instance",
|
|
121
|
+
side_effect=mock_get_library_instance,
|
|
122
|
+
):
|
|
123
|
+
locate_element("test", parent, locator, tag, constraints)
|
|
124
|
+
mock_libs["SeleniumLibrary"].get_webelements.assert_called_with(
|
|
125
|
+
"//span[text()='Hello, world']"
|
|
126
|
+
)
|
|
127
|
+
|
|
128
|
+
|
|
129
|
+
class TestRegisterLocators:
|
|
130
|
+
def setup_method(self):
|
|
131
|
+
LOCATORS.clear()
|
|
132
|
+
|
|
133
|
+
def test_register_locators(self):
|
|
134
|
+
"""Verify that register_locators updates the LOCATORS dictionary"""
|
|
135
|
+
register_locators("test", {"foo": "//div/foo"})
|
|
136
|
+
|
|
137
|
+
expected = {"test": {"foo": "//div/foo"}}
|
|
138
|
+
assert LOCATORS == expected
|
|
139
|
+
|
|
140
|
+
def test_multiple_registrations(self):
|
|
141
|
+
"""Verify that more than one prefix can be registered"""
|
|
142
|
+
|
|
143
|
+
register_locators("test1", {"foo": "//div/foo"})
|
|
144
|
+
register_locators("test2", {"bar": "//div/bar"})
|
|
145
|
+
|
|
146
|
+
expected = {"test1": {"foo": "//div/foo"}, "test2": {"bar": "//div/bar"}}
|
|
147
|
+
assert LOCATORS == expected
|
|
148
|
+
|
|
149
|
+
def test_register_locators_merge(self):
|
|
150
|
+
"""Verify that calling register_locators will merge the new locators
|
|
151
|
+
with existing locators for a given prefix, rather than
|
|
152
|
+
replacing them.
|
|
153
|
+
"""
|
|
154
|
+
register_locators("test1", {"foo": {"one": "//div/one"}})
|
|
155
|
+
register_locators("test1", {"foo": {"two": "//div/two"}})
|
|
156
|
+
|
|
157
|
+
expected = {"test1": {"foo": {"one": "//div/one", "two": "//div/two"}}}
|
|
158
|
+
assert LOCATORS == expected
|
|
@@ -0,0 +1,291 @@
|
|
|
1
|
+
"""Tests for the PageObjects class
|
|
2
|
+
|
|
3
|
+
Testing notes:
|
|
4
|
+
|
|
5
|
+
The PageObjects library uses robot's BuiltIn library. However,
|
|
6
|
+
instantiating that will throw an error if done outside the context of
|
|
7
|
+
a running robot test. To work around that, these tests mock out the
|
|
8
|
+
_get_context method to fool the BuiltIn library into not complaining.
|
|
9
|
+
|
|
10
|
+
These tests use two external files in the same directory as this test:
|
|
11
|
+
FooTestPage.py and BarTestPage.py. FooTestPage has a single keyword,
|
|
12
|
+
BarTestPage has two.
|
|
13
|
+
|
|
14
|
+
"""
|
|
15
|
+
|
|
16
|
+
import os.path
|
|
17
|
+
import sys
|
|
18
|
+
from contextlib import contextmanager
|
|
19
|
+
from unittest import mock
|
|
20
|
+
|
|
21
|
+
import pytest
|
|
22
|
+
import robot.utils
|
|
23
|
+
from robot.libraries.BuiltIn import BuiltIn
|
|
24
|
+
|
|
25
|
+
from cumulusci.robotframework import PageObjects
|
|
26
|
+
from cumulusci.robotframework.CumulusCI import CumulusCI
|
|
27
|
+
from cumulusci.robotframework.pageobjects.BasePageObjects import (
|
|
28
|
+
DetailPage,
|
|
29
|
+
HomePage,
|
|
30
|
+
ListingPage,
|
|
31
|
+
)
|
|
32
|
+
from cumulusci.robotframework.pageobjects.PageObjectLibrary import _PageObjectLibrary
|
|
33
|
+
from cumulusci.utils import temporary_dir
|
|
34
|
+
|
|
35
|
+
HERE = os.path.dirname(__file__)
|
|
36
|
+
FOO_PATH = os.path.join(HERE, "FooTestPage.py")
|
|
37
|
+
CUSTOM_PATH = os.path.join(HERE, "CustomObjectTestPage.py")
|
|
38
|
+
|
|
39
|
+
# this is the importer used by the page objects, which makes it easy
|
|
40
|
+
# peasy to import by file path
|
|
41
|
+
importer = robot.utils.Importer()
|
|
42
|
+
|
|
43
|
+
# These tests don't need an org, so mocking it out will prevent some
|
|
44
|
+
# keywords from trying to create the org.
|
|
45
|
+
cci_lib = CumulusCI()
|
|
46
|
+
cci_lib._org = mock.Mock()
|
|
47
|
+
|
|
48
|
+
|
|
49
|
+
class MockGetLibraryInstance:
|
|
50
|
+
"""Mock robot's get_library_instance method
|
|
51
|
+
|
|
52
|
+
This will return instances of the libraries used in this set of tests.
|
|
53
|
+
"""
|
|
54
|
+
|
|
55
|
+
libs = {
|
|
56
|
+
"SeleniumLibrary": mock.Mock(),
|
|
57
|
+
"cumulusci.robotframework.CumulusCI": cci_lib,
|
|
58
|
+
"cumulusci.robotframework.Salesforce": mock.Mock(),
|
|
59
|
+
"cumulusci.robotframework.SalesforceAPI": mock.Mock(),
|
|
60
|
+
# Note: the fact that we're using "Contact" here is largely
|
|
61
|
+
# irrelevant. The important thing is that we create a page
|
|
62
|
+
# object for the base types of Home, Listing,and Detail
|
|
63
|
+
"ContactHomePage": _PageObjectLibrary(HomePage("Contact")),
|
|
64
|
+
"ContactListingPage": _PageObjectLibrary(ListingPage("Contact")),
|
|
65
|
+
"ContactDetailPage": _PageObjectLibrary(DetailPage("Contact")),
|
|
66
|
+
}
|
|
67
|
+
|
|
68
|
+
def __call__(self, libname):
|
|
69
|
+
if libname in self.libs:
|
|
70
|
+
return self.libs[libname]
|
|
71
|
+
else:
|
|
72
|
+
raise Exception("unknown library: {}".format(libname))
|
|
73
|
+
|
|
74
|
+
|
|
75
|
+
@contextmanager
|
|
76
|
+
def reload_PageObjects(*args):
|
|
77
|
+
# Reset the registry and re-import the built-in page objects
|
|
78
|
+
saved_registry = PageObjects.registry
|
|
79
|
+
PageObjects._reset()
|
|
80
|
+
import cumulusci.robotframework.pageobjects.BasePageObjects # noqa: F401
|
|
81
|
+
import cumulusci.robotframework.pageobjects.ObjectManagerPageObject # noqa: F401
|
|
82
|
+
|
|
83
|
+
yield PageObjects(*args)
|
|
84
|
+
|
|
85
|
+
PageObjects._reset()
|
|
86
|
+
PageObjects.registry = saved_registry
|
|
87
|
+
|
|
88
|
+
|
|
89
|
+
@mock.patch(
|
|
90
|
+
"robot.libraries.BuiltIn.BuiltIn.get_library_instance",
|
|
91
|
+
side_effect=MockGetLibraryInstance(),
|
|
92
|
+
)
|
|
93
|
+
# We have to mock out _get_context or the robot libraries will
|
|
94
|
+
# throw an exception saying it cannot access the execution context.
|
|
95
|
+
@mock.patch("robot.libraries.BuiltIn.BuiltIn._get_context")
|
|
96
|
+
class TestPageObjects:
|
|
97
|
+
def test_PageObject(self, get_context_mock, get_library_instance_mock):
|
|
98
|
+
"""Smoke test to make sure the default registry is set up and keywords exist"""
|
|
99
|
+
|
|
100
|
+
with reload_PageObjects() as po:
|
|
101
|
+
expected_keywords = [
|
|
102
|
+
"current_page_should_be",
|
|
103
|
+
"get_page_object",
|
|
104
|
+
"go_to_page",
|
|
105
|
+
"load_page_object",
|
|
106
|
+
"log_page_object_keywords",
|
|
107
|
+
"wait_for_modal",
|
|
108
|
+
"wait_for_page_object",
|
|
109
|
+
]
|
|
110
|
+
actual_keywords = po.get_keyword_names()
|
|
111
|
+
assert actual_keywords == expected_keywords
|
|
112
|
+
|
|
113
|
+
# fmt: off
|
|
114
|
+
# This is much easier to read than if black were to reformat it.
|
|
115
|
+
expected_registry = {
|
|
116
|
+
("Detail", ""): "<class 'cumulusci.robotframework.pageobjects.BasePageObjects.DetailPage'>",
|
|
117
|
+
("Edit", ""): "<class 'cumulusci.robotframework.pageobjects.BasePageObjects.EditModal'>",
|
|
118
|
+
("Home", ""): "<class 'cumulusci.robotframework.pageobjects.BasePageObjects.HomePage'>",
|
|
119
|
+
("Listing", ""): "<class 'cumulusci.robotframework.pageobjects.BasePageObjects.ListingPage'>",
|
|
120
|
+
("New", ""): "<class 'cumulusci.robotframework.pageobjects.BasePageObjects.NewModal'>",
|
|
121
|
+
("ObjectManager", ""): "<class 'cumulusci.robotframework.pageobjects.ObjectManagerPageObject.ObjectManagerPage'>",
|
|
122
|
+
}
|
|
123
|
+
# fmt: on
|
|
124
|
+
actual_registry = {key: repr(value) for key, value in po.registry.items()}
|
|
125
|
+
assert actual_registry == expected_registry
|
|
126
|
+
|
|
127
|
+
def test_file_in_pythonpath(self, get_context_mock, get_library_instance_mock):
|
|
128
|
+
"""Verify we can find a page object via PYTHONPATH"""
|
|
129
|
+
# PageObjects will throw an error if it can't find the file.
|
|
130
|
+
# As long as this doesn't throw an error, we're golden.
|
|
131
|
+
sys_path = sys.path.copy()
|
|
132
|
+
if HERE not in sys.path:
|
|
133
|
+
sys_path.append(HERE)
|
|
134
|
+
with mock.patch.object(sys, "path", sys_path):
|
|
135
|
+
PageObjects("FooTestPage.py")
|
|
136
|
+
|
|
137
|
+
def test_exception_not_found(self, get_context_mock, get_library_instance_mock):
|
|
138
|
+
"""Verify we get an assertion of we can't find a page object file"""
|
|
139
|
+
with pytest.raises(
|
|
140
|
+
ImportError, match="Unable to find page object file 'bogus.py'"
|
|
141
|
+
):
|
|
142
|
+
PageObjects("bogus.py")
|
|
143
|
+
|
|
144
|
+
def test_import_failed(self, get_context_mock, get_library_instance_mock):
|
|
145
|
+
with temporary_dir() as d:
|
|
146
|
+
with open("busted.py", "w") as f:
|
|
147
|
+
f.write("class Busted # incomplete class\n")
|
|
148
|
+
f.close()
|
|
149
|
+
with mock.patch.object(sys, "path", sys.path + [d]):
|
|
150
|
+
with pytest.raises(
|
|
151
|
+
ImportError,
|
|
152
|
+
match="Unable to import page object 'busted.py': .*",
|
|
153
|
+
):
|
|
154
|
+
PageObjects("busted.py")
|
|
155
|
+
|
|
156
|
+
def test_PageObject_registry_with_custom_pageobjects(
|
|
157
|
+
self, get_context_mock, get_library_instance_mock
|
|
158
|
+
):
|
|
159
|
+
"""Verify that custom page objects get added to the registry"""
|
|
160
|
+
with reload_PageObjects(FOO_PATH, CUSTOM_PATH) as po:
|
|
161
|
+
# fmt: off
|
|
162
|
+
# This is much easier to read than if black were to reformat it.
|
|
163
|
+
expected_registry = {
|
|
164
|
+
("Detail", ""): "<class 'cumulusci.robotframework.pageobjects.BasePageObjects.DetailPage'>",
|
|
165
|
+
("Edit", ""): "<class 'cumulusci.robotframework.pageobjects.BasePageObjects.EditModal'>",
|
|
166
|
+
("Home", ""): "<class 'cumulusci.robotframework.pageobjects.BasePageObjects.HomePage'>",
|
|
167
|
+
("Listing", ""): "<class 'cumulusci.robotframework.pageobjects.BasePageObjects.ListingPage'>",
|
|
168
|
+
("New", ""): "<class 'cumulusci.robotframework.pageobjects.BasePageObjects.NewModal'>",
|
|
169
|
+
("ObjectManager", ""): "<class 'cumulusci.robotframework.pageobjects.ObjectManagerPageObject.ObjectManagerPage'>",
|
|
170
|
+
# the custom page object uses an alias for the object name so it will be in the registry twice
|
|
171
|
+
("Listing", "CustomObject__c"): "<class 'CustomObjectTestPage.CustomObjectListingPage'>",
|
|
172
|
+
("Listing", "Custom Object"): "<class 'CustomObjectTestPage.CustomObjectListingPage'>",
|
|
173
|
+
("Test", "Foo__c"): "<class 'FooTestPage.FooTestPage'>",
|
|
174
|
+
}
|
|
175
|
+
# fmt: on
|
|
176
|
+
actual_registry = {key: repr(value) for key, value in po.registry.items()}
|
|
177
|
+
assert actual_registry == expected_registry
|
|
178
|
+
|
|
179
|
+
def test_namespaced_object_name(self, get_context_mock, get_library_instance_mock):
|
|
180
|
+
"""Verify that the object name is prefixed by the namespace when there's a namespace"""
|
|
181
|
+
with mock.patch.object(
|
|
182
|
+
CumulusCI, "get_namespace_prefix", return_value="foobar__"
|
|
183
|
+
):
|
|
184
|
+
with reload_PageObjects(FOO_PATH) as po:
|
|
185
|
+
|
|
186
|
+
FooTestPage = importer.import_class_or_module_by_path(FOO_PATH)
|
|
187
|
+
MockGetLibraryInstance.libs["FooTestPage"] = _PageObjectLibrary(
|
|
188
|
+
FooTestPage()
|
|
189
|
+
)
|
|
190
|
+
|
|
191
|
+
pobj = po.get_page_object("Test", "Foo__c")
|
|
192
|
+
assert pobj.object_name == "foobar__Foo__c"
|
|
193
|
+
|
|
194
|
+
def test_non_namespaced_object_name(
|
|
195
|
+
self, get_context_mock, get_library_instance_mock
|
|
196
|
+
):
|
|
197
|
+
"""Verify that the object name is not prefixed by a namespace when there is no namespace"""
|
|
198
|
+
with mock.patch.object(CumulusCI, "get_namespace_prefix", return_value=""):
|
|
199
|
+
with reload_PageObjects(FOO_PATH) as po:
|
|
200
|
+
|
|
201
|
+
FooTestPage = importer.import_class_or_module_by_path(FOO_PATH)
|
|
202
|
+
MockGetLibraryInstance.libs["FooTestPage"] = _PageObjectLibrary(
|
|
203
|
+
FooTestPage()
|
|
204
|
+
)
|
|
205
|
+
|
|
206
|
+
pobj = po.get_page_object("Test", "Foo__c")
|
|
207
|
+
assert pobj.object_name == "Foo__c"
|
|
208
|
+
|
|
209
|
+
def test_go_to_page_with_locator(self, get_context_mock, get_library_instance_mock):
|
|
210
|
+
"""Verify 'Go to page' accepts and uses a locator argument
|
|
211
|
+
|
|
212
|
+
See W-8580487 for more details
|
|
213
|
+
"""
|
|
214
|
+
|
|
215
|
+
with reload_PageObjects() as po:
|
|
216
|
+
for page_type in ("Home", "Listing", "Detail"):
|
|
217
|
+
# the exact locator isn't important for the test, we
|
|
218
|
+
# just need to make sure it is passed on to
|
|
219
|
+
# wait_until_loading_is_complete
|
|
220
|
+
locator = f"//div[@class='{page_type}']"
|
|
221
|
+
po.go_to_page(page_type, "Contact", locator=locator)
|
|
222
|
+
sflib = BuiltIn().get_library_instance(
|
|
223
|
+
"cumulusci.robotframework.Salesforce"
|
|
224
|
+
)
|
|
225
|
+
sflib.wait_until_loading_is_complete.assert_called_with(locator=locator)
|
|
226
|
+
|
|
227
|
+
def test_go_to_page_without_locator(
|
|
228
|
+
self, get_context_mock, get_library_instance_mock
|
|
229
|
+
):
|
|
230
|
+
"""Verify 'Go to page' doesn't require a locator"""
|
|
231
|
+
|
|
232
|
+
with reload_PageObjects() as po:
|
|
233
|
+
for page_type in ("Home", "Listing", "Detail"):
|
|
234
|
+
po.go_to_page(page_type, "Contact")
|
|
235
|
+
sflib = BuiltIn().get_library_instance(
|
|
236
|
+
"cumulusci.robotframework.Salesforce"
|
|
237
|
+
)
|
|
238
|
+
sflib.wait_until_loading_is_complete.assert_called_with(locator=None)
|
|
239
|
+
|
|
240
|
+
|
|
241
|
+
@mock.patch(
|
|
242
|
+
"robot.libraries.BuiltIn.BuiltIn.get_library_instance",
|
|
243
|
+
side_effect=MockGetLibraryInstance(),
|
|
244
|
+
)
|
|
245
|
+
class TestBasePage:
|
|
246
|
+
"""Some low-level tests of page object classes"""
|
|
247
|
+
|
|
248
|
+
def test_no_implicit_wait(self, mock_get_library_instance):
|
|
249
|
+
"""Verify the "implicit wait" context manager restores the value"""
|
|
250
|
+
|
|
251
|
+
selib = BuiltIn().get_library_instance("SeleniumLibrary")
|
|
252
|
+
selib.set_selenium_implicit_wait.return_value = 7
|
|
253
|
+
selib.set_selenium_implicit_wait.reset_mock()
|
|
254
|
+
|
|
255
|
+
from cumulusci.robotframework.pageobjects import BasePage
|
|
256
|
+
|
|
257
|
+
page = BasePage()
|
|
258
|
+
with page._no_implicit_wait():
|
|
259
|
+
pass
|
|
260
|
+
|
|
261
|
+
# The first call should pass in zero to turn off the
|
|
262
|
+
# implicit wait. We've configured the mocked function to
|
|
263
|
+
# return '7'. The second call should pass the return value
|
|
264
|
+
# of the first call
|
|
265
|
+
selib.set_selenium_implicit_wait.assert_has_calls(
|
|
266
|
+
(mock.call(0), mock.call(7)), any_order=False
|
|
267
|
+
)
|
|
268
|
+
|
|
269
|
+
def test_no_implicit_wait_with_exception(self, mock_get_library_instance):
|
|
270
|
+
"""Verify the "implicit wait" context manager restores the value even if exception occurs"""
|
|
271
|
+
|
|
272
|
+
selib = BuiltIn().get_library_instance("SeleniumLibrary")
|
|
273
|
+
selib.set_selenium_implicit_wait.return_value = 42
|
|
274
|
+
selib.set_selenium_implicit_wait.reset_mock()
|
|
275
|
+
|
|
276
|
+
from cumulusci.robotframework.pageobjects import BasePage
|
|
277
|
+
|
|
278
|
+
page = BasePage()
|
|
279
|
+
try:
|
|
280
|
+
with page._no_implicit_wait():
|
|
281
|
+
raise Exception("Danger Will Robinson!")
|
|
282
|
+
except Exception:
|
|
283
|
+
pass
|
|
284
|
+
|
|
285
|
+
# The first call should pass in zero to turn off the
|
|
286
|
+
# implicit wait. We've configured the mocked function to
|
|
287
|
+
# return '42'. The second call should pass the return value
|
|
288
|
+
# of the first call
|
|
289
|
+
selib.set_selenium_implicit_wait.assert_has_calls(
|
|
290
|
+
(mock.call(0), mock.call(42)), any_order=False
|
|
291
|
+
)
|
|
@@ -0,0 +1,38 @@
|
|
|
1
|
+
from unittest import mock
|
|
2
|
+
|
|
3
|
+
import pytest
|
|
4
|
+
|
|
5
|
+
from cumulusci.robotframework.Performance import Performance
|
|
6
|
+
from cumulusci.robotframework.SalesforceAPI import SalesforceAPI
|
|
7
|
+
|
|
8
|
+
|
|
9
|
+
class TestKeyword_elapsed_time_for_last_record:
|
|
10
|
+
def test_elapsed_time_for_last_record__query_empty(self):
|
|
11
|
+
perflib = Performance()
|
|
12
|
+
records = {"records": []}
|
|
13
|
+
|
|
14
|
+
with mock.patch.object(perflib, "_salesforce_api", SalesforceAPI()):
|
|
15
|
+
with mock.patch.object(SalesforceAPI, "cumulusci") as cumulusci:
|
|
16
|
+
cumulusci.sf.query_all.return_value = records
|
|
17
|
+
with pytest.raises(Exception) as e:
|
|
18
|
+
perflib.elapsed_time_for_last_record("FOO", "Bar", "Baz", "Baz")
|
|
19
|
+
assert "Matching record not found" in str(e.value)
|
|
20
|
+
|
|
21
|
+
def test_elapsed_time_for_last_record__query_returns_result(self):
|
|
22
|
+
perflib = Performance()
|
|
23
|
+
records = {
|
|
24
|
+
"records": [
|
|
25
|
+
{
|
|
26
|
+
"CreatedDate": "2020-12-29T10:00:01.000+0000",
|
|
27
|
+
"CompletedDate": "2020-12-29T10:00:04.000+0000",
|
|
28
|
+
}
|
|
29
|
+
],
|
|
30
|
+
}
|
|
31
|
+
|
|
32
|
+
with mock.patch.object(perflib, "_salesforce_api", SalesforceAPI()):
|
|
33
|
+
with mock.patch.object(SalesforceAPI, "cumulusci") as cumulusci:
|
|
34
|
+
cumulusci.sf.query_all.return_value = records
|
|
35
|
+
elapsed = perflib.elapsed_time_for_last_record(
|
|
36
|
+
"AsyncApexJob", "CreatedDate", "CompletedDate", "CompletedDate"
|
|
37
|
+
)
|
|
38
|
+
assert elapsed == 3
|
|
@@ -0,0 +1,79 @@
|
|
|
1
|
+
from unittest import mock
|
|
2
|
+
|
|
3
|
+
import pytest
|
|
4
|
+
from SeleniumLibrary.errors import ElementNotFound
|
|
5
|
+
|
|
6
|
+
from cumulusci.robotframework.Salesforce import Salesforce
|
|
7
|
+
|
|
8
|
+
|
|
9
|
+
# _init_locators has a special code block
|
|
10
|
+
class TestSeleniumLibrary:
|
|
11
|
+
def test_init_locators(self):
|
|
12
|
+
"""Verify that locators are initialized if not passed in"""
|
|
13
|
+
with mock.patch.object(Salesforce, "_init_locators"):
|
|
14
|
+
# _init_locators should NOT be called if we pass them in
|
|
15
|
+
sflib = Salesforce(locators={"body": "//whatever"})
|
|
16
|
+
assert not sflib._init_locators.called
|
|
17
|
+
|
|
18
|
+
# _init_locators SHOULD be called if we don't pass them in
|
|
19
|
+
sflib = Salesforce()
|
|
20
|
+
sflib._init_locators.assert_called_once()
|
|
21
|
+
|
|
22
|
+
|
|
23
|
+
@mock.patch("robot.libraries.BuiltIn.BuiltIn._get_context")
|
|
24
|
+
class TestKeyword_wait_until_salesforce_is_ready:
|
|
25
|
+
@classmethod
|
|
26
|
+
def setup_class(cls):
|
|
27
|
+
cls.sflib = Salesforce(locators={"body": "//whatever"})
|
|
28
|
+
|
|
29
|
+
def test_successful_page_load(self, mock_robot_context):
|
|
30
|
+
"""Verify that a succesful page load returns no errors"""
|
|
31
|
+
with mock.patch.object(Salesforce, "wait_for_aura", return_value=True):
|
|
32
|
+
self.sflib.wait_until_salesforce_is_ready(timeout="1")
|
|
33
|
+
|
|
34
|
+
self.sflib.wait_for_aura.assert_called_once()
|
|
35
|
+
self.sflib.selenium.get_webelement.assert_called_once_with("//whatever")
|
|
36
|
+
|
|
37
|
+
def test_reload_on_initial_failure(self, mock_robot_context):
|
|
38
|
+
"""Verify that we attempt a reload when we don't find the lightning component"""
|
|
39
|
+
with mock.patch.object(Salesforce, "wait_for_aura", return_value=True):
|
|
40
|
+
with mock.patch.object(
|
|
41
|
+
Salesforce, "_check_for_classic", return_value=False
|
|
42
|
+
):
|
|
43
|
+
with mock.patch.object(
|
|
44
|
+
Salesforce, "_check_for_login_failure", return_value=False
|
|
45
|
+
):
|
|
46
|
+
with mock.patch.object(
|
|
47
|
+
self.sflib.selenium,
|
|
48
|
+
"get_webelement",
|
|
49
|
+
side_effect=(ElementNotFound(), True),
|
|
50
|
+
):
|
|
51
|
+
self.sflib.wait_until_salesforce_is_ready(timeout="10")
|
|
52
|
+
self.sflib.selenium.go_to.assert_called_once()
|
|
53
|
+
|
|
54
|
+
def test_exception_and_screenshot_on_timeout(self, mock_robot_context):
|
|
55
|
+
"""Verify that we throw an appropriate exception after the timeout"""
|
|
56
|
+
with mock.patch.object(Salesforce, "wait_for_aura", return_value=True):
|
|
57
|
+
self.sflib.selenium.get_webelement.side_effect = ElementNotFound()
|
|
58
|
+
|
|
59
|
+
with pytest.raises(
|
|
60
|
+
Exception, match="Timed out waiting for a lightning page"
|
|
61
|
+
):
|
|
62
|
+
# The timeout needs to be longer than the duration of
|
|
63
|
+
# one loop iteration, but less than the retry interval
|
|
64
|
+
# of 5 seconds. Making it longer should still pass the
|
|
65
|
+
# test, it just makes the test run longer than necessary.
|
|
66
|
+
self.sflib.wait_until_salesforce_is_ready(timeout=0.1)
|
|
67
|
+
|
|
68
|
+
self.sflib.selenium.capture_page_screenshot.assert_called()
|
|
69
|
+
|
|
70
|
+
|
|
71
|
+
@mock.patch("robot.libraries.BuiltIn.BuiltIn._get_context")
|
|
72
|
+
class TestKeyword_breakpoint:
|
|
73
|
+
@classmethod
|
|
74
|
+
def setup_class(cls):
|
|
75
|
+
cls.sflib = Salesforce(locators={"body": "//whatever"})
|
|
76
|
+
|
|
77
|
+
def test_breakpoint(self, mock_robot_context):
|
|
78
|
+
"""Verify that the keyword doesn't raise an exception"""
|
|
79
|
+
assert self.sflib.breakpoint() is None
|
|
@@ -0,0 +1,73 @@
|
|
|
1
|
+
from pathlib import Path
|
|
2
|
+
from unittest import mock
|
|
3
|
+
|
|
4
|
+
from robot.libraries.BuiltIn import RobotNotRunningError
|
|
5
|
+
|
|
6
|
+
from cumulusci.robotframework.Salesforce import Salesforce
|
|
7
|
+
|
|
8
|
+
|
|
9
|
+
# FIXME: we shouldn't have to tweak these tests for every
|
|
10
|
+
# version. The tests should be smarter.
|
|
11
|
+
class TestLocators:
|
|
12
|
+
@mock.patch(
|
|
13
|
+
"cumulusci.robotframework.SalesforceAPI.SalesforceAPI.get_latest_api_version"
|
|
14
|
+
)
|
|
15
|
+
def test_locators_in_robot_context(self, get_latest_api_version):
|
|
16
|
+
"""Verify we can get locators for the current org api version"""
|
|
17
|
+
get_latest_api_version.return_value = 57.0
|
|
18
|
+
|
|
19
|
+
# This instantiates the robot library, mimicking a robot library import.
|
|
20
|
+
# We've mocked out the code that would otherwise throw an error since
|
|
21
|
+
# we're not running in the context of a robot test. The library should
|
|
22
|
+
# return the latest version of the locators.
|
|
23
|
+
sf = Salesforce()
|
|
24
|
+
|
|
25
|
+
expected = "cumulusci.robotframework.locators_57"
|
|
26
|
+
actual = sf.locators_module.__name__
|
|
27
|
+
message = "expected to load '{}', actually loaded '{}'".format(expected, actual)
|
|
28
|
+
assert expected == actual, message
|
|
29
|
+
|
|
30
|
+
@mock.patch(
|
|
31
|
+
"robot.libraries.BuiltIn.BuiltIn.get_library_instance",
|
|
32
|
+
side_effect=RobotNotRunningError(),
|
|
33
|
+
)
|
|
34
|
+
def test_locators_outside_robot_context(self, builtin_mock):
|
|
35
|
+
"""Verify that we get the latest locators if not running in the context of a robot test"""
|
|
36
|
+
|
|
37
|
+
# This instantiates the robot library, mimicing a robot library import
|
|
38
|
+
# however, because we've mocked get_library_instance to throw an error,
|
|
39
|
+
# we expect the library to still be instantiated, but with the latest
|
|
40
|
+
# version of the locators.
|
|
41
|
+
|
|
42
|
+
sf = Salesforce()
|
|
43
|
+
|
|
44
|
+
locator_folder = Path("./cumulusci/robotframework")
|
|
45
|
+
locator_modules = sorted(locator_folder.glob("locators_[0-9][0-9].py"))
|
|
46
|
+
expected = f"cumulusci.robotframework.{locator_modules[-1].stem}"
|
|
47
|
+
|
|
48
|
+
actual = sf.locators_module.__name__
|
|
49
|
+
message = "expected to load '{}', actually loaded '{}'".format(expected, actual)
|
|
50
|
+
assert expected == actual, message
|
|
51
|
+
|
|
52
|
+
def test_locators_57(self):
|
|
53
|
+
"""Verify that locators_57 is a superset of the locators_56
|
|
54
|
+
|
|
55
|
+
This test is far from perfect, but it should at least flag a
|
|
56
|
+
catastrophic error in how locators for a version that augments
|
|
57
|
+
the locators from previous versions.
|
|
58
|
+
|
|
59
|
+
Note: this test assumes that locators_56 doesn't delete any of the
|
|
60
|
+
keys from 54.
|
|
61
|
+
|
|
62
|
+
"""
|
|
63
|
+
import cumulusci.robotframework.locators_56 as locators_56
|
|
64
|
+
import cumulusci.robotframework.locators_57 as locators_57
|
|
65
|
+
|
|
66
|
+
keys_56 = set(locators_56.lex_locators)
|
|
67
|
+
keys_57 = set(locators_57.lex_locators)
|
|
68
|
+
|
|
69
|
+
assert id(locators_56.lex_locators) != id(
|
|
70
|
+
locators_57.lex_locators
|
|
71
|
+
), "locators_56.lex_locators and locators_57.lex_locators are the same object"
|
|
72
|
+
assert len(keys_56) > 0
|
|
73
|
+
assert keys_57.issubset(keys_56)
|